From 928c4fcf26174df9b8cf62d67e0061ad703481e9 Mon Sep 17 00:00:00 2001 From: pin Date: Thu, 4 Feb 2010 14:32:46 +0000 Subject: [PATCH 1/1] =?utf8?q?Cr=C3=A9ation=20branche=20pinbe=20=C3=A0=20p?= =?utf8?q?artir=20d'une=20copie=20de=20branches/V7@73.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit git-svn-id: https://svn.cri.ensmp.fr/svn/minwii/trunk@1 fe552daf-6dbe-4428-90eb-1537e0879342 --- .project | 17 + .pydevproject | 10 + .settings/org.eclipse.core.resources.prefs | 14 + WiiMouse IR G.PIE | 157 ++ WiiMouse IR coeff0.1.PIE | 166 ++ WiiMouse2IR coeff0.1.PIE | 281 ++++ WiiMouse4IR coeff0.1.PIE | 520 ++++++ src/controllers/Wiimote.py | 106 ++ src/controllers/__init__.py | 0 src/cursor/WarpingCursor.py | 155 ++ src/cursor/__init__.py | 0 src/cursor/cursorImages/black/0.png | Bin 0 -> 1499 bytes src/cursor/cursorImages/black/1.png | Bin 0 -> 1618 bytes src/cursor/cursorImages/black/10.png | Bin 0 -> 1393 bytes src/cursor/cursorImages/black/2.png | Bin 0 -> 1769 bytes src/cursor/cursorImages/black/3.png | Bin 0 -> 1917 bytes src/cursor/cursorImages/black/4.png | Bin 0 -> 2034 bytes src/cursor/cursorImages/black/5.png | Bin 0 -> 2154 bytes src/cursor/cursorImages/black/6.png | Bin 0 -> 2358 bytes src/cursor/cursorImages/black/7.png | Bin 0 -> 2450 bytes src/cursor/cursorImages/black/8.png | Bin 0 -> 2627 bytes src/cursor/cursorImages/black/9.png | Bin 0 -> 2550 bytes src/cursor/cursorImages/black/cursorBlack.svg | 99 ++ src/cursor/cursorImages/black/flash.png | Bin 0 -> 904 bytes src/cursor/cursorImages/blue/0.png | Bin 0 -> 919 bytes src/cursor/cursorImages/blue/1.png | Bin 0 -> 1021 bytes src/cursor/cursorImages/blue/10.png | Bin 0 -> 1300 bytes src/cursor/cursorImages/blue/2.png | Bin 0 -> 1120 bytes src/cursor/cursorImages/blue/3.png | Bin 0 -> 1212 bytes src/cursor/cursorImages/blue/4.png | Bin 0 -> 1281 bytes src/cursor/cursorImages/blue/5.png | Bin 0 -> 1412 bytes src/cursor/cursorImages/blue/6.png | Bin 0 -> 1542 bytes src/cursor/cursorImages/blue/7.png | Bin 0 -> 1637 bytes src/cursor/cursorImages/blue/8.png | Bin 0 -> 1788 bytes src/cursor/cursorImages/blue/9.png | Bin 0 -> 1773 bytes src/cursor/cursorImages/blue/cursorBlue.svg | 99 ++ src/cursor/cursorImages/green/0.png | Bin 0 -> 923 bytes src/cursor/cursorImages/green/1.png | Bin 0 -> 1022 bytes src/cursor/cursorImages/green/10.png | Bin 0 -> 1362 bytes src/cursor/cursorImages/green/2.png | Bin 0 -> 1131 bytes src/cursor/cursorImages/green/3.png | Bin 0 -> 1243 bytes src/cursor/cursorImages/green/4.png | Bin 0 -> 1331 bytes src/cursor/cursorImages/green/5.png | Bin 0 -> 1495 bytes src/cursor/cursorImages/green/6.png | Bin 0 -> 1617 bytes src/cursor/cursorImages/green/7.png | Bin 0 -> 1756 bytes src/cursor/cursorImages/green/8.png | Bin 0 -> 1870 bytes src/cursor/cursorImages/green/9.png | Bin 0 -> 1882 bytes src/cursor/cursorImages/green/cursorGreen.svg | 99 ++ src/cursor/cursorImages/red/0.png | Bin 0 -> 897 bytes src/cursor/cursorImages/red/1.png | Bin 0 -> 1032 bytes src/cursor/cursorImages/red/10.png | Bin 0 -> 1374 bytes src/cursor/cursorImages/red/2.png | Bin 0 -> 1127 bytes src/cursor/cursorImages/red/3.png | Bin 0 -> 1237 bytes src/cursor/cursorImages/red/4.png | Bin 0 -> 1353 bytes src/cursor/cursorImages/red/5.png | Bin 0 -> 1462 bytes src/cursor/cursorImages/red/6.png | Bin 0 -> 1605 bytes src/cursor/cursorImages/red/7.png | Bin 0 -> 1731 bytes src/cursor/cursorImages/red/8.png | Bin 0 -> 1850 bytes src/cursor/cursorImages/red/9.png | Bin 0 -> 1848 bytes src/cursor/cursorImages/red/cursorRed.svg | 99 ++ src/data/themes/default/Vera.ttf | Bin 0 -> 65932 bytes src/data/themes/default/box.down.png | Bin 0 -> 312 bytes src/data/themes/default/box.hover.png | Bin 0 -> 324 bytes src/data/themes/default/box.normal.png | Bin 0 -> 242 bytes src/data/themes/default/box.xcf | Bin 0 -> 2004 bytes src/data/themes/default/button.down.tga | Bin 0 -> 786 bytes src/data/themes/default/button.hover.tga | Bin 0 -> 776 bytes src/data/themes/default/button.normal.tga | Bin 0 -> 729 bytes src/data/themes/default/check.png | Bin 0 -> 205 bytes .../themes/default/checkbox.off.hover.tga | Bin 0 -> 442 bytes .../themes/default/checkbox.off.normal.tga | Bin 0 -> 320 bytes src/data/themes/default/checkbox.on.hover.tga | Bin 0 -> 535 bytes .../themes/default/checkbox.on.normal.tga | Bin 0 -> 500 bytes src/data/themes/default/config.txt | 291 ++++ .../themes/default/console.input.focus.png | Bin 0 -> 224 bytes .../themes/default/console.input.normal.png | Bin 0 -> 224 bytes src/data/themes/default/console.png | Bin 0 -> 224 bytes src/data/themes/default/desktop.png | Bin 0 -> 181 bytes src/data/themes/default/desktop.xcf | Bin 0 -> 1975 bytes src/data/themes/default/dialog.bar.png | Bin 0 -> 329 bytes src/data/themes/default/dialog.close.down.tga | Bin 0 -> 677 bytes .../themes/default/dialog.close.hover.tga | Bin 0 -> 668 bytes .../themes/default/dialog.close.normal.tga | Bin 0 -> 582 bytes src/data/themes/default/dialog.png | Bin 0 -> 322 bytes src/data/themes/default/dot.down.png | Bin 0 -> 549 bytes src/data/themes/default/dot.hover.png | Bin 0 -> 548 bytes src/data/themes/default/dot.normal.png | Bin 0 -> 366 bytes src/data/themes/default/dot.xcf | Bin 0 -> 1930 bytes src/data/themes/default/down.png | Bin 0 -> 202 bytes .../themes/default/filebrowser.folder.png | Bin 0 -> 634 bytes src/data/themes/default/generate.py | 98 ++ src/data/themes/default/hslider.bar.hover.tga | Bin 0 -> 776 bytes .../themes/default/hslider.bar.normal.tga | Bin 0 -> 729 bytes src/data/themes/default/hslider.left.tga | Bin 0 -> 372 bytes src/data/themes/default/hslider.right.tga | Bin 0 -> 372 bytes src/data/themes/default/hslider.tga | Bin 0 -> 1231 bytes src/data/themes/default/idot.normal.png | Bin 0 -> 408 bytes src/data/themes/default/input.focus.png | Bin 0 -> 181 bytes src/data/themes/default/input.normal.png | Bin 0 -> 208 bytes src/data/themes/default/left.png | Bin 0 -> 209 bytes src/data/themes/default/list.item.down.png | Bin 0 -> 190 bytes src/data/themes/default/list.item.hover.png | Bin 0 -> 172 bytes src/data/themes/default/list.item.normal.png | Bin 0 -> 172 bytes src/data/themes/default/list.png | Bin 0 -> 129 bytes src/data/themes/default/listitem.down.tga | Bin 0 -> 2226 bytes src/data/themes/default/listitem.hover.tga | Bin 0 -> 2226 bytes src/data/themes/default/listitem.normal.tga | Bin 0 -> 2322 bytes src/data/themes/default/menu.down.tga | Bin 0 -> 528 bytes src/data/themes/default/menu.hover.tga | Bin 0 -> 441 bytes src/data/themes/default/menu.normal.tga | Bin 0 -> 78 bytes src/data/themes/default/notes.txt | 8 + src/data/themes/default/out.tga | Bin 0 -> 795 bytes src/data/themes/default/progressbar.bar.tga | Bin 0 -> 563 bytes src/data/themes/default/progressbar.tga | Bin 0 -> 412 bytes src/data/themes/default/radio.off.hover.tga | Bin 0 -> 582 bytes src/data/themes/default/radio.off.normal.tga | Bin 0 -> 537 bytes src/data/themes/default/radio.on.hover.tga | Bin 0 -> 637 bytes src/data/themes/default/radio.on.normal.tga | Bin 0 -> 646 bytes src/data/themes/default/radio.png | Bin 0 -> 197 bytes src/data/themes/default/rdot.down.png | Bin 0 -> 525 bytes src/data/themes/default/rdot.hover.png | Bin 0 -> 529 bytes src/data/themes/default/rdot.normal.png | Bin 0 -> 370 bytes src/data/themes/default/right.png | Bin 0 -> 206 bytes src/data/themes/default/sbox.normal.png | Bin 0 -> 232 bytes .../default/scroller.slide.bar.hover.tga | Bin 0 -> 342 bytes .../default/scroller.slide.bar.normal.tga | Bin 0 -> 342 bytes src/data/themes/default/scroller.slide.h.tga | Bin 0 -> 1278 bytes src/data/themes/default/scroller.slide.v.tga | Bin 0 -> 1278 bytes src/data/themes/default/select.arrow.down.tga | Bin 0 -> 344 bytes .../themes/default/select.arrow.hover.tga | Bin 0 -> 363 bytes .../themes/default/select.arrow.normal.tga | Bin 0 -> 363 bytes src/data/themes/default/select.arrow.png | Bin 0 -> 156 bytes .../themes/default/select.option.hover.png | Bin 0 -> 190 bytes .../themes/default/select.option.normal.png | Bin 0 -> 172 bytes src/data/themes/default/select.options.png | Bin 0 -> 181 bytes .../themes/default/select.selected.down.tga | Bin 0 -> 322 bytes .../themes/default/select.selected.hover.tga | Bin 0 -> 338 bytes .../themes/default/select.selected.normal.tga | Bin 0 -> 282 bytes src/data/themes/default/slider.bar.hover.tga | Bin 0 -> 776 bytes src/data/themes/default/slider.bar.normal.tga | Bin 0 -> 729 bytes src/data/themes/default/slider.tga | Bin 0 -> 1231 bytes src/data/themes/default/tool.down.tga | Bin 0 -> 528 bytes src/data/themes/default/tool.hover.tga | Bin 0 -> 563 bytes src/data/themes/default/tool.normal.tga | Bin 0 -> 441 bytes src/data/themes/default/up.png | Bin 0 -> 195 bytes src/data/themes/default/vbox.normal.png | Bin 0 -> 233 bytes src/data/themes/default/vdot.down.png | Bin 0 -> 540 bytes src/data/themes/default/vdot.hover.png | Bin 0 -> 527 bytes src/data/themes/default/vdot.normal.png | Bin 0 -> 354 bytes src/data/themes/default/vsbox.normal.png | Bin 0 -> 224 bytes src/data/themes/default/vslider.bar.hover.tga | Bin 0 -> 1412 bytes .../themes/default/vslider.bar.normal.tga | Bin 0 -> 1412 bytes src/data/themes/default/vslider.down.tga | Bin 0 -> 864 bytes src/data/themes/default/vslider.tga | Bin 0 -> 1231 bytes src/data/themes/default/vslider.up.tga | Bin 0 -> 864 bytes src/data/themes/default/x.png | Bin 0 -> 199 bytes src/data/themes/gray/Vera.ttf | Bin 0 -> 65932 bytes src/data/themes/gray/box.down.png | Bin 0 -> 225 bytes src/data/themes/gray/box.normal.png | Bin 0 -> 230 bytes src/data/themes/gray/button.down.png | Bin 0 -> 191 bytes src/data/themes/gray/button.normal.png | Bin 0 -> 199 bytes src/data/themes/gray/checkbox.off.down.png | Bin 0 -> 165 bytes src/data/themes/gray/checkbox.off.normal.png | Bin 0 -> 178 bytes src/data/themes/gray/checkbox.on.down.png | Bin 0 -> 213 bytes src/data/themes/gray/checkbox.on.normal.png | Bin 0 -> 216 bytes src/data/themes/gray/config.txt | 244 +++ src/data/themes/gray/console.input.focus.png | Bin 0 -> 224 bytes src/data/themes/gray/console.input.normal.png | Bin 0 -> 224 bytes src/data/themes/gray/console.png | Bin 0 -> 224 bytes src/data/themes/gray/desktop.png | Bin 0 -> 131 bytes src/data/themes/gray/dialog.bar.png | Bin 0 -> 138 bytes src/data/themes/gray/dialog.close.down.png | Bin 0 -> 270 bytes src/data/themes/gray/dialog.close.normal.png | Bin 0 -> 217 bytes src/data/themes/gray/dialog.png | Bin 0 -> 138 bytes src/data/themes/gray/filebrowser.folder.png | Bin 0 -> 634 bytes src/data/themes/gray/input.focus.png | Bin 0 -> 181 bytes src/data/themes/gray/input.normal.png | Bin 0 -> 208 bytes src/data/themes/gray/list.item.normal.png | Bin 0 -> 172 bytes src/data/themes/gray/list.png | Bin 0 -> 129 bytes src/data/themes/gray/menu.down.png | Bin 0 -> 149 bytes src/data/themes/gray/menu.hover.png | Bin 0 -> 150 bytes src/data/themes/gray/menu.normal.png | Bin 0 -> 120 bytes src/data/themes/gray/menu.option.hover.png | Bin 0 -> 147 bytes src/data/themes/gray/menu.option.normal.png | Bin 0 -> 131 bytes src/data/themes/gray/radio.off.down.png | Bin 0 -> 224 bytes src/data/themes/gray/radio.off.normal.png | Bin 0 -> 238 bytes src/data/themes/gray/radio.on.down.png | Bin 0 -> 248 bytes src/data/themes/gray/radio.on.normal.png | Bin 0 -> 250 bytes src/data/themes/gray/select.arrow.down.png | Bin 0 -> 149 bytes src/data/themes/gray/select.arrow.normal.png | Bin 0 -> 168 bytes src/data/themes/gray/select.arrow.png | Bin 0 -> 156 bytes src/data/themes/gray/select.option.normal.png | Bin 0 -> 172 bytes src/data/themes/gray/select.options.png | Bin 0 -> 181 bytes .../themes/gray/select.selected.normal.png | Bin 0 -> 135 bytes src/data/themes/gray/slider.bar.normal.png | Bin 0 -> 181 bytes src/data/themes/gray/slider.png | Bin 0 -> 145 bytes src/data/themes/gray/tool.down.png | Bin 0 -> 168 bytes src/data/themes/gray/tool.normal.png | Bin 0 -> 168 bytes src/data/themes/tools/config.txt | 11 + src/data/themes/tools/icons48.bkgr.tga | Bin 0 -> 1595 bytes src/data/themes/tools/icons48.code.tga | Bin 0 -> 1360 bytes src/data/themes/tools/icons48.draw.tga | Bin 0 -> 1443 bytes src/data/themes/tools/icons48.eraser.tga | Bin 0 -> 1381 bytes src/data/themes/tools/icons48.fill.tga | Bin 0 -> 1221 bytes src/data/themes/tools/icons48.line.tga | Bin 0 -> 1141 bytes src/data/themes/tools/icons48.pixel.tga | Bin 0 -> 1210 bytes src/data/themes/tools/icons48.select.tga | Bin 0 -> 1457 bytes src/data/themes/tools/icons48.tile.tga | Bin 0 -> 1268 bytes src/dataTools/__init__.py | 0 src/dataTools/__init__.pyc | Bin 0 -> 175 bytes src/dataTools/odict.py | 1399 +++++++++++++++++ src/dataTools/odict.pyc | Bin 0 -> 57964 bytes src/gradients/__init__.py | 0 src/gradients/gradients.py | 576 +++++++ src/gui/DefaultFamiliarizer.py | 27 + src/gui/DummyInstrumentChoice.py | 57 + src/gui/Familiarizer.py | 328 ++++ src/gui/FamiliarizerPGUConfiguration.py | 237 +++ src/gui/InstrumentChoice.py | 315 ++++ src/gui/MINWiiDialog.py | 59 + src/gui/PGUConfiguration.py | 306 ++++ src/gui/PlayingScreen.py | 439 ++++++ src/gui/SongFamiliarizer.py | 583 +++++++ src/gui/SongPlayingScreen.py | 564 +++++++ src/gui/StaticFamiliarizer.py | 457 ++++++ src/gui/__init__.py | 0 src/gui/constants.py | 130 ++ src/instruments/Instrument.py | 46 + src/instruments/__init__.py | 0 .../instrumentImages/accordeon.jpg | Bin 0 -> 31184 bytes .../instrumentImages/accordeonOld.jpg | Bin 0 -> 129956 bytes src/instruments/instrumentImages/celesta.jpg | Bin 0 -> 44497 bytes .../instrumentImages/celestaOld.jpg | Bin 0 -> 269517 bytes src/instruments/instrumentImages/flute.jpg | Bin 0 -> 35201 bytes src/instruments/instrumentImages/guitare.jpg | Bin 0 -> 20831 bytes src/instruments/instrumentImages/orgue.jpg | Bin 0 -> 23105 bytes src/instruments/instrumentImages/piano.jpg | Bin 0 -> 56087 bytes src/instruments/instrumentImages/tuba.jpg | Bin 0 -> 16913 bytes src/instruments/instrumentImages/violon.jpg | Bin 0 -> 15964 bytes .../instrumentImages/violoncelle.jpg | Bin 0 -> 52483 bytes src/launcher/__init__.py | 0 src/logging/EventLog.py | 69 + src/logging/FamiliarizerLog.py | 100 ++ src/logging/Log.py | 135 ++ src/logging/LogPGUAnalyzer.py | 42 + src/logging/LogPGUPlayer.py | 237 +++ src/logging/PickleableEvent.py | 24 + src/logging/__init__.py | 0 src/mxmMidi/DataTypeConverters.py | 217 +++ src/mxmMidi/DataTypeConverters.pyc | Bin 0 -> 5803 bytes src/mxmMidi/EventDispatcher.py | 287 ++++ src/mxmMidi/EventDispatcher.pyc | Bin 0 -> 7056 bytes src/mxmMidi/MidiFileParser.py | 192 +++ src/mxmMidi/MidiFileParser.pyc | Bin 0 -> 4233 bytes src/mxmMidi/MidiInFile.py | 55 + src/mxmMidi/MidiInFile.pyc | Bin 0 -> 2252 bytes src/mxmMidi/MidiInStream.py | 52 + src/mxmMidi/MidiOutFile.py | 448 ++++++ src/mxmMidi/MidiOutStream.py | 471 ++++++ src/mxmMidi/MidiOutStream.pyc | Bin 0 -> 15350 bytes src/mxmMidi/MidiToText.py | 184 +++ src/mxmMidi/RawInstreamFile.py | 108 ++ src/mxmMidi/RawInstreamFile.pyc | Bin 0 -> 4140 bytes src/mxmMidi/RawOutstreamFile.py | 69 + src/mxmMidi/__init__.py | 6 + src/mxmMidi/changes.txt | 45 + src/mxmMidi/constants.py | 210 +++ src/mxmMidi/constants.pyc | Bin 0 -> 3692 bytes src/mxmMidi/example_mimimal_type0.py | 29 + src/mxmMidi/example_print_channel_0.py | 23 + src/mxmMidi/example_print_events.py | 28 + src/mxmMidi/example_print_file.py | 19 + src/mxmMidi/example_transpose_octave.py | 40 + .../experimental/EventDispatcherBase.py | 76 + .../experimental/MidiOutPassThrough.py | 182 +++ src/mxmMidi/experimental/MidiOutStreamBase.py | 135 ++ src/mxmMidi/experimental/readme.txt | 1 + src/mxmMidi/midiout/minimal_type0.mid | Bin 0 -> 35 bytes src/mxmMidi/midiout/transposed.mid | Bin 0 -> 15914 bytes src/mxmMidi/readme.txt | 50 + src/mxmMidi/test/midifiles/midiout.mid | Bin 0 -> 1067 bytes .../test/midifiles/minimal-cubase-type0.mid | Bin 0 -> 59 bytes .../test/midifiles/minimal-cubase-type1.mid | Bin 0 -> 434 bytes src/mxmMidi/test/midifiles/minimal.mid | Bin 0 -> 96 bytes src/mxmMidi/test/midifiles/minimal.txt | 26 + .../test/midifiles/minimal_analyse.txt | 54 + src/mxmMidi/test/midifiles/readme.txt | 7 + src/mxmMidi/test/readme.txt | 3 + src/mxmMidi/version.txt | 1 + src/pgu/__init__.py | 7 + src/pgu/algo.py | 143 ++ src/pgu/ani.py | 90 ++ src/pgu/engine.py | 154 ++ src/pgu/fonts.py | 130 ++ src/pgu/gui/__init__.py | 32 + src/pgu/gui/app.py | 279 ++++ src/pgu/gui/area.py | 454 ++++++ src/pgu/gui/basic.py | 136 ++ src/pgu/gui/button.py | 351 +++++ src/pgu/gui/const.py | 45 + src/pgu/gui/container.py | 414 +++++ src/pgu/gui/deprecated.py | 76 + src/pgu/gui/dialog.py | 168 ++ src/pgu/gui/document.py | 112 ++ src/pgu/gui/form.py | 79 + src/pgu/gui/group.py | 43 + src/pgu/gui/input.py | 169 ++ src/pgu/gui/keysym.py | 72 + src/pgu/gui/layout.py | 172 ++ src/pgu/gui/menus.py | 119 ++ src/pgu/gui/misc.py | 43 + src/pgu/gui/pguglobals.py | 7 + src/pgu/gui/select.py | 180 +++ src/pgu/gui/slider.py | 279 ++++ src/pgu/gui/style.py | 41 + src/pgu/gui/surface.py | 143 ++ src/pgu/gui/table.py | 331 ++++ src/pgu/gui/textarea.py | 287 ++++ src/pgu/gui/theme.py | 485 ++++++ src/pgu/gui/widget.py | 377 +++++ src/pgu/hexvid.py | 127 ++ src/pgu/high.py | 154 ++ src/pgu/html.py | 571 +++++++ src/pgu/isovid.py | 182 +++ src/pgu/layout.py | 4 + src/pgu/text.py | 61 + src/pgu/tilevid.py | 195 +++ src/pgu/timer.py | 68 + src/pgu/vid.py | 560 +++++++ src/songs/MidiToSong.py | 60 + src/songs/Song.py | 137 ++ src/songs/__init__.py | 0 src/songs/midis/bergere.mid | Bin 0 -> 552 bytes src/songs/midis/boheme.mid | Bin 0 -> 1055 bytes src/songs/midis/cerises.mid | Bin 0 -> 719 bytes src/songs/midis/feuillesmortes.mid | Bin 0 -> 717 bytes src/songs/midis/midi_export.mid | Bin 0 -> 86 bytes src/songs/midis/test.mid | Bin 0 -> 275 bytes src/songs/midis/vierose.mid | Bin 0 -> 988 bytes src/songs/smwis/Charles Aznavour/boheme.smwi | 546 +++++++ src/songs/smwis/Edith Piaf/foule.smwi | 400 +++++ src/songs/smwis/Edith Piaf/vierose.smwi | 496 ++++++ .../smwis/Grands Classiques/bergere.smwi | 293 ++++ .../smwis/Grands Classiques/cerises.smwi | 362 +++++ .../Grands Classiques/clairdelalune.smwi | 255 +++ .../Grands Classiques/clairefontaine.smwi | 238 +++ .../smwis/Grands Classiques/eauvive.smwi | 281 ++++ .../smwis/Grands Classiques/frerejacques.smwi | 186 +++ src/songs/smwis/Grands Classiques/jadbt.smwi | 227 +++ .../smwis/Grands Classiques/marseillaise.smwi | 547 +++++++ .../smwis/Grands Classiques/papanoel.smwi | 185 +++ src/songs/smwis/Jean Drejac/vinblanc.smwi | 356 +++++ .../smwis/Johnny Hallyday/penitencier.smwi | 199 +++ .../smwis/Yves Montand/feuillesmortes.smwi | 364 +++++ 354 files changed, 24094 insertions(+) create mode 100755 .project create mode 100755 .pydevproject create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100755 WiiMouse IR G.PIE create mode 100755 WiiMouse IR coeff0.1.PIE create mode 100644 WiiMouse2IR coeff0.1.PIE create mode 100644 WiiMouse4IR coeff0.1.PIE create mode 100755 src/controllers/Wiimote.py create mode 100755 src/controllers/__init__.py create mode 100755 src/cursor/WarpingCursor.py create mode 100755 src/cursor/__init__.py create mode 100755 src/cursor/cursorImages/black/0.png create mode 100755 src/cursor/cursorImages/black/1.png create mode 100755 src/cursor/cursorImages/black/10.png create mode 100755 src/cursor/cursorImages/black/2.png create mode 100755 src/cursor/cursorImages/black/3.png create mode 100755 src/cursor/cursorImages/black/4.png create mode 100755 src/cursor/cursorImages/black/5.png create mode 100755 src/cursor/cursorImages/black/6.png create mode 100755 src/cursor/cursorImages/black/7.png create mode 100755 src/cursor/cursorImages/black/8.png create mode 100755 src/cursor/cursorImages/black/9.png create mode 100755 src/cursor/cursorImages/black/cursorBlack.svg create mode 100644 src/cursor/cursorImages/black/flash.png create mode 100644 src/cursor/cursorImages/blue/0.png create mode 100644 src/cursor/cursorImages/blue/1.png create mode 100644 src/cursor/cursorImages/blue/10.png create mode 100644 src/cursor/cursorImages/blue/2.png create mode 100644 src/cursor/cursorImages/blue/3.png create mode 100644 src/cursor/cursorImages/blue/4.png create mode 100644 src/cursor/cursorImages/blue/5.png create mode 100644 src/cursor/cursorImages/blue/6.png create mode 100644 src/cursor/cursorImages/blue/7.png create mode 100644 src/cursor/cursorImages/blue/8.png create mode 100644 src/cursor/cursorImages/blue/9.png create mode 100644 src/cursor/cursorImages/blue/cursorBlue.svg create mode 100644 src/cursor/cursorImages/green/0.png create mode 100644 src/cursor/cursorImages/green/1.png create mode 100644 src/cursor/cursorImages/green/10.png create mode 100644 src/cursor/cursorImages/green/2.png create mode 100644 src/cursor/cursorImages/green/3.png create mode 100644 src/cursor/cursorImages/green/4.png create mode 100644 src/cursor/cursorImages/green/5.png create mode 100644 src/cursor/cursorImages/green/6.png create mode 100644 src/cursor/cursorImages/green/7.png create mode 100644 src/cursor/cursorImages/green/8.png create mode 100644 src/cursor/cursorImages/green/9.png create mode 100644 src/cursor/cursorImages/green/cursorGreen.svg create mode 100644 src/cursor/cursorImages/red/0.png create mode 100644 src/cursor/cursorImages/red/1.png create mode 100644 src/cursor/cursorImages/red/10.png create mode 100644 src/cursor/cursorImages/red/2.png create mode 100644 src/cursor/cursorImages/red/3.png create mode 100644 src/cursor/cursorImages/red/4.png create mode 100644 src/cursor/cursorImages/red/5.png create mode 100644 src/cursor/cursorImages/red/6.png create mode 100644 src/cursor/cursorImages/red/7.png create mode 100644 src/cursor/cursorImages/red/8.png create mode 100644 src/cursor/cursorImages/red/9.png create mode 100644 src/cursor/cursorImages/red/cursorRed.svg create mode 100644 src/data/themes/default/Vera.ttf create mode 100644 src/data/themes/default/box.down.png create mode 100644 src/data/themes/default/box.hover.png create mode 100644 src/data/themes/default/box.normal.png create mode 100644 src/data/themes/default/box.xcf create mode 100644 src/data/themes/default/button.down.tga create mode 100644 src/data/themes/default/button.hover.tga create mode 100644 src/data/themes/default/button.normal.tga create mode 100644 src/data/themes/default/check.png create mode 100644 src/data/themes/default/checkbox.off.hover.tga create mode 100644 src/data/themes/default/checkbox.off.normal.tga create mode 100644 src/data/themes/default/checkbox.on.hover.tga create mode 100644 src/data/themes/default/checkbox.on.normal.tga create mode 100644 src/data/themes/default/config.txt create mode 100644 src/data/themes/default/console.input.focus.png create mode 100644 src/data/themes/default/console.input.normal.png create mode 100644 src/data/themes/default/console.png create mode 100644 src/data/themes/default/desktop.png create mode 100644 src/data/themes/default/desktop.xcf create mode 100644 src/data/themes/default/dialog.bar.png create mode 100644 src/data/themes/default/dialog.close.down.tga create mode 100644 src/data/themes/default/dialog.close.hover.tga create mode 100644 src/data/themes/default/dialog.close.normal.tga create mode 100644 src/data/themes/default/dialog.png create mode 100644 src/data/themes/default/dot.down.png create mode 100644 src/data/themes/default/dot.hover.png create mode 100644 src/data/themes/default/dot.normal.png create mode 100644 src/data/themes/default/dot.xcf create mode 100644 src/data/themes/default/down.png create mode 100644 src/data/themes/default/filebrowser.folder.png create mode 100644 src/data/themes/default/generate.py create mode 100644 src/data/themes/default/hslider.bar.hover.tga create mode 100644 src/data/themes/default/hslider.bar.normal.tga create mode 100644 src/data/themes/default/hslider.left.tga create mode 100644 src/data/themes/default/hslider.right.tga create mode 100644 src/data/themes/default/hslider.tga create mode 100644 src/data/themes/default/idot.normal.png create mode 100644 src/data/themes/default/input.focus.png create mode 100644 src/data/themes/default/input.normal.png create mode 100644 src/data/themes/default/left.png create mode 100644 src/data/themes/default/list.item.down.png create mode 100644 src/data/themes/default/list.item.hover.png create mode 100644 src/data/themes/default/list.item.normal.png create mode 100644 src/data/themes/default/list.png create mode 100644 src/data/themes/default/listitem.down.tga create mode 100644 src/data/themes/default/listitem.hover.tga create mode 100644 src/data/themes/default/listitem.normal.tga create mode 100644 src/data/themes/default/menu.down.tga create mode 100644 src/data/themes/default/menu.hover.tga create mode 100644 src/data/themes/default/menu.normal.tga create mode 100644 src/data/themes/default/notes.txt create mode 100644 src/data/themes/default/out.tga create mode 100644 src/data/themes/default/progressbar.bar.tga create mode 100644 src/data/themes/default/progressbar.tga create mode 100644 src/data/themes/default/radio.off.hover.tga create mode 100644 src/data/themes/default/radio.off.normal.tga create mode 100644 src/data/themes/default/radio.on.hover.tga create mode 100644 src/data/themes/default/radio.on.normal.tga create mode 100644 src/data/themes/default/radio.png create mode 100644 src/data/themes/default/rdot.down.png create mode 100644 src/data/themes/default/rdot.hover.png create mode 100644 src/data/themes/default/rdot.normal.png create mode 100644 src/data/themes/default/right.png create mode 100644 src/data/themes/default/sbox.normal.png create mode 100644 src/data/themes/default/scroller.slide.bar.hover.tga create mode 100644 src/data/themes/default/scroller.slide.bar.normal.tga create mode 100644 src/data/themes/default/scroller.slide.h.tga create mode 100644 src/data/themes/default/scroller.slide.v.tga create mode 100644 src/data/themes/default/select.arrow.down.tga create mode 100644 src/data/themes/default/select.arrow.hover.tga create mode 100644 src/data/themes/default/select.arrow.normal.tga create mode 100644 src/data/themes/default/select.arrow.png create mode 100644 src/data/themes/default/select.option.hover.png create mode 100644 src/data/themes/default/select.option.normal.png create mode 100644 src/data/themes/default/select.options.png create mode 100644 src/data/themes/default/select.selected.down.tga create mode 100644 src/data/themes/default/select.selected.hover.tga create mode 100644 src/data/themes/default/select.selected.normal.tga create mode 100644 src/data/themes/default/slider.bar.hover.tga create mode 100644 src/data/themes/default/slider.bar.normal.tga create mode 100644 src/data/themes/default/slider.tga create mode 100644 src/data/themes/default/tool.down.tga create mode 100644 src/data/themes/default/tool.hover.tga create mode 100644 src/data/themes/default/tool.normal.tga create mode 100644 src/data/themes/default/up.png create mode 100644 src/data/themes/default/vbox.normal.png create mode 100644 src/data/themes/default/vdot.down.png create mode 100644 src/data/themes/default/vdot.hover.png create mode 100644 src/data/themes/default/vdot.normal.png create mode 100644 src/data/themes/default/vsbox.normal.png create mode 100644 src/data/themes/default/vslider.bar.hover.tga create mode 100644 src/data/themes/default/vslider.bar.normal.tga create mode 100644 src/data/themes/default/vslider.down.tga create mode 100644 src/data/themes/default/vslider.tga create mode 100644 src/data/themes/default/vslider.up.tga create mode 100644 src/data/themes/default/x.png create mode 100644 src/data/themes/gray/Vera.ttf create mode 100644 src/data/themes/gray/box.down.png create mode 100644 src/data/themes/gray/box.normal.png create mode 100644 src/data/themes/gray/button.down.png create mode 100644 src/data/themes/gray/button.normal.png create mode 100644 src/data/themes/gray/checkbox.off.down.png create mode 100644 src/data/themes/gray/checkbox.off.normal.png create mode 100644 src/data/themes/gray/checkbox.on.down.png create mode 100644 src/data/themes/gray/checkbox.on.normal.png create mode 100644 src/data/themes/gray/config.txt create mode 100644 src/data/themes/gray/console.input.focus.png create mode 100644 src/data/themes/gray/console.input.normal.png create mode 100644 src/data/themes/gray/console.png create mode 100644 src/data/themes/gray/desktop.png create mode 100644 src/data/themes/gray/dialog.bar.png create mode 100644 src/data/themes/gray/dialog.close.down.png create mode 100644 src/data/themes/gray/dialog.close.normal.png create mode 100644 src/data/themes/gray/dialog.png create mode 100644 src/data/themes/gray/filebrowser.folder.png create mode 100644 src/data/themes/gray/input.focus.png create mode 100644 src/data/themes/gray/input.normal.png create mode 100644 src/data/themes/gray/list.item.normal.png create mode 100644 src/data/themes/gray/list.png create mode 100644 src/data/themes/gray/menu.down.png create mode 100644 src/data/themes/gray/menu.hover.png create mode 100644 src/data/themes/gray/menu.normal.png create mode 100644 src/data/themes/gray/menu.option.hover.png create mode 100644 src/data/themes/gray/menu.option.normal.png create mode 100644 src/data/themes/gray/radio.off.down.png create mode 100644 src/data/themes/gray/radio.off.normal.png create mode 100644 src/data/themes/gray/radio.on.down.png create mode 100644 src/data/themes/gray/radio.on.normal.png create mode 100644 src/data/themes/gray/select.arrow.down.png create mode 100644 src/data/themes/gray/select.arrow.normal.png create mode 100644 src/data/themes/gray/select.arrow.png create mode 100644 src/data/themes/gray/select.option.normal.png create mode 100644 src/data/themes/gray/select.options.png create mode 100644 src/data/themes/gray/select.selected.normal.png create mode 100644 src/data/themes/gray/slider.bar.normal.png create mode 100644 src/data/themes/gray/slider.png create mode 100644 src/data/themes/gray/tool.down.png create mode 100644 src/data/themes/gray/tool.normal.png create mode 100644 src/data/themes/tools/config.txt create mode 100644 src/data/themes/tools/icons48.bkgr.tga create mode 100644 src/data/themes/tools/icons48.code.tga create mode 100644 src/data/themes/tools/icons48.draw.tga create mode 100644 src/data/themes/tools/icons48.eraser.tga create mode 100644 src/data/themes/tools/icons48.fill.tga create mode 100644 src/data/themes/tools/icons48.line.tga create mode 100644 src/data/themes/tools/icons48.pixel.tga create mode 100644 src/data/themes/tools/icons48.select.tga create mode 100644 src/data/themes/tools/icons48.tile.tga create mode 100644 src/dataTools/__init__.py create mode 100644 src/dataTools/__init__.pyc create mode 100644 src/dataTools/odict.py create mode 100644 src/dataTools/odict.pyc create mode 100755 src/gradients/__init__.py create mode 100755 src/gradients/gradients.py create mode 100644 src/gui/DefaultFamiliarizer.py create mode 100644 src/gui/DummyInstrumentChoice.py create mode 100644 src/gui/Familiarizer.py create mode 100644 src/gui/FamiliarizerPGUConfiguration.py create mode 100755 src/gui/InstrumentChoice.py create mode 100644 src/gui/MINWiiDialog.py create mode 100644 src/gui/PGUConfiguration.py create mode 100755 src/gui/PlayingScreen.py create mode 100644 src/gui/SongFamiliarizer.py create mode 100644 src/gui/SongPlayingScreen.py create mode 100644 src/gui/StaticFamiliarizer.py create mode 100755 src/gui/__init__.py create mode 100755 src/gui/constants.py create mode 100755 src/instruments/Instrument.py create mode 100755 src/instruments/__init__.py create mode 100755 src/instruments/instrumentImages/accordeon.jpg create mode 100755 src/instruments/instrumentImages/accordeonOld.jpg create mode 100755 src/instruments/instrumentImages/celesta.jpg create mode 100755 src/instruments/instrumentImages/celestaOld.jpg create mode 100755 src/instruments/instrumentImages/flute.jpg create mode 100755 src/instruments/instrumentImages/guitare.jpg create mode 100755 src/instruments/instrumentImages/orgue.jpg create mode 100755 src/instruments/instrumentImages/piano.jpg create mode 100755 src/instruments/instrumentImages/tuba.jpg create mode 100755 src/instruments/instrumentImages/violon.jpg create mode 100755 src/instruments/instrumentImages/violoncelle.jpg create mode 100755 src/launcher/__init__.py create mode 100755 src/logging/EventLog.py create mode 100644 src/logging/FamiliarizerLog.py create mode 100755 src/logging/Log.py create mode 100644 src/logging/LogPGUAnalyzer.py create mode 100644 src/logging/LogPGUPlayer.py create mode 100755 src/logging/PickleableEvent.py create mode 100755 src/logging/__init__.py create mode 100644 src/mxmMidi/DataTypeConverters.py create mode 100644 src/mxmMidi/DataTypeConverters.pyc create mode 100644 src/mxmMidi/EventDispatcher.py create mode 100644 src/mxmMidi/EventDispatcher.pyc create mode 100644 src/mxmMidi/MidiFileParser.py create mode 100644 src/mxmMidi/MidiFileParser.pyc create mode 100644 src/mxmMidi/MidiInFile.py create mode 100644 src/mxmMidi/MidiInFile.pyc create mode 100644 src/mxmMidi/MidiInStream.py create mode 100644 src/mxmMidi/MidiOutFile.py create mode 100644 src/mxmMidi/MidiOutStream.py create mode 100644 src/mxmMidi/MidiOutStream.pyc create mode 100644 src/mxmMidi/MidiToText.py create mode 100644 src/mxmMidi/RawInstreamFile.py create mode 100644 src/mxmMidi/RawInstreamFile.pyc create mode 100644 src/mxmMidi/RawOutstreamFile.py create mode 100644 src/mxmMidi/__init__.py create mode 100644 src/mxmMidi/changes.txt create mode 100644 src/mxmMidi/constants.py create mode 100644 src/mxmMidi/constants.pyc create mode 100644 src/mxmMidi/example_mimimal_type0.py create mode 100644 src/mxmMidi/example_print_channel_0.py create mode 100644 src/mxmMidi/example_print_events.py create mode 100644 src/mxmMidi/example_print_file.py create mode 100644 src/mxmMidi/example_transpose_octave.py create mode 100644 src/mxmMidi/experimental/EventDispatcherBase.py create mode 100644 src/mxmMidi/experimental/MidiOutPassThrough.py create mode 100644 src/mxmMidi/experimental/MidiOutStreamBase.py create mode 100644 src/mxmMidi/experimental/readme.txt create mode 100644 src/mxmMidi/midiout/minimal_type0.mid create mode 100644 src/mxmMidi/midiout/transposed.mid create mode 100644 src/mxmMidi/readme.txt create mode 100644 src/mxmMidi/test/midifiles/midiout.mid create mode 100644 src/mxmMidi/test/midifiles/minimal-cubase-type0.mid create mode 100644 src/mxmMidi/test/midifiles/minimal-cubase-type1.mid create mode 100644 src/mxmMidi/test/midifiles/minimal.mid create mode 100644 src/mxmMidi/test/midifiles/minimal.txt create mode 100644 src/mxmMidi/test/midifiles/minimal_analyse.txt create mode 100644 src/mxmMidi/test/midifiles/readme.txt create mode 100644 src/mxmMidi/test/readme.txt create mode 100644 src/mxmMidi/version.txt create mode 100644 src/pgu/__init__.py create mode 100644 src/pgu/algo.py create mode 100644 src/pgu/ani.py create mode 100644 src/pgu/engine.py create mode 100644 src/pgu/fonts.py create mode 100644 src/pgu/gui/__init__.py create mode 100644 src/pgu/gui/app.py create mode 100644 src/pgu/gui/area.py create mode 100644 src/pgu/gui/basic.py create mode 100644 src/pgu/gui/button.py create mode 100644 src/pgu/gui/const.py create mode 100644 src/pgu/gui/container.py create mode 100644 src/pgu/gui/deprecated.py create mode 100644 src/pgu/gui/dialog.py create mode 100644 src/pgu/gui/document.py create mode 100644 src/pgu/gui/form.py create mode 100644 src/pgu/gui/group.py create mode 100644 src/pgu/gui/input.py create mode 100644 src/pgu/gui/keysym.py create mode 100644 src/pgu/gui/layout.py create mode 100644 src/pgu/gui/menus.py create mode 100644 src/pgu/gui/misc.py create mode 100644 src/pgu/gui/pguglobals.py create mode 100644 src/pgu/gui/select.py create mode 100644 src/pgu/gui/slider.py create mode 100644 src/pgu/gui/style.py create mode 100644 src/pgu/gui/surface.py create mode 100644 src/pgu/gui/table.py create mode 100644 src/pgu/gui/textarea.py create mode 100644 src/pgu/gui/theme.py create mode 100644 src/pgu/gui/widget.py create mode 100644 src/pgu/hexvid.py create mode 100644 src/pgu/high.py create mode 100644 src/pgu/html.py create mode 100644 src/pgu/isovid.py create mode 100644 src/pgu/layout.py create mode 100644 src/pgu/text.py create mode 100644 src/pgu/tilevid.py create mode 100644 src/pgu/timer.py create mode 100644 src/pgu/vid.py create mode 100644 src/songs/MidiToSong.py create mode 100755 src/songs/Song.py create mode 100755 src/songs/__init__.py create mode 100644 src/songs/midis/bergere.mid create mode 100644 src/songs/midis/boheme.mid create mode 100644 src/songs/midis/cerises.mid create mode 100644 src/songs/midis/feuillesmortes.mid create mode 100644 src/songs/midis/midi_export.mid create mode 100644 src/songs/midis/test.mid create mode 100644 src/songs/midis/vierose.mid create mode 100644 src/songs/smwis/Charles Aznavour/boheme.smwi create mode 100644 src/songs/smwis/Edith Piaf/foule.smwi create mode 100644 src/songs/smwis/Edith Piaf/vierose.smwi create mode 100644 src/songs/smwis/Grands Classiques/bergere.smwi create mode 100644 src/songs/smwis/Grands Classiques/cerises.smwi create mode 100644 src/songs/smwis/Grands Classiques/clairdelalune.smwi create mode 100644 src/songs/smwis/Grands Classiques/clairefontaine.smwi create mode 100644 src/songs/smwis/Grands Classiques/eauvive.smwi create mode 100644 src/songs/smwis/Grands Classiques/frerejacques.smwi create mode 100644 src/songs/smwis/Grands Classiques/jadbt.smwi create mode 100644 src/songs/smwis/Grands Classiques/marseillaise.smwi create mode 100644 src/songs/smwis/Grands Classiques/papanoel.smwi create mode 100644 src/songs/smwis/Jean Drejac/vinblanc.smwi create mode 100644 src/songs/smwis/Johnny Hallyday/penitencier.smwi create mode 100644 src/songs/smwis/Yves Montand/feuillesmortes.smwi diff --git a/.project b/.project new file mode 100755 index 0000000..30d02f5 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + MINWii + + + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/.pydevproject b/.pydevproject new file mode 100755 index 0000000..e35390d --- /dev/null +++ b/.pydevproject @@ -0,0 +1,10 @@ + + + + + +/MINWiiV7/src + +python 2.6 +Default + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..6a3e2eb --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,14 @@ +#Mon Dec 07 03:31:40 CET 2009 +eclipse.preferences.version=1 +encoding//src/mxmMidi/DataTypeConverters.py=ISO-8859-1 +encoding//src/mxmMidi/EventDispatcher.py=ISO-8859-1 +encoding//src/mxmMidi/MidiFileParser.py=ISO-8859-1 +encoding//src/mxmMidi/MidiInFile.py=ISO-8859-1 +encoding//src/mxmMidi/MidiInStream.py=ISO-8859-1 +encoding//src/mxmMidi/MidiOutFile.py=ISO-8859-1 +encoding//src/mxmMidi/MidiOutStream.py=ISO-8859-1 +encoding//src/mxmMidi/MidiToText.py=ISO-8859-1 +encoding//src/mxmMidi/RawInstreamFile.py=ISO-8859-1 +encoding//src/mxmMidi/RawOutstreamFile.py=ISO-8859-1 +encoding//src/mxmMidi/__init__.py=ISO-8859-1 +encoding//src/mxmMidi/constants.py=ISO-8859-1 diff --git a/WiiMouse IR G.PIE b/WiiMouse IR G.PIE new file mode 100755 index 0000000..dad484d --- /dev/null +++ b/WiiMouse IR G.PIE @@ -0,0 +1,157 @@ +Wiimote1.led1 = true +Wiimote2.led1 = true +Wiimote2.led4 = true +Wiimote3.led2 = true +Wiimote4.led2 = true +Wiimote4.led4 = true +Wiimote5.led3 = true +Wiimote6.led3 = true +Wiimote6.led4 = true +//Mouse Control Script using IR +//by vkapadia with much assistance from inio +//vkapadia@vkapadia.com +// +//Calibration: +//To calibrate, run this program and put the Wiimote on a flat surface face-up. +//Then read the values in the debug line (next to the run button). +//Change these values until the debug line reads approx. all zeros. +var.xtrim = -7 +var.ytrim = -17 +var.ztrim = -7 +// +//Options: +var.deadzone = 5 //distance in pixels that you have to move the wiimote in + //order for it to register movement. Creates a "dead zone" around the pointer + //to make it easier to click. Higher = smoother but less accurate. +//fake cursor init +cursor2.visible = true +//more options to be added later + +//Controls: +//Point Wiimote = Move Mouse +//D-Pad = Arrow Keys +//B-Button = Left Click +//Home = Middle Click +//A-Button = Right Click +//Plus and Minus = Control Volume +//One = Unmapped +//Two = Unmapped +// +//If the pointer hits the edge of the screen, the Wiimote will rumble a bit. +// +//The LEDs attempt to emulate KITT's grill from Knight Rider + +//***Do not edit anything below this line unless you know what you are doing.*** +var.accx = wiimote.RawForceX + var.xtrim +var.accy = wiimote.RawForceY + var.ytrim +var.accz = wiimote.RawForceZ + var.ztrim + +if wiimote.dot1vis and wiimote.dot2vis then + + if var.accy > -7 then + var.orientation = 0 + elseif var.accy > -45 then + if var.accx < 0 then + var.orientation = 3 + else + var.orientation = 1 + endif + else + var.orientation = 2 + endif + + if var.leftpoint = 0 then + if var.orientation = 0 then + if wiimote.dot1x < wiimote.dot2x then + var.leftpoint = 1 + else + var.leftpoint = 2 + endif + endif + if var.orientation = 1 then + if wiimote.dot1y > wiimote.dot2y then + var.leftpoint = 1 + else + var.leftpoint = 2 + endif + endif + if var.orientation = 2 then + if wiimote.dot1x > wiimote.dot2x then + var.leftpoint = 1 + else + var.leftpoint = 2 + endif + endif + if var.orientation = 3 then + if wiimote.dot1y < wiimote.dot2y then + var.leftpoint = 1 + else + var.leftpoint = 2 + endif + endif + endif + + if var.leftpoint = 1 then + var.fix1x = wiimote.dot1x + var.fix1y = wiimote.dot1y + var.fix2x = wiimote.dot2x + var.fix2y = wiimote.dot2y + else + var.fix1x = wiimote.dot2x + var.fix1y = wiimote.dot2y + var.fix2x = wiimote.dot1x + var.fix2y = wiimote.dot1y + endif + + var.dx = var.fix2x - var.fix1x + var.dy = var.fix2y - var.fix1y + var.cx = (var.fix1x+var.fix2x)/1024.0 - 1 + var.cy = (var.fix1y+var.fix2y)/1024.0 - .75 + + var.d = sqrt(var.dx*var.dx+var.dy*var.dy) + + var.dx = var.dx / var.d + var.dy = var.dy / var.d + + var.ox = -var.dy*var.cy-var.dx*var.cx; + var.oy = -var.dx*var.cy+var.dy*var.cx; + + var.ax = (var.ox * screen.desktopwidth) + (screen.desktopwidth / 2) + var.ay = (-var.oy * screen.desktopwidth) + (screen.desktopheight / 2) + + var.dx = var.ax - cursor2.posx + var.dy = var.ay - cursor2.posy + + var.d = sqrt((var.dx*var.dx)+(var.dy*var.dy)) + + var.a = 180 / (200 + var.d * var.d * var.d * .001) + + if var.d <= var.deadzone then var.a = 1 + + //debug = var.d + " " + var.a + + var.finalx = cursor2.posx * var.a + var.ax * (1 - var.a) + var.finaly = cursor2.posy * var.a + var.ay * (1 - var.a) + + + cursor2.posx = smooth(var.finalx,3,5) + cursor2.posy = smooth(var.finaly,3,5) + +else + + var.leftpoint = 0 + +endif + +var.xpos = var.finalx +var.ypos = var.finaly +ppjoy1.analog0 = ensuremaprange(var.xpos,0,screen.desktopwidth,-1,1) +ppjoy1.analog1 = ensuremaprange(var.ypos,0,screen.desktopheight,-1,1) + +if wiimote1.B == true + ppjoy1.digital0 = true +else + ppjoy1.digital0 = false +endif + +debug = var.xpos+ " " + var.ypos diff --git a/WiiMouse IR coeff0.1.PIE b/WiiMouse IR coeff0.1.PIE new file mode 100755 index 0000000..8856f61 --- /dev/null +++ b/WiiMouse IR coeff0.1.PIE @@ -0,0 +1,166 @@ +Wiimote1.led1 = true +Wiimote2.led1 = true +Wiimote2.led4 = true +Wiimote3.led2 = true +Wiimote4.led2 = true +Wiimote4.led4 = true +Wiimote5.led3 = true +Wiimote6.led3 = true +Wiimote6.led4 = true +//Mouse Control Script using IR +//by vkapadia with much assistance from inio +//vkapadia@vkapadia.com +// +//Calibration: +//To calibrate, run this program and put the Wiimote on a flat surface face-up. +//Then read the values in the debug line (next to the run button). +//Change these values until the debug line reads approx. all zeros. +var.xtrim1 = -1 +var.ytrim1 = -25 +var.ztrim1 = 2 + +var.xtrim2 = -1 +var.ytrim2 = -25 +var.ztrim2 = 2 + +var.coeff = 0.1 + +// +//Options: +var.deadzone = 5 //distance in pixels that you have to move the wiimote in + //order for it to register movement. Creates a "dead zone" around the pointer + //to make it easier to click. Higher = smoother but less accurate. +//fake cursor init + +//cursor2.visible = true + +//more options to be added later + +//Controls: +//Point Wiimote = Move Mouse +//D-Pad = Arrow Keys +//B-Button = Left Click +//Home = Middle Click +//A-Button = Right Click +//Plus and Minus = Control Volume +//One = Unmapped +//Two = Unmapped +// +//If the pointer hits the edge of the screen, the Wiimote will rumble a bit. +// +//The LEDs attempt to emulate KITT's grill from Knight Rider + +//***Do not edit anything below this line unless you know what you are doing.*** +var.accx1 = wiimote1.RawForceX1 + var.xtrim1 +var.accy1 = wiimote1.RawForceY1 + var.ytrim1 +var.accz1 = wiimote1.RawForceZ1 + var.ztrim1 + +if wiimote1.dot1vis and wiimote1.dot2vis then + + if var.accy1 > -7 then + var.orientation1 = 0 + elseif var.accy1 > -45 then + if var.accx1 < 0 then + var.orientation1 = 3 + else + var.orientation1 = 1 + endif + else + var.orientation1 = 2 + endif + + if var.leftpoint1 = 0 then + if var.orientation1 = 0 then + if wiimote1.dot1x < wiimote1.dot2x then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + if var.orientation1 = 1 then + if wiimote1.dot1y > wiimote1.dot2y then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + if var.orientation1 = 2 then + if wiimote1.dot1x > wiimote1.dot2x then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + if var.orientation = 3 then + if wiimote1.dot1y < wiimote1.dot2y then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + endif + + if var.leftpoint1 = 1 then + var.fix1x1 = wiimote1.dot1x + var.fix1y1 = wiimote1.dot1y + var.fix2x1 = wiimote1.dot2x + var.fix2y1 = wiimote1.dot2y + else + var.fix1x1 = wiimote1.dot2x + var.fix1y1 = wiimote1.dot2y + var.fix2x1 = wiimote1.dot1x + var.fix2y1 = wiimote1.dot1y + endif + + var.dx1 = var.fix2x1 - var.fix1x1 + var.dy1 = var.fix2y1 - var.fix1y1 + var.cx1 = (var.fix1x1+var.fix2x1)/1024.0 - 1 + var.cy1 = (var.fix1y1+var.fix2y1)/1024.0 - .75 + + var.d1 = sqrt(var.dx1*var.dx1+var.dy1*var.dy1) + + var.dx1 = var.dx1 / var.d1 + var.dy1 = var.dy1 / var.d1 + + var.ox1 = -var.dy1*var.cy1-var.dx1*var.cx1; + var.oy1 = -var.dx1*var.cy1+var.dy1*var.cx1; + + var.ax1 = (var.ox1 * var.coeff*screen.desktopwidth) + (screen.desktopwidth* var.coeff / 2) + var.ay1 = (-var.oy1* var.coeff * screen.desktopwidth) + (screen.desktopheight* var.coeff / 2) + + var.dx1 = var.ax1 - cursor2.posx + var.dy1 = var.ay1 - cursor2.posy + + var.d1 = sqrt((var.dx1*var.dx1)+(var.dy1*var.dy1)) + + var.a1 = 180 / (200 + var.d1 * var.d1 * var.d1 * .001) + + if var.d1 <= var.deadzone then var.a1 = 1 + + //debug = var.d + " " + var.a + + var.finalx1 = cursor2.posx * var.a1 + var.ax1 * (1 - var.a1) + var.finaly1 = cursor2.posy * var.a1 + var.ay1 * (1 - var.a1) + + + cursor2.posx = smooth(var.finalx1,3,5) + cursor2.posy = smooth(var.finaly1,3,5) + +else + + var.leftpoint1 = 0 + +endif + +var.xpos1 = var.finalx1 +var.ypos1 = var.finaly1 +ppjoy1.analog0 = ensuremaprange(var.xpos1,0,screen.desktopwidth* var.coeff,-1,1) +ppjoy1.analog1 = ensuremaprange(var.ypos1,0,screen.desktopheight* var.coeff,-1,1) + +if wiimote1.B or wiimote1.A or wiimote1.Up or wiimote1.down or wiimote1.Left or wiimote1.Right == true + ppjoy1.digital0 = true +else + ppjoy1.digital0 = false +endif + +debug = var.accx1+ " " + var.accy1+ " " + var.accz1 diff --git a/WiiMouse2IR coeff0.1.PIE b/WiiMouse2IR coeff0.1.PIE new file mode 100644 index 0000000..27c9d52 --- /dev/null +++ b/WiiMouse2IR coeff0.1.PIE @@ -0,0 +1,281 @@ +Wiimote1.led1 = true +Wiimote2.led1 = true +Wiimote2.led4 = true +Wiimote3.led2 = true +Wiimote4.led2 = true +Wiimote4.led4 = true +Wiimote5.led3 = true +Wiimote6.led3 = true +Wiimote6.led4 = true +//Mouse Control Script using IR +//by vkapadia with much assistance from inio +//vkapadia@vkapadia.com +// +//Calibration: +//To calibrate, run this program and put the Wiimote on a flat surface face-up. +//Then read the values in the debug line (next to the run button). +//Change these values until the debug line reads approx. all zeros. +var.xtrim1 = -1 +var.ytrim1 = -25 +var.ztrim1 = 2 + +var.xtrim2 = 2 +var.ytrim2 = -30 +var.ztrim2 = 2 + +var.coeff = 0.1 + +// +//Options: +var.deadzone = 5 //distance in pixels that you have to move the wiimote in + //order for it to register movement. Creates a "dead zone" around the pointer + //to make it easier to click. Higher = smoother but less accurate. +//fake cursor init + +//cursor2.visible = true + +//more options to be added later + +//Controls: +//Point Wiimote = Move Mouse +//D-Pad = Arrow Keys +//B-Button = Left Click +//Home = Middle Click +//A-Button = Right Click +//Plus and Minus = Control Volume +//One = Unmapped +//Two = Unmapped +// +//If the pointer hits the edge of the screen, the Wiimote will rumble a bit. +// +//The LEDs attempt to emulate KITT's grill from Knight Rider + +//WIIMOTE 1 +//***Do not edit anything below this line unless you know what you are doing.*** +var.accx1 = wiimote1.RawForceX + var.xtrim1 +var.accy1 = wiimote1.RawForceY + var.ytrim1 +var.accz1 = wiimote1.RawForceZ + var.ztrim1 + +if wiimote1.dot1vis and wiimote1.dot2vis then + + if var.accy1 > -7 then + var.orientation1 = 0 + elseif var.accy1 > -45 then + if var.accx1 < 0 then + var.orientation1 = 3 + else + var.orientation1 = 1 + endif + else + var.orientation1 = 2 + endif + + if var.leftpoint1 = 0 then + if var.orientation1 = 0 then + if wiimote1.dot1x < wiimote1.dot2x then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + if var.orientation1 = 1 then + if wiimote1.dot1y > wiimote1.dot2y then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + if var.orientation1 = 2 then + if wiimote1.dot1x > wiimote1.dot2x then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + if var.orientation = 3 then + if wiimote1.dot1y < wiimote1.dot2y then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + endif + + if var.leftpoint1 = 1 then + var.fix1x1 = wiimote1.dot1x + var.fix1y1 = wiimote1.dot1y + var.fix2x1 = wiimote1.dot2x + var.fix2y1 = wiimote1.dot2y + else + var.fix1x1 = wiimote1.dot2x + var.fix1y1 = wiimote1.dot2y + var.fix2x1 = wiimote1.dot1x + var.fix2y1 = wiimote1.dot1y + endif + + var.dx1 = var.fix2x1 - var.fix1x1 + var.dy1 = var.fix2y1 - var.fix1y1 + var.cx1 = (var.fix1x1+var.fix2x1)/1024.0 - 1 + var.cy1 = (var.fix1y1+var.fix2y1)/1024.0 - .75 + + var.d1 = sqrt(var.dx1*var.dx1+var.dy1*var.dy1) + + var.dx1 = var.dx1 / var.d1 + var.dy1 = var.dy1 / var.d1 + + var.ox1 = -var.dy1*var.cy1-var.dx1*var.cx1; + var.oy1 = -var.dx1*var.cy1+var.dy1*var.cx1; + + var.ax1 = (var.ox1 * var.coeff*screen.desktopwidth) + (screen.desktopwidth* var.coeff / 2) + var.ay1 = (-var.oy1* var.coeff * screen.desktopwidth) + (screen.desktopheight* var.coeff / 2) + + var.dx1 = var.ax1 - cursor2.posx + var.dy1 = var.ay1 - cursor2.posy + + var.d1 = sqrt((var.dx1*var.dx1)+(var.dy1*var.dy1)) + + var.a1 = 180 / (200 + var.d1 * var.d1 * var.d1 * .001) + + if var.d1 <= var.deadzone then var.a1 = 1 + + //debug = var.d + " " + var.a + + var.finalx1 = cursor2.posx * var.a1 + var.ax1 * (1 - var.a1) + var.finaly1 = cursor2.posy * var.a1 + var.ay1 * (1 - var.a1) + + + cursor2.posx = smooth(var.finalx1,3,5) + cursor2.posy = smooth(var.finaly1,3,5) + +else + + var.leftpoint1 = 0 + +endif + +var.xpos1 = var.finalx1 +var.ypos1 = var.finaly1 +ppjoy1.analog0 = ensuremaprange(var.xpos1,0,screen.desktopwidth* var.coeff,-1,1) +ppjoy1.analog1 = ensuremaprange(var.ypos1,0,screen.desktopheight* var.coeff,-1,1) + +if wiimote1.B or wiimote1.A or wiimote1.Up or wiimote1.down or wiimote1.Left or wiimote1.Right == true + ppjoy1.digital0 = true +else + ppjoy1.digital0 = false +endif + +//WIIMOTE 2 +//***Do not edit anything below this line unless you know what you are doing.*** +var.accx2 = wiimote2.RawForceX + var.xtrim2 +var.accy2 = wiimote2.RawForceY + var.ytrim2 +var.accz2 = wiimote2.RawForceZ + var.ztrim2 + +if wiimote2.dot1vis and wiimote2.dot2vis then + + if var.accy2 > -7 then + var.orientation2 = 0 + elseif var.accy2 > -45 then + if var.accx2 < 0 then + var.orientation2 = 3 + else + var.orientation2 = 1 + endif + else + var.orientation2 = 2 + endif + + if var.leftpoint2 = 0 then + if var.orientation2 = 0 then + if wiimote2.dot1x < wiimote2.dot2x then + var.leftpoint2 = 1 + else + var.leftpoint2 = 2 + endif + endif + if var.orientation2 = 1 then + if wiimote2.dot1y > wiimote2.dot2y then + var.leftpoint2 = 1 + else + var.leftpoint2 = 2 + endif + endif + if var.orientation2 = 2 then + if wiimote2.dot1x > wiimote2.dot2x then + var.leftpoint2 = 1 + else + var.leftpoint2 = 2 + endif + endif + if var.orientation = 3 then + if wiimote2.dot1y < wiimote2.dot2y then + var.leftpoint2 = 1 + else + var.leftpoint2 = 2 + endif + endif + endif + + if var.leftpoint2 = 1 then + var.fix1x2 = wiimote2.dot1x + var.fix1y2 = wiimote2.dot1y + var.fix2x2 = wiimote2.dot2x + var.fix2y2 = wiimote2.dot2y + else + var.fix1x2 = wiimote2.dot2x + var.fix1y2 = wiimote2.dot2y + var.fix2x2 = wiimote2.dot1x + var.fix2y2 = wiimote2.dot1y + endif + + var.dx2 = var.fix2x2 - var.fix1x2 + var.dy2 = var.fix2y2 - var.fix1y2 + var.cx2 = (var.fix1x2+var.fix2x2)/1024.0 - 1 + var.cy2 = (var.fix1y2+var.fix2y2)/1024.0 - .75 + + var.d2 = sqrt(var.dx2*var.dx2+var.dy2*var.dy2) + + var.dx2 = var.dx2 / var.d2 + var.dy2 = var.dy2 / var.d2 + + var.ox2 = -var.dy2*var.cy2-var.dx2*var.cx2; + var.oy2 = -var.dx2*var.cy2+var.dy2*var.cx2; + + var.ax2 = (var.ox2 * var.coeff*screen.desktopwidth) + (screen.desktopwidth* var.coeff / 2) + var.ay2 = (-var.oy2* var.coeff * screen.desktopwidth) + (screen.desktopheight* var.coeff / 2) + + var.dx2 = var.ax2 - cursor3.posx + var.dy2 = var.ay2 - cursor3.posy + + var.d2 = sqrt((var.dx2*var.dx2)+(var.dy2*var.dy2)) + + var.a2 = 180 / (200 + var.d2 * var.d2 * var.d2 * .001) + + if var.d2 <= var.deadzone then var.a2 = 1 + + //debug = var.d + " " + var.a + + var.finalx2 = cursor3.posx * var.a2 + var.ax2 * (1 - var.a2) + var.finaly2 = cursor3.posy * var.a2 + var.ay2 * (1 - var.a2) + + + cursor3.posx = smooth(var.finalx2,3,5) + cursor3.posy = smooth(var.finaly2,3,5) + +else + + var.leftpoint2 = 0 + +endif + +var.xpos2 = var.finalx2 +var.ypos2 = var.finaly2 +ppjoy2.analog0 = ensuremaprange(var.xpos2,0,screen.desktopwidth* var.coeff,-1,1) +ppjoy2.analog1 = ensuremaprange(var.ypos2,0,screen.desktopheight* var.coeff,-1,1) + +if wiimote2.B or wiimote2.A or wiimote2.Up or wiimote2.down or wiimote2.Left or wiimote2.Right == true + ppjoy2.digital0 = true +else + ppjoy2.digital0 = false +endif + +debug = var.accx2+ " " + var.accy2+ " " + var.accz2 diff --git a/WiiMouse4IR coeff0.1.PIE b/WiiMouse4IR coeff0.1.PIE new file mode 100644 index 0000000..0aac1ab --- /dev/null +++ b/WiiMouse4IR coeff0.1.PIE @@ -0,0 +1,520 @@ +Wiimote1.led1 = true +Wiimote2.led1 = true +Wiimote2.led4 = true +Wiimote3.led2 = true +Wiimote4.led2 = true +Wiimote4.led4 = true +Wiimote5.led3 = true +Wiimote6.led3 = true +Wiimote6.led4 = true +//Mouse Control Script using IR +//by vkapadia with much assistance from inio +//vkapadia@vkapadia.com +// +//Calibration: +//To calibrate, run this program and put the Wiimote on a flat surface face-up. +//Then read the values in the debug line (next to the run button). +//Change these values until the debug line reads approx. all zeros. +var.xtrim1 = -1 +var.ytrim1 = -25 +var.ztrim1 = 2 + +var.xtrim2 = 3 +var.ytrim2 = -30 +var.ztrim2 = 2 + +var.xtrim3 = 2 +var.ytrim3 = -27 +var.ztrim3 = 2 + +var.xtrim4 = 2 +var.ytrim4 = -30 +var.ztrim4 = 2 + +var.coeff = 0.1 + +// +//Options: +var.deadzone = 5 //distance in pixels that you have to move the wiimote in + //order for it to register movement. Creates a "dead zone" around the pointer + //to make it easier to click. Higher = smoother but less accurate. +//fake cursor init + +//cursor2.visible = true + +//more options to be added later + +//Controls: +//Point Wiimote = Move Mouse +//D-Pad = Arrow Keys +//B-Button = Left Click +//Home = Middle Click +//A-Button = Right Click +//Plus and Minus = Control Volume +//One = Unmapped +//Two = Unmapped +// +//If the pointer hits the edge of the screen, the Wiimote will rumble a bit. +// +//The LEDs attempt to emulate KITT's grill from Knight Rider + +//WIIMOTE 1 +//***Do not edit anything below this line unless you know what you are doing.*** +var.accx1 = wiimote1.RawForceX + var.xtrim1 +var.accy1 = wiimote1.RawForceY + var.ytrim1 +var.accz1 = wiimote1.RawForceZ + var.ztrim1 + +if wiimote1.dot1vis and wiimote1.dot2vis then + + if var.accy1 > -7 then + var.orientation1 = 0 + elseif var.accy1 > -45 then + if var.accx1 < 0 then + var.orientation1 = 3 + else + var.orientation1 = 1 + endif + else + var.orientation1 = 2 + endif + + if var.leftpoint1 = 0 then + if var.orientation1 = 0 then + if wiimote1.dot1x < wiimote1.dot2x then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + if var.orientation1 = 1 then + if wiimote1.dot1y > wiimote1.dot2y then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + if var.orientation1 = 2 then + if wiimote1.dot1x > wiimote1.dot2x then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + if var.orientation1 = 3 then + if wiimote1.dot1y < wiimote1.dot2y then + var.leftpoint1 = 1 + else + var.leftpoint1 = 2 + endif + endif + endif + + if var.leftpoint1 = 1 then + var.fix1x1 = wiimote1.dot1x + var.fix1y1 = wiimote1.dot1y + var.fix2x1 = wiimote1.dot2x + var.fix2y1 = wiimote1.dot2y + else + var.fix1x1 = wiimote1.dot2x + var.fix1y1 = wiimote1.dot2y + var.fix2x1 = wiimote1.dot1x + var.fix2y1 = wiimote1.dot1y + endif + + var.dx1 = var.fix2x1 - var.fix1x1 + var.dy1 = var.fix2y1 - var.fix1y1 + var.cx1 = (var.fix1x1+var.fix2x1)/1024.0 - 1 + var.cy1 = (var.fix1y1+var.fix2y1)/1024.0 - .75 + + var.d1 = sqrt(var.dx1*var.dx1+var.dy1*var.dy1) + + var.dx1 = var.dx1 / var.d1 + var.dy1 = var.dy1 / var.d1 + + var.ox1 = -var.dy1*var.cy1-var.dx1*var.cx1; + var.oy1 = -var.dx1*var.cy1+var.dy1*var.cx1; + + var.ax1 = (var.ox1 * var.coeff*screen.desktopwidth) + (screen.desktopwidth* var.coeff / 2) + var.ay1 = (-var.oy1* var.coeff * screen.desktopwidth) + (screen.desktopheight* var.coeff / 2) + + var.dx1 = var.ax1 - cursor2.posx + var.dy1 = var.ay1 - cursor2.posy + + var.d1 = sqrt((var.dx1*var.dx1)+(var.dy1*var.dy1)) + + var.a1 = 180 / (200 + var.d1 * var.d1 * var.d1 * .001) + + if var.d1 <= var.deadzone then var.a1 = 1 + + //debug = var.d + " " + var.a + + var.finalx1 = cursor2.posx * var.a1 + var.ax1 * (1 - var.a1) + var.finaly1 = cursor2.posy * var.a1 + var.ay1 * (1 - var.a1) + + + cursor2.posx = smooth(var.finalx1,3,5) + cursor2.posy = smooth(var.finaly1,3,5) + +else + + var.leftpoint1 = 0 + +endif + +var.xpos1 = var.finalx1 +var.ypos1 = var.finaly1 +ppjoy1.analog0 = ensuremaprange(var.xpos1,0,screen.desktopwidth* var.coeff,-1,1) +ppjoy1.analog1 = ensuremaprange(var.ypos1,0,screen.desktopheight* var.coeff,-1,1) + +if wiimote1.B or wiimote1.A or wiimote1.Up or wiimote1.down or wiimote1.Left or wiimote1.Right == true + ppjoy1.digital0 = true +else + ppjoy1.digital0 = false +endif + +//WIIMOTE 2 +//***Do not edit anything below this line unless you know what you are doing.*** +var.accx2 = wiimote2.RawForceX + var.xtrim2 +var.accy2 = wiimote2.RawForceY + var.ytrim2 +var.accz2 = wiimote2.RawForceZ + var.ztrim2 + +if wiimote2.dot1vis and wiimote2.dot2vis then + + if var.accy2 > -7 then + var.orientation2 = 0 + elseif var.accy2 > -45 then + if var.accx2 < 0 then + var.orientation2 = 3 + else + var.orientation2 = 1 + endif + else + var.orientation2 = 2 + endif + + if var.leftpoint2 = 0 then + if var.orientation2 = 0 then + if wiimote2.dot1x < wiimote2.dot2x then + var.leftpoint2 = 1 + else + var.leftpoint2 = 2 + endif + endif + if var.orientation2 = 1 then + if wiimote2.dot1y > wiimote2.dot2y then + var.leftpoint2 = 1 + else + var.leftpoint2 = 2 + endif + endif + if var.orientation2 = 2 then + if wiimote2.dot1x > wiimote2.dot2x then + var.leftpoint2 = 1 + else + var.leftpoint2 = 2 + endif + endif + if var.orientation2 = 3 then + if wiimote2.dot1y < wiimote2.dot2y then + var.leftpoint2 = 1 + else + var.leftpoint2 = 2 + endif + endif + endif + + if var.leftpoint2 = 1 then + var.fix1x2 = wiimote2.dot1x + var.fix1y2 = wiimote2.dot1y + var.fix2x2 = wiimote2.dot2x + var.fix2y2 = wiimote2.dot2y + else + var.fix1x2 = wiimote2.dot2x + var.fix1y2 = wiimote2.dot2y + var.fix2x2 = wiimote2.dot1x + var.fix2y2 = wiimote2.dot1y + endif + + var.dx2 = var.fix2x2 - var.fix1x2 + var.dy2 = var.fix2y2 - var.fix1y2 + var.cx2 = (var.fix1x2+var.fix2x2)/1024.0 - 1 + var.cy2 = (var.fix1y2+var.fix2y2)/1024.0 - .75 + + var.d2 = sqrt(var.dx2*var.dx2+var.dy2*var.dy2) + + var.dx2 = var.dx2 / var.d2 + var.dy2 = var.dy2 / var.d2 + + var.ox2 = -var.dy2*var.cy2-var.dx2*var.cx2; + var.oy2 = -var.dx2*var.cy2+var.dy2*var.cx2; + + var.ax2 = (var.ox2 * var.coeff*screen.desktopwidth) + (screen.desktopwidth* var.coeff / 2) + var.ay2 = (-var.oy2* var.coeff * screen.desktopwidth) + (screen.desktopheight* var.coeff / 2) + + var.dx2 = var.ax2 - cursor3.posx + var.dy2 = var.ay2 - cursor3.posy + + var.d2 = sqrt((var.dx2*var.dx2)+(var.dy2*var.dy2)) + + var.a2 = 180 / (200 + var.d2 * var.d2 * var.d2 * .001) + + if var.d2 <= var.deadzone then var.a2 = 1 + + //debug = var.d + " " + var.a + + var.finalx2 = cursor3.posx * var.a2 + var.ax2 * (1 - var.a2) + var.finaly2 = cursor3.posy * var.a2 + var.ay2 * (1 - var.a2) + + + cursor3.posx = smooth(var.finalx2,3,5) + cursor3.posy = smooth(var.finaly2,3,5) + +else + + var.leftpoint2 = 0 + +endif + +var.xpos2 = var.finalx2 +var.ypos2 = var.finaly2 +ppjoy2.analog0 = ensuremaprange(var.xpos2,0,screen.desktopwidth* var.coeff,-1,1) +ppjoy2.analog1 = ensuremaprange(var.ypos2,0,screen.desktopheight* var.coeff,-1,1) + +if wiimote2.B or wiimote2.A or wiimote2.Up or wiimote2.down or wiimote2.Left or wiimote2.Right == true + ppjoy2.digital0 = true +else + ppjoy2.digital0 = false +endif + +debug = var.accx2+ " " + var.accy2+ " " + var.accz2 + +//WIIMOTE 3 +//***Do not edit anything below this line unless you know what you are doing.*** +var.accx3 = wiimote3.RawForceX + var.xtrim3 +var.accy3 = wiimote3.RawForceY + var.ytrim3 +var.accz3 = wiimote3.RawForceZ + var.ztrim3 + +if wiimote3.dot1vis and wiimote3.dot2vis then + + if var.accy3 > -7 then + var.orientation3 = 0 + elseif var.accy3 > -45 then + if var.accx3 < 0 then + var.orientation3 = 3 + else + var.orientation3 = 1 + endif + else + var.orientation3 = 2 + endif + + if var.leftpoint3 = 0 then + if var.orientation3 = 0 then + if wiimote3.dot1x < wiimote3.dot2x then + var.leftpoint3 = 1 + else + var.leftpoint3 = 2 + endif + endif + if var.orientation3 = 1 then + if wiimote3.dot1y > wiimote3.dot2y then + var.leftpoint3 = 1 + else + var.leftpoint3 = 2 + endif + endif + if var.orientation3 = 2 then + if wiimote3.dot1x > wiimote3.dot2x then + var.leftpoint3 = 1 + else + var.leftpoint3 = 2 + endif + endif + if var.orientation3 = 3 then + if wiimote3.dot1y < wiimote3.dot2y then + var.leftpoint3 = 1 + else + var.leftpoint3 = 2 + endif + endif + endif + + if var.leftpoint3 = 1 then + var.fix1x3 = wiimote3.dot1x + var.fix1y3 = wiimote3.dot1y + var.fix2x3 = wiimote3.dot2x + var.fix2y3 = wiimote3.dot2y + else + var.fix1x3 = wiimote3.dot2x + var.fix1y3 = wiimote3.dot2y + var.fix2x3 = wiimote3.dot1x + var.fix2y3 = wiimote3.dot1y + endif + + var.dx3 = var.fix2x3 - var.fix1x3 + var.dy3 = var.fix2y3 - var.fix1y3 + var.cx3 = (var.fix1x3+var.fix2x3)/1024.0 - 1 + var.cy3 = (var.fix1y3+var.fix2y3)/1024.0 - .75 + + var.d3 = sqrt(var.dx3*var.dx3+var.dy3*var.dy3) + + var.dx3 = var.dx3 / var.d3 + var.dy3 = var.dy3 / var.d3 + + var.ox3 = -var.dy3*var.cy3-var.dx3*var.cx3; + var.oy3 = -var.dx3*var.cy3+var.dy3*var.cx3; + + var.ax3 = (var.ox3 * var.coeff*screen.desktopwidth) + (screen.desktopwidth* var.coeff / 2) + var.ay3 = (-var.oy3* var.coeff * screen.desktopwidth) + (screen.desktopheight* var.coeff / 2) + + var.dx3 = var.ax3 - cursor4.posx + var.dy3 = var.ay3 - cursor4.posy + + var.d3 = sqrt((var.dx3*var.dx3)+(var.dy3*var.dy3)) + + var.a3 = 180 / (200 + var.d3 * var.d3 * var.d3 * .001) + + if var.d3 <= var.deadzone then var.a3 = 1 + + //debug = var.d + " " + var.a + + var.finalx3 = cursor4.posx * var.a3 + var.ax3 * (1 - var.a3) + var.finaly3 = cursor4.posy * var.a3 + var.ay3 * (1 - var.a3) + + + cursor4.posx = smooth(var.finalx3,3,5) + cursor4.posy = smooth(var.finaly3,3,5) + +else + + var.leftpoint3 = 0 + +endif + +var.xpos3 = var.finalx3 +var.ypos3 = var.finaly3 +ppjoy3.analog0 = ensuremaprange(var.xpos3,0,screen.desktopwidth* var.coeff,-1,1) +ppjoy3.analog1 = ensuremaprange(var.ypos3,0,screen.desktopheight* var.coeff,-1,1) + +if wiimote3.B or wiimote3.A or wiimote3.Up or wiimote3.down or wiimote3.Left or wiimote3.Right == true + ppjoy3.digital0 = true +else + ppjoy3.digital0 = false +endif + +debug = var.accx1+ " " + var.accy1+ " " + var.accz1 + +//WIIMOTE 3 +//***Do not edit anything below this line unless you know what you are doing.*** +var.accx4 = wiimote4.RawForceX + var.xtrim4 +var.accy4 = wiimote4.RawForceY + var.ytrim4 +var.accz4 = wiimote4.RawForceZ + var.ztrim4 + +if wiimote4.dot1vis and wiimote4.dot2vis then + + if var.accy4 > -7 then + var.orientation4 = 0 + elseif var.accy4 > -45 then + if var.accx4 < 0 then + var.orientation4 = 3 + else + var.orientation4 = 1 + endif + else + var.orientation4 = 2 + endif + + if var.leftpoint4 = 0 then + if var.orientation4 = 0 then + if wiimote4.dot1x < wiimote4.dot2x then + var.leftpoint4 = 1 + else + var.leftpoint4 = 2 + endif + endif + if var.orientation4 = 1 then + if wiimote4.dot1y > wiimote4.dot2y then + var.leftpoint4 = 1 + else + var.leftpoint4 = 2 + endif + endif + if var.orientation4 = 2 then + if wiimote4.dot1x > wiimote4.dot2x then + var.leftpoint4 = 1 + else + var.leftpoint4 = 2 + endif + endif + if var.orientation4 = 3 then + if wiimote4.dot1y < wiimote4.dot2y then + var.leftpoint4 = 1 + else + var.leftpoint4 = 2 + endif + endif + endif + + if var.leftpoint4 = 1 then + var.fix1x4 = wiimote4.dot1x + var.fix1y4 = wiimote4.dot1y + var.fix2x4 = wiimote4.dot2x + var.fix2y4 = wiimote4.dot2y + else + var.fix1x4 = wiimote4.dot2x + var.fix1y4 = wiimote4.dot2y + var.fix2x4 = wiimote4.dot1x + var.fix2y4 = wiimote4.dot1y + endif + + var.dx4 = var.fix2x4 - var.fix1x4 + var.dy4 = var.fix2y4 - var.fix1y4 + var.cx4 = (var.fix1x4+var.fix2x4)/1024.0 - 1 + var.cy4 = (var.fix1y4+var.fix2y4)/1024.0 - .75 + + var.d4 = sqrt(var.dx4*var.dx4+var.dy4*var.dy4) + + var.dx4 = var.dx4 / var.d4 + var.dy4 = var.dy4 / var.d4 + + var.ox4 = -var.dy4*var.cy4-var.dx4*var.cx4; + var.oy4 = -var.dx4*var.cy4+var.dy4*var.cx4; + + var.ax4 = (var.ox4 * var.coeff*screen.desktopwidth) + (screen.desktopwidth* var.coeff / 2) + var.ay4 = (-var.oy4* var.coeff * screen.desktopwidth) + (screen.desktopheight* var.coeff / 2) + + var.dx4 = var.ax4 - cursor5.posx + var.dy4 = var.ay4 - cursor5.posy + + var.d4 = sqrt((var.dx4*var.dx4)+(var.dy4*var.dy4)) + + var.a4 = 180 / (200 + var.d4 * var.d4 * var.d4 * .001) + + if var.d4 <= var.deadzone then var.a4 = 1 + + //debug = var.d + " " + var.a + + var.finalx4 = cursor5.posx * var.a4 + var.ax4 * (1 - var.a4) + var.finaly4 = cursor5.posy * var.a4 + var.ay4 * (1 - var.a4) + + + cursor5.posx = smooth(var.finalx4,3,5) + cursor5.posy = smooth(var.finaly4,3,5) + +else + + var.leftpoint4 = 0 + +endif + +var.xpos4 = var.finalx4 +var.ypos4 = var.finaly4 +ppjoy4.analog0 = ensuremaprange(var.xpos4,0,screen.desktopwidth* var.coeff,-1,1) +ppjoy4.analog1 = ensuremaprange(var.ypos4,0,screen.desktopheight* var.coeff,-1,1) + +if wiimote4.B or wiimote4.A or wiimote4.Up or wiimote4.down or wiimote4.Left or wiimote4.Right == true + ppjoy4.digital0 = true +else + ppjoy4.digital0 = false +endif + diff --git a/src/controllers/Wiimote.py b/src/controllers/Wiimote.py new file mode 100755 index 0000000..7536881 --- /dev/null +++ b/src/controllers/Wiimote.py @@ -0,0 +1,106 @@ +''' +Created on 15 juil. 2009 + +@author: Samuel Benveniste +''' +from gui.constants import * + +class Wiimote: + ''' + Object representing a Wiimote + + number: + The number of the Wiimote + port: + The pypm object representing the MIDI port on which the Wiimote emits + instrument: + The instrument associated with the Wiimote + cursor: + The cursor associated with the Wiimote + ''' + + def __init__(self, number, portNumber, port, instrument, cursor): + ''' + Constructor + + number: + The number of the Wiimote + portNumber: + The number of the port (as numbered by pypm) on which the wiimote emits + port: + The pypm object representing the MIDI port on which the Wiimote emits + instrument: + The instrument associated with the Wiimote + cursor: + The cursor associated with the Wiimote + ''' + + self.number = number + self.portNumber = portNumber + self.port = port + self.instrument = instrument + self.cursor = cursor + self.numberPlayed = 0 + + def getNoteOnHexCode(self): + return (0x90 + self.instrument.channel - 1) + + def getAftertouchHexCode(self): + return (0xA0 + self.instrument.channel - 1) + + def getCCHexCode(self): + return (0xB0 + self.instrument.channel - 1) + + def playNote(self, note, velocity): + noteNumber = self.instrument.getNote(note) + + if noteNumber != None : + noteOnHexCode = self.getNoteOnHexCode() + CCHexCode = self.getCCHexCode() + else : + noteNumber = defaultInstrumentNote + noteOnHexCode = defaultNoteOnHexCode + CCHexCode = defaultCCHexCode + + self.port.write_short(noteOnHexCode, noteNumber , 127) + self.port.write_short(CCHexCode, 07, velocity) + + def playNoteByNoteNumber(self, midiNoteNumber, velocity): + noteNumber = self.instrument.getNoteByNoteNumber(midiNoteNumber) + + if noteNumber != None : + noteOnHexCode = self.getNoteOnHexCode() + CCHexCode = self.getCCHexCode() + else : + noteNumber = defaultInstrumentNote + noteOnHexCode = defaultNoteOnHexCode + CCHexCode = defaultCCHexCode + + self.port.write_short(noteOnHexCode, noteNumber , 127) + self.port.write_short(CCHexCode, 07, velocity) + + self.numberPlayed += 1 + + def stopNote(self, note): + noteNumber = self.instrument.getNote(note) + if noteNumber != None : + noteOnHexCode = self.getNoteOnHexCode() + else : + noteNumber = defaultInstrumentNote + noteOnHexCode = defaultNoteOnHexCode + + self.port.write_short(noteOnHexCode, noteNumber, 0) + + def stopNoteByNoteNumber(self, midiNoteNumber): + noteNumber = self.instrument.getNoteByNoteNumber(midiNoteNumber) + if noteNumber != None : + noteOnHexCode = self.getNoteOnHexCode() + else : + noteNumber = defaultInstrumentNote + noteOnHexCode = defaultNoteOnHexCode + + self.port.write_short(noteOnHexCode, noteNumber, 0) + + def allNotesOff(self): + CCHexCode = self.getCCHexCode() + self.port.write_short(CCHexCode,123,0) \ No newline at end of file diff --git a/src/controllers/__init__.py b/src/controllers/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/src/cursor/WarpingCursor.py b/src/cursor/WarpingCursor.py new file mode 100755 index 0000000..57985e1 --- /dev/null +++ b/src/cursor/WarpingCursor.py @@ -0,0 +1,155 @@ +''' +Created on 29 mai 2009 + +@author: samsam +''' + +import os, sys, math + +import pygame +from pygame.sprite import Sprite + +class WarpingCursor(Sprite): + ''' + The class for animating the warping cursor + + screen: + the screen on which the WarpingCursor is painted + images: + The images constituting the animation of the cursor + durations: + The duration of each image in the animation + centerPosition: + The Position of the center of the cursor + _imagePointer: + A pointer to the current image + _animationOffset: + The time elapsed since when the current image should have been displayed + ''' + screen = None + images = None + durations = None + centerPosition = None + _imagePointer = None + _animationOffset = None + + + def __init__(self, scr, images, durations, initCenterPosition,flashImage): + ''' + Constructor + + scr: + the screen on which the WarpingCursor is painted + images: + The images constituting the animation of the cursor + durations: + The duration of each image in the animation + initCenterPosition: + The Position of the center of the cursor at the beginning + ''' + self.screen = scr + self.images = images + self.flashImagePath = flashImage + self.durations = durations + self.centerPosition = initCenterPosition + self.flashLength = 100 + self.flashing = False + self.image = pygame.image.load(self.images[0]).convert_alpha() + self._imagePointer = 0 + self._animationOffset = 0 + self._flashTimer = 0 + + def update(self, elapsedTime, centerPosition): + ''' + Update the cursor's look and position + + elapsedTime: + The time passed since the previous update + centerPosition: + the new position of the creep + ''' + self._updateImage(elapsedTime) + self.centerPosition = centerPosition + if self.flashing : + self._flashTimer += elapsedTime + if self._flashTimer > self.flashLength: + self.flashing = False + + def _updateImage(self, elapsedTime): + ''' + Update the cursor's image + + elapsedTime: + The time passed since the previous update + ''' + self._animationOffset += elapsedTime + + if self._animationOffset > self.durations[self._imagePointer]: + #New animation offset is computed first, before updating the pointer + self._animationOffset -= self.durations[self._imagePointer] + #point to the next image (restarts from the beginning when it reaches the end) + self._imagePointer = (self._imagePointer + 1) % len(self.images) + + if self.flashing: + self.image = pygame.image.load(self.flashImagePath).convert_alpha() + else : + self.image = pygame.image.load(self.images[self._imagePointer]).convert_alpha() + + def flash(self,flashLength = None): + self._flashTimer = 0 + self.flashing = True + if flashLength: + self.flashlength = flashLength + + def blit(self,surface): + ''' + Draw the circle on surface + ''' + + newPos = (self.centerPosition[0] - self.image.get_width() / 2, self.centerPosition[1] - self.image.get_height() / 2) + surface.blit(self.image, newPos) + +def createImageListFromPath(path, imageCount): + ''' + Create a list of images for a cursor (the concatenation of the original and reversed lists of images). + Images must be stored as path/imageNumber.png + + path: + The folder where the images for that cursor are stored + imageCount: + The number of images in the folder + ''' + + tempImages = [''.join([path, '/', str(i), '.png']) for i in range(imageCount)] + #tempImagesReversed = tempImages[:] + #tempImagesReversed.reverse() + #return(tempImages+tempImagesReversed) + return(tempImages) + +#testing +if __name__ == "__main__" : + window = pygame.display.set_mode((1680, 1050), pygame.FULLSCREEN) + screen = pygame.display.get_surface() + clock = pygame.time.Clock() + + images = createImageListFromPath('cursorImages/black',11) + durations = [50 for i in range(22)] + position = (400, 300) + cursor = WarpingCursor(screen, images, durations, position) + + while True: + # Limit frame speed to 50 FPS + # + timePassed = clock.tick(50) + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + sys.exit() + if event.type == pygame.MOUSEMOTION: + position = event.pos + + cursor.update(timePassed, position) + cursor.blit(screen) + pygame.display.flip() + + diff --git a/src/cursor/__init__.py b/src/cursor/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/src/cursor/cursorImages/black/0.png b/src/cursor/cursorImages/black/0.png new file mode 100755 index 0000000000000000000000000000000000000000..d676349a2e625ff228624850ffab8e94fa4cd5e4 GIT binary patch literal 1499 zcmV<11tj{3P)rG;Hu zDp*ov>9V-7tQU`a$U!eTEuO?{PaayxMS9sqij}2EDQqb%vTU&wJZR{~)l62gcHK08 zrju!Ydob17ZJJJ7JM{x|$Uo-u&HFR&{bnR0!fufy=@5WkMNy)Rv2dkQ30jtQ)HF>$ z5lKFuufRE9lx6wva=H9hKA)ceFiJ!(cYW@i29PA_7=Z5%A3l6}d3pKENF=h-*Vm^s zH#bAmH0ZhxUDwgj(11)P^X_>5{5i(P#tIJ}Jm9LTKFZ~C!$kB85v6w|LPU-Z00G9> zO~#nn+1XjRb?X)xhCxnQT3Vvpw{O#h3l~a^F-r)M1kmKz$ALJLBz)Jv za8?NMIv$T(wrzhj`SlD846OQmz9N9WT?GKp&p9t8lgY}yn6G1ee4JEOH5p?+?I-|% ze!t&enx3BCZ})ekQYq4Py|7h?TJmRnK3{2aa?&OB_oPxOQdQNg)txqzZxTYh8X6kf z_ij^*@$qr0j*0&b?2Yo0s;Up;@%W01zMC>IFtA#koj#aiHwL&I4u|vmHQP9)tE;QX z7`s861pvT>5HCkZM_rZNin+NtVvL#Vuh{Pb$g-ShYirB9t5}~{EM^KJlC(Ym0F^OT zn35=RG=%5jeMio_6&&iCjP)kdT&ut;696x>>Ua$9rEQDwY27_+< zI7ZiXR4SFvWdORSX>R*CM%Q(irg>DhEUW2LZGn}Q6-AaLY1OuEw|yLA+cqRgBH8Qp zzQ|^?Zu>YUlgWT{zAO{bGs7_4_Hj%mlL2FFQ7)BAe}0NBU>F8uSe zoJb@r7kxhzu#X1&|lND)(2D#!8w1ENF=QN9uq@DLlvLTx21gD0M!sD6h(R5+uOS@vy*Mx z6pzPOgb=R)oT=+q?+f&PVBc$OY%C5A4${ZE*o}^kQaBvWtE&1C+q~($tpMwSL={Cz zg+igiUM@RkW@f0Ztu0@@19KVGM!bkwx0et24dP72pFC<9{ zmCNNOBJwcCUI56HN~HzMvYr9>1Hf-YRNn2m{{tK|GG}MI6z%{3002ovPDHLkV1luH BxFrAp literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/black/1.png b/src/cursor/cursorImages/black/1.png new file mode 100755 index 0000000000000000000000000000000000000000..7703e899090c5ac158be19484c7a20e99e7b17c8 GIT binary patch literal 1618 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 D@_Cg8 literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/black/4.png b/src/cursor/cursorImages/black/4.png new file mode 100755 index 0000000000000000000000000000000000000000..7c9d191a50859b8b64fce3155fca1bfff8e63553 GIT binary patch literal 2034 zcmVS&cDRT|j9U z7-dW;{W&dt_hKl6EPv;eg?WKt)DI#<{7fseJ_n z1Bh!J^7(wE6_b;b)YjHU<>lpJ#+b@EZvn7PvmOn?nIH(? zN|F>PDJcoPc=1BB=%p|;G(?q^l@Z2RgfaFV0P~s}0AP`2`Bgzd!E|S5=b8y$h=G9t zDlRS#an8p9IM&1ffI`msC%4bMSh-WVKqSmou@Hc$dj!3U_sNZIJZe;PrY* zQIyD1(`hmB+c@VxH#ax0`?OgK9*>7+*TnxU?1kb5MNyu+-R|fH>RlA|_4PBeyVDn2 z>_P+Q^78V6>$TfxMR9R)h%xpZEoK0K#5o`D=;+u`k;`FVV1O87k@lpJK@k2*$tlD+|Dmp~ZbomwiHQk1efspAP?yU^7cN|&=H_N({z+PEJme!C;63*a`rp+1c44U6F|B%$YL;fKHw~NmEl( zEB04al`dYqNC0U6{{5tP%RYGUU=YAJ0Pwe}s;Y>dAnon#1c0`0-%g)De_k~&9*@($ zeftOiUAuNoPine)^(rZfavO}Xe_Xk8MOTpA+*|@c4<0K6 z)>hiGWy?<@=X_^QPLAg7Y+_;pBO@c&wQCnjOG`EL^Yim@^ypDUqfrbD3~1(CtyUxw zi9d<}tQLz!bAbN-egHsWVWDPj5=m}vZ?9&q)oMi~63G@-Ro$j%1bz<&qS2@<3W6{b zkH<9!Fc=H~06p9!lH9bkG+kUl5J)r{jbnblUvmJb(+L20_UxHvZW2kZ%jMF{9UUEo zBuP^u5xw{Me3}F7-Mbe6@bu|Z&D_Lrmg>q$MC5Qdf&k6}fFMcIFWueUx&j4*LE5ut4*{Ue%uH%)Yg@9f$KxTJ%|-wy zJ3E_3Mn-hy^!a>bFc@M0HiL*DNm5HqO^xn@a4;C8OP4N@AP95MMimtmbp85us;{r7 zs;Vl=&(EKG+^(popz-l>z3Hg2v5_(|GI}U^9sqFMVzH!roP7B3Avqk5IU@_(&Ye4{ zy}dovG*nbnG!3Ad<{c>+=iGnu=FO~Ar%q{JPzw2xA1D=X#LFJHcd z%jJrys%j&miTPEDuWdHl^zXH#l0->KNr*A_JuOmJ5oKBSHZ?VEtiol`+1W{wBn1GZ z(-MWP<5^i*q1BwM)*JD7oC*pGrUgOxmX@oH%Ch`pSy@>q)ylzI!|isfvMj#>z-Wcy zt}M&)U~O%!x`BGXKub$Yf^+@}fQ43BUeA>z>GQ2yw>EqjdU|?DlB6(zLRw7gVn5Qa zCJr;kA{%LM>*#|18}XVZ>0|O+rs`aD=RD1)YPQA7_|~QIyxvXFE6Ml%5$vp zrT3}~%rkOamSwNaW}Ciy_wJerfBg6{Ii1en>>HSKnEeD|%?-?&5CMG6Isa&}Sb{Y* zHSzB5Zq1|8*VjjNb#*g#yFI`dn-)c}7J#HxPbwdKFaUp%B%*1 zIXOA7SS-lN$w69L8vK4gd_Euiem~y5dl$Wb|9&D62*6-4{4*R5w*$CGL_u9T^cq-T zMgZ_<0Edi5qm6U^CqWQwu~=*y5g8a`V*p0O;qW_ERo?^X1@MT7VyWi-FW-@>s+GrR Q(EtDd07*qoM6N<$f=MT~cK`qY literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/black/5.png b/src/cursor/cursorImages/black/5.png new file mode 100755 index 0000000000000000000000000000000000000000..34b149dda3f94a787d676973b72227cfff2a7c93 GIT binary patch literal 2154 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 literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/black/7.png b/src/cursor/cursorImages/black/7.png new file mode 100755 index 0000000000000000000000000000000000000000..68ec2dd9f729d801359d65a30943bc171b2a58e9 GIT binary patch literal 2450 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 literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/black/9.png b/src/cursor/cursorImages/black/9.png new file mode 100755 index 0000000000000000000000000000000000000000..e5e4f092c9e399abfecefae5f06378c2cdbbba5f GIT binary patch literal 2550 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 M07*qoM6N<$g6S64e*gdg literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/black/cursorBlack.svg b/src/cursor/cursorImages/black/cursorBlack.svg new file mode 100755 index 0000000..7c3c9b4 --- /dev/null +++ b/src/cursor/cursorImages/black/cursorBlack.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/cursor/cursorImages/black/flash.png b/src/cursor/cursorImages/black/flash.png new file mode 100644 index 0000000000000000000000000000000000000000..412cbcee1a0eb61bbf41bac44a82e61407c9f487 GIT binary patch literal 904 zcmV;319$w1P)8^nS{N+dubDH1`I9tnwp9#KTR zLKIP^PC-XWfuN@24G;wq4?qM$iL4Y9G)W|6#}0VC?B!2kK$!TlyIy*4OkuP%6onK@krCT4Ut$Qoc9s zB-zmR_OSfm*1)u*BYb>#vtbE|h)Kff*Do6d5$O9NwqXf*9=d+D_ZrVb?f&(h0|y84 z)-Yi9Us5;>18Q?qCT_3qmJlg^r;XU4K!PGPfSVauT$C5XA|3!lAX8KF47iyA*OhD2 z?EN+&PFxqZX)<%OgrxgJK_XC$_4WEx3?q}1k`vp;Wh#Y{q{T$x;sOQneGEZvYkf34PC?+i=Dwc(!v9^XcNehX}_BLjQe>)8T zz7H>HDPi%vdiKNsfcbe$v^O6-R#q?#{4a-k0NC2XRC1ESvA>U*+s_S|InNVUDX2tL z1;qE^83yn2R}C*R(?q8KlER@>qs9gYNV;cd_}pJf!8tj>>OZBYW@+GZ8DEpmL_cih zGQKtIXj$N}ZTXWWPTH232BAvRsl?QFH>x#r)hf>8mlcdk1%-Cv zfdJd-T#nO)0zSnjD;S4|c%RR6wv%1hLbs(<@@kEnfpF`+s5yu eB|M4a*?$2W^iv-%offtL0000wGziIxw63X0u}Z})DDwbN zP$T6bcmkdv{jGPEbhluow5h2`5k-ni7A}_c{OmoqvF)#Be1cl2Q#&(RFod zt>Q{W*Jo!^x2x1#UP@=gdQu4g06OtJ4Xahfolbhu&(Y~f)v998 z(-3q5`tYI#Kw%K*B8qg=YQ3EB$Fy2f6zL`ibO8!q!~p1%=V@54Ycid_p7W4fcy`%X zo2~dI?Y3mCZl7CDPi|Px(=dx=^Bj$aW{W-X)5iWOR0e@A>UB*r)cYj$x+aV0^h1b! zY~Un{bn_O`CN0zHJj8-d^ppWm(epHX%{adkw#9V!LY|v^4@~5@&HBJZ tejDA7jQmko4RU|kV`T%6%w%@m=065>-8|0Di`M`E002ovPDHLkV1oU?tGoaJ literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/blue/1.png b/src/cursor/cursorImages/blue/1.png new file mode 100644 index 0000000000000000000000000000000000000000..894e8c4a836e16c156c787f3ff1d415296b72c7c GIT binary patch literal 1021 zcmVf9{%hc2^7(FA@lW=Ir6EIkce#d+^qL z06lmX@&&y43B(VO`+IIl@Z!NjuAzq>gn}M|uy`qfq8pR2dEUb&YOTKQ#*O>NAN&tH zEHlqDnVro1XXYgFSmx$%fpyDb&GRVQHu*4Qxz}R}z!<*UHs@i;SrBkK9P$}Bl;}RX z?MV&H&G7=LWV38`yS&fm=~pVag#vai2jc+n{hMgF3F~#bXJ`E7x*YxZ!9PG45LGy_k0OdVT$Hk&98;#_I-=)!zibY*|o{mBJL=1plJB~Wls``V$ z^u&)D45VsR{n4-S`cVcfOIyb1s#eo*`qF=ushRs9NY8sBdiC;eKU#3dW({Z(`eu{eU zrCL>gG&}t?#ojfrT`cPIDQ26v32{f~WZAd}H< zxvU^viNB{@j+Py|Z2zMQWwBPN;HE7qE|m(dWwB;?9>qcdJ8eO6DHO0hkD_JU!iNvhv+G7>uU;kBMlJ`v9!u8m zUyV<%2gcky8xxgH1Irk``+l;OzIg)&2XJ^8#lb;TmL$F(CCn__<~(Tw0Q>vkI8p5H zCtttsgKcv@ABLRyK7S|Q1iX7UjanmoAHt9`D+oAkw+W}$)O2XK34?%BYdGX{z5e(l z>r+#&(;X#=XM8ay(RE#pK7LHQPyd`xpTKoFlIV_iWLu?@F4FGVKc!UC1w_fNncq@A zk4?RvLs~_%p4ifJNG)pCle@YxF}vyYam@4qhi;je*(0Xw7iRg8@0N+#J!ZXSVs;O@ r?-==CT{W2b%N`ROxML=@>o)%aOB(n&5X}7?00000NkvXXu0mjfsmAA6 literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/blue/10.png b/src/cursor/cursorImages/blue/10.png new file mode 100644 index 0000000000000000000000000000000000000000..8ef30f7b5956a74638bd7869548b2ed1eaca5317 GIT binary patch literal 1300 zcmV+v1?&2WP)Y&lSdrJKX-P96i3001Ww6-Lz3<(99^bvM@6Iuj=vT&20DduspL03B15P`~pmXE_tmV*J_JH^GI{!+P zf%_8Gz6Y1oQvsDg_w#xE15z)g(e^&5)H6p9;6uh}(-^s4!K1|(Ib*a58agrqpd4t? z7#)5saF3Bg&>|?8mdm7h28`jdwfycJg|tia+iziXH28aG2j0F-zpSmL>Kqdie|Ahx z@yXxl^r;sL()6^nv?RTJDb;FfQ>_-%EiDDPg+i*?xY5@V0^Lm-WPDs&Uzhgx+krc2 ze?MqDKHhO@-R;Q$=uTXxV`I|Or&7J%J$O|0deGO{SfYtLT^RsP$8~o7x>T+94<1#u z8uXoDVmg%p&}HA6H%7XBTXOE}!#CwzForR)&&1_K1E9RM+Ko20R$5s(I`F7gR)R4- z9J`==l7UCQ>6@R=4!)`R`PilO$ZG&p@GYI0ne5@4nwg1RN(G;R)oAjC3)0@+@fq0L z3m81Ju-ak(bk?`GSzbOq_@N;GqH@{$MtUU)13CqK1Wa>(G%^B}3gq+YH(*Dp!$T;Q;LV$suz(>8+#&=IFg0~@ z;2~g{nraIh;FblhMr*EJ%Ydp&#V}np#^^7J@59k|@8I<5Ot@0({d*`DTVuxXx3!j$ zaBy(&og_usjNy}Yj+P6L&!1s;H%qK^+T9Jz&!V0-)Iypf!PbLWB$W=H~tt;9!b z*$&rKDzLScC1SF+w%XvamTifT%>&JY=ze>0^0-d{Uo<)CJ_2Whl z7(DO}G^)s5~7VHY?R?0fWcD=KtIw1H-;+mASd&GcY$7d#y6uW}snW(RZ1& zu#i3c!b0rD)?y2D#K3^Hszw{-a?-{|cJLb;!I++dd=)ehYoK9b+!)n;CbF1`g#|x+ zgK4~tHyUV|xEV8jnwvYC2fJ4DulZ29>1Fi=74zNDEEg|ItE*oReswkIGXefVEN5Ir z!^FdcPBk$hJ$oh{9CQzTa1gYem`DT{=wTvbQf0%$tnZl!mts+xot4(sq)NsA(^I`3 z)UB-rxy52Kcw@}jPJC&9X8plhUO2}$Y4$GpJe)bx`ZMe6*TD^28d=L{=lD_LkB-Tm z9EN6M0Q98OZ1htaeLso5D*IYO9wS9#^c>ILsgL3seHOds>9#@0$a&D?TuzlUB1O zexy)bDDAjZtD;6UVi9oXe6pI&Se;;>!o$|o}e^?e9-@frT zur5*RC=f|)70^I1s3p^slT7MlWkuTCQ`_wBN-HZ;GN}{OloJeU2{h1lJZ%Kt4_XX` zR7$1f6bkJJ-HJj%N~Pq4LMnk4LH)i807Y$EJBfr&b2M-0gH)*PVZy2X_s2fTVg?rx=8?NAQV#RF4y_nlFLbr zp>+PnJ{J%SYAKbH)7=n%O)BMWJ9Jq9XxKFU-5%T(g@R<7azMk9FdBQh^!PaS$;poP zgZIkhB#e(!2hxBiARK0XZjOPjM%D&%a}0#T%r}0@3IL_ibTM588s>uM*I@+=@U#(x3*7Ddu{w6 z5`jvE5#!fQe;?O{z)xmVAmFv}6T>t)E*Aayv#BZA+G=gz+Va}?L9ys1%zT~1hlkRm zN7C1?*KJ?Ec(%hse|$A3alh+wP%QGNA5Ud$4Bozl*;#n?3Z6Xi>hpPc_s+A8jrrlp z>jBs0px<%W+uz3pf8GU8pTftF@a7G?e(lvwO?h>G1rJ_|(s9@W^ei6NcYiwe{)or* z9rTQz-^@vrEsKr!@BQoEyXM0Ouq-wt%FPqmLNck7Za>-IC7IL-c*(AwKTFEm&T@ul=S4`&(dij#?l8D~DX1ye$cQ3lH2>D-q mYS8l^dvq+|ikPl_Zu1`v>>Qgc!H;qP0000R7SD6U=?g+j29 z?vh2;0T(WlO(GPs)IZ>&yGM3yiHpKpyaz%E#1y)56&I}_ff9r^F<$k0-eT04#MF52 zO;U57?m2jA+$s}1Qa9|uAk;x<(4)at>R-8^I0FDhD z&j5js09jzQ`X=OZWF*3h%f&LlHGm_w3II6k@h~3<@GO(DFYv3#WXM2( zXC4pp0B3Cx0Puy&#d0jhTD^XE!M9Pbld%|Ut$*W%B>_TkRZ3RVX*TaZ^vg)6*_4u1 zA-HNvfDl}rm|!)Vz3oaHpkD9Kuh$iKVL`Pui&6>DG#m@VK+%c-07xW&d>+`| z?$6!cR@_9wn$J=RFbouJo5(gcNKGRX39{B>Jy)x#dzyB;`Jx{>6PaD5M0=*yG%^?@ zH#f--ACzrws%!1wd(G5?qEkxPUCiz6k*{Bq)6*Bl-1M}%wzp@Gk4wcINqD{doJ`u& zc{jd)S7tYoNz&`(XLhZ~R>NVQ+VARa5DxPcP@7#tzodK|i+VnWZ50mt#ugvL)*^>} zbC(w)hIf0tZ9{#)!7dR)d&JZs4D%shmx$p#X6+I&ya(M^g#1yj8Vvo*9;O9c5%XZL a+x!nQg_jpLwe#%&0000r(iXeYC`BTpbX2CWU=310M!^giXMDD}48{a+ zm@$MnM|v7Q?z!(A`^|gzy%~)pdWEJT0^oP0@SABOrR#{hF2))Si~xXPU|ZL*>AF~R z9IUol_y@pWB=&pmJE#Fo!*u}D(J21d-^Wxuj>G9`L=p+;u^8Yr0H{{mtx|!zxQP9= zHT)8Z;P20$@h5;q616}=Ncw632SOn(7zQ27Vm+THS6As9py#bV?=vqPw9~BGYL);V^3evjDGMr~!a+)8tAj#l2$j;)I_@u}G#; z+%rwC0E}OV0f6_zVb*dv9yXhoC*DJ|N#=4qJo+~7_hdjR&KU*|3I(< z2TE}+kO8GQH#Ecp+y36t+pukNXz2e8lc!he;L@vj}quHrrial*0n@Vx-d(1X|(QL{T3oy&G3;-Mm zhgrMKdA?T^i{#NzI$p7l4TM5mNT=yst;BC5otCnLN4hnV&@@~(4E+1<9U>DGfl8_l zeEI}@{0J;B%kL8tz}>sRjT^n^US0+sJivaVfnQ0~yx}uvS*-W^>AZPECX@2Lp4E~` ziRl%V#X2Bs14tqo<=cEdc*5;%a(1>YbbOqgnUQKUpO>G<$J_s(ofS?{K?naBr$++Ha3FwSuT^I5E}p^0GLT8xf?7M`RI`d zdiRpz=lLZ_lGm?A$nD$Yu8)skcUL%o}nGU=%$I3(sjhWy{jLT%fQwa zFgXcKP5I|fO$m2vOLF-|EC%R0;>vX~7Q{fQB-hDF|6C6q*URMxu^8aG7*mY~M*7u2 zqk$0>v~$;$tM2>mX~W}sxq?6$2DYnJ|3u4@>-+b?JOA*ZGnXG!t8!qbbRC;P4BWfd zDIy3w^Ik4Ls8#`8$EI>!tOYS}=MFGDEFx^%Ki{^6J3K78{GwU~To-G~aj;sc!1pNB zG~n4Ypw$ANJOLc%{9MNoPOBw3G|g}CazyDkSVga;#KVWOqRz~a^>fs-^}56Y!VQY! zQli&lZhf7+c~bCH_tlM!J`k(Nbfv*e2x(z03k zn^F>!$p|MXI?8EY;D+YaD{^$S`-Wz8RAPF?$qmh=Y$+=hSzWyq*0Q7}620d>b4$rS z-qim*$13digDw6HM~m$D!(Fyb^zZSy*ZTSa2Tz#j+eb{t0sZ`t?}Ul|eaw2oME^eM rK4s*GdexxsU-k%W;FOswd)?+ghkDmm>Q_F`!d zrH8UmPdx}Z2p&CD=+TniJbCxjgHVeF54#{j+oVD-g@RhdHWaM5wmKT^oU3BYXtP%Kv3$_kuk z&#<$)iiXBU{Q31OCILJnu@NW{l3ESmrAUOMrb#=U=2k98E-g_Ti;H9~N2b%s0Hru!n%te3VEMBI>e zjdJ56hD|L@Ot5?~Cyq_*V@qW$#&_8)_bxEs6Oqkw?_hPRT4Ik17_=;I|BTf}7yJ9N z!~z_oC+EXbA{4@fmBNR-d^C!m0w%`HIQ4Iqi;X1>Vf^hok~G8`6$%a_T?N&mi+li~viM?S9?JC`Gy zoB4t=f7uv`u%uHG@9dD>-Id|;>62apr1-eQs=He_{bF&Ej6_%h*a(2PJ39DHC;0Gi zWf)9N>84)6)KrCMcv#Q3ql4c7-iA_qGBm{RejPu2AeEA!0|S~FpMd-Kg-a>n_KTq* zepiZ5R4fLoy&Z<%wfN;rpj?*gv9Vz5xfhQgOJ6Pvw_mik!-&OTDZ@b0-MjihJ}-So z2M~|@_p60?T)4d4evn82hJmDV9JJ{Oc>P-X-d_Jc{|1-K<@SR_0&pC(sZt58eg!y= zln4NjPU|Ik8eFc01&QGYi3Ct8p;hSyJ1CtH4(oc>hRfx0>p+<%){8}d#)bj(^vJba zsGSE~uAUx=;RnT{9GEG?z-PY#fXaCN5dw7PRj~*d20kmt!D=aJFs4C_du$-Qs zCk;aqxO$bGnep#CGb28LaLmu^#jYx+d4>(m*jS~o1IPyt$hEcF_G@cmZ;x@S{8Zlp4_QiPOdGh+NP^Z|IU*&wv;^Mrrx%tp7%bDT1_djwF5;u zzNtUgW0j8|fmg49LZNcJ0#uGu(rMtv4dB|fVEm^ZtFTTFw*Fs7i>&viPo*JtFG%6VstVJ%8l$h^XJstR4~d`=R@YkpI+Q4eI{S9)SfM5p!XGxA_NBOE&o< Slk`&n00008(SDXnQ7ikMw60OZM6-8p_?vTWl^%RkJ_R_ zx~K*5EnG-JY3N_jMWOpZp&QW_y79Fj1tCI9AMzf!apB5EDO3xoHT4I@zM4i8nVc@J zF*BOXk0gD4IdI`Je)oLmI5Rijy>~n$Q7b$i_yAm&BwW=rgk>2aUB~%c4rc*CQSe2U zv7zf&%Vx1!DBvFef05X$Id`=NJRSrA!~y~QvA2icLm}j2G59(=A$N2D#RdTBbg89M z(345*t*zlVpAUb3`-VROBuVU4C4{7_2C&KN><_`{jp7}lL2gO*YI5-efEWq)y1^_mx zDtFw>^DkeLt*vHZl0-(MFH8ZO(Q2JoC`mWi3!0`krefIGyE2P)U96%oc-t6k)uHB%SnNpH7XUKHA9?}KUX~9|KpP8{A)78aY zfHx&c!qr#|KD&j_%uK1DNC55aRjr@OqP<;kmdjNMu^4=kgsYOKA>7#s*(x}n2VT7r zeV-2)8mdKZc?=B+Zb0P9=dI&AJ0WWt!jdc_R9w4O!tye(yDR$Fua^?l6F#5d21Ksq zW$XBk4nUR>l5`#C?F^*TrT*p1wF$L?k=vNF96CAxUB`JTm%~{*0~;IWfjkaQhub_Tk;fu<(WfAa>&cu~QE;!t-FHS6I+%75m`_0S2Terx~P3OWlH^mquM}NPw zv1ON(bh)VC+A=Rf0J5cpeD;jYSlq`m+no&CjjcliRc|dOlVSs_t*x@? zwl)!yOuA*SytR1Zkk8{mNL8`?_%Tl3xdYd=XQ2SRe-C{61gx)%YZop67cT;rE&-CG z`qzvnPr!Tk@bCUUx=E~={%CY#xD$=Lymwj&Y1Jrn*e0URQw*UYD07*qoM6N<$g3%qs@c;k- literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/blue/7.png b/src/cursor/cursorImages/blue/7.png new file mode 100644 index 0000000000000000000000000000000000000000..0a2033bb1586832bad054409c2255368337efff6 GIT binary patch literal 1637 zcmV-r2AcVaP)#9WK~!jg)mlwR8)+DRGGm-1q9_#!DONEE_EZajN>Jz$mO^WK z@Zez&o@5bnEO_zI!_t$+o0rY4hrM|+l%@;rf=VrTZlUTSwY9boELLM;GI{p!C7qdM zzGT$6yFT#2Xuj`#o_BuUdEfUN7fDvr=gz_xSiIfw8TfHNKs55r+*x3b^16v$YNXXUFgaw!KCg;ScwTq42J z)l0V`kzh&Fm{Sx^)zc`ALaK_Xwl@6!;svzPQD*_+-~dRafZbgq>HtPW3I>4(4*+$fg(QQ*Kl8FQv2s9Qg8-akZQ7qPXB9UOJ{7lq5*fpWj=i}R0jA!)> ze*8#=LiVCmmAreG93LmAr^Of_7ynaL`!%7EuvrhW7|+Vl$r56#9heCQc~URhynapk z{k0+@5%T$SGLw<7&1A%!NThbX-!E*-P$-BH3vkBP0f22D4-f0b`L#9D z@-;G~Qev&ymd7JFWJo5-@~!majs3#`x0_GHVM-sXbeinxu@c5&;>=tW<(O}=+0!Gq zWC({v+F@}3V3(%J(}P@&93Hk3Ei7DIcr_LlthR@T1*aXhwn$B57GRgzfvHf4$1;NX z`PwtzY*b%~`FZ)=P>9EXc)@`rIy(3=9=D&I$&j6$hT(hn8i&1$pjZ^PD?FW@@_-PJ zlN}v=N%0b<*X?FrmJ-j+Sp!n9IP-vAr!c*dZE) zS5a_Z@%a$!>w{`HDVa2m+uMOiq?uCf5s3&cI}K*^^+EOd5L8qZy_MRv8s@V{D?xFHkw>63BnG>2~n z%v@#-W&{F2K93tpJwxVN$K`5VU}b6{Y=I9^`|3Wes0l%Y@%Ty`4F*xv_q z9eYYPi`{e@y4|ElkBsAQ-+Z;(f(_ltA4LzI1E*hm0{r$$PeRA?Dk_Rg$ zCk?*-e)+sgDuG7H-0ZBiqwwa<)d(krZF6U1cGiBLC7EM`bo%R8vc26fIyOd@uAt3T zDhb;ap7wUZZ3jy_O$P?+00000NkvXXu0mjfmY5Zl literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/blue/8.png b/src/cursor/cursorImages/blue/8.png new file mode 100644 index 0000000000000000000000000000000000000000..c75055c483a35902b424dd97ffd19c8d2db96a22 GIT binary patch literal 1788 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 + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/cursor/cursorImages/green/0.png b/src/cursor/cursorImages/green/0.png new file mode 100644 index 0000000000000000000000000000000000000000..a6018131000a308f42c59c1ed8725ff8d96048c4 GIT binary patch literal 923 zcmV;M17!S(P)n3 zpf=%0_zV06^tav(bhmI5T52mP2#K*VBpV$BGQ3*|%4PMg1M2MfOr{tz3GaJ2=i@uy zcXEgh)zsBMPqE6Du2) zRlYgZsk-VaDHpoXsZLc^`NqmduG|wuA-SHH3;%>T&MQBts1kM5Ni6y~I_jvRN|aZA zfH+2cdQ}66z?Xj>D!gr}^=iVGX{n`9;jJ(K91*;V0mPTQ@`JkS$`8_*HqX&eV>(+Czbx!uLZvVNysr8Wp@fxfqMf*ibsbW z7E)D~fI|)oMT$rFPr`HMj#f#D)8axGa^;Q?o&gR5g7IfQr#h-h2nh)Y#=wCwnEfhM zFKtmtsZ#X}X5aYuVTqEHwxFbxC^c!c-xE^ZDrNK zh|!k${i}aA#$vB8xlCI}VlKJFVy}&ZbCp#C4$hT{iThbK5EJ)JMAYrki_;dAlpeh} zBI=qc)9+21YZqDHn+owU&wHiZ^1-% x+pG&FvfJohGV(_qHOTy7kChE9nMv)q%}-$(-8`fMXv6>j002ovPDHLkV1j9cr4IlA literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/green/1.png b/src/cursor/cursorImages/green/1.png new file mode 100644 index 0000000000000000000000000000000000000000..a0343a6cb8ff13facc406102f48c5c7921264c68 GIT binary patch literal 1022 zcmV;`4~;Y{1|f@TXAs&3#X6 zAVcO8P|A_p?$Z6;$M2OWxq0%|3J(P!d{o-B;~KT@Ip@E)xX0i5{s&MK>P#g>(nJqp z(U!gM$cYLnTp#E_XFAiQwA9jp4pdO#+L064viA{-lk0iC@CC$fR@qKb#i*&~#G+rK zsiul5Mp+a8p-3G2u_CtFA!7jVJFE;U{7M@g=Klr>t_Xul~%$ zkLatfvdX>Tukqzg28_&(Bj>iF%3$WopHNX{;K;c(GCNZlFfuz!TDonh@!s0UG}O?N zmj2Vki_^xDldAX;4K?J*xqWFmJ^R9DmF=W4ZC;|H%3%0T{P1G`5Gp-+r)8CUDe8Te zvdX<-boy6_eQIDgP;m1e(PmQm>MKxigV@z`1`vx`WjnKs^KYfDx`tC}{Et00V9VYw zsu-m!@#hp(jBMHadTapk$&r)j@?cgp)s!PALVS{h8LsI{tE>*zSet4=_@1n>#wx1= zpak3-$dTLLVrwx~WfQQ))?$v__I*vbw(PrUmc(h%QcJe%JA`Y1O&`Dana`LdgN z`1n0w(-_P~iISVPs7WbNat&s~cz8jcyp^_~Ny(G9JiNeISpI15nlyh8%Pd%71q;hJ zG4b*&4D7MTU&FG;UgGVqutH3{j4k`FrB`3676FYiOkQvPRjbS(T;4Vpu%<9Bl}tkDqJIW^bxj{ zA7fLmkC0Z;yeGEw5mJkq_vG%whjW}>A3bw@z@bMb=Jtr`;R|zo$oI&^{2sGDGBLjg s-A|1CudW)*{bi4-4LmWE+I5?M0GD&C!u#BIR{#J207*qoM6N<$g6oy@?EnA( literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/green/10.png b/src/cursor/cursorImages/green/10.png new file mode 100644 index 0000000000000000000000000000000000000000..a57da5ed281be8afd04189b4adde9e0822098fea GIT binary patch literal 1362 zcmV-Y1+DstP)*F` z$hJh~5+M<}NKJ`kSC)*CIYn||glLhlFyM4FL~c@$+G%3h0#k56e73>tycD@Z%QAbn zcLxV=bjAHUGyA=re^)cJYb4RE4CV^(i^2SyB6ZVXIvuXV;o1N!_N&E~gth~McS4K6 zZ$h7&KDnfZeuymMQCjJL5DwK{T)FKdM7D8``oY_c%)F6l1ln7Sj59Lxi1srxfUt;3 zBXf9K;2tA~h)IM^%4L$=0|xVbiqxM0!PTUxnI=t+8~`8qz#)f;(>g_JFCh3q=uOSa z39kI@T35YIZ5q;$3Myz_>)O(moSZ6ha@x|C*0rvJ3L4Uo+SHb0G;TMQLWl>|PST?u z&1gnN6;-c_Dr!bE>QPUv)Oyg60mQ?&F0;yNTGKkvLEYd{9q2&QnpRfXY9=1mWdLzE zuB*KA+SP8;;8E>rS9#^DnYf$C0HQZ8=f^d!K*6cQR}?7FxW>KsWv1S$1`sJLyX$GJ zSQ+gmmcv(6Qc2zF_Km{)F$0L4Z*DWExpRZBXijs!QE-TyLIx(ImHO3x zE~yihlT*L?eWNg`iUBM8HhOqbi|5ULq(v?Io=9&cVGtd_zksRCk1}M~Vv98C#1pWy z)FFpt$x@^k4h#6k0{02Q1LVnH7N?mld z94x7#Y(gEjvh@*H=^`o0=5TE`TFG)EbYbLUvlja`9N1*DWkB^R%4V@&t-+MS!3{QA z3RRDyYz9-Z4!0c+mMF2uUQ5A}XpcQg9J|&y+_n`uku$G(-7>JG@-Yc*THsamzzbfq zf~hXWFugK}tH5qJ+C>-dd5<|hMLIVLaf2Ja`}12Xv}dvJ!qE*jSYxeqgf+Cr+6j1z zeJ8Y6Seub)Wzu~!_Y`vLOicE8qJh)-_MCWDw|3nkC6;wnZ~}4h%2t#XQqChIva$H+(ZV6Fnc0zX-7m%(%jwTC~qF_=$6+YYw@{0>YBHNE)$4`^I7 UJTwO;2><{907*qoM6N<$g3m64EdT%j literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/green/2.png b/src/cursor/cursorImages/green/2.png new file mode 100644 index 0000000000000000000000000000000000000000..3c611a144f36c3ebd1660e19f2fec55f80c95548 GIT binary patch literal 1131 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 literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/green/6.png b/src/cursor/cursorImages/green/6.png new file mode 100644 index 0000000000000000000000000000000000000000..9732994221919fc648dd415eb3992f4eeb1eb7a3 GIT binary patch literal 1617 zcmV-X2Cn&uP)NjdliyujohF)( znZ({+pF?0E=Y8MjnKS3i`<^omfa*nq8Z1fuhK%b$1*1OsBDUy{kMoB*#Qk$9qRCf^`l8rqM&VR)1K4Z z_qgJXmaM1A9ZJzm4BYqt7 z%o8R0ElBX4P~=nu2z3Vt?2R#&&5`?Q8;BJ)YH!rKrF1w5{QkHbNHo^$I?7EJVBS)0zH=(;F1qg)# z1ophF^YhFTCVYb2WiB(s5WgR`A%?ijQhxmRiv$R@n3%59gInAxBG64Y?|JXa z7T`Va>888L$1QHTvRz>X6Eh{$QYc`wi>|M39K7VE6SR>=CYa!W1J~q_aKHf*OwdT9 zq#c78h+#>t+YA;AM(&M@#A>NL&sk$t$gHTRhvmBX`<;h zAPHH1{24bX@gRdvuwHt}Q-6k$Cr>ZEj^9BBtJtZ7y*sDKuypGOiD3z^YdGywD5h`hgxOqDV~zR4GIh(E~jw z8LJ!yG+-Grt{XuGqaEt-RqC8mP77L)Bn1@EP2H@IaS7biO$8K?BrRw`Ipr$$?@)&? zs9@Ca$rm}QUCUurtJ>GTB&k=u3Mq6ttP2oQNWJQnB<*Wot6HttKdi8P@BCtGZf0+cGHhT^O?z!V1fl-DYHzxmZoWwzi$?cD2{XvH}Wy7sf1wu)@kHbJ1|) z_&^8FwNDkNOI;}RT^O?x3{&Q(YQyE_&eQ`hBb`t}rp!-X#%XmDHT(PKovp%xO+ZB_&Dy>UVBfIc#dvPARqFI+b|Fv!X)8OEpyuyX+Pf zM$dRw)#fObaGlKA*u;oAL53MVE&dEM?D&ll!^W=IzbKi*Lpr_28bN|iuo-6RCO^ZB z<1a{%HP))y6s6O6ENC9{*a_G|3$x7DOn#PGT4-_nJ?611yAuVCmy$A1o<92O+F>ZQ zlhH??tNNm3Nr}gzew%H2=qV!5PCL^~lO|o(E=`(grfH|W$hL9v!xE#<{@_&U3z~Z-@|2c;dRUtGKN~jT>7VY;cWhMa0~+ zYh3emvQu?qi#oOzZET+NyyRUjH9F6EUUjKFj&fUzCl2`<)DQ_M@aB;oHQ&*l2Cr|_ zj52zoH%cg>9qmYx+SI17!s=9~OqpI?>ZzV`PxtoIN_QgSMSm8mDHw^fyS;w&JJSao z6o@#pM@&CDoZ&;h0ug8Tn6*H}**)k!Cggwhsll25*rR3v$He@y&u#tzoqM0=zUH-q P00000NkvXXu0mjfp}PS+ literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/green/7.png b/src/cursor/cursorImages/green/7.png new file mode 100644 index 0000000000000000000000000000000000000000..8c77ca768173a167d18f42506e322e5d562726cf GIT binary patch literal 1756 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 IM6N<$g3tbrGXMYp literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/green/9.png b/src/cursor/cursorImages/green/9.png new file mode 100644 index 0000000000000000000000000000000000000000..b950aa17d1e7f32b0321e3734e0fc028c2c04a4a GIT binary patch literal 1882 zcmV-g2c`IlP)bMK~!jg<(f}uQ(GR#zrDAeo1|J$5tBS(Yf~${u_EZA1PTr~ zh>I4r3wg8XN>C{NS%^bdT@So&L{#X;g-ka^D(&LIAPxo*H4EWk7S9G+o5pTR^|eh+ z(womLrs?G7-rCl->4W+H$mVeFIiGLtxykwc&aDBoRn@4*FX^v_j57fRqNdD1e_PVhUm}X+JJsoLRHGTz z|3Z>7WihEqdsL%KQ=0mdU;gL6>-T?38b!=i#XyZ}>g!Z@+mP}1HnkOh(ogjlbV1E( z){>Sqp$TP_(X^)ZNuMN1A%*mVeo$CpHK|E{`IS;iPxVwo8e05SzZyjq|4~rkXT;*B zfPf8sgldJZ`S8ufh-DKb07#SO0S`FOc`PinPFPr+=R6O1K$!mke zpg@u&U36_3yfV7zB1w`01$ybtuiTCHEg3K{dMvE3gA5jn6zQiQ6LUjA``OQ*S7JZ= zH*}4ONk9D*DKf}l(Zc#_VDx;K0Ry9FFMGeniL<~0-E^-xaV@o+`IB`Dmk&~SCoG3tmKKhtt)&;zt zW|^grJ^}cLre*CWa&T)=q zmg%K8zw+zk_=&AFa4kx7u|R=a+;R;TBE%csY&(2OZ+Jt9kZays+@e5%DA7fsYn}## z>V5d;#uy_`+%?D^_VA8(I|g6UJKnK}J+ArV#2I6Zm8DegGEhfde~efbpq+Nd#Rdi= zjO;jkNh6G4U^p1sX$K%iEL%rizr%pgJ_{?GAi*%hF86)(RSmwRKKfi7!wi!kfrXV7 z+E;F%=QO7mY;2Bl)N#=v4l&Ps)eX!u&mj&uSdMZO8=KRdUJ&Y8HPArAF9Qtll9w*m z4|!O1_>vy-(8cqTmkcmK0}a0bl90cSx?GABx4G@;e3-*5v%G5tmRaU7haF6}xy?A^ z)KQlc@=K_zndW(bC{ah}8{F76_>yjL!@(3K3P3Z>^Fm#QA>&M^I{okUUMZy$@6RKoLDW&&%uTFLP4H;*QfCAA*HJV8!9UbdcuMTxo5!G8A>QKGv9c@V^)u=`@ zpg`0xWk$jZucm(`MHEr3YOBfWsan-4qKKpIlRhb|uuPc|!>)uG#fDp|@|4NKN+ zMj6lB^hc4`^3EtDOV+Gm%AD~sP`RXbQ5IPTwO&_~)l;waT3__V(bl3CO={B4Dw|r}N)#y) zBSi}0D5018rx~QjmD!=^C5lfDQCQsg#M6}RCo_y86`8;`AXmKT1 zdGhXrraYy*&wW=CahJPQH*lA`E{^-$_f9D(OX>?0Xrb%{%^LE30zim4rgpJIwO+FbKq z;?nwsEh*Q5|lH1U|n6e(^RyhxG9Jf?{z&#^;< zNRZfkdA;;0Kj27{<`kzqCldcHzg*`!&v-_G!kW+p3OwT(*SYR0mz2jTPLU@4{RbT7 zCQ3(4S+ZQ_@|u&D!iSG$nu!skdnIDTXr>t-zICs^%w@7M_zMRSr`9>M#ILFro z*=!u=IHQbi?;&5A3CA(3jm;w-5h1c=@CXqe@dz7xXO3CROt=oZOKbWjH#x$Q4MQK{ z2sgR8`pj(QpnF?iHApI{-}IYiR-*h>gWyWEs#QPg$8CGn;Q#Msk2TEf+Uqv|0fnfx U@g*RjH2?qr07*qoM6N<$f)P}QiU0rr literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/green/cursorGreen.svg b/src/cursor/cursorImages/green/cursorGreen.svg new file mode 100644 index 0000000..34e8bc6 --- /dev/null +++ b/src/cursor/cursorImages/green/cursorGreen.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/cursor/cursorImages/red/0.png b/src/cursor/cursorImages/red/0.png new file mode 100644 index 0000000000000000000000000000000000000000..839bc89b0e9f997da26bd2e137e08991f93a0a7f GIT binary patch literal 897 zcmV-{1AhF8P)s8^aGHB z8p#ilC*TR_w@w7z7KubloeBzsgwjMvtHfZCeYOZ8Aql%Ne~$U2>5w>QxO2I4@1#g# zZBi*6z&V6CgJD=u6ca&k4BtNj07&@&MY%^1^x=73gyAiK-ylb8fAz`+QmI1#4zk$` zj7C3UniDvVj(lE0E{FL7fWhE(^?CssjS>3&AJFw1{Q2_>Km+7(B^@NAEg(%*y`+>L zZTpe68rkhKGMx@ttC6<-NGUz4>Lr16R6S9I9}uWg(}paSJht1>MK7b>CQBucnl>a* zC2+7=1As}xxT9q~vDw_5@b@&Eq-8zPFzyJLn=t^KQqzWX-3h1D?TLS3Iwf6qGW#`7 z*E1kQg;I`LuZP=L{*HP*q?BU{QCZD^5EW)JW42m5*FLA!A~TtPnphq-QpPL(g;tA{ za=a{@K0mOUHjE`~mQk;VvorDGV1G=NhH*#Nox~{jb6j^a%T5a^_Pv2BE$e9~*(NH} z>2rz&s{GUdkfx>$x0>hIrP<^xl;;1~uLe~0lBJRtufi`-Dm|AS3kHBgO1atcU|Y1? zq?8_kLy{1)n$AI?5TaOItuoyu#UfBBga8}>GXvS|1xj-^ z07&^DpeXl=HJ~W>0zuGEtbrit3wT}^y=ZFUbIyb-`LuV z)?(tDyL-`I--`jqUW}ODhErmPd~XkSV#lm+Q*2@f-HS%P)l-ASKlWJNz@nMhp4nVq-&8_uq+3|u<`w6y4@uJv_8Tx4)OgKp4T7<_JDs8 z>D;;Ni4DYJi$H;NdV@~qDYo6CP%z164Kf)<4}j~QKh363rP86*`U}(C<>$|TfC?h* ziFAm_cn>T{BC#!6dy>l?%g&BSqakB+a3Hd?Ba+Jaxi`6S16YQ(fU-B+MLXQQk#-Wol32C z@7hPyY9guBA5GjmZM2S7{28^Hh}Ne!O{eP@Y%jsv#c z1J)Hvtx+hLQEM8TLcv6-HHBq4WV1%pdd4Q3HLxs4VHoyk?;18IC-C*_blT2jz%cAM zzP~&b18?8L(GjFl&}zZUm!Q;t{_NIdGT{5mak|~5&<*_fF%bXa#o+zZC;0dgo;?e% zk4y%--K7wR7e?{HgZuwb7*553tDt_!~3Qg~j2 zX49WuPgA1V^zpogA_(@VRPJ14y>}{=4neRt2g#gB2h-f;-MgsA^!B`e52m?`Nat)v zwkf&Xanu8QYjU|`flZl*E#;hS>gS@YGV_J4xhO5pd~tU!%IkA+z%ds`Oc$rq%pUSx zT-Y;v%z81z&g?<=Wh4Kqs|GWF*<*48m(4_W-R2jp5CDo7h6+vq0000*ULaFx*NPOC)%QiN1& zQCj-5C~o{g5JXx8TPRvmC^jIvu%%c;TnJJGI~D7~xGcJ~(1jGNf;KTtN#dw6$;^Gb zxS1w1_uiSgljM#soJGDl=g#xq^ON&^VE5j zSbGV_iB;^^-3>c;LT@j0c0wit>9qUVvu7|g1P>p=zyM^kaOY0t@3nRk$9W6sxB54+ zG2c{N>#eO)U!QdMu0reneW|}+YHzQ!Hypvi`j(KjU&|Q(2d7ff(WBDnXn62)<#N*T zb`3PQO|Bq0|6$_?|kaPBjj` zsPpIjW+5*~YmR}Fo=$7mHfHIRt5A^EulJjUPxZfnMB<^R!-WftMxRwS>u2D1Nf<#I z$d%kLmMnph5om6%d|!!5`8>3@!|3R2%oqnLWr0JU0o%5{Jn#VVIPBO_8j~#WvBj8o zJOg&^iUur<{Fy$m#9|$u@Yb!1jT2t}Os`sCg(uwM_0({!TnSB0<QAm}u&749i2_}=#0fm*9%~-50EiMfXM#d9br7QjJ*hdGDIJeLE7SQ1WMbWPx8j z;VV}b8z;Q{nX*RE0z4@RFJBJB!;nb$4T@e8tXbn0#^ywUR*RG)7JF1OU~CL-+=vpf zvToffhX=TeG*(P#PI>Ozn>IB%3z$`JuU|g!x#nbK8G$#YynMOQ=+eM|AG}kn5zQv` z#$5As?CNrhO^s5aAZ^&-XW(LyyLwq=|Nh1qIC8`M zg{^PrGM5{O%UW+~F&2}qU5gHWU_eSH{oekFpefjZYvT2px=ZQcL_#`qX7S&#**JoC{aF1CxF-4oO>}iF>=B#IO6%4I!AtOE z5NEIf*Tjhm50y4=mTumZ949=qeb3W zJB^P^*RM+l4oDpxmB5Q@en&OF>c3I~81ov|-okNOYP!3mQf~g5$$+(PA~HA#&!5+J z_c7*Qq&JZ6Rqb1K24-g>F8HqMY|N(_Gd;8SlC^TxZeZ5PQbAUJcc=QBBe*D78kQ%# zfmtJ~1Se$eUv-*sWXzv}uLLXW<*02BR9~~rz(L?`U^UjZ0WCOAa^~|%Acyo1FbMn% goJYz9Jh5i|2L;jZY}>v4DYr5g>ujH%+ysqR4P?ft#*0NA5p7GsZ_Q3HSSzYfMLwYG!K`K_QBAu=`$HcjTeLhuM z)`n84Y8T!8HK|m!nVn9h*s}s=6^R^NNw#U1TCI^{VOGBs07LS4ikF(_FG?n(W+)xc z*gplh-E)e^OWpPGH;Bg@%Z^h5U__?r?DF8U$mJx{ED1&=VKmot3C73kM5CRpOs|q? z6voHvKmuqA@cE{hni}e+Uu`ipHH6PM4S>Kax4Y8OlDJ!JZc1)u%qM=g;BQD`#v40$|%?29?UFV*);Ygk-XH zeKOf-;{<^KR4Sv!f46Ld@87}iZ(Z;AH`+LefobkiC^+-BXcX4hTi36z@n0HlF!BeEZgz z6K>stL;@Z>aK=`l0Jgn7NU5|%K5qlg%mt4gHS+z-m$10ln8n1+ZV^{eR09j7gtOt!>MO4`A!b(p1o#0nPPkP tqWiRv|JAPsJ^!;u=K@ZP>Duo${{T%ccrRTF9MS*)002ovPDHLkV1hGc9Pj`D literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/red/3.png b/src/cursor/cursorImages/red/3.png new file mode 100644 index 0000000000000000000000000000000000000000..3088b82736ef6c86558c126499fc02fa55a2ab8e GIT binary patch literal 1237 zcmV;`1SsJjkGkGj6 z{RM~PUt}^b0L*|)8}fr>eGTZK-9AMra|{Hs42Q|ZMb?dl1u`5a1A#21%+YS2BG6H< zKlM0%guob8HO*i!$7Hg8r>h~EB!j^mRW(gujKC3V1pq!eo%8hj*BFag=lE{KVx-@{ zMyGS0fX^BMz(uNRnxRmUrBdUZ-$1EEhC;>4+qh^>fDogUa-Gp=x$&OwLNr>YlP zSY>*c=g`=6a2*sP!ikCBrVYM+P1Gq0nVYK)DRe%>jWx?PJcJ+ZtySUN2B6bRF=%Ye2CG!uHSwPd4ObfVs7x?i5n4CPgZ#)h>e-1o&V2(4D0yJ&OxFT*49w(0; zC4)ip*?2RNSyf6Di{$vYE@EJSeEO7}n+U9>Jh7$@+EL7rpxYg1IBeeVc4RVoaW^wVe*bQ*?QocMyW`xpBO7HP zkhPYjfd~Y$1V-5oTgo=s)VIa4O3NQ?wZ+k5%OCEx#qoMuTyV6-71Q?V)Uua++ZT4r zUbAiwu`PSiy;I2l>QjT3|JcL0fSqER_PNb}sz~aha6@1G00000NkvXXu0mjfYQsT- literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/red/4.png b/src/cursor/cursorImages/red/4.png new file mode 100644 index 0000000000000000000000000000000000000000..8e7549d4a3a0604e921216e7368ceffa674e9d5e GIT binary patch literal 1353 zcmV-P1-AN$P)mI183x?5yVzC-~(p&@DXtRw`)AICsa|{N_Sd6BzxJU+rq}Q9HrsZj~ zjS*-w%f}3HD}f=}?P>aac}An=N$-Scl=S)XwA<4Jh6q@jD*$j&*B9vVtTG&K9`UUR zhe?lTmAbw_z||Z9ziPl$f%Sc)yFCJd^^NRQmtwaH7^26s`b)BnS(Hj5#R5azRshgO zyFI<9dA?DE!`zrk)i3s@0Gn-$K3{%+8SVl;pC~)(1OQ#swC0uvi3IuP4f*O7`SBxZ z7|rn;jgp#{C(y+j0fY2#mHN?$YaNZ>)O`VMqa$grc6<> z9hS@F^XGyjKw7Qj>C@!HhvdizdFc|_-o7d3{(Ul=m5&z;lAWDXLIB{P%~q5ui7Vv& zenCuC$X44X7$GG6Ljs=3~3vDs^c_R9I_ke8Hob97WKq>{? zxdZg}nvWfi8_4Hljh7NPZip}H?b~FbusfRq>hB^R@K5^eOrFEjcqoK6^&qy-OZBBF4B} z;CQ9g9l_L(@?0|4UM=TuvogFY5!to#vzrHYq7E-@_RHY z`bc#Ba?>657-gP3f5D_v= literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/red/5.png b/src/cursor/cursorImages/red/5.png new file mode 100644 index 0000000000000000000000000000000000000000..a18a1a47df5d7598916188bd895f8a8b9c22ef08 GIT binary patch literal 1462 zcmV;n1xfmeP)e_6}&~klOXhF3*r{L*rRFbK|QENLp1iH(X>sQ#>uybmvoZ0 z>CT%}yV(yO6Uh92@B8Mx_nY7Ey-`S_X(&oNfIpzBzr!>m(6kUNYX^$OtpEUB{|rr= zfn{Y-C`_YV{u{twAQzhM+O+^h2>>_^zyD7xEF429w1m^A+tJaXAsEDR1AuJSZt1jz zM~@be$!tM;`xx^12LK*{%(>!0Qmz4BdOQQv^#Y^OIVKY1^faaM_AQx6kkRNIb-h53 zXMliLmX8eaHUfP#j2vUJ0#hk@(v6Txk+E2ThLI!CN1$zE1ppzM<|{@b^Bf-DIN~cY zJWNI+^EAy@1VS4l060R!$T1#YVyX1w$X8J+k@5IaWi*a7CqPwusq2eOCd)sb`3fYH zW$OAORkhch09Ea!&$r0&@t@9p8RO%m&$q6K#?waEHouQ`ymgB#yIf+im`FS7rVtRIuDeSQ=I6;vmqvv*iB$tN%ZG)LjmhN|Cx=AP}e((939aPTJYT1i5FAO)4BFA3h{Meq4R;w{PUr zr{swf_WfQjdH1foh-h?0XGR=I!%T`!bc?HTs$dKagV1+pdAEy7!J=$bv`m; zPlL;sC7IXY$rF2R#N%?d;qWYh9#B;W+28-&v0fElQLxX8XRA^dg zxpsAei3xFSYXiEw<;boDuUEX_YJEFFFbHT`NQGtXa3$ctf##on6>bGs)(#cL;#OAz zy1Ja({2QtQ-n|39d~s$I3tb?JTmu0h9Cl`t%>ugqS%s#}NC}8W#dT^*M2?Msn`xQN0-83X!m={1MqqXp zc=N`&-Fm1Bs6HGg$Yue{%BUz5rjbrtjt#rI0Il-cxOPo~Wdl5T0Aw=a_u<3N?b2xr zg~GJERN~4NJCzt3l6>{n;KK(p5DOfXOoIT zUc4wOwDoZBo?Qz7qQLp?JeMT7MnTg|NjWw~?%r(^GEFiT6J_T8`(lk;y()-q-(G*; z?c4IT@tP%Nvqk;vEP4L?>bkd4>+U9BzjoEt+C@Dp2N#BsYij#^a*`Yz6oq_er>NEd zQ9qnIMGg#zV#u=G`5zu;WruG0AmqnxY~}N0HoGyt8fd1=Ne#w9jq+0S#Tf`%1Wm QoB#j-07*qoM6N<$f*hZ;2><{9 literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/red/6.png b/src/cursor/cursorImages/red/6.png new file mode 100644 index 0000000000000000000000000000000000000000..6a6c2afe165bed474d15ad6ce16fc5dc39075ea2 GIT binary patch literal 1605 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 Z=3m*n9=+hYFNXjC002ovPDHLkV1hCBR*wJx literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/red/8.png b/src/cursor/cursorImages/red/8.png new file mode 100644 index 0000000000000000000000000000000000000000..785a4b17fb2b5f96ed560e471bac14f373bc6531 GIT binary patch literal 1850 zcmV-A2gUe_P)K~!jg)mmLh6kQm8cBXZ9*EB>bvo_1sh$1MklBKK<`nsqr z>aHL!ic0V{=&B5Fio&8Ox{!(pii&GcNK+&ps9@zC5%dc6TU9DV|o1jdc70f3t>S1Uc9el|3W z9`RT-G>{%oKV7a?0`Ac<04Sxy;b&D5=*2aS#7^yy|J_U;wO4GwBsEKq4}0FX(C!*AN>-@hj(PBi;#Q&Vch zjp*so+{&oKW+N|M62~<(@Ruw7{$lF}*zMKydIQ1(;jp#{je_&?$PXVzkGxUW%9Wxn zmrHXsBfMTM><|n9a;PZg@ZjiCQJ|ubPo9iE`6&E;vbb2(xoVX-rn#9^lmLMoqX88x zDG@i~A3w~lbMj>R$Vc(&mG*5g>TPTk$CQ-x5vb4&$j-jS+FEf?b+stO>rFrTC~9g% z-HR59_iJm(?Ce`40Rm3i?IBZ09Q!ICJQy?n{Q1-Ty)nj5ZEd989wOibfwe3w{3!@% zX%Qb@xNz*qN3nai$YK9}@qS_9PXcQtNYZkYmpg?l=gJi^>sh}(sbnc7#Ol0$UF?^a zJ0VHSCAeH36cot9&3pF}3mXe8SOCnJq4%FY1%ieYx}ZRY%jJepFW z!0g#+!Nxz;pExjZYAy&6>V)OF>Rn3zS3grq0 z^!AFc>Q6Qx6v~xM4~0Tv-{D9Dvtc4ucPuvm5)`FZ@U6*{0okyojqWtoh}CWMl+I2- zQF>GJ? zb^@x}At4ZGhtH=91Lx1zuSuYxA&o5Kpt~D*_Dt_jpAO{Y=zX70MIg{FAriTd`g*a* zx?zJT?Ao<7GL3^9H-Jb)@2_1e-mk9@A`-c89n6J778*SZrsp9hbSga1ePt+``51nPG=*?VElxp zr9~@qL}$QmCttoy|I7~zkaOmUvw!%oIL4IF#7il+Y!L+&7n5JVrq_VYn?;>7XKF4T zg=I<^FRB0dQA@0i0#~d^y_6CU2M?OdE9cIMV=R;UL}itW7qt?HQRwQ`z9Seyt=QD}U)yt<)05kcBNKC@n@JfD9(=(z6G9JA_1{KW^|q9K3O oUk(2HKYJu^fN0GB_II2A04Tdyr1l4*T>t<807*qoM6N<$f*=HO761SM literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/red/9.png b/src/cursor/cursorImages/red/9.png new file mode 100644 index 0000000000000000000000000000000000000000..e4c9758c5b80494c0076e1304b1fd644d17bbd2f GIT binary patch literal 1848 zcmV-82gmq{P)6MvL`nJ42FD|On*U={>H3XF>KwMkM-+;vNG}ij~{@~CrW20 zpsK)x34q-$N}=c!cs#)E+rZVUy?FapLM(O)k;p$Fdxyk_WM&005~!uw+(VZuz*nzG zk_?B*`}aw=o18R>1O_fP8@Xu{dHFK=^{Z&()hp8F3earsAy7-em?^JJ$vbGZzNgdK z%f?0#w4;OEvxgizc5u?^iqS}}UQIrGCfaOlB%RJ)TCML1II<%ESV*(Ehi-S6kqGJc zlXZ2Z)%yFyQ_k_le&zw|20a;W;%5vsC za^wgZi;)ctF)B)kl2r410wk%1W5$H|(}*9MN!C$7qd$|5iKobNr_%WO^sNcoX%bXwW$RF`81n**w`q#HPzF& za%JSm$I;qK78dGbU%Mt&K{1r_^#V+$db(TzlH{&k`UdLiMxJ~eO--c9q>b-%inqSY z6`;vfuN43kP*KG8;N3g@y1jO-SetW+GiUS<@yr>q?NF2efr3NB&JW-av3*HydUPy{Xw9nUx3YakEc(QU%u#HFuQl>o_riPZ>FAyr%#hM z+dUxwu+U^u>G6;kE@&&uve>kZCg#l1a@w**Omve;C13%8N|u#-

_Bm`$X64Qmj_ImlslpW zp}buC+v^qiwk$g&M5A^T7Xuv~+DdkN?g$Qs2@|xxJ354bXw)u2RSQ%0K=MtaiDWME z9#GXnsqdnyYAcz|IbfC{lDP!??Ia0`(haXyKV*Eq95Ble$z0+iMp3#Y$g&S!FEDYU zwo+$j?g$QsWG)jY3IVe0lMs!z_l>DU`2E79`Y#}PfrB6`jDX3~{A9l(Vvb%c_V~a`FqN^{BFC)# zBJ>B{!6142Ho0SmSY9(FZ8nqZ){zYjV)-1#L3j2(HJCgZc<};w_io@%4N6Oa<;%tY mS@_i8fB3OSYB8hsxy`?k`M2pRPTlJO0000sM literal 0 HcmV?d00001 diff --git a/src/cursor/cursorImages/red/cursorRed.svg b/src/cursor/cursorImages/red/cursorRed.svg new file mode 100644 index 0000000..54f5fc0 --- /dev/null +++ b/src/cursor/cursorImages/red/cursorRed.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/data/themes/default/Vera.ttf b/src/data/themes/default/Vera.ttf new file mode 100644 index 0000000000000000000000000000000000000000..58cd6b5e61eff273e920942e28041f8ddcf1e1b5 GIT binary patch literal 65932 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

B-* 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 PH#2y;`njxgN@xNA4H$mL literal 0 HcmV?d00001 diff --git a/src/data/themes/default/box.normal.png b/src/data/themes/default/box.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..90f8d40fd304b07e37697a3a931086da85358fcd GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_N(lo;$oUI%}34yg=9-yBTAg}b8}PkN*J7rQWHy3QxwWG zOEMHfGEx=XJ$(b-r>N!u6-IfwIEHAPUpjFkS3>{~v;HMV7RUep`DIH4Vq{)@5|PPa zGv0Q5Y5?QOa+OVYgbRXH9~2yT*Kn3mdyAHm;Di?|#WqZ7fgc5M4W;v`HHTRN}T0mo!nJ;m)N9AtWjxmHq(N-8fbgyRuzKPR^MVT=@yT zaz^6D4GAd`N5n7SN<>9?FSd)*Bt?irCVJl4ncdm-oAJc5yCjbMCx&S|mTV?x!PsA9jBSlm#}06Lv#ogR zp4)2qD!8~Hch8$5%j{P25sMC9GA(H5W*`98omhrj#I>$O^4uWPj*RO&(;lnyj89)$P}LOs+5T8PMJn)o>!;inDt z(HP?pyp<-r_QeM_$99w6Rk57o;gMu-$4ZLjY-84zeZYBT0l(y&?EjzdJ183we2&20 zSqYrx2Ir(XLyAE=^DwR>4YhhrtMSn3og#`!Zz)yG^sS2A3=fYa_aatO z2Z3`1x~OO`+fc-KcVbxzn4+sNSElQ`hIwpx?x{2Fv8$pn=|mtW|9+M-c8&b!SzG=a z=Ls1cfAJ&4BNSgbl-SCmYT+wy?yFApXCe0t|Cp|%7bR~T!nUmUZN%$w4wy%~1t3Wq bqdArWYaq!#?1fADFC_WDGE2)cSP{PgP;V%# literal 0 HcmV?d00001 diff --git a/src/data/themes/default/button.down.tga b/src/data/themes/default/button.down.tga new file mode 100644 index 0000000000000000000000000000000000000000..64873c1cd66f4f03473de6427a0eaab58b11c70a GIT binary patch literal 786 zcmds#zb`{k6vxkduNDJBnlwQ)EJDPB!5|TfRiZ;Dk%$}bcqZXC~#w}^jzzQZC>VTKOvRV*+WF3e4%{Bi?TdAmcbQoct6iNKpFT4=2nu^7?F z1d^}bAq)}~n>w3HOLG&7mn(3*{5ld|Ucn*}C^K!-XZQ!vsR5)4rx6H=I<&sE+6|RU z_d~MjKDZ=BGDyj_o;qu0TaY^669}o+;vedI%bUwVWRJqg9d{u?P$Y*W?ozOB0+VB{ z{%}vmAtXH+b`aAP6wadXu4eo#UC$y$5|ScWBmzyAW$4nM<@(ha9&GcMU$kM6sM!8b xsxJhiLm`wNcHmZ?_FdsmL|I_m}pYSc0!1$1W~avr1GcG zMlekhFrd3lQbY_SMG%$aJy%S`M{tX~-<&z;7I#KuNPfPsgk^ZdHBD18>VPJPrNMG` zW*WtdBfK`Bkox?1gF&Lg4jtNSGcdq1vlmCFRfFB_JR{ld1Q;X{_-Bh2T6-a3<-|9! z->P3CM52;VhrU#z(I|p)7Ea?ahjgQshe0AxW?P#>jJey(@cf4aghU-$Kglk@tKKX@ zPIHUD^xHENUa4S0NPYi5)b&V@4<=E)o=5d+4rzi-a!A5n{{^@6CBqW<;kO(wItWh2Po}`K+wlbk69pn)rQQ_6nTL-MgrqHgRW4HTK pREyLsz#vg#iwSM+ujyFCf|p)}Up_?Yy?qCRM1>s&wD-@Ne*qx=op1mE literal 0 HcmV?d00001 diff --git a/src/data/themes/default/button.normal.tga b/src/data/themes/default/button.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..e9371c7448e8b84155f06771fc6db8bd046e779c GIT binary patch literal 729 zcmds#p^k$<5Qc~1?g=VS-dn;pXG#u1prTJef+}eh2=KV3q6Ps3RY3)UV*cZw^0U^mmiLcO$8p48HYjZv+6<#8LS5H*JRaC$SvH9ZGjyoeuwcco zC<;u|1b?1qtVmRtd3uD=>2yMHzu#ezsJP3fJ;d`oG);q`>pEB@Dw?0 cE$R0fV{kkk(Y7tN<2b@5QDKG!>V0{)-vq(I!~g&Q literal 0 HcmV?d00001 diff --git a/src/data/themes/default/check.png b/src/data/themes/default/check.png new file mode 100644 index 0000000000000000000000000000000000000000..4ef58a39ba7317ce58258e464443ffd61d118a9e GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_N(loB8(;#4wG&Ig=9-yBTAg}b8}PkN*J7rQWHy3QxwWG zOEMHfGEx=XJ$(b-r>N!u6`FdwIEHAPPfl2%{G)&F@eZYi*5e(^+67|`mHE6S3?($Y tCb-Px*g2O)o5SLhy`0>?hDFQ_49ooa*;a5D9|ju0;OXk;vd$@?2>^)YIf?)P literal 0 HcmV?d00001 diff --git a/src/data/themes/default/checkbox.off.hover.tga b/src/data/themes/default/checkbox.off.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..9a4d8a8ecdd70dbea5c4688a30f63a80bc9af4a0 GIT binary patch literal 442 zcmYk3Jr06E5QPV0WyKLJJqEWhR)iaP1Qs;Jf-@LSL9G0#P1HsbEtEzIO(-a~9Or?o zy9u-3dzr`XWQj)9FPB^zPssB;N~LfJB2db*AlX6DP030(50oD{AY%9hxwL+5 zyWg~OS=}?H>b7PDT7azP=P9&gR2%|U#ldF>1P~QK`Jw`r2H)yW&v`cicSjr9PEhP; z65mZZHbjOL$iB#N-pQdSLsZw5e2Li=j2KQ!QW85{mzfpT@0|5#!~GrsA~;TODS&l4 K>&stS5Ay|t!v);{ literal 0 HcmV?d00001 diff --git a/src/data/themes/default/checkbox.off.normal.tga b/src/data/themes/default/checkbox.off.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..de59f19cc67a09dc652b138e8f2c347bb6e003f1 GIT binary patch literal 320 zcmZwDAr1o}5QX8vR_zfgd(5)cT!bTl0FOiA2^t&;X1dd4cb_PN{2wGhAbQX_HrnX< z`pFzKzt0Ued<-GW5}UOaa*TnjwIXxQz&*yuI)uPVNb;@5Jkr*RVt2kQh0_mq^FUpJWW%XDuVL1ZDk5du(+lYDX3EARV=IH4u6NZeD z*>0W68%~w}KhWQ|-xD$RYwX*3(#9$cWUS|M^AbKUka`*!U?BBj>EFdIMNr&J1G?*W otyW=nff$}f9`styYjKwkaox@UhLZ%#0Aka;b^A{G0Z_d4KXt7kvH$=8 literal 0 HcmV?d00001 diff --git a/src/data/themes/default/checkbox.on.normal.tga b/src/data/themes/default/checkbox.on.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..9cf658e3b815328b86f90509de416788b8c8f7b0 GIT binary patch literal 500 zcmaKpy%GU26ov09Rh|GPp29<@jVD@^We%gxXINV(z4KGGA O`&$0W(jKFv_)EX3nik+EmY4WvX?u4LQt^2l|6AR^?tNSkQ?Jqu| X!b?@ldn*!wPG<0Q^>bP0l+XkK=dD^C literal 0 HcmV?d00001 diff --git a/src/data/themes/default/console.input.normal.png b/src/data/themes/default/console.input.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..a14e329597b452fd83b32900020c119a1497bfad GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj%ROBjLp(a)PBY{?tRTQ59@q9~ zGG8`x3xEG{w<9)^bMY#FfaYdocq)N$r-=?wavw4^J{jY Xms2EpS~On+oy_3r>gTe~DWM4fgkDGG8`x3xEG{w<9)^bMY#FfaYdocq)N$r-=?wavw4^J{jY Xms2EpS~On+oy_3r>gTe~DWM4fgkD literal 0 HcmV?d00001 diff --git a/src/data/themes/default/desktop.xcf b/src/data/themes/default/desktop.xcf new file mode 100644 index 0000000000000000000000000000000000000000..2c504ab270ec11e145efecdc488295452bea49e7 GIT binary patch literal 1975 zcmcIk&2G~`5MJAfoilzUcUIFhmAQXH?qrWH}K$2on*{g_i_TI6vNPk9;qhL@{r#mQL&s zTz-0Tx{?B=r(DMf9TbFWKmW5rp^N#<^@7mnJzWdNWsyE8qGzL zHb~K%rnMy>N_;3W!HabU#@{kl9x!Hq&>pP%%IPZhA5Le|T*Z^JF zIZ#nLMeHaY3){`;)r`KE(Q6r<=7(}=aiCBQ3(zx0`IVR-m7+VwS@TogW`3dlm3f|` zC!5Ur2b5%kl>u8GupL=tXA%W;2OFIAsJ!NiPHvkks;9Z4x=O6CO3|HyE9+a{RwABL zo`|z+iCl(k{TKX{OtM?-2UwsLxea>M>0zNl4RBaZ(v9Z`-OCIi`81t0M%$({J9?|e zr~!O5C+jus6TWgkZ!5o`J<*r}UOtVXVX60B?~NZv7vYe5(QFA*`hIkF+wVv9^tjOH zro`S?N@iT_yLp?v`XAu(TI{y$e(x6G=FThQv%F^VP#UZyP1eLzG&ZM$8mj(gkhXd_ nvgDC{8~-KBtI5;}_$@wQeAt50nYGa$u<=0A1 z24`HiJ*dCE%eSC!-Bwf2ws^ZLk#p;~J~hui+mUCnlI`&(jxo3?uWT?<#yov>TOl!3(%;z6a%VmgzAP7MaMJjaAxv60-s?|%3X0ta~L}Ys8 zIj6*8akSenP@T?-l3>v7uCPx;iV1c4deki{rBVZ`UJuL;cacz~7si{*JwO$UKBQ3a zVH%-`EOPn$g;vWn%ETyV)TRwbuWqoJ;iu13Q>jyox?Oz_L}YsUC!5QH y>z-pgen)>g4WTBJ5H=Ah*F7^8#{Bz+EXzi@e66o3fbzUg*hFNga0%nxd4u0P1qitS literal 0 HcmV?d00001 diff --git a/src/data/themes/default/dialog.close.hover.tga b/src/data/themes/default/dialog.close.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..9f36bb78a9879bdc5ec685e5d9dd0f50eb56b387 GIT binary patch literal 668 zcma)4J!`^17(R`3=urF#9s4iNbQFRFi;_uPinN0`bk$r^6`@mC!AuUN1vl;FmbsfC zh;edjp&f#h!c(7B(DWQ=^YLFI-R~Qaou~@uA zZ8kqJh^WwELT42l(xlDi1LpHDsO2)oNfgB(NGcsBnB4WSk*v{B=uM{|ND)zSX{Gtf z=kw_IS5Sk&8Wi9M!5SGNN+k4|bLpqpU#)sjtyZKbJVt`9%b3nO&NIA9WrjA_)JQna z%RxfQ5WbXe@R`tPJ9qfsM21@x3Qs7PXDF3sy6!fkB53W$v8+3&dOaEaFA{Wh_Ke>u zr3ufA(CMtv?dtQZzuNXKMx#%7lSvFU o9>*|At56osD+bm-(y=-8j}Oh+L|uqc_trARx7Ls#>nMJ06VDwxTkwBV+l+?=}! zf*7Z4Ewn?BQcmA_MN>*MynOfEb8o^)gg6oVD=+fm^sFnT6u0_-p@5~uvRuBvc>Ij@ z`W0%o`+`NH!VVqAt2l7PvfaMJYV`rN*`zp*;}nGbogF&pJj@7ItyX}+eExM*+JJtC~tmJpuz^h=j=fl$g9 z2vX+%M>mO-N)M=3m#9>h=n@nuAPM%e4UThzu-VjaLNYox2q|rJIx%{^1VO)_AV(r7 zf<+?GQz+PG@+SyA4ad2}Ac}NQBr3i>#34<%?lmTpcLcLp3N@Xkut=0#_bQ7%`^dI^ Zjz;5N2O2{y7N4+4RM_DojQ7t^@(p3`Cbj?o literal 0 HcmV?d00001 diff --git a/src/data/themes/default/dialog.png b/src/data/themes/default/dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..26ae2a69d8af049d1a02cf08095accfaa98ff7c0 GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYYs>cdx@v7EBjS;QE@rhukUsh0fl5sTq8=H^K)}k^GX<;i&7IyQd1Pl zGfOfQLNZbn+&z5*-lwSM0TnLuba4#vIR18;A>UyI9#?r$r=7t^SZ7#dscrM==;U^d zdvRfz(psw}jeZqJtB(EWzt5#nqQfiT^n$7UoGn`i$7dV!*5y+ec3j+P(qPz@Icru^ zuVMWi2bUY$)@nw$w6Py!f??03Oo~)sy!w-ROE+wFg89ZJ6 KT-G@yGywpP6L*{d literal 0 HcmV?d00001 diff --git a/src/data/themes/default/dot.down.png b/src/data/themes/default/dot.down.png new file mode 100644 index 0000000000000000000000000000000000000000..ab117a712849ff228fcc40e0f32f1c716d72fe0f GIT binary patch literal 549 zcmV+=0^0qFP)03CEi zSad^gZEa<4bO1wgWnpw>WFU8GbZ8({Xk{QrNlj4iWF>9@00D_fL_t(I%cYY$EW=S0 z#((#p8_xuZcqE7jBQbchRU$-e1iN4nCYwP_Y|_bKFqIe#NIW7jPy-!22NDxWMfxDx z{uMojdR1F#<6F+nIXT}s=R5Z(VngEi)o+LKJF%#^M5gB#IJt3RzPw_-ymE5mWO{yq zqT&+ygB1SwWmP9Z&KFZFr4L~V? ztn3^a**HL_rp28NAoSr6KATwEn|OTiDh)`frGv{r2m*c*MX9BO(-oU&0AFPT7heB| z{DO)W`zscnTVYl;!io(Ia9vOVULQ#zzdY`!NkIeT-CmJd(}F04lIS%{SnG(G@6y5j zC&AnPCS{hkq$(fVx4$}2?!7H3)R2;%f$>AXkbt4W7QWxXfS=v{?eBj8NN#l@3DjhW~(pPB0I!g*wmc~}5qXf5@FV=`$!mo-;V)?7iE nw4Y1;;FuU%M;(*;?>WB%?2D=pu|Jz)00000NkvXXu0mjf@7v<@ literal 0 HcmV?d00001 diff --git a/src/data/themes/default/dot.hover.png b/src/data/themes/default/dot.hover.png new file mode 100644 index 0000000000000000000000000000000000000000..090f07dff519a66a7bcabe96f5787346f613d4a1 GIT binary patch literal 548 zcmV+<0^9wGP)WFU8GbZ8({Xk{QrNlj4iWF>9@00D?eL_t(I%cYaeD@0)w z#(#IbNVD(}CL~!6VM9!_a{AViYa2ACetWk*+LZ6jrcBnG21f`6d}x}60HmYMO-PrZ$N4QB zZEmiP_N4%LuWR5Y8Y36z^^I_}pY-6av>LQ{P6QNJSw{a00-z)krpVc1nUu}EOk-oA zOP;?7%!>ey){dMeUtI(&1#Uz(?XYT;MY zw-#rRX5xF4%bd*&PtQ?Qke_w`nEt`~>?DuDb1TY9#x+V?p1|4NhpW36XKf7t!O$(f my&Zyk+n5RC$7A}_Ie!9%jf_1{&txJ100004nJ za0`PlBg3pY5H=O_N(lo;$jSOhB1qQLb4^U5hc#~xw)x%B@E6*sfi`2DGKG8 zB^e4K8L0~Hp1uL^Q&jVS3a@#(IEHAPFTJ?Yi#brB_2K(tr@NvwZ$utp=MXx0=-jn) z=BKnHS#q{+GT;!4isEeK;8b$toVD>p-ll_R>t{DwmOne=^D0tkb-=2o7*+mQtDuBu zXMOifUv#B;N5Q&KZG-an)3&S-NZ++@?Pb%i0zqm1$Cv*v*)!wRqPNb*x#uTp_6TY} ze(G@YTT++)W?s>{$j$dW(oX-2YL0l9xk?ppfutRL= zNs~+AH`eZTy5A9Uw<*K2^btd{zuZ~x<)NQV%sU(p@BGgo^v`_rnar14fIejKboFyt I=akR{01+mTi~s-t literal 0 HcmV?d00001 diff --git a/src/data/themes/default/dot.xcf b/src/data/themes/default/dot.xcf new file mode 100644 index 0000000000000000000000000000000000000000..31007503cf1d455e5bd4d315eec8a3415d10dfd8 GIT binary patch literal 1930 zcmc&!Pfrt35TD&{|Ih-WRYE|MRSpH3D(GDkh%rsnmtIR3BMy$t?-DVCZh{qX7<>!-06e54RVrJ|=e2@`HF4nRf~jRJZAINQtW|Y! zRa2j(U%X=PD40|5E~JoNL;homkRNwnIIXInOnX(B&SX!ms{b;n1zpdM0ZWbahUg1!K9F z(X*vC3WkN^v#T0cy;aQRN}6?EAV*&{buAY|84r&nhbZt4h<_srZ3`=;Xg9ZE_-TIK zDyz>kWzC#?#G683ZjuX*cslPK@N@`@`t+DjAN1)%KK&YW&LxOvh|gdWb0v3|{FFa= zx~LR;gEl^nr$4$zz#fu0jKDh{A5X>#M=nVfbqB)!?iB-FJ2;Ig<<|r5QPS zdYfo$DZ2Dy3}d!wSENeIuGsi*%9y-C1t`>M5Vx7;XBUc*_0=|hy&daP*#Ap>_eY>@&CTo#Li)> zb+|JD?7lA^939p1J6Hs;?FEK-0bo1B+qPsYm1DcIJxr8BSB_Ie_mXIqf@V3%NpyYJ zS22Q!27NQmzJ8%CCLSdO-*X`#AKJl>U6Zf{Kl2)hVrB<0yRjP3u8Dc>B`?i5-rWYr zeX|%OC(&>f*J&ge*@PQ$+X+TC(13c4nJ za0`PlBg3pY5H=O_G`>M9D*j5yTzUZg=9-yBTAg}b8}PkN*J7rQWHy3QxwWG zOEMHfGEx=XJ$(b-r>N!u6&iWEIEHAPPfn2FYY_DMe_ZuA$Mb*3*G(1ld|@v(IZ#Al piov6@%k^v4B_7D)xycqF3p9H_C&MN6MJYht44$rjF6*2UngA!OI`IGi literal 0 HcmV?d00001 diff --git a/src/data/themes/default/filebrowser.folder.png b/src/data/themes/default/filebrowser.folder.png new file mode 100644 index 0000000000000000000000000000000000000000..4a3bd2c9f195ac82fcedfff2addaa9ab5765783a GIT binary patch literal 634 zcmV-=0)_pFP)=?sNKF%hFR9Ed+5{q(7SYOOvqw;46lJqq~(%G3}DM+uyYGGSj~?#&Cb zGc#D0_3s|W<8f>|L!sm+zy1rS=uq4&b0Qoi(AYw2TRn}9_28_4vkH>q(c~n-aL0j% z!nGa?*B7R_qk9`DE`qZRvV^QHfe2y@#uzf=Z@G2ndUY_FO!@%H=klEC>?c%ujjVhI zBZwG`)@Y-*vsM_bnV$PrSy#P60H?Uc$y$ZC;bOGLXoWU^kV;lsbEGC%?T~kaLT#WP z&n;8h%wvo~>s?jtz*=k8b44PN$YCHfG{x9jnWt3D@2SdDigMY-amvgttTOiOBauk= z;b39yJ9U8)g?w%YaCtfVgLhxnnEtTL*ENrht{xHtHy9cks(P^z5k!Re`ItEQMY(tT zstjH}E9Y9m5(Iyy=y6e5vGkW41`eXj?_Z+ldG UE_YNIx&QzG07*qoM6N<$f*jN&VE_OC literal 0 HcmV?d00001 diff --git a/src/data/themes/default/generate.py b/src/data/themes/default/generate.py new file mode 100644 index 0000000..a161556 --- /dev/null +++ b/src/data/themes/default/generate.py @@ -0,0 +1,98 @@ +import pygame +from pygame.locals import * +pygame.display.init() +pygame.display.set_mode((80,80),32) + +def prep(name): + fname = name+".png" + img = pygame.image.load(fname) + w,h = img.get_width()/2,img.get_height()/2 + + out = pygame.Surface((w*3,h*3),SWSURFACE|SRCALPHA,32) + out.fill((0,0,0,0)) + out.blit(img.subsurface(0,0,w,h),(0,0)) + out.blit(img.subsurface(w,0,w,h),(w*2,0)) + out.blit(img.subsurface(0,h,w,h),(0,h*2)) + out.blit(img.subsurface(w,h,w,h),(w*2,h*2)) + for i in range(0,w): + img = out.subsurface((w-1,0,1,h*3)).convert_alpha() + out.blit(img,(w+i,0)) + for i in range(0,h): + img = out.subsurface((0,h-1,w*3,1)).convert_alpha() + out.blit(img,(0,h+i)) + + return out,w,h + +todo = [ + ('button.normal','dot.normal',None,3,3,'789456123'), + ('button.hover','dot.hover',None,3,3,'789456123'), + ('button.down','dot.down',None,3,3,'789456123'), + + ('checkbox.off.normal','box.normal',None,2,2,'7913'), + ('checkbox.on.normal','box.down','check',2,2,'7913'), + ('checkbox.off.hover','box.hover',None,2,2,'7913'), + ('checkbox.on.hover','box.hover','check',2,2,'7913'), + + ('radio.off.normal','dot.normal',None,2,2,'7913'), + ('radio.on.normal','dot.down','radio',2,2,'7913'), + ('radio.off.hover','dot.hover',None,2,2,'7913'), + ('radio.on.hover','dot.hover','radio',2,2,'7913'), + + ('tool.normal','box.normal',None,3,3,'789456123'), + ('tool.hover','box.hover',None,3,3,'789456123'), + ('tool.down','box.down',None,3,3,'789456123'), + + ('hslider','idot.normal',None,3,3,'789456123'), + ('hslider.bar.normal','dot.normal',None,3,3,'789456123'), + ('hslider.bar.hover','dot.hover',None,3,3,'789456123'), + ('hslider.left','sbox.normal','left',2,2,'7913'), + ('hslider.right','sbox.normal','right',2,2,'7913'), + + + ('vslider','idot.normal',None,3,3,'789456123'), + ('vslider.bar.normal','vdot.normal',None,3,3,'789456123'), + ('vslider.bar.hover','vdot.hover',None,3,3,'789456123'), + ('vslider.up','vsbox.normal','up',2,2,'7913'), + ('vslider.down','vsbox.normal','down',2,2,'7913'), + + ('dialog.close.normal','rdot.hover',None,2,2,'7913'), + ('dialog.close.hover','rdot.hover','x',2,2,'7913'), + ('dialog.close.down','rdot.down','x',2,2,'7913'), + + ('menu.normal','desktop',None,1,1,'7'), + ('menu.hover','box.normal',None,3,3,'789456123'), + ('menu.down','box.down',None,3,3,'789456123'), + + ('select.selected.normal','box.normal',None,3,3,'788455122'), + ('select.selected.hover','box.hover',None,3,3,'788455122'), + ('select.selected.down','box.down',None,3,3,'788455122'), + + ('select.arrow.normal','box.hover',None,3,3,'889556223'), + ('select.arrow.hover','box.hover',None,3,3,'889556223'), + ('select.arrow.down','box.down',None,3,3,'889556223'), + + ('progressbar','sbox.normal',None,3,3,'789456123'), + ('progressbar.bar','box.hover',None,3,3,'789456123'), + ] + +for fname,img,over,ww,hh,s in todo: + print fname + img,w,h = prep(img) + out = pygame.Surface((ww*w,hh*h),SWSURFACE|SRCALPHA,32) + out.fill((0,0,0,0)) + n = 0 + for y in range(0,hh): + for x in range(0,ww): + c = int(s[n]) + xx,yy = (c-1)%3,2-(c-1)/3 + out.blit(img.subsurface((xx*w,yy*h,w,h)),(x*w,y*h)) + n += 1 + if over != None: + over = pygame.image.load(over+".png") + out.blit(over,(0,0)) + pygame.image.save(out,fname+".tga") + + + + + diff --git a/src/data/themes/default/hslider.bar.hover.tga b/src/data/themes/default/hslider.bar.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..5e5c53ac1428b920b58b7def0ed2e9fcf7c46617 GIT binary patch literal 776 zcmds#y-EX75QQf$HadsmL|I_m}pYSc0!1$1W~avr1GcG zMlekhFrd3lQbY_SMG%$aJy%S`M{tX~-<&z;7I#KuNPfPsgk^ZdHBD18>VPJPrNMG` zW*WtdBfK`Bkox?1gF&Lg4jtNSGcdq1vlmCFRfFB_JR{ld1Q;X{_-Bh2T6-a3<-|9! z->P3CM52;VhrU#z(I|p)7Ea?ahjgQshe0AxW?P#>jJey(@cf4aghU-$Kglk@tKKX@ zPIHUD^xHENUa4S0NPYi5)b&V@4<=E)o=5d+4rzi-a!A5n{{^@6CBqW<;kO(wItWh2Po}`K+wlbk69pn)rQQ_6nTL-MgrqHgRW4HTK pREyLsz#vg#iwSM+ujyFCf|p)}Up_?Yy?qCRM1>s&wD-@Ne*qx=op1mE literal 0 HcmV?d00001 diff --git a/src/data/themes/default/hslider.bar.normal.tga b/src/data/themes/default/hslider.bar.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..e9371c7448e8b84155f06771fc6db8bd046e779c GIT binary patch literal 729 zcmds#p^k$<5Qc~1?g=VS-dn;pXG#u1prTJef+}eh2=KV3q6Ps3RY3)UV*cZw^0U^mmiLcO$8p48HYjZv+6<#8LS5H*JRaC$SvH9ZGjyoeuwcco zC<;u|1b?1qtVmRtd3uD=>2yMHzu#ezsJP3fJ;d`oG);q`>pEB@Dw?0 cE$R0fV{kkk(Y7tN<2b@5QDKG!>V0{)-vq(I!~g&Q literal 0 HcmV?d00001 diff --git a/src/data/themes/default/hslider.left.tga b/src/data/themes/default/hslider.left.tga new file mode 100644 index 0000000000000000000000000000000000000000..2fe406ce451470f6a5e10102e6708b068b69780a GIT binary patch literal 372 zcma)&yAH!33`O0wQ$C?%zcS4`Q@)Ndf+a(wEMXxMLc;AOR8F@toy)N;1JRwnr=Wr! zPl_?Vrm`%#0ugBX5Lcixh7c}sJdT4gggcPb4g0=xodifkzpg7cNq|H&#u%=(*4)D0 zK)7lEQr0S^xJ&(@KSVdr^Eoq-bo9%zwFhqwiuF{LD;*|v=_gx{drXO?B*4&nt8B80#i;t8rkd+)h(&T$WW z0imP;watv<$Oauf=pSLNJ!cw_xG_yrSp_7-JkMo$kPtD(@?20A!@90A?)zTi@0T75 C>)?a{ literal 0 HcmV?d00001 diff --git a/src/data/themes/default/hslider.tga b/src/data/themes/default/hslider.tga new file mode 100644 index 0000000000000000000000000000000000000000..ff3b4b2441783bfb9e173697c482402673d69250 GIT binary patch literal 1231 zcmeH{v2KGv5Jb=Tpzs&COqtI-I}Ng;{DeCfmK%3&p~Ed55*4CAazO!-@x<>U5*IX9 zlr9u#*qL2+_jb>ig&CivS(=yEwR6s_B$?TEyVY*DQ@r2r6&wx+0kEv$S6<1>@`)P$ zbUGJl0)qmj4-!54 z@|&V4)HIFSwpHA9oua<)1;7G>0wpmV?mh--5gGP!xd^Z8^{UM<46-0BFep%Z-;kmy zi_D0Q3YYiW?WQ>h3k(W})Y3rOK}BRm^bhm_2n&ouV#$ka=>Sy_@kWFU8GbZ8({Xk{QrNlj4iWF>9@0096=L_t(2&u!67iW6}V1@K?} z)25S*D4m5U-eQ(>gzQ|*d6JyPoWY&P5kg>SXOMi+>2hJTGhnSAy!WVj^-}2QR(^Yq7Gl$+<>jW~}I)?X_BqAkrr1K5D#ItAx}!dDhxm zM8%y(V{U3BK;?}QPKdAh$!8zDRb6RFonLl-D7C4X`k(vHgpu0JRH;miU%CHEDq|C+ z2<3*pMMWsR)XSUg1L~#HIXdfZh~dn$qw*LBdncDyl5}yh_Yf5?*A&Aa(#65E7LoXt z|NrEDP}W$)*4ECG)=#Y`J6rc*XcNBY(B{K6?b>e=Y+hkyqO-yP0000JzBqaR!|KEP;G6N%{z|*da*?Of+vM#J}T+GHR+q{B}!Mc@M U$67OcGEf_Xr>mdKI;Vst04J<3!vFvP literal 0 HcmV?d00001 diff --git a/src/data/themes/default/input.normal.png b/src/data/themes/default/input.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..8519a982dd6354ccde877b80b731b4eb7019bc2d GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYYs>cdx@v7EBjRr9tLfhX&;J`fkLt+t`Q~9`MJ5Nc_j?aMX8A;sVNHO znI#ztAsML(?w-B@?^9IsfC^1KT^vI!PABJNWF#zLOGr#e@bK_haA687x0r!p0B4Vs sN!EoGj*HoPrA$hAk{YitPLXC|nCrzhW#Yo4xzopr0MO?-f&c&j literal 0 HcmV?d00001 diff --git a/src/data/themes/default/left.png b/src/data/themes/default/left.png new file mode 100644 index 0000000000000000000000000000000000000000..b9656660e50d8b4100ae57f2f59811563dedbd7c GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_G`>M96~H5{-qs2A=whwh!W@g+}zZ>5(ej@)Wnk16ovB4 zk_?5Aj8p}8Pv3y|DXMuug_fQ!jv*T7lM^HaKFH5J+!8Mpe6YUctIv<654rw5o^b3L y+Z!$k$$!QM21&sOI<8La*|9c3#d5(528N$GoZS7(CW!(KVeoYIb6Mw<&;$S)u|Sys literal 0 HcmV?d00001 diff --git a/src/data/themes/default/list.item.down.png b/src/data/themes/default/list.item.down.png new file mode 100644 index 0000000000000000000000000000000000000000..fd9dc2115bc7f5d5082c25dfb71ba0d300aed608 GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYYs>cdx@v7EBjS;QE^QMw)bW8fkLt+t`Q~9`MJ5Nc_j?aMX8A;sVNHO znI#ztAsML(?w-B@?^9IsfC`m7T^vI!PAA)Z`fAT?${@@<^}q_p#caJ&CRrCijEVdV Yj;EMjXfFQX2UN}A>FVdQ&MBb@0PCwXZ2$lO literal 0 HcmV?d00001 diff --git a/src/data/themes/default/list.item.hover.png b/src/data/themes/default/list.item.hover.png new file mode 100644 index 0000000000000000000000000000000000000000..627790d726869468c8bd45a9d23ca90a5df374c6 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggic2PDik^L1iM}R`IC9V-A&iT2ysd*&~&PAz-C8;S2<(VZJ3LzP(3hti10q;{( z^MDGKJY5_^EKVo?`TyUZ*_1(;dFp``j*HoPrA)FefEW|`86+<<>v{@Z&IGDv@O1Ta JS?83{1OUG4EfoL& literal 0 HcmV?d00001 diff --git a/src/data/themes/default/list.item.normal.png b/src/data/themes/default/list.item.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..627790d726869468c8bd45a9d23ca90a5df374c6 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggic2PDik^L1iM}R`IC9V-A&iT2ysd*&~&PAz-C8;S2<(VZJ3LzP(3hti10q;{( z^MDGKJY5_^EKVo?`TyUZ*_1(;dFp``j*HoPrA)FefEW|`86+<<>v{@Z&IGDv@O1Ta JS?83{1OUG4EfoL& literal 0 HcmV?d00001 diff --git a/src/data/themes/default/list.png b/src/data/themes/default/list.png new file mode 100644 index 0000000000000000000000000000000000000000..99ad5bc74853220acf1b646ef254feb983fd9946 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+k!3HE-=Cy!09-c0aAr`%FuWaOXP~>pE*xh|l z%jcL@&aw4AJyVaoJ0871xG6+5EzIP!k6@^7Lx)A%JH7)i4wc$RWxambUf=t?bFSI< cqR%{b7850IyyJMa2WTdPr>mdKI;Vst0Q8+N7ytkO literal 0 HcmV?d00001 diff --git a/src/data/themes/default/listitem.down.tga b/src/data/themes/default/listitem.down.tga new file mode 100644 index 0000000000000000000000000000000000000000..13e2e57db0817408e90a13a6dd04b6855e954050 GIT binary patch literal 2226 zcmZQzU}As)2?lWn1(h%Ful@h>?g|8h*ywy*axigxG|;S9_gB#r-#^#*A3LtcAr4Xx zk|PE;{=d2}l&1LfI_>{3d}^K6e-H-oVKgo|m|A=^NbiAp45N573`WzyXc`!hG;nH- z!vE82<-r)lCKZG9;xpswZpZ($#P?4o{=a`B{yz#069b78gJJ5CX(;>E^@jhn#9y8+ O_)kmx|I5Muw8Q|W59%iX literal 0 HcmV?d00001 diff --git a/src/data/themes/default/listitem.hover.tga b/src/data/themes/default/listitem.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..8bdf60a8ed7809db720aec37fbd863cd9ed80887 GIT binary patch literal 2226 zcmZQzU}As)2?lWn1(olg@BfG3hd>&HVSG|)?E2q7+y9@I`1$RH|1t2b`Tw62iwWp| zaK7O`E%Eh3iT@!u9!P^Qh!0~EL*v(fVY|csQ9K$3qiJ9?4GcsYxPBn~KNug3{C}Ms zOhEsGGX?)?iJxC<|Ns12ClJGE7#qYV7Q^&_Xc!x!_x;0#|7nT8zuEc!`|Iuh;WUU% O3MQcc|M!dkX^8=OT$fe= literal 0 HcmV?d00001 diff --git a/src/data/themes/default/listitem.normal.tga b/src/data/themes/default/listitem.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..a2994aa020df6a19e1a18400a799b8425b1cd732 GIT binary patch literal 2322 zcmeIzAqv1S429vaQ&djupgmYshzNw5ii*;^yfU#PJTnsbY()4WBA0wqq{#j3y}`8B t0@IumOk)f%MFg143{0&xq`W~kkPZB?0aXQ)yMw9s4kqSre0SGcsSfonSTFzp literal 0 HcmV?d00001 diff --git a/src/data/themes/default/menu.down.tga b/src/data/themes/default/menu.down.tga new file mode 100644 index 0000000000000000000000000000000000000000..f89d4b4fc4c26282fb6f7a491cd16d9a634b866c GIT binary patch literal 528 zcmc(cp$@_@5Qc9A#S_diN#H4X2sGhISQkh}rfUhB053p7z`;nS7|1Hj1ep4xf0uQA z11hfHcipYMmZ(R~2q~m!U`?9HakIdZ&46-%pubNR`tvZs&)%*iszPw8ia86=0_1&Mo+h3q_rr)qei$-=Qjh=zAV31}>d))C1-6^XzpK5vd>5Hx x@B5rNB1Zz`bx_y2OVRj zm7cG^^gi?Z*kH~302xcH=bVzgcga$UWJ*bJ3n8%b-ZP;-D1};3hz%hQGsfJC3!cC^ h$I4pE-?Qi}g%UT2F-qo~C2Osctu@Ip#zngR1^{}>HZK4G literal 0 HcmV?d00001 diff --git a/src/data/themes/default/notes.txt b/src/data/themes/default/notes.txt new file mode 100644 index 0000000..f6541e4 --- /dev/null +++ b/src/data/themes/default/notes.txt @@ -0,0 +1,8 @@ +dot and box.xcf: + +color -170 + +.down +.hover +64 brightness +.normal, grayscale +127 brightness, +48 contrast + diff --git a/src/data/themes/default/out.tga b/src/data/themes/default/out.tga new file mode 100644 index 0000000000000000000000000000000000000000..7ed46cc770ccb426951607e43af1dbe07c238d3a GIT binary patch literal 795 zcmds#p^m~p6h&XRS+ie&MDAySL_&gRh6-p32`K`6Ef_Eu0tAbK;IIhz1jOB**(_}K z6ShgG=iPVjOxqc=5Bs?)RwpKA#mqD4lW$lUk$E(0aX=-)^_ccDtQo z2tcMC%n`99NtDlKGZ}=gpr>gnH=Rypyubi*Pz2F@S-tnlNgMR9^{~r)>Uca>p6AK{ z2YJZ4-R`eH&~CSt7eyh1!k=LVD{sx`b1fDN`Q>t{9%PV%VhF%guh&ELdvl4lS}l$C z`@JFvrBe>}JRxGW!{MOxbUMi$k4ME25-k$J{5rWTl4Y4Tn~nOH%SADSLWe-`{yF(y DcjCJ* literal 0 HcmV?d00001 diff --git a/src/data/themes/default/progressbar.bar.tga b/src/data/themes/default/progressbar.bar.tga new file mode 100644 index 0000000000000000000000000000000000000000..184ae9c05106d72adf0ba24827500803501c28b0 GIT binary patch literal 563 zcmc(dF%E(-6owzh$rCU-dJJx1oCr7Y2$pC7nL8U!L7Y@(6Lpb92W62#69$Hk&;Agw zH?T=xzyDAFw!AV;Z?C?+J(HZNmbz1R0y3r-dQ?Jo8xOnaczUL0WojfdG1kYXsyuZ9jqAyZ@7($^#ZvWBZ7qii3Jvr5R%)cw$kej>goR`TNb&=cUDJCUbVt28=VbQYnWYqFN{M)e5cKfgtDqjJ1GS(KCxVt)YyXhWIld~! T$jmu2Ypu-I8gq>C;qU989V!M@ literal 0 HcmV?d00001 diff --git a/src/data/themes/default/radio.off.hover.tga b/src/data/themes/default/radio.off.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..6b0f7371ac3b374bc3ea416f800d17c29abb53f9 GIT binary patch literal 582 zcmZvaJxjx26oqdLI5_nuIQlbU>Q+z@KTs!iD1x9kINByeq(mn-q0~--s5n_V`7!7s z*rhF4&}3ztzmRtO# z-<@0VO9cx;>ihrE^+rw(CsDnbNA-FR9>F2GBw?>VVQYO{J;}ocgrs#&5Zks8lsq&l zyXuuH85ksjLoi7MdgAt|PW~)HrIB2jP>TxlFi2E5S$f;VT5<~Q`UTw1Yf*iMW&tLN j5?f4YbN?fc#cdqyts*EN!TD(4!z58*hXL*V^OJl7owGIa literal 0 HcmV?d00001 diff --git a/src/data/themes/default/radio.off.normal.tga b/src/data/themes/default/radio.off.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..3da51d84e18e68f990517804a10a460d1c022b7c GIT binary patch literal 537 zcmZvZA&-MV5QS%pJJp|X^8O`kQv}6=;1@JOK|r;l^*Dm4K|oVgQA7n`-ti{6-le$} zn{VE{ncbZg`H-KrmbH9-ZC%$Df7zh4VdyZ7q6lr z;|PDAXRJt6n0a}GQCXG}!!w}1ZzTV6@5 literal 0 HcmV?d00001 diff --git a/src/data/themes/default/radio.on.hover.tga b/src/data/themes/default/radio.on.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..d26764b3f6583b8cf94d4a70a5ef6fff5e5a05d8 GIT binary patch literal 637 zcmaKqJ4*vW6oqFqU}2S?VClbDH+BIP@qt>YMGyqV!qT|2n~1Nw&pr3<%$*TpQ1qU#2#cZN1jD3l+c4xYlniI4 zr;xio#Yf{6>gW3tl0=0WI*eDbAjI%+KaO^@4Ap7BVW88lg3$XiLkFGR8Wx%;zJa}F z?FN?8M8#z)#8)&LMYWKESAR((Q7>m8Nd(GFyYyKs^S73es620*{#_E(TqcdUP`aIkBACAkh8{yfL(p(@ zZA>rrX}z~>O@f+nNbb&YY*g|->ct&BiQ+CS5N6Buh(@kN3t*Q9`jKwqjPZQ&{iVmEMLzjoHjXSp41pWj?a->c00o|MNfRzIWagsg%MMkbtyyL>b2Pf}sdQn_*L9 z0}ggq@%(rT_v`Z=Hi-%|bQrJ80*m4F`N z)jxzHQE{lVr_@weA#*v8h@W0U)K5FGNd(GFJM<~N5FYJD)H@BC{y!wt=zwu-F0{c- z#k-)A@lFs{m=lsqNs+b|+skSa+xkn-_XK80hJ;$F>%R^&%Z<4pl1D8_9XIQJH2iL> z!w5rJpAD8Z92ud;cy_6N9I#pUXO@geCxdIW_VC literal 0 HcmV?d00001 diff --git a/src/data/themes/default/rdot.down.png b/src/data/themes/default/rdot.down.png new file mode 100644 index 0000000000000000000000000000000000000000..35cd4fe50694e63bd35a2ab903f525865f69ed8e GIT binary patch literal 525 zcmV+o0`mQdP)WFU8GbZ8({Xk{QrNlj4iWF>9@00D7HL_t(I%cYaCO9D|G z$3G`mMuH6@C?}j0{RIg{v^fMvV?%#I4sp#nG&OW{(qLOt4Q+vg;^0(+4yWKy&@6~T z!g-qJYcP*HQ&9RY4}S0czTfYAzweWn4Kb%KO&5IAjWI#*({I6;zR;A zf#WJL%bPUgWyWrLg8_S)44<8jBm+WIRYq@bbXgpls`5~)2^nD5vasrPkIL-X z2*=%Cug3!*18jYKETs;xIcJPZLk4&chdBrY=G%8!pP*t{&}@zg^55Sa#^XyV7phgq zfs}8z1<@$$tE*lIt`NC{)&2USP%3#mi9{$wPS+P3VJ1Vl)%uebu^)->e0hmK5SV%Y zzGZQAb;V1g@h8g8aoOkNERo<;)7akG0pPt-;Vzfswp?a78hQGp|9*>?Z{03CEi zSad^gZEa<4bO1wgWnpw>WFU8GbZ8({Xk{QrNlj4iWF>9@00DJLL_t(I%cYaCO9EjS z#(!rg2@ZuCS~(jXwFG6GN4pTNL4rj8Lt9hzH$;=rDuHu>5_;k(y7;d z4eE8u30BYY!uRn#@AE$2^Gd3!;sSv?r1=AR{^3R_#6>E_VLZ-SGz!3nu2a-B9&$PH z-fGPdNe%@fnMiPXc82WrPHrU-!mj3M#QozV`9i@anJN$`2M1(S6|>R6WHBRKIjJ802^m0NUuWOv`}s0A^X81L8U}PaV}g=paTJOCs&lDU zvlU3CZdVWtvMS573LGJF25VrNlwM!4b6^3t#Ugj9)KcBAb2+RD=}eUO0s(H$&++i|xeXx&} Tf4`2100000NkvXXu0mjfhHKk! literal 0 HcmV?d00001 diff --git a/src/data/themes/default/rdot.normal.png b/src/data/themes/default/rdot.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..636a207a8942c742d4a0c059298ae25103c04b24 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_N(lo!hB{TGk=2A$(FcAlsM<-=BDPAFgO>bCYGe8D3oWG zWGIAWq$;?3`UbpDQOyG?yyfZQ7@~2$_2NQ5W<~*)3)`P$1o`kcW_f&I32Jl*T`W-J zxPQVD4LgQL2gkq!j!nMYY#ah&h2^T#wgTe~DWM4fK;(`+ literal 0 HcmV?d00001 diff --git a/src/data/themes/default/right.png b/src/data/themes/default/right.png new file mode 100644 index 0000000000000000000000000000000000000000..613779e969fcf56922802cb40da215df628d556e GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_G`>M970lk4j!+8Lb4^U5hc#~xw)x%B@E6*sfi`2DGKG8 zB^e4K8L0~Hp1uL^Q&jVS3e7xS978nDCnqd0{?V^_#KnVCSTT6UhUhQy>zUZv{`VB9 u`n23R+i|td?N469k@p^MLd;!!3=Gi4nJ za0`PlBg3pY5H=O_G`>M9Lxf?K21-7Lb4^U5hc#~xw)x%B@E6*sfi`2DGKG8 zB^e4K8L0~Hp1uL^Q&jVS3IjY{978nDFTH5U*Al?Pe36rjd;7ngCP{)$%a$nV&G>b) z*LiW*^;HtDq`Y>#@UoD#kojS~fmuO8fU(1Y|HiFW&fr78Bz5@y$jp#EA=a|{H`_g9 W1MZ(9LUVy;GkCiCxvX1thw0A#yo@04hou!;Jh^qePTgSg=zLbJl(8)W}TEi^p E>$hF&0RR91 literal 0 HcmV?d00001 diff --git a/src/data/themes/default/scroller.slide.v.tga b/src/data/themes/default/scroller.slide.v.tga new file mode 100644 index 0000000000000000000000000000000000000000..cbaa875fd5befa961c44d3d55aadf3c3c6a0ca9a GIT binary patch literal 1278 zcmZQzU}As)eg;tn1(pB*|1+FEefmGC7^LsUjT>NnyLa#YziZbng80CJ1OG2wy7d3? zOUd8fB*gg(K{5~JWydZYVYa)pu9jREraBTOIU&OJu&{pmXC-jGeByP J^-@w^0RW3P>j3}& literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.arrow.down.tga b/src/data/themes/default/select.arrow.down.tga new file mode 100644 index 0000000000000000000000000000000000000000..d7210021954d1a01ab58930a8ef8be840e0043f7 GIT binary patch literal 344 zcmZQz;9`IQ2?hxU1&wJy?*9gm*tGvZ0Al^`|MKq2f5tEGul)xx8bJ&u5DO*(Ry6I^ z{Z&xq_s`Y;Z@ho5@qY`51(ChFFBB?!YMs{q#?$Mx|1*MEAVw320a12f9>n(l(`d%( zKea{y=zz8I{~6${Mi2|?(A|y@)};F<;(^{cnFu6+ET|{1H$Yimo-Tm0{(m_LWii0Q F4gifTtwaC- literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.arrow.hover.tga b/src/data/themes/default/select.arrow.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..162d8e710c6af869547e5a9c6007de6a20353e19 GIT binary patch literal 363 zcmZQz;9`IQ2?hxU1&wJA4i5htfCR&||3Cm@{qO(&`Tl>#@1Gz32QeB!3?>i@CIVJ8 z?ftX;Q032W&Hvx{{Px2CEg%*|_QClEsOes2x5U4O&|tD*@f*8+y76a z8LR*L!APJ34ut<_fU_DwET}`z6hK&$o?mMRdgEFrh-in(zJIt7!s`G2di(#T?{9Vj X0|v+fF&aS(h#~*KUxcz8V8IChiHq8t literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.arrow.normal.tga b/src/data/themes/default/select.arrow.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..162d8e710c6af869547e5a9c6007de6a20353e19 GIT binary patch literal 363 zcmZQz;9`IQ2?hxU1&wJA4i5htfCR&||3Cm@{qO(&`Tl>#@1Gz32QeB!3?>i@CIVJ8 z?ftX;Q032W&Hvx{{Px2CEg%*|_QClEsOes2x5U4O&|tD*@f*8+y76a z8LR*L!APJ34ut<_fU_DwET}`z6hK&$o?mMRdgEFrh-in(zJIt7!s`G2di(#T?{9Vj X0|v+fF&aS(h#~*KUxcz8V8IChiHq8t literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.arrow.png b/src/data/themes/default/select.arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..19de7608b2ab5532393829e773261757d94b49df GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngk!2%>}d+x6RQk(@Ik;M!Q+`=Ht$S`Y;1V}}R zr>`sfRd!J}UM?=P?Fm33Yfl%)5Q)plDG5LzkaB?S-eHMy$$!ZQcAwBXzrb^zqj{G3 xq$hbfWow(f)+HTaOf&kEKI3Eqd&z<##!otm`#r2yN&$^w@O1TaS?83{1OOi>Eo=Y) literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.option.hover.png b/src/data/themes/default/select.option.hover.png new file mode 100644 index 0000000000000000000000000000000000000000..fd9dc2115bc7f5d5082c25dfb71ba0d300aed608 GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYYs>cdx@v7EBjS;QE^QMw)bW8fkLt+t`Q~9`MJ5Nc_j?aMX8A;sVNHO znI#ztAsML(?w-B@?^9IsfC`m7T^vI!PAA)Z`fAT?${@@<^}q_p#caJ&CRrCijEVdV Yj;EMjXfFQX2UN}A>FVdQ&MBb@0PCwXZ2$lO literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.option.normal.png b/src/data/themes/default/select.option.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..627790d726869468c8bd45a9d23ca90a5df374c6 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggic2PDik^L1iM}R`IC9V-A&iT2ysd*&~&PAz-C8;S2<(VZJ3LzP(3hti10q;{( z^MDGKJY5_^EKVo?`TyUZ*_1(;dFp``j*HoPrA)FefEW|`86+<<>v{@Z&IGDv@O1Ta JS?83{1OUG4EfoL& literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.options.png b/src/data/themes/default/select.options.png new file mode 100644 index 0000000000000000000000000000000000000000..477a8264a0517c31697ae2635546d97044c923a8 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggic2PEV4b`1;d_W=D64!_l=ltB<)VvY~=c3falGGH1^30M9g^-L?1$R&1fcGh? zc|e8Qo-U3d7N?UF76>JzBqaR!|KEP;G6N%{z|*da*?Of+vM#J}T+GHR+q{B}!Mc@M U$67OcGEf_Xr>mdKI;Vst04J<3!vFvP literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.selected.down.tga b/src/data/themes/default/select.selected.down.tga new file mode 100644 index 0000000000000000000000000000000000000000..7d952a043304a6c8e28b9001ac841af34e82ad32 GIT binary patch literal 322 zcmZQz;9`IQ2?hxU1r0E78j$=CV*Q`?9|#yhtS|4c{crs8?h23qvL=F95EZZPuY#~z z@1JY@KjHqldZ@(JeW4Im)9H2E{~J%O)B4W#ztx@>jczUh; z|H&X0#K~88JN{<@IpF@u#Q*nC#KY-EkiZ0x2-I)a8=$N&PZvO0|Gyjrvlzgk1OO@e BlEwf4 literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.selected.hover.tga b/src/data/themes/default/select.selected.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..91dd7940702bbcb47d25770e3498ad97417ce494 GIT binary patch literal 338 zcmZQz;9`IQ2?hxU1q}uV2M2~}K;l1$^?%xbAYcTszJGrBzw!I$`yk@s|A`=eHOBpYZ(Fe5k~O^9>MI)Ad7%{~NC#ivQ05Vod$;AB+Ur zeIWe*WDpDDAO=Lu M|L+&UEJ&yU07kpMWdHyG literal 0 HcmV?d00001 diff --git a/src/data/themes/default/select.selected.normal.tga b/src/data/themes/default/select.selected.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..54b8927a5efe15c587d7d2c03e3c7db0a1f412ec GIT binary patch literal 282 zcmcJ~D-OUQ3;@v1?gW#QyCyrqk|jF?M*smHhr$yyI1)?;r8~kZn%AW12VjLSHrQZ4 zsCs(FA$+jMRBMe@N@2wqS>F4p(^`wd7=ti$k!X~ZlAHg~GInUKQ7EPG9-4PM=U5>G PR!WJLb7s|ANkHGfvCDyW literal 0 HcmV?d00001 diff --git a/src/data/themes/default/slider.bar.hover.tga b/src/data/themes/default/slider.bar.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..5e5c53ac1428b920b58b7def0ed2e9fcf7c46617 GIT binary patch literal 776 zcmds#y-EX75QQf$HadsmL|I_m}pYSc0!1$1W~avr1GcG zMlekhFrd3lQbY_SMG%$aJy%S`M{tX~-<&z;7I#KuNPfPsgk^ZdHBD18>VPJPrNMG` zW*WtdBfK`Bkox?1gF&Lg4jtNSGcdq1vlmCFRfFB_JR{ld1Q;X{_-Bh2T6-a3<-|9! z->P3CM52;VhrU#z(I|p)7Ea?ahjgQshe0AxW?P#>jJey(@cf4aghU-$Kglk@tKKX@ zPIHUD^xHENUa4S0NPYi5)b&V@4<=E)o=5d+4rzi-a!A5n{{^@6CBqW<;kO(wItWh2Po}`K+wlbk69pn)rQQ_6nTL-MgrqHgRW4HTK pREyLsz#vg#iwSM+ujyFCf|p)}Up_?Yy?qCRM1>s&wD-@Ne*qx=op1mE literal 0 HcmV?d00001 diff --git a/src/data/themes/default/slider.bar.normal.tga b/src/data/themes/default/slider.bar.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..e9371c7448e8b84155f06771fc6db8bd046e779c GIT binary patch literal 729 zcmds#p^k$<5Qc~1?g=VS-dn;pXG#u1prTJef+}eh2=KV3q6Ps3RY3)UV*cZw^0U^mmiLcO$8p48HYjZv+6<#8LS5H*JRaC$SvH9ZGjyoeuwcco zC<;u|1b?1qtVmRtd3uD=>2yMHzu#ezsJP3fJ;d`oG);q`>pEB@Dw?0 cE$R0fV{kkk(Y7tN<2b@5QDKG!>V0{)-vq(I!~g&Q literal 0 HcmV?d00001 diff --git a/src/data/themes/default/slider.tga b/src/data/themes/default/slider.tga new file mode 100644 index 0000000000000000000000000000000000000000..ff3b4b2441783bfb9e173697c482402673d69250 GIT binary patch literal 1231 zcmeH{v2KGv5Jb=Tpzs&COqtI-I}Ng;{DeCfmK%3&p~Ed55*4CAazO!-@x<>U5*IX9 zlr9u#*qL2+_jb>ig&CivS(=yEwR6s_B$?TEyVY*DQ@r2r6&wx+0kEv$S6<1>@`)P$ zbUGJl0)qmj4-!54 z@|&V4)HIFSwpHA9oua<)1;7G>0wpmV?mh--5gGP!xd^Z8^{UM<46-0BFep%Z-;kmy zi_D0Q3YYiW?WQ>h3k(W})Y3rOK}BRm^bhm_2n&ouV#$ka=>Sy_@k)%*iszPw8ia86=0_1&Mo+h3q_rr)qei$-=Qjh=zAV31}>d))C1-6^XzpK5vd>5Hx x@B5rNB1Zz`bxV;Z?C?+J(HZNmbz1R0y3r-dQ?Jo8xOnaczUL0WojfdG1kYXsyuZ9jqAyZ_y2OVRj zm7cG^^gi?Z*kH~302xcH=bVzgcga$UWJ*bJ3n8%b-ZP;-D1};3hz%hQGsfJC3!cC^ h$I4pE-?Qi}g%UT2F-qo~C2Osctu@Ip#zngR4nJ za0`PlBg3pY5H=O_G`>M9723kX3d!f6p}4*jVN)>&&^HED`9XhN=+4nJ za0`PlBg3pY5H=O_G`>M?9#%zOgz>=A=whwh!W@g+}zZ>5(ej@)Wnk16ovB4 zk_?5Aj8p}8Pv3y|DXMuug@K+fjv*T7mrgX~I$*%Ve17gNCxyTNg`Hmpytw4}v!R(S z+ir<5pTipA#v|vCpFVt+LC>o9*vWGT+dP>vcw4dqnpAm<_`Y)9b~w1O&UKm8ySu^{ XWCi4uYlY_n4QKFl^>bP0l+XkK4WUU2 literal 0 HcmV?d00001 diff --git a/src/data/themes/default/vdot.down.png b/src/data/themes/default/vdot.down.png new file mode 100644 index 0000000000000000000000000000000000000000..e9e781e23e8b7ba4dbdb695a040e7d0c0f74254e GIT binary patch literal 540 zcmV+%0^|LOP)WFU8GbZ8({Xk{QrNlj4iWF>9@00DqWL_t(I%bk-uEJJY= z#((#w)gn=YSArm33loXP$RHv%f=z@lc*P(QuL#n_<}nZ=MiQGe(stD@7z`u`3lb8K zE-lse{td0$hh7?I`sXC)JKy*J&L@$$ghpTbt06K>nG`iN4X6D_pp}oVz^$6lbJSVoE1Z2lml!Ue1oyS^0aot#^R_rDakK z#;}H;DpFF@7}~XxS6i>jlmYS!3Yl260HB~LA7 zIN#BV5(vcFzQ483#`p*U--o6PpYL8)J6m`>ajB=Q875Cv9k;nWFU8GbZ8({Xk{QrNlj4iWF>9@00DDJL_t(I%cYaOFN0AS z#eetpsx%#_pg}}TC1oMinA+Gx8VQL>h!7_KfWgOt#bgsA5i5x_(%C3w5<>@rPy-UF zYO2-VYtdV8KWO4?_ax`s=Q;Nt5eNh*14Vg=V!|vIIvfsM14E>{dWhAx0?_dCfV{aR zaebwf%vp?n8mNB%FrLX7?lX$JL<*8=0POBQT>XPInGo68Bz_xJc@rZq_KyY$E-qo( zY*a#xt&Z`PEgIdudQAhMskw!z`2_%^s;JkuO|NcX)R>x66SH%e<~Jcqg?Ur?eYV?b zagU4vC!X!sOB7yvKNPaN&-{+jyF3=Y?qk-4npD~t29 zkV?EK@l4KCe1%*l&B^u}@!P2GgD7gFF4IS6H;>LXOPSuTFF{I6nZ$qV`~`hkdJ-~Y RJbnNG002ovPDHLkV1g8>*+u{W literal 0 HcmV?d00001 diff --git a/src/data/themes/default/vdot.normal.png b/src/data/themes/default/vdot.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..f64089b67bb732495a850e5b8aa5ac07178e0c3d GIT binary patch literal 354 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n3BBRT^JhNO&16Od7K3vk;M!Q z+`=Ht$S`Y;1W=H@#M9T6{Tee5o0z53)r-@CLb4^U5hc#~xw)x%B@E6*sfi`2DGKG8 zB^e4K8L0~Hp1uL^Q&jVS3Qu{uIEHAPuf4d@i#brF<>C8#9xiJ{a*in3IS8-DE*={?795f3KARVDvvk$NdGim?HGUbk^hU%=ljx@f;peyc zmz?ocx)#8AWad78nTUG literal 0 HcmV?d00001 diff --git a/src/data/themes/default/vsbox.normal.png b/src/data/themes/default/vsbox.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..2deca1798912ebfa9abb6b7584d72f61a2e390b4 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n3BBRT^Rni_n+Ah4nJ za0`PlBg3pY5H=O_G`>M9Lx*~zb7>Ug=9-yBTAg}b8}PkN*J7rQWHy3QxwWG zOEMHfGEx=XJ$(b-r>N!u6?%BOIEHAP-#XEetHD5kIonE;hdvPabj)~L*3+vY2sm-k__Zdz%{J4AIPv?yHi5^>1%k9_96PoFgqq+xZ OCWEJ|pUXO@geCyKSW15Y literal 0 HcmV?d00001 diff --git a/src/data/themes/default/vslider.bar.hover.tga b/src/data/themes/default/vslider.bar.hover.tga new file mode 100644 index 0000000000000000000000000000000000000000..0a3f70a388033bd577beb9014cf3b9e434b78cb0 GIT binary patch literal 1412 zcmZQz;9`IQ2?hxU1&tO52M2~;An_l}Y65YYL0oTd@Bb}zN&nZ*kN)3zY@Ne@=2f!- z{+H$Z{dab9{0~wAR@(^Dzyjvh7yW;Db?*NM=NtZCKa}{t^TKwA|18%JM*e?rrr`gB z3oZZCll{RO!Ft$08bSJcyX*hIf42Ys^Vw7@`4~f+L7LjY_MxhmvPEHPpA`-2L1pv+Bx(5IN literal 0 HcmV?d00001 diff --git a/src/data/themes/default/vslider.bar.normal.tga b/src/data/themes/default/vslider.bar.normal.tga new file mode 100644 index 0000000000000000000000000000000000000000..07ee06e0a2f5e46a41a9a56a86dec6e323f8b7bf GIT binary patch literal 1412 zcmeH{A#a0F6op^Xc4EJva&rF?SY}Ex2ZCQff`Who0Uk#X7z7X$0t5muXT3LJ8yzKE zYx@M@CilyE@8;Yi#Iu;sQ5?m~>$@aL;^X`Q|GiPUqf%8>Se6CHad0wC6FaI5!+c}IF6B~DRf_As+q zmZ7d|7AHa`lzC0lFbu;V`KD>0D9SgFJkK#r(}MrH`@#2pzWc1-wk=%OWgeuDaUB22 zmu2~b$N5~>zkEOG_kI81Y4kk*$NcW|&$fTp{I~S)_WrE#i~SLI?(b@TT;E>`FR~8j S$IZd@J0fk{-ipYJi2VfbkS|&Q literal 0 HcmV?d00001 diff --git a/src/data/themes/default/vslider.down.tga b/src/data/themes/default/vslider.down.tga new file mode 100644 index 0000000000000000000000000000000000000000..61c75a67e08966f8994c81b15bd7b1b505c84f0a GIT binary patch literal 864 zcmd6my$ZrG7)4`$9Gv(%wP)gw>gg`5$gfRxrIfM`pV?@pwJx%|1 zueDy|{neD;ZA6XD3!i#=PkgV`sopp?^B#G)P`6&>-Y)gY+nF}ahrVe0Bj4ZpT4_J~ FJ`ePSz#aeq literal 0 HcmV?d00001 diff --git a/src/data/themes/default/vslider.tga b/src/data/themes/default/vslider.tga new file mode 100644 index 0000000000000000000000000000000000000000..ff3b4b2441783bfb9e173697c482402673d69250 GIT binary patch literal 1231 zcmeH{v2KGv5Jb=Tpzs&COqtI-I}Ng;{DeCfmK%3&p~Ed55*4CAazO!-@x<>U5*IX9 zlr9u#*qL2+_jb>ig&CivS(=yEwR6s_B$?TEyVY*DQ@r2r6&wx+0kEv$S6<1>@`)P$ zbUGJl0)qmj4-!54 z@|&V4)HIFSwpHA9oua<)1;7G>0wpmV?mh--5gGP!xd^Z8^{UM<46-0BFep%Z-;kmy zi_D0Q3YYiW?WQ>h3k(W})Y3rOK}BRm^bhm_2n&ouV#$ka=>Sy_@k4nJ za0`PlBg3pY5H=O_N(loB0@@UtJ9=_Lb4^U5hc#~xw)x%B@E6*sfi`2DGKG8 zB^e4K8L0~Hp1uL^Q&jVS3iUl*978nDCnre6Jg^rNV^*G}pv=YX%GhPsVxb)7J;7xr mhh-0oc7esD1?KF`3=FluxLNLRkp2kN%HZkh=d#Wzp$Py-c{9!c literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/Vera.ttf b/src/data/themes/gray/Vera.ttf new file mode 100644 index 0000000000000000000000000000000000000000..58cd6b5e61eff273e920942e28041f8ddcf1e1b5 GIT binary patch literal 65932 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

B-* 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 MUHx3vIVCg!0K(ivAOHXW literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/box.normal.png b/src/data/themes/gray/box.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..e4599d914d20a14308756718d0faf00868795156 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$w=kChtK@@~-+)50C9V-A&iT2ysd*&~&PAz-C8;S2 z<(VZJ3LzP(3hti10q;{(^MDGyJY5_^EKVn|8IZt#=(P)V8EJo z>1wxn=eE+bZL%x$7Tn-o%+@32u#!>d#w7KVY!+5llio79d2Kdk5I$-s_E|Dk3}`BY Mr>mdKI;Vst0L$k|g8%>k literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/button.down.png b/src/data/themes/gray/button.down.png new file mode 100644 index 0000000000000000000000000000000000000000..efb67bc772e32dc7787fe3158a9c28fa5adb3c91 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYYs>cdx@v7EBjS$VJL_bn^CXG{wM=P)v}@kkgHuub?c fy=(W1y6Ct)r@7qwcVw#r&1LX(^>bP0l+XkK+zC3q literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/button.normal.png b/src/data/themes/gray/button.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..73931504c39a2355fe2081798f710b84557f61f7 GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYYs>cdx@v7EBjS$VJ;KBiw09S0fj<5T^vI^j=#O8$k*V&<8pC-3jeix z;*C$ZJXoG{XE z)7O>#Dz}KB6@Opd9WS7ei>HfYh{fr*lNI?G6nL2V5A8SabosF0?-~vsF#`@ivzJSk zoxFQgG0ly!qvLH+zGwp1wS?(sRO3Ie@^kvtGfYr{XE z)7O>#Dz`8C2~qtk_|^f zo>bpcT(Ba`U}i@E;~iVuJL`lWFf*LdVcm0{_rSp<=^F>^8?5A#@04v565P1Sk-c+^ W$OXAWjwgYJGkCiCxvX{XE z)7O>#Dz}KBm5S0KRgeKCo-U3d7N?VQGBSRgcTiigetmjEVnRZKMZp7xle3olya2Kj z8YCKY9JCUW76@Fp&LGRo{fYO$GRftPFS-gdkG*D^p_XzsTyKuTS?(5-$0iK1hI(f! zVi_*C_!~Rw3taNq+v1XE2Qnq$&;S4b>%C$a7_RJ5iT~WpeiLXvgQu&X%Q~loCIC8d BMXvw= literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/checkbox.on.normal.png b/src/data/themes/gray/checkbox.on.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..5ee17b1f3a356962f932100971d01276f7b2e795 GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#Dz`8lMT5V40v4QmweB2cV~Zpd0ijhJaxXH2}#k5 zAI<+PXFtJ%!?9B0y)B=@(v-I6nJgA842Eu#6Qac#*y5hWH+I;F#~ciGw2Wz<&1+QB z7J7A?6aPA{QxB!?nik+EmY4WvX?u4LQt^2l|6AR^?tNSkQ?Jqu| X!b?@ldn*!wPG<0Q^>bP0l+XkK=dD^C literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/console.input.normal.png b/src/data/themes/gray/console.input.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..a14e329597b452fd83b32900020c119a1497bfad GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gj%ROBjLp(a)PBY{?tRTQ59@q9~ zGG8`x3xEG{w<9)^bMY#FfaYdocq)N$r-=?wavw4^J{jY Xms2EpS~On+oy_3r>gTe~DWM4fgkDGG8`x3xEG{w<9)^bMY#FfaYdocq)N$r-=?wavw4^J{jY Xms2EpS~On+oy_3r>gTe~DWM4fgkDDQYKj!K#Ym}3|84p VbB>+fbqA=L!PC{xWt~$(69A_QAd&z8 literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/dialog.bar.png b/src/data/themes/gray/dialog.bar.png new file mode 100644 index 0000000000000000000000000000000000000000..ffac15dfb489d8ec7b10a9b39938c40492e5e746 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^5`sfRc;X>A&H=Eo^?PWO-~oc5R22v2@8Z0QW6qY%&nj16g*3~cjk(xivpY7c%@7; ft}F;_E?{J^lVjFMta363YGUwo^>bP0l+XkK{XE z)7O>#Dz`8+faBXhrRaXq+k-OcBg4E=>qE`6WV-uT?)V(DCCMyZsaRzEIs_gr&1Zp>5r Q3FvSJPgg&ebxsLQ02ftk>i_@% literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/dialog.close.normal.png b/src/data/themes/gray/dialog.close.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..73dc9e482c26102d098fdc167335ba0ab6ee0105 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~i!3HGN^yhQ|Db50q$YKTtZeb8+WSBKa0w~B{ z;_2(kewAC8o5y@H+v|Nmp$bnI#}JM4OD7rfH7M}7+P6J6Fff|-+sdMf<*v%b&sWZx zFo{0wSAD-!*YwPp7d}0LVhroH{BL`n%F5s);iFbyci?BkwJJ4>{=?sNKF%hFR9Ed+5{q(7SYOOvqw;46lJqq~(%G3}DM+uyYGGSj~?#&Cb zGc#D0_3s|W<8f>|L!sm+zy1rS=uq4&b0Qoi(AYw2TRn}9_28_4vkH>q(c~n-aL0j% z!nGa?*B7R_qk9`DE`qZRvV^QHfe2y@#uzf=Z@G2ndUY_FO!@%H=klEC>?c%ujjVhI zBZwG`)@Y-*vsM_bnV$PrSy#P60H?Uc$y$ZC;bOGLXoWU^kV;lsbEGC%?T~kaLT#WP z&n;8h%wvo~>s?jtz*=k8b44PN$YCHfG{x9jnWt3D@2SdDigMY-amvgttTOiOBauk= z;b39yJ9U8)g?w%YaCtfVgLhxnnEtTL*ENrht{xHtHy9cks(P^z5k!Re`ItEQMY(tT zstjH}E9Y9m5(Iyy=y6e5vGkW41`eXj?_Z+ldG UE_YNIx&QzG07*qoM6N<$f*jN&VE_OC literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/input.focus.png b/src/data/themes/gray/input.focus.png new file mode 100644 index 0000000000000000000000000000000000000000..477a8264a0517c31697ae2635546d97044c923a8 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggic2PEV4b`1;d_W=D64!_l=ltB<)VvY~=c3falGGH1^30M9g^-L?1$R&1fcGh? zc|e8Qo-U3d7N?UF76>JzBqaR!|KEP;G6N%{z|*da*?Of+vM#J}T+GHR+q{B}!Mc@M U$67OcGEf_Xr>mdKI;Vst04J<3!vFvP literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/input.normal.png b/src/data/themes/gray/input.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..8519a982dd6354ccde877b80b731b4eb7019bc2d GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYYs>cdx@v7EBjRr9tLfhX&;J`fkLt+t`Q~9`MJ5Nc_j?aMX8A;sVNHO znI#ztAsML(?w-B@?^9IsfC^1KT^vI!PABJNWF#zLOGr#e@bK_haA687x0r!p0B4Vs sN!EoGj*HoPrA$hAk{YitPLXC|nCrzhW#Yo4xzopr0MO?-f&c&j literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/list.item.normal.png b/src/data/themes/gray/list.item.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..627790d726869468c8bd45a9d23ca90a5df374c6 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggic2PDik^L1iM}R`IC9V-A&iT2ysd*&~&PAz-C8;S2<(VZJ3LzP(3hti10q;{( z^MDGKJY5_^EKVo?`TyUZ*_1(;dFp``j*HoPrA)FefEW|`86+<<>v{@Z&IGDv@O1Ta JS?83{1OUG4EfoL& literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/list.png b/src/data/themes/gray/list.png new file mode 100644 index 0000000000000000000000000000000000000000..99ad5bc74853220acf1b646ef254feb983fd9946 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+k!3HE-=Cy!09-c0aAr`%FuWaOXP~>pE*xh|l z%jcL@&aw4AJyVaoJ0871xG6+5EzIP!k6@^7Lx)A%JH7)i4wc$RWxambUf=t?bFSI< cqR%{b7850IyyJMa2WTdPr>mdKI;Vst0Q8+N7ytkO literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/menu.down.png b/src/data/themes/gray/menu.down.png new file mode 100644 index 0000000000000000000000000000000000000000..3555053bfe0251f0f1c2987a4167f3ccc9140006 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggiZV_>7<2~(f?SMiio-U3d7N?VQGBOetNL;yoeY1gqK?_SoK%ST|^V9`sfRc=uR2Ei{46N`XC;+`&!ArhC9_Y^&3VOBhF#DPU3)Ft1Q!PSSU#VhFPH=q&* MPgg&ebxsLQ0AsWp$N&HU literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/menu.option.hover.png b/src/data/themes/gray/menu.option.hover.png new file mode 100644 index 0000000000000000000000000000000000000000..8ae05f3807b52283505e6743b9638adfdb8861a6 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggiZczpXspKG!UqB%vPZ!4!i_^(Zf=(taU`t3$NU+$d*5?#_#!1Z3Fo3g1$|UQ; n3dhB4y;3G6JV{H!N?913N?8(3&T%gV>SpkC^>bP0l+XkK!Qv!c literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/menu.option.normal.png b/src/data/themes/gray/menu.option.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..394200b42c3ac64e16d8d1cddcd544220bed76e2 GIT binary patch literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggiZczpXl|{y(fj}W8PZ!4!i_^(_iXO5sn=%M9Pd%{0aWPx3lu6bF5Mv@ggH<-u VoMWeV-2tj*@O1TaS?83{1ORFwACmw8 literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/radio.off.down.png b/src/data/themes/gray/radio.off.down.png new file mode 100644 index 0000000000000000000000000000000000000000..5a6e9a30b6a6299472b5f5e60573842927aaa881 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#Dz}KZCI7;EpRIvH^`0({Ar_~TQw}gmNlE>CERgOZo_u84#{-SbH@+BKSXdbR z`Tu|Z!i^gz3Lb7~Yis*&&>O5)l3=Q^d_hwq5FEUBPcDx`c~e@9)W$|r=`sTo6B7d? z!vGG6lN)7kii+$`xYBTN0^f{;nMV#DY)rXbn6_*J1OFVUi^ZzSOK(atbnbJ_(+ilk Q8t4=TPgg&ebxsLQ04mW{XE z)7O>#Dz}KZCEE=q@A*KXUQZXt5R21qCokkXY#`uV8~i^lp}=6e{q8^K4?KuqVrKqi zFW0qY+x4uV69;-0P0q0w;Fg&w$^UNC-p+KLr4@B6v^g14DnVty(R!McgM#@`d}2dF!_St|*%IK>h>w{{+{I(W&`gxBT2J%P{TirHZgm i75mCoPq}HipYiqWoqn7=1#^H7WAJqKb6Mw<&;$SwLRfhK literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/radio.on.down.png b/src/data/themes/gray/radio.on.down.png new file mode 100644 index 0000000000000000000000000000000000000000..483bd66a93982dc07f7db7f79c1b3ac4e78b3c32 GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#Dz}KZg?{tuN1K2`(>+}rLo7}wryO9Cl9KxOSRma+Jo(77j|Uo=Z+tPfu&^-r z^Z)<+g&Q|c6g=F}*4Fmlpf^~pB*9c+`GTfKAUJsMo?IS>@}{&Hsf~@M(q#rFCME_( zh5;NBg*VqFCo~?~U-XbAEIgr{XE z)7O>#Dz}KZxmD&nscAr=nVv3=Ar`0423zwTRuK8Tx@b0^tTmH)^_}I;$MXz~j0)t- z7xA_%@OnAHJn9oWH#ghzRd)_9J)YvyW7zj&!?h-rJ>NG8284zsaU^Oyn8VBSpIXIyy(f1 uNtdrwzU5=^-fnWvNACRfw5dfU=kl$T4*6L~9;^jAlEKr}&t;ucLK6UgLR?({ literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/select.arrow.down.png b/src/data/themes/gray/select.arrow.down.png new file mode 100644 index 0000000000000000000000000000000000000000..9ef850e3fd10384425c1ff6143be2e3ea25f80b5 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggiZczp{?)V+&`+!0wo-U3d7N?VQGBOetuq7lWByezkSa4yAsdSlvVE|{3lu6cw q6^@J9dZkQCc#;~gFiw$XVVJv&?ZlVZSj9_U#e|ZAf(2dO3{7oZyS0K0z5$J7@O1Ta JS?83{1OT6*E(ibs literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/select.arrow.png b/src/data/themes/gray/select.arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..19de7608b2ab5532393829e773261757d94b49df GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngk!2%>}d+x6RQk(@Ik;M!Q+`=Ht$S`Y;1V}}R zr>`sfRd!J}UM?=P?Fm33Yfl%)5Q)plDG5LzkaB?S-eHMy$$!ZQcAwBXzrb^zqj{G3 xq$hbfWow(f)+HTaOf&kEKI3Eqd&z<##!otm`#r2yN&$^w@O1TaS?83{1OOi>Eo=Y) literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/select.option.normal.png b/src/data/themes/gray/select.option.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..627790d726869468c8bd45a9d23ca90a5df374c6 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggic2PDik^L1iM}R`IC9V-A&iT2ysd*&~&PAz-C8;S2<(VZJ3LzP(3hti10q;{( z^MDGKJY5_^EKVo?`TyUZ*_1(;dFp``j*HoPrA)FefEW|`86+<<>v{@Z&IGDv@O1Ta JS?83{1OUG4EfoL& literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/select.options.png b/src/data/themes/gray/select.options.png new file mode 100644 index 0000000000000000000000000000000000000000..477a8264a0517c31697ae2635546d97044c923a8 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9oCO|{#S9GG!XV7ZFl!D-1$&97 zuPggic2PEV4b`1;d_W=D64!_l=ltB<)VvY~=c3falGGH1^30M9g^-L?1$R&1fcGh? zc|e8Qo-U3d7N?UF76>JzBqaR!|KEP;G6N%{z|*da*?Of+vM#J}T+GHR+q{B}!Mc@M U$67OcGEf_Xr>mdKI;Vst04J<3!vFvP literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/select.selected.normal.png b/src/data/themes/gray/select.selected.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..e1463f82ab6de6edd058df7200401a40d1e37f2a GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1$&97 zuPggiZV@3alSid{j{t?#JY5_^JdVFTYskpJz;Sp(WBvJ~EWf3gB^yL?Pw_xOos76H Viw=jk(`29y22WQ%mvv4FO#oP#9}@ro literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/slider.bar.normal.png b/src/data/themes/gray/slider.bar.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b335bdab5d005a4bd4d67d8d1c33b36377a91314 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1$&97 zuPggiZeea?;p4YegMmUJo-U3d9>M)G mU93wZ6Dya9M!8de literal 0 HcmV?d00001 diff --git a/src/data/themes/gray/tool.normal.png b/src/data/themes/gray/tool.normal.png new file mode 100644 index 0000000000000000000000000000000000000000..17b344d82007069424742ef6b6bc14138b3b11b0 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1$&97 zuPggiZeeb1;9)t)?fieL!h|giE&=D0CvrUc$92Ll zL}-#rkf0;$jqE!4d%qYKOqj#S%*G>Oknmt-mHdk-=a~YYv9WLL<36F}Ss(;7lEKr} K&t;ucLK6To$uH#q literal 0 HcmV?d00001 diff --git a/src/data/themes/tools/config.txt b/src/data/themes/tools/config.txt new file mode 100644 index 0000000..b663eb0 --- /dev/null +++ b/src/data/themes/tools/config.txt @@ -0,0 +1,11 @@ +tool.draw image icons48.draw.tga +tool.pixel image icons48.pixel.tga +tool.line image icons48.line.tga +tool.fill image icons48.fill.tga + +tool.select image icons48.select.tga +tool.eraser image icons48.eraser.tga + +tool.tile image icons48.tile.tga +tool.code image icons48.code.tga +tool.bkgr image icons48.bkgr.tga diff --git a/src/data/themes/tools/icons48.bkgr.tga b/src/data/themes/tools/icons48.bkgr.tga new file mode 100644 index 0000000000000000000000000000000000000000..67a614ba79f13cc33f5ebebfc9dc7558fc47ea19 GIT binary patch literal 1595 zcmd6oIc@_n3`LpNr*N6lm+^sS;vET)4enf}OOqoq{7<$B3p0TSX)Is_ivM#JWt+|H zvKF?m`Qwj{)3>9{*75nfq)%;KeBRl&dB5~!NO61<@S!cyRYhMbDxuhJgg)pf-Acki z5^*GWuMp6B9f@ew=U$v7gKjI@q_-O&?=pdiL$YEyTE zyk{BHZ{m*nqgAxU)TOQ#euEkL!OQ!jU!&3Jb(&?brkl}3a=tYhoh*YAmEMKbM!ooo z&o#I0vtrt%_mg(W9GNVn>45H<<;)XpR8zF#rJR>@Q$rDDP~Ije?+vr3&^x+OGnp0& zVKW*MI!eOhRAru{jk2)X&ZKVa=+J9V8xHiA86cr%e r|4s^u+QllPB#~d#qRW&USHz&IjF#h-^(C4Pxce6c(49C^{xkdnS}K88 literal 0 HcmV?d00001 diff --git a/src/data/themes/tools/icons48.code.tga b/src/data/themes/tools/icons48.code.tga new file mode 100644 index 0000000000000000000000000000000000000000..bfe961542fb5df662eb89dcb1cc5a3010b03982e GIT binary patch literal 1360 zcmbu9NlrsC5Jdg6bBb&J03~wk~qQ()g@sLCmKsG z042p)p(pCa(i^JuyTm@A3M@&-H3?_n8HV>@hBtWUY*?h#E8;UY)xYAMvQ2GO9Pt-C z=PKQdu$cuS&x96;gK1SEmY9tOB}wiqlenYNjzhd8oFFXK!6&h{;}!y`Jmc*vba;7a zswdg!@t;s>drXKBt3vIvgs_VjGdp08Z@{c`a*|4whl-v~I^i{| zfn*A%x0Xrv83fcdt2yuQM5xJYQj(l9A;11CB*l6Iftc?l8Z(n%p2k+avXF}TnWR_( mZ@~Mp*tXn?nAw5UUa8pnX=v^*8?ew@g4wZdd*K|5tU- z*rlwNam~uCtgXM3Hro?e|M3}dM)YVJ!xB54up%~}&!a%L@F4m8Yamn5K&%7Xc>9hE z824;N+9Ed5E+O2pB~9!Ws7G3mUXhAT(rcg_wv;9|(PW4xO-#$|p!qRw+ruX|i6#># zJOX0H7JEYO%}Cik?$0tJ1+6-GjGJc0iPEoXerLvo*Y8 z!Bj0r3QtHeq?`~^tdFBDjz_Ft*D?LaxCE~IGSl{ zJ%=rm@(S_K^qDHFK5vIK^+e5-F~VkGi|>dth$oIt*6AU zEG3pya@Yul7rea-P>e-MpX)jb)k zqHAVZ>w0n6IxDl#VC0A`xI-lHkZ$ zjVzN|DDPr~v0}1jo}^DA#S_c)Vhp?fg%iu9E@7r`&5R~wn0?rrkCzFo;jp!`g{@)az*?9b$b@+vJADirY)J0y^@;S-0PGh&8D6-qZ`Vfk@=?Xj(d za1nmKRak|~1j)}{NYDAN!`GHA|p!tbu&wrcNFjw#$1lG{B4LVJQ)U5Fi z&JH9f*KE{)F9(*!q;`)KqUkBC`Es@MA*E1Z{x`lE#q$=@!THJ=oz7q`EN6iyWB2&o Lv_jJ#P}%A?UL{Uy literal 0 HcmV?d00001 diff --git a/src/data/themes/tools/icons48.line.tga b/src/data/themes/tools/icons48.line.tga new file mode 100644 index 0000000000000000000000000000000000000000..19f9f9c89cb9c05876e181dcade9c54631c1cde0 GIT binary patch literal 1141 zcmbu8%Sr=55Jfv%zrv-<{FEOuzKzfLegs4jgaOIgmEYlixG!_gkgg;kI5>-<>ejtg zx4W5A*2?@FmSI`nm{P8U30U*-8F5bbXc@Cl?5tu%tZmyUkZn9j9)HcqG#nr{0NZ^3 zjtdy~gd%MjtF%i9cZ8&g-2yd83(_k}u`0a=x*?=Au}YI6o-{E><_3q0RjIyolhVX0 z%~N__yhMZF#2PT~CMn+a81`1}y4q4F21^^=g+q3VZ)ex%c&ek0$zBNV9g)2fB=3{G z)pCc-KoatlL0)L=QS!wzF%_P2o5s;{17{_aHCky%P1CQG)}I>-+nc?XD?h zt^C-$%**=58^;y*1U9^X)Otqr=&>$M?6hM=Y_V9>0@=ial(n9GKN3mXd4RnJ`X|PU{As(8TlDR=~heNS$1JFKvtZud6WpqN+t|4I$K=lZZ)kC~r(xr=85mB>K?in`L zRQ^BOi{!SvUgn}q*dN{39nM%&b{AyZR!m5?N#`{pQH(OG14cQ^S&6)tT5Yte@TNpz zkJ=5{5vUk_4+YY*wdwCqsa-M|i*1ZVR|KZ+P{0Ax-vOdnTe0oVID*N|xcM9|$W{{N n<=Kj41-urywoS{@fDx27i&>k>ZT=ff_&BF1FX*SjW8UgF9IX}J literal 0 HcmV?d00001 diff --git a/src/data/themes/tools/icons48.select.tga b/src/data/themes/tools/icons48.select.tga new file mode 100644 index 0000000000000000000000000000000000000000..09ee6310d024e7a87551a309eaa640afb98c799e GIT binary patch literal 1457 zcmeH{I}XA?3`CcfQ&3Xoiu{E{1xQpBIRQsBnP1`> z;;2>MLa5MITA)mXh6tzFQk{Ui10gG{NU6j?EVXNAZdCCuaSrqH*@3YnHx zV2Z+8n~Im+7)G($sw!>HrWmN21$xkzobow!kaI?yfFBJM_q8dnfT{a_Hjqn>9aDN> jV1yMp?8}%;_FS++hW$9YoEkaF@(Lk4XiMQDdS|253%-Q?q(sq7V5S zfJgCU^_37Ykz5CLm3m77wHHNuU6K7mhVlS&kSV_?jVh4oaV@eS-NmZ8!jeW&3fw^E u+N(U|Syhnc2#VE1e$k<>1394>h#3II`7NXX literal 0 HcmV?d00001 diff --git a/src/dataTools/odict.py b/src/dataTools/odict.py new file mode 100644 index 0000000..2c8391d --- /dev/null +++ b/src/dataTools/odict.py @@ -0,0 +1,1399 @@ +# odict.py +# An Ordered Dictionary object +# Copyright (C) 2005 Nicola Larosa, Michael Foord +# E-mail: nico AT tekNico DOT net, fuzzyman AT voidspace DOT org DOT uk + +# This software is licensed under the terms of the BSD license. +# http://www.voidspace.org.uk/python/license.shtml +# Basically you're free to copy, modify, distribute and relicense it, +# So long as you keep a copy of the license with it. + +# Documentation at http://www.voidspace.org.uk/python/odict.html +# For information about bugfixes, updates and support, please join the +# Pythonutils mailing list: +# http://groups.google.com/group/pythonutils/ +# Comments, suggestions and bug reports welcome. + +"""A dict that keeps keys in insertion order""" +from __future__ import generators + +__author__ = ('Nicola Larosa ,' + 'Michael Foord ') + +__docformat__ = "restructuredtext en" + +__revision__ = '$Id: odict.py 129 2005-09-12 18:15:28Z teknico $' + +__version__ = '0.2.2' + +__all__ = ['OrderedDict', 'SequenceOrderedDict'] + +import sys +INTP_VER = sys.version_info[:2] +if INTP_VER < (2, 2): + raise RuntimeError("Python v.2.2 or later required") + +import types, warnings + +class OrderedDict(dict): + """ + A class of dictionary that keeps the insertion order of keys. + + All appropriate methods return keys, items, or values in an ordered way. + + All normal dictionary methods are available. Update and comparison is + restricted to other OrderedDict objects. + + Various sequence methods are available, including the ability to explicitly + mutate the key ordering. + + __contains__ tests: + + >>> d = OrderedDict(((1, 3),)) + >>> 1 in d + 1 + >>> 4 in d + 0 + + __getitem__ tests: + + >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[2] + 1 + >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[4] + Traceback (most recent call last): + KeyError: 4 + + __len__ tests: + + >>> len(OrderedDict()) + 0 + >>> len(OrderedDict(((1, 3), (3, 2), (2, 1)))) + 3 + + get tests: + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.get(1) + 3 + >>> d.get(4) is None + 1 + >>> d.get(4, 5) + 5 + >>> d + OrderedDict([(1, 3), (3, 2), (2, 1)]) + + has_key tests: + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.has_key(1) + 1 + >>> d.has_key(4) + 0 + """ + + def __init__(self, init_val=(), strict=False): + """ + Create a new ordered dictionary. Cannot init from a normal dict, + nor from kwargs, since items order is undefined in those cases. + + If the ``strict`` keyword argument is ``True`` (``False`` is the + default) then when doing slice assignment - the ``OrderedDict`` you are + assigning from *must not* contain any keys in the remaining dict. + + >>> OrderedDict() + OrderedDict([]) + >>> OrderedDict({1: 1}) + Traceback (most recent call last): + TypeError: undefined order, cannot get items from dict + >>> OrderedDict({1: 1}.items()) + OrderedDict([(1, 1)]) + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d + OrderedDict([(1, 3), (3, 2), (2, 1)]) + >>> OrderedDict(d) + OrderedDict([(1, 3), (3, 2), (2, 1)]) + """ + self.strict = strict + dict.__init__(self) + if isinstance(init_val, OrderedDict): + self._sequence = init_val.keys() + dict.update(self, init_val) + elif isinstance(init_val, dict): + # we lose compatibility with other ordered dict types this way + raise TypeError('undefined order, cannot get items from dict') + else: + self._sequence = [] + self.update(init_val) + +### Special methods ### + + def __delitem__(self, key): + """ + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> del d[3] + >>> d + OrderedDict([(1, 3), (2, 1)]) + >>> del d[3] + Traceback (most recent call last): + KeyError: 3 + >>> d[3] = 2 + >>> d + OrderedDict([(1, 3), (2, 1), (3, 2)]) + >>> del d[0:1] + >>> d + OrderedDict([(2, 1), (3, 2)]) + """ + if isinstance(key, types.SliceType): + # FIXME: efficiency? + keys = self._sequence[key] + for entry in keys: + dict.__delitem__(self, entry) + del self._sequence[key] + else: + # do the dict.__delitem__ *first* as it raises + # the more appropriate error + dict.__delitem__(self, key) + self._sequence.remove(key) + + def __eq__(self, other): + """ + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d == OrderedDict(d) + True + >>> d == OrderedDict(((1, 3), (2, 1), (3, 2))) + False + >>> d == OrderedDict(((1, 0), (3, 2), (2, 1))) + False + >>> d == OrderedDict(((0, 3), (3, 2), (2, 1))) + False + >>> d == dict(d) + False + >>> d == False + False + """ + if isinstance(other, OrderedDict): + # FIXME: efficiency? + # Generate both item lists for each compare + return (self.items() == other.items()) + else: + return False + + def __lt__(self, other): + """ + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> c = OrderedDict(((0, 3), (3, 2), (2, 1))) + >>> c < d + True + >>> d < c + False + >>> d < dict(c) + Traceback (most recent call last): + TypeError: Can only compare with other OrderedDicts + """ + if not isinstance(other, OrderedDict): + raise TypeError('Can only compare with other OrderedDicts') + # FIXME: efficiency? + # Generate both item lists for each compare + return (self.items() < other.items()) + + def __le__(self, other): + """ + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> c = OrderedDict(((0, 3), (3, 2), (2, 1))) + >>> e = OrderedDict(d) + >>> c <= d + True + >>> d <= c + False + >>> d <= dict(c) + Traceback (most recent call last): + TypeError: Can only compare with other OrderedDicts + >>> d <= e + True + """ + if not isinstance(other, OrderedDict): + raise TypeError('Can only compare with other OrderedDicts') + # FIXME: efficiency? + # Generate both item lists for each compare + return (self.items() <= other.items()) + + def __ne__(self, other): + """ + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d != OrderedDict(d) + False + >>> d != OrderedDict(((1, 3), (2, 1), (3, 2))) + True + >>> d != OrderedDict(((1, 0), (3, 2), (2, 1))) + True + >>> d == OrderedDict(((0, 3), (3, 2), (2, 1))) + False + >>> d != dict(d) + True + >>> d != False + True + """ + if isinstance(other, OrderedDict): + # FIXME: efficiency? + # Generate both item lists for each compare + return not (self.items() == other.items()) + else: + return True + + def __gt__(self, other): + """ + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> c = OrderedDict(((0, 3), (3, 2), (2, 1))) + >>> d > c + True + >>> c > d + False + >>> d > dict(c) + Traceback (most recent call last): + TypeError: Can only compare with other OrderedDicts + """ + if not isinstance(other, OrderedDict): + raise TypeError('Can only compare with other OrderedDicts') + # FIXME: efficiency? + # Generate both item lists for each compare + return (self.items() > other.items()) + + def __ge__(self, other): + """ + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> c = OrderedDict(((0, 3), (3, 2), (2, 1))) + >>> e = OrderedDict(d) + >>> c >= d + False + >>> d >= c + True + >>> d >= dict(c) + Traceback (most recent call last): + TypeError: Can only compare with other OrderedDicts + >>> e >= d + True + """ + if not isinstance(other, OrderedDict): + raise TypeError('Can only compare with other OrderedDicts') + # FIXME: efficiency? + # Generate both item lists for each compare + return (self.items() >= other.items()) + + def __repr__(self): + """ + Used for __repr__ and __str__ + + >>> r1 = repr(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f')))) + >>> r1 + "OrderedDict([('a', 'b'), ('c', 'd'), ('e', 'f')])" + >>> r2 = repr(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd')))) + >>> r2 + "OrderedDict([('a', 'b'), ('e', 'f'), ('c', 'd')])" + >>> r1 == str(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f')))) + True + >>> r2 == str(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd')))) + True + """ + return '%s([%s])' % (self.__class__.__name__, ', '.join( + ['(%r, %r)' % (key, self[key]) for key in self._sequence])) + + def __setitem__(self, key, val): + """ + Allows slice assignment, so long as the slice is an OrderedDict + >>> d = OrderedDict() + >>> d['a'] = 'b' + >>> d['b'] = 'a' + >>> d[3] = 12 + >>> d + OrderedDict([('a', 'b'), ('b', 'a'), (3, 12)]) + >>> d[:] = OrderedDict(((1, 2), (2, 3), (3, 4))) + >>> d + OrderedDict([(1, 2), (2, 3), (3, 4)]) + >>> d[::2] = OrderedDict(((7, 8), (9, 10))) + >>> d + OrderedDict([(7, 8), (2, 3), (9, 10)]) + >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4))) + >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8))) + >>> d + OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)]) + >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)), strict=True) + >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8))) + >>> d + OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)]) + + >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)), strict=True) + >>> a[3] = 4 + >>> a + OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> a + OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]) + Traceback (most recent call last): + ValueError: slice assignment must be from unique keys + >>> a = OrderedDict(((0, 1), (1, 2), (2, 3))) + >>> a[3] = 4 + >>> a + OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> a + OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> a + OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> a[::-1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> a + OrderedDict([(3, 4), (2, 3), (1, 2), (0, 1)]) + + >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> d[:1] = 3 + Traceback (most recent call last): + TypeError: slice assignment requires an OrderedDict + + >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) + >>> d[:1] = OrderedDict([(9, 8)]) + >>> d + OrderedDict([(9, 8), (1, 2), (2, 3), (3, 4)]) + """ + if isinstance(key, types.SliceType): + if not isinstance(val, OrderedDict): + # FIXME: allow a list of tuples? + raise TypeError('slice assignment requires an OrderedDict') + keys = self._sequence[key] + # NOTE: Could use ``range(*key.indices(len(self._sequence)))`` + indexes = range(len(self._sequence))[key] + if key.step is None: + # NOTE: new slice may not be the same size as the one being + # overwritten ! + # NOTE: What is the algorithm for an impossible slice? + # e.g. d[5:3] + pos = key.start or 0 + del self[key] + newkeys = val.keys() + for k in newkeys: + if k in self: + if self.strict: + raise ValueError('slice assignment must be from ' + 'unique keys') + else: + # NOTE: This removes duplicate keys *first* + # so start position might have changed? + del self[k] + self._sequence = (self._sequence[:pos] + newkeys + + self._sequence[pos:]) + dict.update(self, val) + else: + # extended slice - length of new slice must be the same + # as the one being replaced + if len(keys) != len(val): + raise ValueError('attempt to assign sequence of size %s ' + 'to extended slice of size %s' % (len(val), len(keys))) + # FIXME: efficiency? + del self[key] + item_list = zip(indexes, val.items()) + # smallest indexes first - higher indexes not guaranteed to + # exist + item_list.sort() + for pos, (newkey, newval) in item_list: + if self.strict and newkey in self: + raise ValueError('slice assignment must be from unique' + ' keys') + self.insert(pos, newkey, newval) + else: + if key not in self: + self._sequence.append(key) + dict.__setitem__(self, key, val) + + def __getitem__(self, key): + """ + Allows slicing. Returns an OrderedDict if you slice. + >>> b = OrderedDict([(7, 0), (6, 1), (5, 2), (4, 3), (3, 4), (2, 5), (1, 6)]) + >>> b[::-1] + OrderedDict([(1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1), (7, 0)]) + >>> b[2:5] + OrderedDict([(5, 2), (4, 3), (3, 4)]) + >>> type(b[2:4]) + + """ + if isinstance(key, types.SliceType): + # FIXME: does this raise the error we want? + keys = self._sequence[key] + # FIXME: efficiency? + return OrderedDict([(entry, self[entry]) for entry in keys]) + else: + return dict.__getitem__(self, key) + + __str__ = __repr__ + + def __setattr__(self, name, value): + """ + Implemented so that accesses to ``sequence`` raise a warning and are + diverted to the new ``setkeys`` method. + """ + if name == 'sequence': + warnings.warn('Use of the sequence attribute is deprecated.' + ' Use the keys method instead.', DeprecationWarning) + # NOTE: doesn't return anything + self.setkeys(value) + else: + # FIXME: do we want to allow arbitrary setting of attributes? + # Or do we want to manage it? + object.__setattr__(self, name, value) + + def __getattr__(self, name): + """ + Implemented so that access to ``sequence`` raises a warning. + + >>> d = OrderedDict() + >>> d.sequence + [] + """ + if name == 'sequence': + warnings.warn('Use of the sequence attribute is deprecated.' + ' Use the keys method instead.', DeprecationWarning) + # NOTE: Still (currently) returns a direct reference. Need to + # because code that uses sequence will expect to be able to + # mutate it in place. + return self._sequence + else: + # raise the appropriate error + raise AttributeError("OrderedDict has no '%s' attribute" % name) + + def __deepcopy__(self, memo): + """ + To allow deepcopy to work with OrderedDict. + + >>> from copy import deepcopy + >>> a = OrderedDict([(1, 1), (2, 2), (3, 3)]) + >>> a['test'] = {} + >>> b = deepcopy(a) + >>> b == a + True + >>> b is a + False + >>> a['test'] is b['test'] + False + """ + from copy import deepcopy + return self.__class__(deepcopy(self.items(), memo), self.strict) + + +### Read-only methods ### + + def copy(self): + """ + >>> OrderedDict(((1, 3), (3, 2), (2, 1))).copy() + OrderedDict([(1, 3), (3, 2), (2, 1)]) + """ + return OrderedDict(self) + + def items(self): + """ + ``items`` returns a list of tuples representing all the + ``(key, value)`` pairs in the dictionary. + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.items() + [(1, 3), (3, 2), (2, 1)] + >>> d.clear() + >>> d.items() + [] + """ + return zip(self._sequence, self.values()) + + def keys(self): + """ + Return a list of keys in the ``OrderedDict``. + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.keys() + [1, 3, 2] + """ + return self._sequence[:] + + def values(self, values=None): + """ + Return a list of all the values in the OrderedDict. + + Optionally you can pass in a list of values, which will replace the + current list. The value list must be the same len as the OrderedDict. + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.values() + [3, 2, 1] + """ + return [self[key] for key in self._sequence] + + def iteritems(self): + """ + >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iteritems() + >>> ii.next() + (1, 3) + >>> ii.next() + (3, 2) + >>> ii.next() + (2, 1) + >>> ii.next() + Traceback (most recent call last): + StopIteration + """ + def make_iter(self=self): + keys = self.iterkeys() + while True: + key = keys.next() + yield (key, self[key]) + return make_iter() + + def iterkeys(self): + """ + >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iterkeys() + >>> ii.next() + 1 + >>> ii.next() + 3 + >>> ii.next() + 2 + >>> ii.next() + Traceback (most recent call last): + StopIteration + """ + return iter(self._sequence) + + __iter__ = iterkeys + + def itervalues(self): + """ + >>> iv = OrderedDict(((1, 3), (3, 2), (2, 1))).itervalues() + >>> iv.next() + 3 + >>> iv.next() + 2 + >>> iv.next() + 1 + >>> iv.next() + Traceback (most recent call last): + StopIteration + """ + def make_iter(self=self): + keys = self.iterkeys() + while True: + yield self[keys.next()] + return make_iter() + +### Read-write methods ### + + def clear(self): + """ + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.clear() + >>> d + OrderedDict([]) + """ + dict.clear(self) + self._sequence = [] + + def pop(self, key, *args): + """ + No dict.pop in Python 2.2, gotta reimplement it + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.pop(3) + 2 + >>> d + OrderedDict([(1, 3), (2, 1)]) + >>> d.pop(4) + Traceback (most recent call last): + KeyError: 4 + >>> d.pop(4, 0) + 0 + >>> d.pop(4, 0, 1) + Traceback (most recent call last): + TypeError: pop expected at most 2 arguments, got 3 + """ + if len(args) > 1: + raise TypeError, ('pop expected at most 2 arguments, got %s' % + (len(args) + 1)) + if key in self: + val = self[key] + del self[key] + else: + try: + val = args[0] + except IndexError: + raise KeyError(key) + return val + + def popitem(self, i=-1): + """ + Delete and return an item specified by index, not a random one as in + dict. The index is -1 by default (the last item). + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.popitem() + (2, 1) + >>> d + OrderedDict([(1, 3), (3, 2)]) + >>> d.popitem(0) + (1, 3) + >>> OrderedDict().popitem() + Traceback (most recent call last): + KeyError: 'popitem(): dictionary is empty' + >>> d.popitem(2) + Traceback (most recent call last): + IndexError: popitem(): index 2 not valid + """ + if not self._sequence: + raise KeyError('popitem(): dictionary is empty') + try: + key = self._sequence[i] + except IndexError: + raise IndexError('popitem(): index %s not valid' % i) + return (key, self.pop(key)) + + def setdefault(self, key, defval = None): + """ + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.setdefault(1) + 3 + >>> d.setdefault(4) is None + True + >>> d + OrderedDict([(1, 3), (3, 2), (2, 1), (4, None)]) + >>> d.setdefault(5, 0) + 0 + >>> d + OrderedDict([(1, 3), (3, 2), (2, 1), (4, None), (5, 0)]) + """ + if key in self: + return self[key] + else: + self[key] = defval + return defval + + def update(self, from_od): + """ + Update from another OrderedDict or sequence of (key, value) pairs + + >>> d = OrderedDict(((1, 0), (0, 1))) + >>> d.update(OrderedDict(((1, 3), (3, 2), (2, 1)))) + >>> d + OrderedDict([(1, 3), (0, 1), (3, 2), (2, 1)]) + >>> d.update({4: 4}) + Traceback (most recent call last): + TypeError: undefined order, cannot get items from dict + >>> d.update((4, 4)) + Traceback (most recent call last): + TypeError: cannot convert dictionary update sequence element "4" to a 2-item sequence + """ + if isinstance(from_od, OrderedDict): + for key, val in from_od.items(): + self[key] = val + elif isinstance(from_od, dict): + # we lose compatibility with other ordered dict types this way + raise TypeError('undefined order, cannot get items from dict') + else: + # FIXME: efficiency? + # sequence of 2-item sequences, or error + for item in from_od: + try: + key, val = item + except TypeError: + raise TypeError('cannot convert dictionary update' + ' sequence element "%s" to a 2-item sequence' % item) + self[key] = val + + def rename(self, old_key, new_key): + """ + Rename the key for a given value, without modifying sequence order. + + For the case where new_key already exists this raise an exception, + since if new_key exists, it is ambiguous as to what happens to the + associated values, and the position of new_key in the sequence. + + >>> od = OrderedDict() + >>> od['a'] = 1 + >>> od['b'] = 2 + >>> od.items() + [('a', 1), ('b', 2)] + >>> od.rename('b', 'c') + >>> od.items() + [('a', 1), ('c', 2)] + >>> od.rename('c', 'a') + Traceback (most recent call last): + ValueError: New key already exists: 'a' + >>> od.rename('d', 'b') + Traceback (most recent call last): + KeyError: 'd' + """ + if new_key == old_key: + # no-op + return + if new_key in self: + raise ValueError("New key already exists: %r" % new_key) + # rename sequence entry + value = self[old_key] + old_idx = self._sequence.index(old_key) + self._sequence[old_idx] = new_key + # rename internal dict entry + dict.__delitem__(self, old_key) + dict.__setitem__(self, new_key, value) + + def setitems(self, items): + """ + This method allows you to set the items in the dict. + + It takes a list of tuples - of the same sort returned by the ``items`` + method. + + >>> d = OrderedDict() + >>> d.setitems(((3, 1), (2, 3), (1, 2))) + >>> d + OrderedDict([(3, 1), (2, 3), (1, 2)]) + """ + self.clear() + # FIXME: this allows you to pass in an OrderedDict as well :-) + self.update(items) + + def setkeys(self, keys): + """ + ``setkeys`` all ows you to pass in a new list of keys which will + replace the current set. This must contain the same set of keys, but + need not be in the same order. + + If you pass in new keys that don't match, a ``KeyError`` will be + raised. + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.keys() + [1, 3, 2] + >>> d.setkeys((1, 2, 3)) + >>> d + OrderedDict([(1, 3), (2, 1), (3, 2)]) + >>> d.setkeys(['a', 'b', 'c']) + Traceback (most recent call last): + KeyError: 'Keylist is not the same as current keylist.' + """ + # FIXME: Efficiency? (use set for Python 2.4 :-) + # NOTE: list(keys) rather than keys[:] because keys[:] returns + # a tuple, if keys is a tuple. + kcopy = list(keys) + kcopy.sort() + self._sequence.sort() + if kcopy != self._sequence: + raise KeyError('Keylist is not the same as current keylist.') + # NOTE: This makes the _sequence attribute a new object, instead + # of changing it in place. + # FIXME: efficiency? + self._sequence = list(keys) + + def setvalues(self, values): + """ + You can pass in a list of values, which will replace the + current list. The value list must be the same len as the OrderedDict. + + (Or a ``ValueError`` is raised.) + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.setvalues((1, 2, 3)) + >>> d + OrderedDict([(1, 1), (3, 2), (2, 3)]) + >>> d.setvalues([6]) + Traceback (most recent call last): + ValueError: Value list is not the same length as the OrderedDict. + """ + if len(values) != len(self): + # FIXME: correct error to raise? + raise ValueError('Value list is not the same length as the ' + 'OrderedDict.') + self.update(zip(self, values)) + +### Sequence Methods ### + + def index(self, key): + """ + Return the position of the specified key in the OrderedDict. + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.index(3) + 1 + >>> d.index(4) + Traceback (most recent call last): + ValueError: list.index(x): x not in list + """ + return self._sequence.index(key) + + def insert(self, index, key, value): + """ + Takes ``index``, ``key``, and ``value`` as arguments. + + Sets ``key`` to ``value``, so that ``key`` is at position ``index`` in + the OrderedDict. + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.insert(0, 4, 0) + >>> d + OrderedDict([(4, 0), (1, 3), (3, 2), (2, 1)]) + >>> d.insert(0, 2, 1) + >>> d + OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2)]) + >>> d.insert(8, 8, 1) + >>> d + OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2), (8, 1)]) + """ + if key in self: + # FIXME: efficiency? + del self[key] + self._sequence.insert(index, key) + dict.__setitem__(self, key, value) + + def reverse(self): + """ + Reverse the order of the OrderedDict. + + >>> d = OrderedDict(((1, 3), (3, 2), (2, 1))) + >>> d.reverse() + >>> d + OrderedDict([(2, 1), (3, 2), (1, 3)]) + """ + self._sequence.reverse() + + def sort(self, *args, **kwargs): + """ + Sort the key order in the OrderedDict. + + This method takes the same arguments as the ``list.sort`` method on + your version of Python. + + >>> d = OrderedDict(((4, 1), (2, 2), (3, 3), (1, 4))) + >>> d.sort() + >>> d + OrderedDict([(1, 4), (2, 2), (3, 3), (4, 1)]) + """ + self._sequence.sort(*args, **kwargs) + +class Keys(object): + # FIXME: should this object be a subclass of list? + """ + Custom object for accessing the keys of an OrderedDict. + + Can be called like the normal ``OrderedDict.keys`` method, but also + supports indexing and sequence methods. + """ + + def __init__(self, main): + self._main = main + + def __call__(self): + """Pretend to be the keys method.""" + return self._main._keys() + + def __getitem__(self, index): + """Fetch the key at position i.""" + # NOTE: this automatically supports slicing :-) + return self._main._sequence[index] + + def __setitem__(self, index, name): + """ + You cannot assign to keys, but you can do slice assignment to re-order + them. + + You can only do slice assignment if the new set of keys is a reordering + of the original set. + """ + if isinstance(index, types.SliceType): + # FIXME: efficiency? + # check length is the same + indexes = range(len(self._main._sequence))[index] + if len(indexes) != len(name): + raise ValueError('attempt to assign sequence of size %s ' + 'to slice of size %s' % (len(name), len(indexes))) + # check they are the same keys + # FIXME: Use set + old_keys = self._main._sequence[index] + new_keys = list(name) + old_keys.sort() + new_keys.sort() + if old_keys != new_keys: + raise KeyError('Keylist is not the same as current keylist.') + orig_vals = [self._main[k] for k in name] + del self._main[index] + vals = zip(indexes, name, orig_vals) + vals.sort() + for i, k, v in vals: + if self._main.strict and k in self._main: + raise ValueError('slice assignment must be from ' + 'unique keys') + self._main.insert(i, k, v) + else: + raise ValueError('Cannot assign to keys') + + ### following methods pinched from UserList and adapted ### + def __repr__(self): return repr(self._main._sequence) + + # FIXME: do we need to check if we are comparing with another ``Keys`` + # object? (like the __cast method of UserList) + def __lt__(self, other): return self._main._sequence < other + def __le__(self, other): return self._main._sequence <= other + def __eq__(self, other): return self._main._sequence == other + def __ne__(self, other): return self._main._sequence != other + def __gt__(self, other): return self._main._sequence > other + def __ge__(self, other): return self._main._sequence >= other + # FIXME: do we need __cmp__ as well as rich comparisons? + def __cmp__(self, other): return cmp(self._main._sequence, other) + + def __contains__(self, item): return item in self._main._sequence + def __len__(self): return len(self._main._sequence) + def __iter__(self): return self._main.iterkeys() + def count(self, item): return self._main._sequence.count(item) + def index(self, item, *args): return self._main._sequence.index(item, *args) + def reverse(self): self._main._sequence.reverse() + def sort(self, *args, **kwds): self._main._sequence.sort(*args, **kwds) + def __mul__(self, n): return self._main._sequence*n + __rmul__ = __mul__ + def __add__(self, other): return self._main._sequence + other + def __radd__(self, other): return other + self._main._sequence + + ## following methods not implemented for keys ## + def __delitem__(self, i): raise TypeError('Can\'t delete items from keys') + def __iadd__(self, other): raise TypeError('Can\'t add in place to keys') + def __imul__(self, n): raise TypeError('Can\'t multiply keys in place') + def append(self, item): raise TypeError('Can\'t append items to keys') + def insert(self, i, item): raise TypeError('Can\'t insert items into keys') + def pop(self, i=-1): raise TypeError('Can\'t pop items from keys') + def remove(self, item): raise TypeError('Can\'t remove items from keys') + def extend(self, other): raise TypeError('Can\'t extend keys') + +class Items(object): + """ + Custom object for accessing the items of an OrderedDict. + + Can be called like the normal ``OrderedDict.items`` method, but also + supports indexing and sequence methods. + """ + + def __init__(self, main): + self._main = main + + def __call__(self): + """Pretend to be the items method.""" + return self._main._items() + + def __getitem__(self, index): + """Fetch the item at position i.""" + if isinstance(index, types.SliceType): + # fetching a slice returns an OrderedDict + return self._main[index].items() + key = self._main._sequence[index] + return (key, self._main[key]) + + def __setitem__(self, index, item): + """Set item at position i to item.""" + if isinstance(index, types.SliceType): + # NOTE: item must be an iterable (list of tuples) + self._main[index] = OrderedDict(item) + else: + # FIXME: Does this raise a sensible error? + orig = self._main.keys[index] + key, value = item + if self._main.strict and key in self and (key != orig): + raise ValueError('slice assignment must be from ' + 'unique keys') + # delete the current one + del self._main[self._main._sequence[index]] + self._main.insert(index, key, value) + + def __delitem__(self, i): + """Delete the item at position i.""" + key = self._main._sequence[i] + if isinstance(i, types.SliceType): + for k in key: + # FIXME: efficiency? + del self._main[k] + else: + del self._main[key] + + ### following methods pinched from UserList and adapted ### + def __repr__(self): return repr(self._main.items()) + + # FIXME: do we need to check if we are comparing with another ``Items`` + # object? (like the __cast method of UserList) + def __lt__(self, other): return self._main.items() < other + def __le__(self, other): return self._main.items() <= other + def __eq__(self, other): return self._main.items() == other + def __ne__(self, other): return self._main.items() != other + def __gt__(self, other): return self._main.items() > other + def __ge__(self, other): return self._main.items() >= other + def __cmp__(self, other): return cmp(self._main.items(), other) + + def __contains__(self, item): return item in self._main.items() + def __len__(self): return len(self._main._sequence) # easier :-) + def __iter__(self): return self._main.iteritems() + def count(self, item): return self._main.items().count(item) + def index(self, item, *args): return self._main.items().index(item, *args) + def reverse(self): self._main.reverse() + def sort(self, *args, **kwds): self._main.sort(*args, **kwds) + def __mul__(self, n): return self._main.items()*n + __rmul__ = __mul__ + def __add__(self, other): return self._main.items() + other + def __radd__(self, other): return other + self._main.items() + + def append(self, item): + """Add an item to the end.""" + # FIXME: this is only append if the key isn't already present + key, value = item + self._main[key] = value + + def insert(self, i, item): + key, value = item + self._main.insert(i, key, value) + + def pop(self, i=-1): + key = self._main._sequence[i] + return (key, self._main.pop(key)) + + def remove(self, item): + key, value = item + try: + assert value == self._main[key] + except (KeyError, AssertionError): + raise ValueError('ValueError: list.remove(x): x not in list') + else: + del self._main[key] + + def extend(self, other): + # FIXME: is only a true extend if none of the keys already present + for item in other: + key, value = item + self._main[key] = value + + def __iadd__(self, other): + self.extend(other) + + ## following methods not implemented for items ## + + def __imul__(self, n): raise TypeError('Can\'t multiply items in place') + +class Values(object): + """ + Custom object for accessing the values of an OrderedDict. + + Can be called like the normal ``OrderedDict.values`` method, but also + supports indexing and sequence methods. + """ + + def __init__(self, main): + self._main = main + + def __call__(self): + """Pretend to be the values method.""" + return self._main._values() + + def __getitem__(self, index): + """Fetch the value at position i.""" + if isinstance(index, types.SliceType): + return [self._main[key] for key in self._main._sequence[index]] + else: + return self._main[self._main._sequence[index]] + + def __setitem__(self, index, value): + """ + Set the value at position i to value. + + You can only do slice assignment to values if you supply a sequence of + equal length to the slice you are replacing. + """ + if isinstance(index, types.SliceType): + keys = self._main._sequence[index] + if len(keys) != len(value): + raise ValueError('attempt to assign sequence of size %s ' + 'to slice of size %s' % (len(name), len(keys))) + # FIXME: efficiency? Would be better to calculate the indexes + # directly from the slice object + # NOTE: the new keys can collide with existing keys (or even + # contain duplicates) - these will overwrite + for key, val in zip(keys, value): + self._main[key] = val + else: + self._main[self._main._sequence[index]] = value + + ### following methods pinched from UserList and adapted ### + def __repr__(self): return repr(self._main.values()) + + # FIXME: do we need to check if we are comparing with another ``Values`` + # object? (like the __cast method of UserList) + def __lt__(self, other): return self._main.values() < other + def __le__(self, other): return self._main.values() <= other + def __eq__(self, other): return self._main.values() == other + def __ne__(self, other): return self._main.values() != other + def __gt__(self, other): return self._main.values() > other + def __ge__(self, other): return self._main.values() >= other + def __cmp__(self, other): return cmp(self._main.values(), other) + + def __contains__(self, item): return item in self._main.values() + def __len__(self): return len(self._main._sequence) # easier :-) + def __iter__(self): return self._main.itervalues() + def count(self, item): return self._main.values().count(item) + def index(self, item, *args): return self._main.values().index(item, *args) + + def reverse(self): + """Reverse the values""" + vals = self._main.values() + vals.reverse() + # FIXME: efficiency + self[:] = vals + + def sort(self, *args, **kwds): + """Sort the values.""" + vals = self._main.values() + vals.sort(*args, **kwds) + self[:] = vals + + def __mul__(self, n): return self._main.values()*n + __rmul__ = __mul__ + def __add__(self, other): return self._main.values() + other + def __radd__(self, other): return other + self._main.values() + + ## following methods not implemented for values ## + def __delitem__(self, i): raise TypeError('Can\'t delete items from values') + def __iadd__(self, other): raise TypeError('Can\'t add in place to values') + def __imul__(self, n): raise TypeError('Can\'t multiply values in place') + def append(self, item): raise TypeError('Can\'t append items to values') + def insert(self, i, item): raise TypeError('Can\'t insert items into values') + def pop(self, i=-1): raise TypeError('Can\'t pop items from values') + def remove(self, item): raise TypeError('Can\'t remove items from values') + def extend(self, other): raise TypeError('Can\'t extend values') + +class SequenceOrderedDict(OrderedDict): + """ + Experimental version of OrderedDict that has a custom object for ``keys``, + ``values``, and ``items``. + + These are callable sequence objects that work as methods, or can be + manipulated directly as sequences. + + Test for ``keys``, ``items`` and ``values``. + + >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4))) + >>> d + SequenceOrderedDict([(1, 2), (2, 3), (3, 4)]) + >>> d.keys + [1, 2, 3] + >>> d.keys() + [1, 2, 3] + >>> d.setkeys((3, 2, 1)) + >>> d + SequenceOrderedDict([(3, 4), (2, 3), (1, 2)]) + >>> d.setkeys((1, 2, 3)) + >>> d.keys[0] + 1 + >>> d.keys[:] + [1, 2, 3] + >>> d.keys[-1] + 3 + >>> d.keys[-2] + 2 + >>> d.keys[0:2] = [2, 1] + >>> d + SequenceOrderedDict([(2, 3), (1, 2), (3, 4)]) + >>> d.keys.reverse() + >>> d.keys + [3, 1, 2] + >>> d.keys = [1, 2, 3] + >>> d + SequenceOrderedDict([(1, 2), (2, 3), (3, 4)]) + >>> d.keys = [3, 1, 2] + >>> d + SequenceOrderedDict([(3, 4), (1, 2), (2, 3)]) + >>> a = SequenceOrderedDict() + >>> b = SequenceOrderedDict() + >>> a.keys == b.keys + 1 + >>> a['a'] = 3 + >>> a.keys == b.keys + 0 + >>> b['a'] = 3 + >>> a.keys == b.keys + 1 + >>> b['b'] = 3 + >>> a.keys == b.keys + 0 + >>> a.keys > b.keys + 0 + >>> a.keys < b.keys + 1 + >>> 'a' in a.keys + 1 + >>> len(b.keys) + 2 + >>> 'c' in d.keys + 0 + >>> 1 in d.keys + 1 + >>> [v for v in d.keys] + [3, 1, 2] + >>> d.keys.sort() + >>> d.keys + [1, 2, 3] + >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)), strict=True) + >>> d.keys[::-1] = [1, 2, 3] + >>> d + SequenceOrderedDict([(3, 4), (2, 3), (1, 2)]) + >>> d.keys[:2] + [3, 2] + >>> d.keys[:2] = [1, 3] + Traceback (most recent call last): + KeyError: 'Keylist is not the same as current keylist.' + + >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4))) + >>> d + SequenceOrderedDict([(1, 2), (2, 3), (3, 4)]) + >>> d.values + [2, 3, 4] + >>> d.values() + [2, 3, 4] + >>> d.setvalues((4, 3, 2)) + >>> d + SequenceOrderedDict([(1, 4), (2, 3), (3, 2)]) + >>> d.values[::-1] + [2, 3, 4] + >>> d.values[0] + 4 + >>> d.values[-2] + 3 + >>> del d.values[0] + Traceback (most recent call last): + TypeError: Can't delete items from values + >>> d.values[::2] = [2, 4] + >>> d + SequenceOrderedDict([(1, 2), (2, 3), (3, 4)]) + >>> 7 in d.values + 0 + >>> len(d.values) + 3 + >>> [val for val in d.values] + [2, 3, 4] + >>> d.values[-1] = 2 + >>> d.values.count(2) + 2 + >>> d.values.index(2) + 0 + >>> d.values[-1] = 7 + >>> d.values + [2, 3, 7] + >>> d.values.reverse() + >>> d.values + [7, 3, 2] + >>> d.values.sort() + >>> d.values + [2, 3, 7] + >>> d.values.append('anything') + Traceback (most recent call last): + TypeError: Can't append items to values + >>> d.values = (1, 2, 3) + >>> d + SequenceOrderedDict([(1, 1), (2, 2), (3, 3)]) + + >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4))) + >>> d + SequenceOrderedDict([(1, 2), (2, 3), (3, 4)]) + >>> d.items() + [(1, 2), (2, 3), (3, 4)] + >>> d.setitems([(3, 4), (2 ,3), (1, 2)]) + >>> d + SequenceOrderedDict([(3, 4), (2, 3), (1, 2)]) + >>> d.items[0] + (3, 4) + >>> d.items[:-1] + [(3, 4), (2, 3)] + >>> d.items[1] = (6, 3) + >>> d.items + [(3, 4), (6, 3), (1, 2)] + >>> d.items[1:2] = [(9, 9)] + >>> d + SequenceOrderedDict([(3, 4), (9, 9), (1, 2)]) + >>> del d.items[1:2] + >>> d + SequenceOrderedDict([(3, 4), (1, 2)]) + >>> (3, 4) in d.items + 1 + >>> (4, 3) in d.items + 0 + >>> len(d.items) + 2 + >>> [v for v in d.items] + [(3, 4), (1, 2)] + >>> d.items.count((3, 4)) + 1 + >>> d.items.index((1, 2)) + 1 + >>> d.items.index((2, 1)) + Traceback (most recent call last): + ValueError: list.index(x): x not in list + >>> d.items.reverse() + >>> d.items + [(1, 2), (3, 4)] + >>> d.items.reverse() + >>> d.items.sort() + >>> d.items + [(1, 2), (3, 4)] + >>> d.items.append((5, 6)) + >>> d.items + [(1, 2), (3, 4), (5, 6)] + >>> d.items.insert(0, (0, 0)) + >>> d.items + [(0, 0), (1, 2), (3, 4), (5, 6)] + >>> d.items.insert(-1, (7, 8)) + >>> d.items + [(0, 0), (1, 2), (3, 4), (7, 8), (5, 6)] + >>> d.items.pop() + (5, 6) + >>> d.items + [(0, 0), (1, 2), (3, 4), (7, 8)] + >>> d.items.remove((1, 2)) + >>> d.items + [(0, 0), (3, 4), (7, 8)] + >>> d.items.extend([(1, 2), (5, 6)]) + >>> d.items + [(0, 0), (3, 4), (7, 8), (1, 2), (5, 6)] + """ + + def __init__(self, init_val=(), strict=True): + OrderedDict.__init__(self, init_val, strict=strict) + self._keys = self.keys + self._values = self.values + self._items = self.items + self.keys = Keys(self) + self.values = Values(self) + self.items = Items(self) + self._att_dict = { + 'keys': self.setkeys, + 'items': self.setitems, + 'values': self.setvalues, + } + + def __setattr__(self, name, value): + """Protect keys, items, and values.""" + if not '_att_dict' in self.__dict__: + object.__setattr__(self, name, value) + else: + try: + fun = self._att_dict[name] + except KeyError: + OrderedDict.__setattr__(self, name, value) + else: + fun(value) + +if __name__ == '__main__': + if INTP_VER < (2, 3): + raise RuntimeError("Tests require Python v.2.3 or later") + # turn off warnings for tests + warnings.filterwarnings('ignore') + # run the code tests in doctest format + import doctest + m = sys.modules.get('__main__') + globs = m.__dict__.copy() + globs.update({ + 'INTP_VER': INTP_VER, + }) + doctest.testmod(m, globs=globs) + diff --git a/src/dataTools/odict.pyc b/src/dataTools/odict.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9e213b284d27e7565108612523c557ef7827fa3 GIT binary patch literal 57964 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 http://mypage.bluewin.ch/DR0ID +# +# +# +""" +Allow to draw some gradients relatively easy. +""" + +__author__ = "$Author: DR0ID $" +__version__= "$Revision: 109 $" +__date__ = "$Date: 2007-08-09 20:33:32 +0200 (Do, 09 Aug 2007) $" + +import pygame +import math + +BLEND_MODES_AVAILABLE = False +vernum = pygame.vernum +if vernum[0]>=1 and vernum[1]>=8: + BLEND_MODES_AVAILABLE = True + + +class ColorInterpolator(object): + ''' + ColorInterpolator(distance, color1, color2, rfunc, gfunc, bfunc, afunc) + + interpolates a color over the distance using different functions for r,g,b,a + separately (a= alpha). + ''' + def __init__(self, distance, color1, color2, rfunc, gfunc, bfunc, afunc): + object.__init__(self) + + self.rInterpolator = FunctionInterpolator(color1[0], color2[0], distance, rfunc) + self.gInterpolator = FunctionInterpolator(color1[1], color2[1], distance, gfunc) + self.bInterpolator = FunctionInterpolator(color1[2], color2[2], distance, bfunc) + if len(color1)==4 and len(color2)==4: + self.aInterpolator = FunctionInterpolator(color1[3], color2[3], distance, afunc) + else: + self.aInterpolator = FunctionInterpolator(255, 255, distance, afunc) + + def eval(self, x): + ''' + eval(x) -> color + + returns the color at the position 0<=x<=d (actually not bound to this interval). + ''' +## print "colorInterp x", x, self.rInterpolator.eval(x), self.gInterpolator.eval(x), self.bInterpolator.eval(x) + return [self.rInterpolator.eval(x), + self.gInterpolator.eval(x), + self.bInterpolator.eval(x), + self.aInterpolator.eval(x)] + + + +class FunctionInterpolator(object): + ''' + FunctionINterpolator(startvalue, endvalue, trange, func) + + interpolates a function y=f(x) in the range trange with + startvalue = f(0) + endvalue = f(trange) + using the function func + ''' + def __init__(self, startvalue, endvalue, trange, func): + object.__init__(self) + # function + self.func = func + # y-scaling + self.a = endvalue-startvalue + if self.a == 0: + self.a = 1. + # x-scaling + if trange!=0: + self.b = 1./abs(trange) + else: + self.b = 1. + # x-displacement + self.c = 0 + # y-displacement + self.d = min(max(startvalue,0),255) + + def eval(self, x): + ''' + eval(x)->float + + return value at position x + ''' + # make sure that the returned value is in [0,255] +## return int(round(min(max(self.a*self.func(self.b*(x+self.c))+self.d, 0), 255))) + return int(min(max(self.a*self.func(self.b*(x+self.c))+self.d, 0), 255)) + + + +##def gradient(surface, +## startpoint, +## endpoint, +## startcolor, +## endcolor, +## Rfunc = (lambda x:x), +## Gfunc = (lambda x:x), +## Bfunc = (lambda x:x), +## Afunc = (lambda x:1), +## type = "line", +## mode = None ): +## ''' +## surface : surface to draw on +## startpoint: (x,y) point on surface +## endpoint : (x,y) point on surface +## startcolor: (r,g,b,a) color at startpoint +## endcolor : (r,g,b,a) color at endpoint +## Rfunc : function y = f(x) with startcolor =f(0) and endcolor = f(1) where 0 is at startpoint and 1 at endpoint +## Gfunc : --- " --- +## Bfunc : --- " --- +## Afunc : --- " --- +## these functions are evaluated in the range 0 <= x <= 1 and 0<= y=f(x) <= 1 +## type : "line", "circle" or "rect" +## mode : "+", "-", "*", None (how the pixels are drawen) +## +## returns : surface with the color characteristics w,h = (d, 256) and d = length of endpoint-startpoint +## +## ''' +## dx = endpoint[0]-startpoint[0] +## dy = endpoint[1]-startpoint[1] +## d = int(round(math.hypot(dx, dy))) +## angle = math.degrees( math.atan2(dy, dx) ) +## +## color = ColorInterpolator(d, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc) +## +## if type=="line": +## h = int(2.*math.hypot(*surface.get_size())) +### bigSurf = pygame.Surface((d, h)).convert_alpha() +## bigSurf = pygame.Surface((d, h), pygame.SRCALPHA)#.convert_alpha() +### bigSurf = pygame.Surface((d, 1), pygame.SRCALPHA)#.convert_alpha() +## bigSurf.lock() +## bigSurf.fill((0,0,0,0)) +## bigSurf.set_colorkey((0,0,0,0)) +## for x in range(d): +## pygame.draw.line(bigSurf, color.eval(x), (x,0), (x,h), 1) +### for x in range(d): +### bigSurf.set_at((x, 0), color.eval(x)) +### bigSurf = pygame.transform.scale(bigSurf, (d, h)) +## +## bigSurf = pygame.transform.rotate(bigSurf, -angle) #rotozoom(bigSurf, -angle, 1) +## bigSurf.set_colorkey((0,0,0, 0)) +## rect = bigSurf.get_rect() +## srect = pygame.Rect(rect) +## dx = d/2. * math.cos(math.radians(angle)) +## dy = d/2. * math.sin(math.radians(angle)) +## rect.center = startpoint +## rect.move_ip(dx, dy) +## bigSurf.unlock() +## +## elif type=="circle": +## bigSurf = pygame.Surface((2*d, 2*d)).convert_alpha() +## bigSurf.fill((0,0,0,0)) +## bigSurf.lock() +## for x in range(d, 0, -1): +## pygame.draw.circle(bigSurf, color.eval(x), (d,d), x) +## bigSurf.unlock() +## rect = bigSurf.get_rect() +## srect = pygame.Rect(rect) +## rect.center = (startpoint[0], startpoint[1]) +## +## elif type=="rect": +## bigSurf = pygame.Surface((2*d, 2*d)).convert_alpha() +## bigSurf.fill((0,0,0,0)) +## c = bigSurf.get_rect().center +## bigSurf.lock() +## for x in range(d,-1,-1): +## r = pygame.Rect(0,0,2*x,2*x) +## r.center = c +## pygame.draw.rect(bigSurf, color.eval(x), r) +## bigSurf.unlock() +## bigSurf = pygame.transform.rotozoom(bigSurf, -angle, 1) +## bigSurf.set_colorkey((0,0,0, 0)) +## +## rect = bigSurf.get_rect() +## srect = pygame.Rect(rect) +## rect.center = startpoint +## else: +## raise NameError("type must be one of \"line\",\"circle\" or \"rect\"") +## +## if mode is None: +## surface.blit(bigSurf, rect, srect) +## else: +## if mode=="+": +## cf = pygame.color.add +## elif mode=="*": +## cf = pygame.color.multiply +## elif mode=="-": +## cf = pygame.color.subtract +## else: +## raise NameError("type must be one of \"+\", \"*\", \"-\" or None") +## irect = surface.get_clip().clip(rect) +## surface.lock() +## for x in range(irect.left, irect.left+irect.width): +## for y in range(irect.top, irect.top+irect.height): +## surface.set_at((x,y), cf(surface.get_at((x,y)), bigSurf.get_at((x-rect.left, y-rect.top)) ) ) +## surface.unlock() +## +## del bigSurf +## char = pygame.Surface((d+1, 257)) +### char.fill((0,0,0)) +### ox = 0 +### oldcol = color.eval(0) +### for x in range(d): +### col = color.eval(x) +### pygame.draw.line(char, (255,0,0), (x, 256-col[0]), (ox, 256-oldcol[0])) +### pygame.draw.line(char, (0,255,0), (x, 256-col[1]), (ox, 256-oldcol[1])) +### pygame.draw.line(char, (0,0,255), (x, 256-col[2]), (ox, 256-oldcol[2])) +### pygame.draw.line(char, (255,255,255), (x, 256-col[3]), (ox, 256-oldcol[3])) +### ox = x +### oldcol = col +### +## return char + + + + +def vertical(size, startcolor, endcolor): + """ + Draws a vertical linear gradient filling the entire surface. Returns a + surface filled with the gradient (numeric is only 2-3 times faster). + """ + height = size[1] + bigSurf = pygame.Surface((1,height)).convert_alpha() + dd = 1.0/height + sr, sg, sb, sa = startcolor + er, eg, eb, ea = endcolor + rm = (er-sr)*dd + gm = (eg-sg)*dd + bm = (eb-sb)*dd + am = (ea-sa)*dd + for y in range(height): + bigSurf.set_at((0,y), + (int(sr + rm*y), + int(sg + gm*y), + int(sb + bm*y), + int(sa + am*y)) + ) + return pygame.transform.scale(bigSurf, size) + + +def horizontal(size, startcolor, endcolor): + """ + Draws a horizontal linear gradient filling the entire surface. Returns a + surface filled with the gradient (numeric is only 2-3 times faster). + """ + width = size[0] + bigSurf = pygame.Surface((width, 1)).convert_alpha() + dd = 1.0/width + sr, sg, sb, sa = startcolor + er, eg, eb, ea = endcolor + rm = (er-sr)*dd + gm = (eg-sg)*dd + bm = (eb-sb)*dd + am = (ea-sa)*dd + for y in range(width): + bigSurf.set_at((y,0), + (int(sr + rm*y), + int(sg + gm*y), + int(sb + bm*y), + int(sa + am*y)) + ) + return pygame.transform.scale(bigSurf, size) + + +def radial(radius, startcolor, endcolor): + """ + Draws a linear raidal gradient on a square sized surface and returns + that surface. + """ + bigSurf = pygame.Surface((2*radius, 2*radius)).convert_alpha() + bigSurf.fill((0,0,0,0)) + dd = -1.0/radius + sr, sg, sb, sa = endcolor + er, eg, eb, ea = startcolor + rm = (er-sr)*dd + gm = (eg-sg)*dd + bm = (eb-sb)*dd + am = (ea-sa)*dd + + draw_circle = pygame.draw.circle + for rad in range(radius, 0, -1): + draw_circle(bigSurf, (er + int(rm*rad), + eg + int(gm*rad), + eb + int(bm*rad), + ea + int(am*rad)), (radius, radius), rad) + return bigSurf + +def squared(width, startcolor, endcolor): + """ + Draws a linear sqared gradient on a square sized surface and returns + that surface. + """ + bigSurf = pygame.Surface((width, width)).convert_alpha() + bigSurf.fill((0,0,0,0)) + dd = -1.0/(width/2) + sr, sg, sb, sa = endcolor + er, eg, eb, ea = startcolor + rm = (er-sr)*dd + gm = (eg-sg)*dd + bm = (eb-sb)*dd + am = (ea-sa)*dd + + draw_rect = pygame.draw.rect + for currentw in range((width/2), 0, -1): + pos = (width/2)-currentw + draw_rect(bigSurf, (er + int(rm*currentw), + eg + int(gm*currentw), + eb + int(bm*currentw), + ea + int(am*currentw)), pygame.Rect(pos, pos, 2*currentw, 2*currentw )) + return bigSurf + + +def vertical_func(size, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1)): + """ + Draws a vertical linear gradient filling the entire surface. Returns a + surface filled with the gradient (numeric is only 2x faster). + Rfunc, Gfunc, Bfunc and Afunc are function like y = f(x). They define + how the color changes. + """ + height = size[1] + bigSurf = pygame.Surface((1,height)).convert_alpha() + color = ColorInterpolator(height, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc) + for y in range(0, height): + bigSurf.set_at((0,y), color.eval(y+0.1)) + return pygame.transform.scale(bigSurf, size) + + +def horizontal_func(size, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1)): + """ + Draws a horizontal linear gradient filling the entire surface. Returns a + surface filled with the gradient (numeric is only 2x faster). + Rfunc, Gfunc, Bfunc and Afunc are function like y = f(x). They define + how the color changes. + """ + width = size[0] + bigSurf = pygame.Surface((width, 1)).convert_alpha() + color = ColorInterpolator(width, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc) + for y in range(0, width): + bigSurf.set_at((y, 0), color.eval(y+0.1)) + return pygame.transform.scale(bigSurf, size) + +def radial_func(radius, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), colorkey=(0,0,0,0)): + """ + Draws a linear raidal gradient on a square sized surface and returns + that surface. + """ + bigSurf = pygame.Surface((2*radius, 2*radius)).convert_alpha() + if len(colorkey)==3: + colorkey += (0,) + bigSurf.fill(colorkey) + color = ColorInterpolator(radius, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc) + draw_circle = pygame.draw.circle + for rad in range(radius, 0, -1): + draw_circle(bigSurf, color.eval(rad), (radius, radius), rad) + return bigSurf + +def radial_func_offset(radius, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), colorkey=(0,0,0,0), offset=(0,0)): + """ + Draws a linear raidal gradient on a square sized surface and returns + that surface. + offset is the amount the center of the gradient is displaced of the center of the image. + Unfotunately this function ignores alpha. + """ + bigSurf = pygame.Surface((2*radius, 2*radius))#.convert_alpha() + + mask = pygame.Surface((2*radius, 2*radius), pygame.SRCALPHA)#.convert_alpha() + mask.fill(colorkey) + mask.set_colorkey((255,0,255)) + pygame.draw.circle(mask, (255,0,255), (radius, radius), radius) + + if len(colorkey)==3: + colorkey += (0,) + bigSurf.fill(colorkey) + + color = ColorInterpolator(radius, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc) + draw_circle = pygame.draw.circle + radi = radius + int(math.hypot(offset[0], offset[1])+1) + for rad in range(radi, 0, -1): + draw_circle(bigSurf, color.eval(rad), (radius+offset[0], radius+offset[1]), rad) + + bigSurf.blit(mask, (0,0)) + bigSurf.set_colorkey(colorkey) + return bigSurf + + +def squared_func(width, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), offset=(0,0)): + """ + Draws a linear sqared gradient on a square sized surface and returns + that surface. + """ + bigSurf = pygame.Surface((width, width)).convert_alpha() + bigSurf.fill((0,0,0,0)) + color = ColorInterpolator(width/2, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc) + draw_rect = pygame.draw.rect + widthh = width+2*int(max(abs(offset[0]),abs(offset[1]))) + for currentw in range((widthh/2), 0, -1): +## pos = (width/2)-currentw + rect = pygame.Rect(0, 0, 2*currentw, 2*currentw ) + rect.center = (width/2+offset[0], width/2+offset[1]) + draw_rect(bigSurf, color.eval(currentw), rect) + return bigSurf + +def draw_gradient(surface, startpoint, endpoint, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), mode=0): + """ + Instead of returning an Surface, this function draw it directy onto the + given Surface and returns the rect. + """ + dx = endpoint[0]-startpoint[0] + dy = endpoint[1]-startpoint[1] + d = int(round(math.hypot(dx, dy))) + angle = math.degrees( math.atan2(dy, dx) ) + + h = int(2.*math.hypot(*surface.get_size())) + + bigSurf = horizontal_func((d,h), startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc) + +## bigSurf = pygame.transform.rotate(bigSurf, -angle) #rotozoom(bigSurf, -angle, 1) + bigSurf = pygame.transform.rotozoom(bigSurf, -angle, 1) +## bigSurf.set_colorkey((0,0,0, 0)) + rect = bigSurf.get_rect() + srect = pygame.Rect(rect) + dx = d/2. * math.cos(math.radians(angle)) + dy = d/2. * math.sin(math.radians(angle)) + rect.center = startpoint + rect.move_ip(dx, dy) + if BLEND_MODES_AVAILABLE: + return surface.blit(bigSurf, rect, None, mode) + else: + return surface.blit(bigSurf, rect) + + +def draw_circle(surface, startpoint, endpoint, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), mode=0): + """ + Instead of returning an Surface, this function draw it directy onto the + given Surface and returns the rect. + """ + dx = endpoint[0]-startpoint[0] + dy = endpoint[1]-startpoint[1] + radius = int(round(math.hypot(dx, dy))) + pos = (startpoint[0]-radius, startpoint[1]-radius) + if BLEND_MODES_AVAILABLE: + return surface.blit(radial_func(radius, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc), pos, None, mode) + else: + return surface.blit(radial_func(radius, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc), pos) + +def draw_squared(surface, startpoint, endpoint, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), mode=0): + """ + Instead of returning an Surface, this function draw it directy onto the + given Surface and returns the rect. + """ + dx = endpoint[0]-startpoint[0] + dy = endpoint[1]-startpoint[1] + angle = math.degrees( math.atan2(dy, dx) ) + width = 2*int(round(math.hypot(dx, dy))) + + bigSurf = squared_func(width, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc) + + bigSurf = pygame.transform.rotozoom(bigSurf, -angle, 1) +## bigSurf.set_colorkey((0,0,0, 0)) + rect = bigSurf.get_rect() + rect.center = startpoint + if BLEND_MODES_AVAILABLE: + return surface.blit(bigSurf, rect, None, mode) + else: + return surface.blit(bigSurf, rect) + + +def chart(startpoint, endpoint, startcolor, endcolor, Rfunc = (lambda x:x), Gfunc = (lambda x:x), Bfunc = (lambda x:x), Afunc = (lambda x:1), scale=None): + """ + This returns a Surface where the change of the colors over the distance + (the width of the image) is showen as a line. + scale: a float, 1 is not scaling + """ + dx = endpoint[0]-startpoint[0] + dy = endpoint[1]-startpoint[1] + distance = int(round(math.hypot(dx, dy))) + color = ColorInterpolator(distance, startcolor, endcolor, Rfunc, Gfunc, Bfunc, Afunc) + bigSurf = pygame.Surface((distance, 256)) + bigSurf.fill((0,)*3) + oldcol = color.eval(0) + for x in range(distance): + r, g, b, a = color.eval(x) + pygame.draw.line(bigSurf, (255, 0, 0, 128), (x-1, oldcol[0]), (x, r)) + pygame.draw.line(bigSurf, (0, 255, 0, 128), (x-1, oldcol[1]), (x, g)) + pygame.draw.line(bigSurf, (0, 0, 255, 128), (x-1, oldcol[2]), (x, b)) + pygame.draw.line(bigSurf, (255, 255, 255, 128), (x-1, oldcol[3]), (x, a)) + oldcol = (r,g,b,a) + if scale: +## return pygame.transform.scale(bigSurf, size) + return pygame.transform.rotozoom(bigSurf, 0, scale) + return pygame.transform.flip(bigSurf, 0, 1) +#------------------------------------------------------------------------------ + + + + +def genericFxyGradient(surf, clip, color1, color2, func, intx, yint, zint=None): + """ + genericFxyGradient(size, color1, color2,func, intx, yint, zint=None) + + some sort of highfield drawer :-) + + surf : surface to draw + clip : rect on surf to draw in + color1 : start color + color2 : end color + func : function z = func(x,y) + xint : interval in x direction where the function is evaluated + yint : interval in y direction where the function is evaluated + zint : if not none same as yint or xint, if None then the max and min value + of func is taken as z-interval + + color = a*func(b*(x+c), d*(y+e))+f + """ + # make shure that x1 self.blinkLength: + self._blinkOffset -= self.blinkLength + self.blinkOn = not self.blinkOn + + if self.replay: + self.eventLog.update(timePassed) + pickledEventsToPost = self.eventLog.getPickledEvents() + for pickledEvent in pickledEventsToPost: + pygame.event.post(pickledEvent.event) + + events = pygame.event.get() + + if not self.replay: + pickledEvents = [PickleableEvent(event.type,event.dict) for event in events] + if pickledEvents != [] : + self.eventLog.appendEventGroup(pickledEvents) + + for event in events: + self.input(event) + + for i in range(len(self.wiimotes)): + if self.activeWiimotes[i]: + self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i]) + if self.buttonDown[i] : + self.wiimotes[i].cursor.flash() + self.wiimotes[i].cursor.blit(self.playerScreen) + + self.screen.blit(self.playerScreen, (0,0)) + + pygame.display.flip() + + for i in range(len(self.wiimotes)): + if self.activeWiimotes[i]: + self.wiimotes[i].stopNote(self.notes[i]) + + def drawBackground(self): + self.savedScreen.fill((255,255,255)) + + if self.extendedScale : + self.scaleSize = self.longScaleSize + else: + self.scaleSize = self.shortScaleSize + + self.noteRects = [pygame.Rect(i * self.width / self.scaleSize+self.blitOrigin[0], self.blitOrigin[1], self.width / self.scaleSize + 1, self.height+1) for i in range(self.scaleSize)] + #inflate last noteRect to cover the far right pixels + self.noteRects[-1].width = self.noteRects[-1].width + 1 + + #create bounding rect + self.boundingRect = self.noteRects[0].unionall(self.noteRects) + + #fill the rectangles with a color gradient + #We start with blue + startingHue = 0.66666666666666663 + + for rectNumber in range(self.scaleSize): + colorRatio = float(rectNumber) / (self.scaleSize - 1) + #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up + hue = startingHue * (1 - colorRatio) + if self.song != None: + if rectNumber + self.offset == self.highlightedNote: + #The color of the bottom of the rectangle in hls coordinates + bottomColorHls = (hue, 0.6, 1) + #The color of the top of the rectangle in hls coordinates + topColorHls = (hue, 0.9, 1) + else: + #The color of the bottom of the rectangle in hls coordinates + bottomColorHls = (hue, 0.2, 1) + #The color of the top of the rectangle in hls coordinates + topColorHls = (hue, 0.4, 1) + else: + #The color of the bottom of the rectangle in hls coordinates + bottomColorHls = (hue, 0.6, 1) + #The color of the top of the rectangle in hls coordinates + topColorHls = (hue, 0.9, 1) + + #convert to rgb ranging from 0 to 255 + bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)] + topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)] + #add transparency + bottomColorRgb.append(255) + topColorRgb.append(255) + #convert to tuple + bottomColorRgb = tuple(bottomColorRgb) + topColorRgb = tuple(topColorRgb) + + self.savedScreen.blit(gradients.vertical(self.noteRects[rectNumber].size, topColorRgb, bottomColorRgb), self.noteRects[rectNumber]) + + textBlitPoint = (self.noteRects[rectNumber].left+(self.noteRects[rectNumber].width-self.renderedNoteNames[rectNumber].get_width())/2, + self.noteRects[rectNumber].bottom-self.renderedNoteNames[rectNumber].get_height()) + + self.savedScreen.blit(self.renderedNoteNames[rectNumber], textBlitPoint) + + pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[rectNumber], 2) + + + if self.song != None and self.blinkOn: + borderSize = self.borderSize + pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 0), self.noteRects[self.highlightedNote-self.offset].inflate(borderSize/2,borderSize/2), borderSize) + + def initializeWiimotes(self): + for loop in self.wiimotes: + if loop.port == None : + loop.port = pygame.midi.Output(loop.portNumber) + self.notes.append(0) + self.buttonDown.append(False) + self.velocityLock.append(False) + + def updateCursorPositionFromJoy(self, joyEvent): + joyName = pygame.joystick.Joystick(joyEvent.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if correctedJoyId < len(self.cursorPositions): + if joyEvent.axis == 0 : + self.cursorPositions[correctedJoyId] = (int((joyEvent.value + 1) / 2 * self.screen.get_width()), self.cursorPositions[correctedJoyId][1]) + if joyEvent.axis == 1 : + self.cursorPositions[correctedJoyId] = (self.cursorPositions[correctedJoyId][0], int((joyEvent.value + 1) / 2 * self.screen.get_height())) + + def heightToVelocity(self, pos, controllerNumber): + if self.song != None: + if self.boundingRect.collidepoint(pos) and (self.highlightedNote == self.notes[controllerNumber] or self.velocityLock[controllerNumber]): + velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity) + else : + if self.easyMode: + velocity = None + else: + velocity = self.minimalVelocity/3 + else: + if self.boundingRect.collidepoint(pos): + velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity) + else : + velocity = self.minimalVelocity + return(velocity) + + def widthToNote(self, pos): + nn = 0 + try : + while self.noteRects[nn].collidepoint(pos) == False: + nn = nn + 1 + return(nn + self.offset) + except(IndexError): + return(None) + + def input(self, event): + + if event.type == pygame.QUIT: + for loop in self.wiimotes: + del loop.port + pygame.midi.quit() + sys.exit(0) + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_q: + self.done = True + + if event.key == pygame.K_i: + self.backToInstrumentChoice = True + self.done = True + + if event.type == pygame.JOYAXISMOTION: + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + self.updateCursorPositionFromJoy(event) + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if self.buttonDown[correctedJoyId]: + if self.notes[correctedJoyId] != None: + velocity = self.heightToVelocity(pos, correctedJoyId) + CCHexCode = wiimote.getCCHexCode() + wiimote.port.write_short(CCHexCode, 07, velocity) + if self.cascade: + n = self.widthToNote(pos) + if n != self.notes[correctedJoyId]: + wiimote.stopNote(self.notes[correctedJoyId]) + self.notes[correctedJoyId] = n + + if self.song != None : + if self.highlightedNote == self.notes[correctedJoyId]: + self.highlightedNote = self.songIterator.next() + self.velocityLock[correctedJoyId] = True + else: + self.velocityLock[correctedJoyId] = False + + velocity = self.heightToVelocity(pos, correctedJoyId) + + wiimote.playNote(self.notes[correctedJoyId],velocity) + + if event.type == pygame.JOYBUTTONDOWN : + + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if not self.buttonDown[correctedJoyId]: + savedNote = self.notes[correctedJoyId] + self.notes[correctedJoyId] = self.widthToNote(pos) + + if self.song != None : + if self.highlightedNote == self.notes[correctedJoyId]: + self.highlightedNote = self.songIterator.next() + self.velocityLock[correctedJoyId] = True + + velocity = self.heightToVelocity(pos, correctedJoyId) + + if velocity != None : + if self.easyMode : + wiimote.stopNote(savedNote) + wiimote.playNote(self.notes[correctedJoyId],velocity) + self.buttonDown[correctedJoyId] = True + + if event.type == pygame.JOYBUTTONUP: + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + self.buttonDown[correctedJoyId] = False + wiimote = self.wiimotes[correctedJoyId] + if not self.easyMode: + wiimote.stopNote(self.notes[correctedJoyId]) + self.velocityLock[correctedJoyId] = False + + if event.type == pygame.MOUSEMOTION: + + self.updateCursorPositionFromMouse(event) + + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if self.buttonDown[correctedJoyId]: + if self.notes[correctedJoyId] != None: + velocity = self.heightToVelocity(pos, correctedJoyId) + CCHexCode = wiimote.getCCHexCode() + wiimote.port.write_short(CCHexCode, 07, velocity) + if self.cascade: + n = self.widthToNote(pos) + if n != self.notes[correctedJoyId]: + wiimote.stopNote(self.notes[correctedJoyId]) + self.notes[correctedJoyId] = n + + if self.song != None : + if self.highlightedNote == self.notes[correctedJoyId]: + self.highlightedNote = self.songIterator.next() + self.velocityLock[correctedJoyId] = True + else: + self.velocityLock[correctedJoyId] = False + + velocity = self.heightToVelocity(pos, correctedJoyId) + + wiimote.playNote(self.notes[correctedJoyId],velocity) + + if event.type == pygame.MOUSEBUTTONDOWN: + + if event.button == 1: + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if not self.buttonDown[correctedJoyId]: + self.notes[correctedJoyId] = self.widthToNote(pos) + + if self.song != None : + if self.highlightedNote == self.notes[correctedJoyId]: + self.highlightedNote = self.songIterator.next() + self.velocityLock[correctedJoyId] = True + + velocity = self.heightToVelocity(pos, correctedJoyId) + + wiimote.playNote(self.notes[correctedJoyId],velocity) + self.buttonDown[correctedJoyId] = True + + if event.button == 2: + + self.done = True + + if event.type == pygame.MOUSEBUTTONUP: + + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + wiimote.stopNote(self.notes[correctedJoyId]) + self.buttonDown[correctedJoyId] = False + self.velocityLock[correctedJoyId] = False + + def hasChanged(self): + changed = False + if self.song != None: + if self.blinkOn != self.savedBlinkOn or self.highlightedNote != self.savedHighlightedNote: + self.savedBlinkOn = self.blinkOn + self.savedHighlightedNote = self.highlightedNote + changed = True + return(changed) + + def updateCursorPositionFromMouse(self, mouseEvent): + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + self.cursorPositions[correctedJoyId] = mouseEvent.pos + + def moveToNextNote(self): + while True: + if self.song == None: + yield(None) + else: + for note in self.song: + yield note diff --git a/src/gui/SongFamiliarizer.py b/src/gui/SongFamiliarizer.py new file mode 100644 index 0000000..69ab03c --- /dev/null +++ b/src/gui/SongFamiliarizer.py @@ -0,0 +1,583 @@ +''' +Created on 23 juil. 2009 + +@author: Samuel Benveniste +''' +from math import floor, ceil +import pygame +import sys +import colorsys +import constants +from gradients import gradients +from logging.PickleableEvent import PickleableEvent +from logging.EventLog import EventLog + + +class SongFamiliarizer: + ''' + The screen on which the game is played + + wiimotes: + The wiimotes used in this session + window: + The main display window + screen: + The main display surface + clock: + The clock used to animate the screen + savedScreen: + The background that is painted every time + playerScreen: + The buffer for painting everything before bliting + width: + The width of the window in pixels + height: + The height of the window in pixels + extendScale : + True if the scale is G to C instead of C to C + cascade: + True if crossing from note to note with a button pressed triggers a new note + scaleSize: + The size of the scale used + cursorPositions: + The positions of the cursors on the screen, in pixels + ''' + + + + def __init__(self, wiimotes, window, screen, clock, joys, portOffset, song, activeWiimotes, cascade=False, extendedScale=False, easyMode = False, replay = False, eventLog = None, defaultInstrumentChannel = 16, defaultNote = 60): + ''' + Constructor + ''' + self.firstClickTime = None + self.firstClickInTime = None + self.duration = None + self.clicks = 0 + self.clicksIn = 0 + + pygame.font.init() + self.font = pygame.font.Font(None,60) + self.congratulations = ["Bien !","Tres Bien !","Bravo !","Excellent !","Felicitations !"] + self.renderedCongratulations = [self.font.render(congratulation,False,(0,0,0)) for congratulation in self.congratulations] + self.congratulationCount = None + self.isCongratulating = False + self.congratulationTimer = 0 + self.congratulationLength = 2000 + self.congratulationPos = None + + self.blinkLength = 200 + self.minimalVelocity = 90 + self.shortScaleSize = 8 + self.longScaleSize = 11 + if not extendedScale: + self.offset = self.longScaleSize - self.shortScaleSize + else: + self.offset = 0 + self.borderSize = 5 + self.highlightedNote = 0 + self.highlightedNoteNumber = 0 + self.syllabus = None + self.savedHighlightedNote = 0 + self.scaleFactor = 1 + self.level = 3 + + self.wiimotes = wiimotes + self.activeWiimotes = activeWiimotes + self.window = window + self.screen = screen + self.width = int(floor(screen.get_width()*self.scaleFactor)) + self.height = int(floor(screen.get_height()*self.scaleFactor)) + self.blitOrigin = ((self.screen.get_width()-self.width)/2,(self.screen.get_height()-self.height)/2) + self.joys = joys + self.clock = clock + self.cursorPositions = [] + self.savedScreen = pygame.Surface(self.screen.get_size()) + self.savedScreen.fill((255,255,255)) + self.playerScreen = pygame.Surface(self.savedScreen.get_size()) + self.playerScreen.blit(self.savedScreen, (0, 0)) + self.extendedScale = extendedScale + self.cascade = cascade + self.portOffset =portOffset + self.eventLog = eventLog + self.song = song + self.songIterator = self.song.getSongIterator() + self.midiNoteNumbers = self.song.scale + self.replay = replay + self.quarterNoteLength = 800 + self.cascadeLockLengthMultiplier = 1 + self.cascadeLockLength = self.quarterNoteLength * self.cascadeLockLengthMultiplier + + self.defaultInstrumentChannel = defaultInstrumentChannel + self.defaultNote = defaultNote + + self.done = False + self.backToInstrumentChoice = False + self.easyMode = easyMode + + if eventLog == None: + self.eventLog = EventLog() + self.replay = False + else: + self.eventLog = eventLog + self.replay = replay + + #Initializes the highlightedNote and highlightedNoteNumber etc... + self.moveToNextNote() + + self.blinkOn = False + self.savedBlinkOn = False + ##Will prevent the song to move on if two consecutive notes are identical and the buttons have not been released in between the two + ##i.e. it guarantees that there will be an attack between two identical consecutive notes + self.highlightIsFree = True + + self.noteRects = [] + self.boundingRect = None + self.notes = [] + + self.buttonDown = [] + self.velocityLock = [] + + self._blinkOffset = 0 + self._cascadeLockTimer = 0 + self.cascadeIsFree = True + + self.font = pygame.font.Font(None,50) + self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers] + + self.drawBackground() + self.initializeWiimotes() + + events = pygame.event.get() + + #The main loop + while not self.done : + + #Clear the cursors from the screen + if self.hasChanged(): + self.drawBackground() + self.playerScreen.blit(self.savedScreen, (0, 0)) + + # Limit frame speed to 50 FPS + # + timePassed = self.clock.tick(10000) + + self._blinkOffset += timePassed + if self.buttonDown and not self.cascadeIsFree : + self._cascadeLockTimer += timePassed + if self._cascadeLockTimer > self.cascadeLockLength : + self.cascadeIsFree = True + + + if self._blinkOffset > self.blinkLength: + self._blinkOffset -= self.blinkLength + self.blinkOn = not self.blinkOn + + if self.replay: + self.eventLog.update(timePassed) + pickledEventsToPost = self.eventLog.getPickledEvents() + for pickledEvent in pickledEventsToPost: + pygame.event.post(pickledEvent.event) + + events = pygame.event.get() + + if not self.replay: + pickledEvents = [PickleableEvent(event.type,event.dict) for event in events] + if pickledEvents != [] : + self.eventLog.appendEventGroup(pickledEvents) + + for event in events: + self.input(event) + + if self.isCongratulating : + self.congratulationTimer += timePassed + if self.congratulationTimer < self.congratulationLength : + self.blitCongratulation() + else : + self.isCongratulating = False + + for i in range(len(self.wiimotes)): + if self.activeWiimotes[i]: + self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i]) + if self.buttonDown[i] : + self.wiimotes[i].cursor.flash() + self.wiimotes[i].cursor.blit(self.playerScreen) + + self.screen.blit(self.playerScreen, (0,0)) + + pygame.display.flip() + + for i in range(len(self.wiimotes)): + if self.activeWiimotes[i]: + self.wiimotes[i].stopNoteByNoteNumber(self.midiNoteNumbers[self.notes[i]]) + if self.replay : + self.duration = self.eventLog.getCurrentTime() + + def drawBackground(self): + self.savedScreen.fill((255,255,255)) + + if self.extendedScale : + self.scaleSize = self.longScaleSize + else: + self.scaleSize = self.shortScaleSize + + self.noteRects = [pygame.Rect(i * self.width / self.scaleSize+self.blitOrigin[0], self.blitOrigin[1], self.width / self.scaleSize + 1, self.height+1) for i in range(self.scaleSize)] + #inflate last noteRect to cover the far right pixels + self.noteRects[-1].width = self.noteRects[-1].width + 1 + + self.noteRects[self.highlightedNote-self.offset].inflate_ip(self.noteRects[self.highlightedNote-self.offset].width*2,0) + + #create bounding rect + self.boundingRect = self.noteRects[0].unionall(self.noteRects) + + self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers] + + #fill the rectangles with a color gradient + #We start with blue + startingHue = 0.66666666666666663 + +# for rectNumber in range(self.scaleSize): +# colorRatio = float(rectNumber) / (self.scaleSize - 1) +# #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up +# hue = startingHue * (1 - colorRatio) +# if rectNumber + self.offset != self.highlightedNote: +# #The color of the bottom of the rectangle in hls coordinates +# bottomColorHls = (hue, 0.1, 1) +# #The color of the top of the rectangle in hls coordinates +# topColorHls = (hue, 0.1, 1) +# +# #convert to rgb ranging from 0 to 255 +# bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)] +# topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)] +# #add transparency +# bottomColorRgb.append(255) +# topColorRgb.append(255) +# #convert to tuple +# bottomColorRgb = tuple(bottomColorRgb) +# topColorRgb = tuple(topColorRgb) +# +# self.savedScreen.blit(gradients.vertical(self.noteRects[rectNumber].size, topColorRgb, bottomColorRgb), self.noteRects[rectNumber]) +# +# noteNameBlitPoint = (self.noteRects[rectNumber].left+(self.noteRects[rectNumber].width-self.renderedNoteNames[rectNumber].get_width())/2, +# self.noteRects[rectNumber].bottom-self.renderedNoteNames[rectNumber].get_height()) +# +# self.savedScreen.blit(self.renderedNoteNames[rectNumber], noteNameBlitPoint) +# +# pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[rectNumber], 2) + + colorRatio = float(self.highlightedNote-self.offset) / (self.scaleSize - 1) + #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up + hue = startingHue * (1 - colorRatio) + #The color of the bottom of the rectangle in hls coordinates + bottomColorHls = (hue, 0.6, 1) + #The color of the top of the rectangle in hls coordinates + topColorHls = (hue, 0.9, 1) + + #convert to rgb ranging from 0 to 255 + bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)] + topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)] + #add transparency + bottomColorRgb.append(255) + topColorRgb.append(255) + #convert to tuple + bottomColorRgb = tuple(bottomColorRgb) + topColorRgb = tuple(topColorRgb) + + self.savedScreen.blit(gradients.vertical(self.noteRects[self.highlightedNote-self.offset].size, topColorRgb, bottomColorRgb), self.noteRects[self.highlightedNote-self.offset]) + +# noteNameBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-self.renderedNoteNames[self.highlightedNote-self.offset].get_width())/2, +# self.noteRects[self.highlightedNote-self.offset].bottom-self.renderedNoteNames[self.highlightedNote-self.offset].get_height()) +# +# self.savedScreen.blit(self.renderedNoteNames[self.highlightedNote-self.offset], noteNameBlitPoint) +# +# if self.syllabus : +# renderedSyllabus = self.font.render(self.syllabus,False,(0,0,0)) +# +# syllabusBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-renderedSyllabus.get_width())/2, +# self.noteRects[self.highlightedNote-self.offset].centery-renderedSyllabus.get_height()/2) +# +# self.savedScreen.blit(renderedSyllabus, syllabusBlitPoint) + + pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[self.highlightedNote-self.offset], 2) + +# if self.song != None and self.blinkOn: +# borderSize = self.borderSize +# pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 0), self.noteRects[self.highlightedNote-self.offset].inflate(borderSize/2,borderSize/2), borderSize) + + def initializeWiimotes(self): + for loop in self.wiimotes: + if loop.port == None : + loop.port = pygame.midi.Output(loop.portNumber) + self.notes.append(0) + self.cursorPositions.append(loop.cursor.centerPosition) + self.buttonDown.append(False) + self.velocityLock.append(False) + + def updateCursorPositionFromJoy(self, joyEvent): + joyName = pygame.joystick.Joystick(joyEvent.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if correctedJoyId < len(self.cursorPositions): + if joyEvent.axis == 0 : + self.cursorPositions[correctedJoyId] = (int((joyEvent.value + 1) / 2 * self.screen.get_width()), self.cursorPositions[correctedJoyId][1]) + if joyEvent.axis == 1 : + self.cursorPositions[correctedJoyId] = (self.cursorPositions[correctedJoyId][0], int((joyEvent.value + 1) / 2 * self.screen.get_height())) + + def heightToVelocity(self, pos, controllerNumber): + if self.song != None: + if self.boundingRect.collidepoint(pos) and (self.highlightedNote == self.notes[controllerNumber] or self.velocityLock[controllerNumber]): + velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity) + else : + if self.easyMode: + velocity = None + else: + velocity = 60 + else: + if self.boundingRect.collidepoint(pos): + velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity) + else : + velocity = self.minimalVelocity + return(velocity) + + def widthToNote(self, pos): + nn = 0 + try : + if self.noteRects[self.highlightedNote-self.offset].collidepoint(pos) : + return self.highlightedNote + else : + while self.noteRects[nn].collidepoint(pos) == False: + nn = nn + 1 + return(nn + self.offset) + except(IndexError): + return(None) + + def congratulate(self,targetRect,posy): + if self.congratulationCount != None : + if self.congratulationCount < len(self.congratulations)-1: + self.congratulationCount += 1 + else : + self.congratulationCount = 0 + self.congratulationTimer = 0 + self.congratulationPos = (targetRect.left+(targetRect.width-self.renderedCongratulations[self.congratulationCount].get_width())/2,posy) + self.isCongratulating = True + + def resetCongratulation(self): + self.congratulationCount = None + self.congratulationPos = None + self.isCongratulating = False + + def blitCongratulation(self): + self.playerScreen.blit(self.renderedCongratulations[self.congratulationCount],self.congratulationPos) + + def input(self, event): + + if event.type == pygame.QUIT: + for loop in self.wiimotes: + del loop.port + pygame.midi.quit() + sys.exit(0) + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_q: + self.nextLevel = None + self.done = True + + if event.key == pygame.K_w: + self.nextLevel = 0 + self.done = True + + if event.key == pygame.K_e: + self.nextLevel = 1 + self.done = True + + if event.key == pygame.K_r: + self.nextLevel = 2 + self.done = True + + if event.key == pygame.K_t: + self.nextLevel = 3 + self.done = True + + if event.type == pygame.JOYAXISMOTION: + + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + self.updateCursorPositionFromJoy(event) + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if self.buttonDown[correctedJoyId]: + if self.notes[correctedJoyId] != None: + velocity = self.heightToVelocity(pos, correctedJoyId) + if velocity != None : + CCHexCode = wiimote.getCCHexCode() + wiimote.port.write_short(CCHexCode, 07, velocity) + if self.cascade and self.cascadeIsFree : + n = self.widthToNote(pos) + if self.highlightedNote == n: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + self.velocityLock[correctedJoyId] = True + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.moveToNextNote() + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + + if event.type == pygame.JOYBUTTONDOWN : + + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + self.wiimotes[correctedJoyId].cursor.flash() + if self.replay: + self.clicks += 1 + if self.firstClickTime == None : + self.firstClickTime = self.eventLog.getCurrentTime() + + if not self.buttonDown[correctedJoyId]: + n = self.widthToNote(pos) + if self.highlightedNote == n: + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + if self.easyMode: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + self.velocityLock[correctedJoyId] = True + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.congratulate(self.noteRects[self.notes[correctedJoyId]],pos[1]) + if self.replay: + self.clicksIn += 1 + if self.firstClickInTime == None : + self.firstClickInTime = self.eventLog.getCurrentTime() + + self.moveToNextNote() + else : + self.resetCongratulation() + if not self.easyMode : + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + if velocity != None : + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.buttonDown[correctedJoyId] = True + + if event.type == pygame.JOYBUTTONUP: + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + self.buttonDown[correctedJoyId] = False + wiimote = self.wiimotes[correctedJoyId] + if not self.easyMode: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.velocityLock[correctedJoyId] = False + + if event.type == pygame.MOUSEMOTION: + + self.updateCursorPositionFromMouse(event) + + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if self.buttonDown[correctedJoyId]: + self.wiimotes[correctedJoyId].cursor.flash() + if self.notes[correctedJoyId] != None: + velocity = self.heightToVelocity(pos, correctedJoyId) + if velocity != None : + CCHexCode = wiimote.getCCHexCode() + wiimote.port.write_short(CCHexCode, 07, velocity) + if self.cascade and self.cascadeIsFree : + n = self.widthToNote(pos) + if self.highlightedNote == n: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + self.velocityLock[correctedJoyId] = True + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.moveToNextNote() + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + + if event.type == pygame.MOUSEBUTTONDOWN: + + if event.button == 1: + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + self.wiimotes[correctedJoyId].cursor.flash() + if self.replay: + self.clicks += 1 + if self.firstClickTime == None : + self.firstClickTime = self.eventLog.getCurrentTime() + + if not self.buttonDown[correctedJoyId]: + n = self.widthToNote(pos) + if self.highlightedNote == n: + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + if self.easyMode: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + self.velocityLock[correctedJoyId] = True + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.congratulate(self.noteRects[self.notes[correctedJoyId]],pos[1]) + if self.replay: + self.clicksIn += 1 + if self.firstClickInTime == None : + self.firstClickInTime = self.eventLog.getCurrentTime() + + self.moveToNextNote() + else : + self.resetCongratulation() + if not self.easyMode : + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + if velocity != None : + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.buttonDown[correctedJoyId] = True + + if event.button == 2: + + self.done = True + + if event.type == pygame.MOUSEBUTTONUP: + if event.button == 1 : + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + self.buttonDown[correctedJoyId] = False + if not self.easyMode: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.velocityLock[correctedJoyId] = False + + def hasChanged(self): + changed = False + if self.song != None: + if self.blinkOn != self.savedBlinkOn or self.highlightedNote != self.savedHighlightedNote: + self.savedBlinkOn = self.blinkOn + self.savedHighlightedNote = self.highlightedNote + changed = True + return(changed) + + def updateCursorPositionFromMouse(self, mouseEvent): + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + self.cursorPositions[correctedJoyId] = mouseEvent.pos + + def moveToNextNote(self): + self.savedMidiNoteNumbers = self.midiNoteNumbers[:] + self.highlightedNote, self.highlightedNoteNumber, self.syllabus, self.cascadeLockLengthMultiplier = self.songIterator.next() + self.midiNoteNumbers[self.highlightedNote] = self.highlightedNoteNumber diff --git a/src/gui/SongPlayingScreen.py b/src/gui/SongPlayingScreen.py new file mode 100644 index 0000000..a06e831 --- /dev/null +++ b/src/gui/SongPlayingScreen.py @@ -0,0 +1,564 @@ +''' +Created on 23 juil. 2009 + +@author: Samuel Benveniste +''' +from math import floor, ceil +import pygame +import sys +import colorsys +import constants +from gradients import gradients +from logging.PickleableEvent import PickleableEvent + + +class SongPlayingScreen: + ''' + The screen on which the game is played + + wiimotes: + The wiimotes used in this session + window: + The main display window + screen: + The main display surface + clock: + The clock used to animate the screen + savedScreen: + The background that is painted every time + playerScreen: + The buffer for painting everything before bliting + width: + The width of the window in pixels + height: + The height of the window in pixels + extendScale : + True if the scale is G to C instead of C to C + cascade: + True if crossing from note to note with a button pressed triggers a new note + scaleSize: + The size of the scale used + cursorPositions: + The positions of the cursors on the screen, in pixels + ''' + + + + def __init__(self, instrumentChoice, song, cascade=False, extendedScale=False, easyMode = False, alwaysDown = False, eventLog = None, replay = None, defaultInstrumentChannel = 16, defaultNote = 60): + ''' + Constructor + ''' + self.songDurations = [] + self.totalDuration = None + self.clicks = [0] + self.clicksIn = [0] + self.clicksPerMinute = [0] + self.clicksInPerMinute = [0] + self.meanTimeBetweenNotes = [] + self.firstClick = None + self.firstClickIn = None + + self.blinkLength = 200 + self.minimalVelocity = 90 + self.shortScaleSize = 8 + self.longScaleSize = 11 + if not extendedScale: + self.offset = self.longScaleSize - self.shortScaleSize + else: + self.offset = 0 + self.borderSize = 5 + self.highlightedNote = 0 + self.highlightedNoteNumber = 0 + self.syllabus = None + self.savedHighlightedNote = 0 + self.alwaysDown = alwaysDown + self.nextLevel = None + + self.wiimotes = instrumentChoice.wiimotes + self.activeWiimotes = instrumentChoice.activeWiimotes + self.window = instrumentChoice.window + self.screen = instrumentChoice.screen + self.blitOrigin = instrumentChoice.blitOrigin + self.clock = instrumentChoice.clock + self.width = instrumentChoice.width + self.height = instrumentChoice.height + self.cursorPositions = instrumentChoice.cursorPositions + self.savedScreen = instrumentChoice.savedScreen + self.playerScreen = instrumentChoice.playerScreen + self.extendedScale = extendedScale + self.cascade = cascade + self.joys = instrumentChoice.joys + self.portOffset = instrumentChoice.portOffset + if eventLog == None : + self.eventLog = instrumentChoice.eventLog + else : + self.eventLog = eventLog + self.cursorPositions = instrumentChoice.cursorPositions + self.song = song + self.songIterator = self.song.getSongIterator() + self.midiNoteNumbers = self.song.scale + if replay == None : + self.replay = instrumentChoice.replay + else : + self.replay = replay + self.quarterNoteLength = song.quarterNoteLength + self.cascadeLockLengthMultiplier = 1 + self.nextCascadeLockLengthMultiplier = 1 + self.cascadeLockLength = self.quarterNoteLength * self.cascadeLockLengthMultiplier + + self.defaultInstrumentChannel = defaultInstrumentChannel + self.defaultNote = defaultNote + + self.done = False + self.backToInstrumentChoice = False + self.easyMode = easyMode + + #Initializes the highlightedNote and highlightedNoteNumber etc... + self.moveToNextNote() + self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier + + self.blinkOn = False + self.savedBlinkOn = False + ##Will prevent the song to move on if two consecutive notes are identical and the buttons have not been released in between the two + ##i.e. it guarantees that there will be an attack between two identical consecutive notes + self.highlightIsFree = True + + self.noteRects = [] + self.boundingRect = None + self.notes = [] + + self.buttonDown = [] + self.velocityLock = [] + + self._blinkOffset = 0 + self._cascadeLockTimer = 0 + self.cascadeIsFree = True + + self.font = pygame.font.Font(None,80) + self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers] + + self.drawBackground() + self.initializeWiimotes() + + self.songStartTime = self.eventLog.getCurrentTime() + + #The main loop + while not self.done : + + #Clear the cursors from the screen + if self.hasChanged(): + self.drawBackground() + self.playerScreen.blit(self.savedScreen, (0, 0)) + + # Limit frame speed to 50 FPS + # + timePassed = self.clock.tick(10000) + + self._blinkOffset += timePassed + if (self.buttonDown or self.alwaysDown) and not self.cascadeIsFree : + self._cascadeLockTimer += timePassed + if self._cascadeLockTimer > self.cascadeLockLengthMultiplier*self.quarterNoteLength : + self.cascadeIsFree = True + self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier + + + if self._blinkOffset > self.blinkLength: + self._blinkOffset -= self.blinkLength + self.blinkOn = not self.blinkOn + + if self.replay: + self.eventLog.update(timePassed) + pickledEventsToPost = self.eventLog.getPickledEvents() + for pickledEvent in pickledEventsToPost: + pygame.event.post(pickledEvent.event) + + events = pygame.event.get() + + if not self.replay: + pickledEvents = [PickleableEvent(event.type,event.dict) for event in events] + if pickledEvents != [] : + self.eventLog.appendEventGroup(pickledEvents) + + for event in events: + self.input(event) + + for i in range(len(self.wiimotes)): + if self.activeWiimotes[i]: + self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i]) + if self.buttonDown[i] or self.alwaysDown: + self.wiimotes[i].cursor.flash() + self.wiimotes[i].cursor.blit(self.playerScreen) + + self.screen.blit(self.playerScreen, (0,0)) + + pygame.display.flip() + + for i in range(len(self.wiimotes)): + if self.activeWiimotes[i]: + self.wiimotes[i].stopNoteByNoteNumber(self.midiNoteNumbers[self.notes[i]]) + if self.replay : + self.totalDuration = self.eventLog.getCurrentTime() + + def drawBackground(self): + self.savedScreen.fill((255,255,255)) + + if self.extendedScale : + self.scaleSize = self.longScaleSize + else: + self.scaleSize = self.shortScaleSize + + self.noteRects = [pygame.Rect(i * self.width / self.scaleSize+self.blitOrigin[0], self.blitOrigin[1], self.width / self.scaleSize + 1, self.height+1) for i in range(self.scaleSize)] + #inflate last noteRect to cover the far right pixels + self.noteRects[-1].width = self.noteRects[-1].width + 1 + + self.noteRects[self.highlightedNote-self.offset].inflate_ip(self.noteRects[self.highlightedNote-self.offset].width*2,0) + + #create bounding rect + self.boundingRect = self.noteRects[0].unionall(self.noteRects) + + self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers] + + #fill the rectangles with a color gradient + #We start with blue + startingHue = 0.66666666666666663 + + for rectNumber in range(self.scaleSize): + colorRatio = float(rectNumber) / (self.scaleSize - 1) + #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up + hue = startingHue * (1 - colorRatio) + if rectNumber + self.offset != self.highlightedNote: + #The color of the bottom of the rectangle in hls coordinates + bottomColorHls = (hue, 0.1, 1) + #The color of the top of the rectangle in hls coordinates + topColorHls = (hue, 0.1, 1) + + #convert to rgb ranging from 0 to 255 + bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)] + topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)] + #add transparency + bottomColorRgb.append(255) + topColorRgb.append(255) + #convert to tuple + bottomColorRgb = tuple(bottomColorRgb) + topColorRgb = tuple(topColorRgb) + + self.savedScreen.blit(gradients.vertical(self.noteRects[rectNumber].size, topColorRgb, bottomColorRgb), self.noteRects[rectNumber]) + + noteNameBlitPoint = (self.noteRects[rectNumber].left+(self.noteRects[rectNumber].width-self.renderedNoteNames[rectNumber+self.offset].get_width())/2, + self.noteRects[rectNumber].bottom-self.renderedNoteNames[rectNumber+self.offset].get_height()) + + self.savedScreen.blit(self.renderedNoteNames[rectNumber+self.offset], noteNameBlitPoint) + + pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[rectNumber], 2) + + colorRatio = float(self.highlightedNote-self.offset) / (self.scaleSize - 1) + #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up + hue = startingHue * (1 - colorRatio) + #The color of the bottom of the rectangle in hls coordinates + bottomColorHls = (hue, 0.6, 1) + #The color of the top of the rectangle in hls coordinates + topColorHls = (hue, 0.9, 1) + + #convert to rgb ranging from 0 to 255 + bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)] + topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)] + #add transparency + bottomColorRgb.append(255) + topColorRgb.append(255) + #convert to tuple + bottomColorRgb = tuple(bottomColorRgb) + topColorRgb = tuple(topColorRgb) + + self.savedScreen.blit(gradients.vertical(self.noteRects[self.highlightedNote-self.offset].size, topColorRgb, bottomColorRgb), self.noteRects[self.highlightedNote-self.offset]) + + noteNameBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-self.renderedNoteNames[self.highlightedNote].get_width())/2, + self.noteRects[self.highlightedNote-self.offset].bottom-self.renderedNoteNames[self.highlightedNote].get_height()) + + self.savedScreen.blit(self.renderedNoteNames[self.highlightedNote], noteNameBlitPoint) + + if self.syllabus : + renderedSyllabus = self.font.render(self.syllabus,False,(0,0,0)) + + syllabusBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-renderedSyllabus.get_width())/2, + self.noteRects[self.highlightedNote-self.offset].centery-renderedSyllabus.get_height()/2) + + self.savedScreen.blit(renderedSyllabus, syllabusBlitPoint) + + pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[self.highlightedNote-self.offset], 2) + + if self.song != None and self.blinkOn: + borderSize = self.borderSize + pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 0), self.noteRects[self.highlightedNote-self.offset].inflate(borderSize/2,borderSize/2), borderSize) + + def initializeWiimotes(self): + for loop in self.wiimotes: + if loop.port == None : + loop.port = pygame.midi.Output(loop.portNumber) + self.notes.append(0) + self.buttonDown.append(False) + self.velocityLock.append(False) + + def updateCursorPositionFromJoy(self, joyEvent): + joyName = pygame.joystick.Joystick(joyEvent.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if correctedJoyId < len(self.cursorPositions): + if joyEvent.axis == 0 : + self.cursorPositions[correctedJoyId] = (int((joyEvent.value + 1) / 2 * self.screen.get_width()), self.cursorPositions[correctedJoyId][1]) + if joyEvent.axis == 1 : + self.cursorPositions[correctedJoyId] = (self.cursorPositions[correctedJoyId][0], int((joyEvent.value + 1) / 2 * self.screen.get_height())) + + def heightToVelocity(self, pos, controllerNumber): + if self.song != None: + if self.boundingRect.collidepoint(pos) and (self.highlightedNote == self.notes[controllerNumber] or self.velocityLock[controllerNumber]): + velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity) + else : + if self.easyMode: + velocity = None + else: + velocity = 60 + else: + if self.boundingRect.collidepoint(pos): + velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity) + else : + velocity = self.minimalVelocity + return(velocity) + + def widthToNote(self, pos): + nn = 0 + try : + if self.noteRects[self.highlightedNote-self.offset].collidepoint(pos) : + return self.highlightedNote + else : + while self.noteRects[nn].collidepoint(pos) == False: + nn = nn + 1 + return(nn + self.offset) + except(IndexError): + return(None) + + def logClick(self): + self.clicks[-1] += 1 + if self.firstClick == None : + self.firstClick = self.eventLog.getCurrentTime() + minute = int(floor((self.eventLog.getCurrentTime()-self.songStartTime)/60000)) + if minute > len(self.clicksPerMinute)-1: + self.clicksPerMinute.append(0) + self.clicksPerMinute[-1] += 1 + + def logClickIn(self): + self.clicksIn[-1] += 1 + if self.clicksIn[-1] > len(self.song.notes)-1 : + self.clicksIn.append(0) + self.clicks.append(0) + self.songDurations.append(self.eventLog.getCurrentTime()) + if self.firstClickIn == None : + self.firstClickIn = self.eventLog.getCurrentTime() + minute = int(floor((self.eventLog.getCurrentTime()-self.songStartTime)/60000)) + if minute > len(self.clicksInPerMinute)-1: + self.clicksInPerMinute.append(0) + self.clicksInPerMinute[-1]+=1 + + def input(self, event): + + if event.type == pygame.QUIT: + for loop in self.wiimotes: + del loop.port + pygame.midi.quit() + sys.exit(0) + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_q: + self.nextLevel = None + self.done = True + + if event.key == pygame.K_i: + self.backToInstrumentChoice = True + self.done = True + + if event.key == pygame.K_w: + self.nextLevel = 0 + self.done = True + + if event.key == pygame.K_e: + self.nextLevel = 1 + self.done = True + + if event.key == pygame.K_r: + self.nextLevel = 2 + self.done = True + + if event.key == pygame.K_t: + self.nextLevel = 3 + self.done = True + + if event.type == pygame.JOYAXISMOTION: + + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + self.updateCursorPositionFromJoy(event) + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if (self.buttonDown[correctedJoyId] or self.alwaysDown): + if self.notes[correctedJoyId] != None: + velocity = self.heightToVelocity(pos, correctedJoyId) + if velocity != None : + CCHexCode = wiimote.getCCHexCode() + wiimote.port.write_short(CCHexCode, 07, velocity) + if self.cascade and self.cascadeIsFree : + n = self.widthToNote(pos) + if self.highlightedNote == n: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + self.velocityLock[correctedJoyId] = True + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.moveToNextNote() + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + + if event.type == pygame.JOYBUTTONDOWN : + + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + self.wiimotes[correctedJoyId].cursor.flash() + if self.replay: + self.logClick() + + if not (self.buttonDown[correctedJoyId] or self.alwaysDown): + n = self.widthToNote(pos) + if self.highlightedNote == n: + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + if self.easyMode: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + self.velocityLock[correctedJoyId] = True + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + if self.replay : + self.logClickIn() + self.moveToNextNote() + else : + if not self.easyMode : + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + if velocity != None and self.notes[correctedJoyId] != None : + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.buttonDown[correctedJoyId] = True + + if event.type == pygame.JOYBUTTONUP: + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + self.buttonDown[correctedJoyId] = False + wiimote = self.wiimotes[correctedJoyId] + if not self.easyMode: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.velocityLock[correctedJoyId] = False + + if event.type == pygame.MOUSEMOTION: + + self.updateCursorPositionFromMouse(event) + + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if (self.buttonDown[correctedJoyId] or self.alwaysDown): + self.wiimotes[correctedJoyId].cursor.flash() + if self.notes[correctedJoyId] != None: + velocity = self.heightToVelocity(pos, correctedJoyId) + if velocity != None : + CCHexCode = wiimote.getCCHexCode() + wiimote.port.write_short(CCHexCode, 07, velocity) + if self.cascade and self.cascadeIsFree : + n = self.widthToNote(pos) + if self.highlightedNote == n: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + self.velocityLock[correctedJoyId] = True + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.moveToNextNote() + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + + if event.type == pygame.MOUSEBUTTONDOWN: + + if event.button == 1: + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + self.wiimotes[correctedJoyId].cursor.flash() + if self.replay: + self.logClick() + + if not (self.buttonDown[correctedJoyId] or self.alwaysDown): + n = self.widthToNote(pos) + if self.highlightedNote == n: + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + if self.easyMode: + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + self.velocityLock[correctedJoyId] = True + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + if self.replay : + self.logClickIn() + self.moveToNextNote() + else : + if not self.easyMode : + self._cascadeLockTimer = 0 + self.cascadeIsFree = False + self.notes[correctedJoyId] = n + velocity = self.heightToVelocity(pos, correctedJoyId) + if velocity != None and self.notes[correctedJoyId] != None : + wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity) + self.buttonDown[correctedJoyId] = True + + if event.button == 2: + + self.done = True + + if event.type == pygame.MOUSEBUTTONUP: + if event.button == 1 : + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + self.buttonDown[correctedJoyId] = False + if not self.easyMode: + if self.notes[correctedJoyId] != None : + wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]]) + self.velocityLock[correctedJoyId] = False + + def hasChanged(self): + changed = False + if self.song != None: + if self.blinkOn != self.savedBlinkOn or self.highlightedNote != self.savedHighlightedNote: + self.savedBlinkOn = self.blinkOn + self.savedHighlightedNote = self.highlightedNote + changed = True + return(changed) + + def updateCursorPositionFromMouse(self, mouseEvent): + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + self.cursorPositions[correctedJoyId] = mouseEvent.pos + + def moveToNextNote(self): + self.savedMidiNoteNumbers = self.midiNoteNumbers[:] + self.highlightedNote, self.highlightedNoteNumber, self.syllabus, self.nextCascadeLockLengthMultiplier = self.songIterator.next() + self.midiNoteNumbers[self.highlightedNote] = self.highlightedNoteNumber diff --git a/src/gui/StaticFamiliarizer.py b/src/gui/StaticFamiliarizer.py new file mode 100644 index 0000000..0e095c8 --- /dev/null +++ b/src/gui/StaticFamiliarizer.py @@ -0,0 +1,457 @@ +''' +Created on 23 juil. 2009 + +@author: Samuel Benveniste +''' +from math import floor, ceil +import pygame +import pygame.midi +import sys +import colorsys +import constants +from gradients import gradients +from logging.PickleableEvent import PickleableEvent +from instruments.Instrument import Instrument +from cursor.WarpingCursor import * +from controllers.Wiimote import Wiimote +from logging.EventLog import EventLog + + +class StaticFamiliarizer: + ''' + The screen on which the game is played + + wiimotes: + The wiimotes used in this session + window: + The main display window + screen: + The main display surface + clock: + The clock used to animate the screen + savedScreen: + The background that is painted every time + playerScreen: + The buffer for painting everything before bliting + width: + The width of the window in pixels + height: + The height of the window in pixels + extendScale : + True if the scale is G to C instead of C to C + cascade: + True if crossing from note to note with a button pressed triggers a new note + scaleSize: + The size of the scale used + cursorPositions: + The positions of the cursors on the screen, in pixels + ''' + + + + def __init__(self, wiimotes, window, screen, clock, joys, portOffset,activeWiimotes,replay = False, level = 0, defaultInstrumentChannel = 16, defaultNote = 60, eventLog = None): + ''' + Constructor + ''' + self.firstClickTime = None + self.firstClickInTime = None + self.duration = None + self.clicks = 0 + self.clicksIn = 0 + + pygame.font.init() + self.font = pygame.font.Font(None,60) + self.congratulations = ["Bien !","Tres Bien !","Bravo !","Excellent !","Felicitations !"] + self.renderedCongratulations = [self.font.render(congratulation,False,(0,0,0)) for congratulation in self.congratulations] + self.congratulationCount = None + self.isCongratulating = False + self.congratulationTimer = 0 + self.congratulationLength = 2000 + self.congratulationPos = None + + self.blinkLength = 200 + self.minimalVelocity = 64 + self.shortScaleSize = 8 + self.longScaleSize = 11 + self.borderSize = 5 + self.savedHighlightedNote = 0 + self.scaleFactor = 1 + self.wiimotes = wiimotes + self.window = window + self.screen = screen + self.clock = clock + self.width = int(floor(screen.get_width()*self.scaleFactor)) + self.height = int(floor(screen.get_height()*self.scaleFactor)) + self.blitOrigin = ((self.screen.get_width()-self.width)/2,(self.screen.get_height()-self.height)/2) + self.joys = joys + self.portOffset = portOffset + self.savedScreen = pygame.Surface(self.screen.get_size()) + self.savedScreen.fill((255,255,255)) + self.playerScreen = pygame.Surface(self.savedScreen.get_size()) + self.playerScreen.blit(self.savedScreen, (0, 0)) + self.cursorPositions = [] + self.level = level + self.nextLevel = None + self.activeWiimotes = activeWiimotes + + for i in range(len(self.wiimotes)): + #Set the screen for the cursors (it can't be set before) + self.wiimotes[i].cursor.screen = self.playerScreen + self.cursorPositions.append(self.wiimotes[i].cursor.centerPosition) + + if eventLog == None: + self.eventLog = EventLog() + self.replay = False + else: + self.eventLog = eventLog + self.replay = replay + + self.defaultInstrumentChannel = defaultInstrumentChannel + self.defaultNote = defaultNote + + self.done = False + self.backToInstrumentChoice = False + self.easyMode = False + + self.noteRects = [] + self.boundingRect = None + self.notes = [] + self.buttonDown = [] + self.velocityLock = [] + + self.drawBackground() + self.initializeWiimotes() + events = pygame.event.get() + + #The main loop + while not self.done : + + self.playerScreen.blit(self.savedScreen, (0, 0)) + + # Limit frame speed to 50 FPS + # + timePassed = self.clock.tick(10000) + + if self.replay: + self.eventLog.update(timePassed) + pickledEventsToPost = self.eventLog.getPickledEvents() + for pickledEvent in pickledEventsToPost: + pygame.event.post(pickledEvent.event) + + events = pygame.event.get() + + if not self.replay: + pickledEvents = [PickleableEvent(event.type,event.dict) for event in events] + if pickledEvents != [] : + self.eventLog.appendEventGroup(pickledEvents) + + for event in events: + self.input(event) + + if self.isCongratulating : + self.congratulationTimer += timePassed + if self.congratulationTimer < self.congratulationLength : + self.blitCongratulation() + else : + self.isCongratulating = False + + for i in range(len(self.wiimotes)): + if self.activeWiimotes[i]: + self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i]) + if self.buttonDown[i] : + self.wiimotes[i].cursor.flash() + self.wiimotes[i].cursor.blit(self.playerScreen) + + self.screen.blit(self.playerScreen, (0,0)) + + pygame.display.flip() + + for i in range(len(self.wiimotes)): + if self.activeWiimotes[i]: + if self.notes[i] != None : + self.wiimotes[i].stopNote(self.notes[i]) + if self.replay : + self.duration = self.eventLog.getCurrentTime() + + def drawBackground(self): + self.savedScreen.fill((255,255,255)) + if self.level == 0 : + A = [4] + else : + A = [1,7] + + self.noteRects = [pygame.Rect(i * self.width / 11+self.blitOrigin[0], self.blitOrigin[1], (self.width / 11 + 1)*3, self.height+1) for i in A] + + #create bounding rect + self.boundingRect = self.noteRects[0].unionall(self.noteRects) + + #fill the rectangles with a color gradient + #We start with blue + startingHue = 0.66666666666666663 + + for rectNumber in range(len(self.noteRects)) : + colorRatio = float(A[rectNumber]) / (11 - 1) + #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up + hue = startingHue * (1 - colorRatio) + #The color of the bottom of the rectangle in hls coordinates + bottomColorHls = (hue, 0.6, 1) + #The color of the top of the rectangle in hls coordinates + topColorHls = (hue, 0.9, 1) + + #convert to rgb ranging from 0 to 255 + bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)] + topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)] + #add transparency + bottomColorRgb.append(255) + topColorRgb.append(255) + #convert to tuple + bottomColorRgb = tuple(bottomColorRgb) + topColorRgb = tuple(topColorRgb) + + self.savedScreen.blit(gradients.vertical(self.noteRects[rectNumber].size, topColorRgb, bottomColorRgb), self.noteRects[rectNumber]) + + pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[rectNumber], 2) + + def initializeWiimotes(self): + for loop in self.wiimotes: + if loop.port == None : + loop.port = pygame.midi.Output(loop.portNumber) + self.notes.append(0) + self.buttonDown.append(False) + self.velocityLock.append(False) + + def updateCursorPositionFromJoy(self, joyEvent): + joyName = pygame.joystick.Joystick(joyEvent.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if correctedJoyId < len(self.cursorPositions): + if joyEvent.axis == 0 : + self.cursorPositions[correctedJoyId] = (int((joyEvent.value + 1) / 2 * self.screen.get_width()), self.cursorPositions[correctedJoyId][1]) + if joyEvent.axis == 1 : + self.cursorPositions[correctedJoyId] = (self.cursorPositions[correctedJoyId][0], int((joyEvent.value + 1) / 2 * self.screen.get_height())) + + def heightToVelocity(self, pos, controllerNumber): + velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity) + return(velocity) + + def widthToNote(self, pos): + nn = 0 + try : + while self.noteRects[nn].collidepoint(pos) == False: + nn = nn + 1 + return(nn) + except(IndexError): + return(None) + + def congratulate(self,targetRect,posy): + if self.congratulationCount != None : + if self.congratulationCount < len(self.congratulations)-1: + self.congratulationCount += 1 + else : + self.congratulationCount = 0 + self.congratulationTimer = 0 + self.congratulationPos = (targetRect.left+(targetRect.width-self.renderedCongratulations[self.congratulationCount].get_width())/2,posy) + self.isCongratulating = True + + def resetCongratulation(self): + self.congratulationCount = None + self.congratulationPos = None + self.isCongratulating = False + + def blitCongratulation(self): + self.playerScreen.blit(self.renderedCongratulations[self.congratulationCount],self.congratulationPos) + + def input(self, event): + + print event + + if event.type == pygame.QUIT: + for loop in self.wiimotes: + del loop.port + pygame.midi.quit() + sys.exit(0) + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_q: + self.nextLevel = None + self.done = True + + if event.key == pygame.K_w: + self.nextLevel = 0 + self.done = True + + if event.key == pygame.K_e: + self.nextLevel = 1 + self.done = True + + if event.key == pygame.K_r: + self.nextLevel = 2 + self.done = True + + if event.key == pygame.K_t: + self.nextLevel = 3 + self.done = True + + if event.type == pygame.JOYAXISMOTION: + + + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + self.updateCursorPositionFromJoy(event) + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if self.buttonDown[correctedJoyId]: + wiimote.cursor.flash() + if self.notes[correctedJoyId] != None: + velocity = self.heightToVelocity(pos, correctedJoyId) + CCHexCode = wiimote.getCCHexCode() + wiimote.port.write_short(CCHexCode, 07, velocity) + + if event.type == pygame.JOYBUTTONDOWN : + + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + wiimote.cursor.flash() + if self.replay : + self.clicks += 1 + if self.firstClickTime == None : + self.firstClickTime = self.eventLog.getCurrentTime() + + if not self.buttonDown[correctedJoyId]: + self.notes[correctedJoyId] = self.widthToNote(pos) + + velocity = self.heightToVelocity(pos, correctedJoyId) + + if self.notes[correctedJoyId] != None : + wiimote.playNote(self.notes[correctedJoyId],velocity) + self.congratulate(self.noteRects[self.notes[correctedJoyId]],pos[1]) + if self.replay : + self.clicksIn += 1 + if self.firstClickInTime == None : + self.firstClickInTime = self.eventLog.getCurrentTime() + else : + self.resetCongratulation() + + self.buttonDown[correctedJoyId] = True + + if event.type == pygame.JOYBUTTONUP: + joyName = pygame.joystick.Joystick(event.joy).get_name() + correctedJoyId = constants.joyNames.index(joyName) + if self.activeWiimotes[correctedJoyId]: + wiimote = self.wiimotes[correctedJoyId] + wiimote.stopNote(self.notes[correctedJoyId]) + self.buttonDown[correctedJoyId] = False + self.velocityLock[correctedJoyId] = False + + if event.type == pygame.MOUSEMOTION: + + self.updateCursorPositionFromMouse(event) + + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + + if self.buttonDown[correctedJoyId]: + wiimote.cursor.flash() + if self.notes[correctedJoyId] != None: + velocity = self.heightToVelocity(pos, correctedJoyId) + CCHexCode = wiimote.getCCHexCode() + wiimote.port.write_short(CCHexCode, 07, velocity) + + if event.type == pygame.MOUSEBUTTONDOWN: + + if event.button == 1: + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + pos = self.cursorPositions[correctedJoyId] + wiimote.cursor.flash() + if self.replay : + self.clicks += 1 + if self.firstClickTime == None : + self.firstClickTime = self.eventLog.getCurrentTime() + + if not self.buttonDown[correctedJoyId]: + self.notes[correctedJoyId] = self.widthToNote(pos) + + velocity = self.heightToVelocity(pos, correctedJoyId) + + if self.notes[correctedJoyId] != None : + wiimote.playNote(self.notes[correctedJoyId],velocity) + self.congratulate(self.noteRects[self.notes[correctedJoyId]],pos[1]) + if self.replay : + self.clicksIn += 1 + if self.firstClickInTime == None : + self.firstClickInTime = self.eventLog.getCurrentTime() + else : + self.resetCongratulation() + + self.buttonDown[correctedJoyId] = True + + if event.button == 2: + + self.done = True + + if event.type == pygame.MOUSEBUTTONUP: + + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + wiimote = self.wiimotes[correctedJoyId] + wiimote.stopNote(self.notes[correctedJoyId]) + self.buttonDown[correctedJoyId] = False + self.velocityLock[correctedJoyId] = False + + def hasChanged(self): + return(True) + + def updateCursorPositionFromMouse(self, mouseEvent): + correctedJoyId = 0 + while not self.activeWiimotes[correctedJoyId] : + correctedJoyId += 1 + self.cursorPositions[correctedJoyId] = mouseEvent.pos + +if __name__ == "__main__" : + pygame.init() + modeResolution = (1024,768) + window = pygame.display.set_mode(modeResolution,pygame.FULLSCREEN) + pygame.font.init() + + pygame.midi.init() + instruments = [Instrument(constants.scaleDict["majorScale"], i + 1, "".join(["../instruments/instrumentImages/", constants.instrumentImagePathList[i], ".jpg"]), constants.octaves[i]) for i in range(9)] + + joys = [[id,pygame.joystick.Joystick(id).get_name()] for id in range(pygame.joystick.get_count())] + for joy in joys: + if joy[1] in constants.joyNames: + pygame.joystick.Joystick(joy[0]).init() + + ports = [pygame.midi.get_device_info(id)[1] for id in range(pygame.midi.get_count())] + portOffset = ports.index(constants.portNames[0]) + print(portOffset) + + events = pygame.event.get() + + screen = pygame.display.get_surface() + clock = pygame.time.Clock() + cursorImages = [createImageListFromPath('../cursor/cursorImages/black', 11),createImageListFromPath('../cursor/cursorImages/red', 11)] + durations = [75 for i in range(len(cursorImages[0]))] + + wiimoteCount = 1 + cursors = [WarpingCursor(None, cursorImages[i], durations, (300 * i, 300 * i),flashImage = '../cursor/cursorImages/black/flash.png' ) for i in range(wiimoteCount)] + wiimotes = [Wiimote(i, i + portOffset, None, instruments[i], cursors[i]) for i in range(wiimoteCount)] + + fam = StaticFamiliarizer(instruments, wiimotes, window, screen, clock, joys, portOffset) + + for loop in fam.wiimotes: + del loop.port + + pygame.midi.quit() + + pygame.quit() diff --git a/src/gui/__init__.py b/src/gui/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/src/gui/constants.py b/src/gui/constants.py new file mode 100755 index 0000000..df13903 --- /dev/null +++ b/src/gui/constants.py @@ -0,0 +1,130 @@ +from songs.Song import Song,loadSongFromMidi +from dataTools.odict import OrderedDict + +joyNames = ["PPJoy Virtual joystick 1", "PPJoy Virtual joystick 2", "PPJoy Virtual joystick 3", "PPJoy Virtual joystick 4"] +portNames = ["Out To MIDI Yoke: 1","Out To MIDI Yoke: 2","Out To MIDI Yoke: 3","Out To MIDI Yoke: 4"] + +readabilityDict = OrderedDict([("majeure" , "majorScale"), + ("mineure naturelle" , "minorScale"), + ("majeure myxolydienne" , "myxolydianScale"), + ("mineure dorienne" , "dorianScale"), + ("phrygienne espagnole" , "spanishPhrygianScale"), + ("lydienne" , "lydianScale"), + ("phrygienne" , "phrygianScale"), + ("J'ai du bon tabac" , "jadbt"), + ("L'eau vive" , "eauvive"), + ("Le penitencier" , "penitencier"), + ("La foule" , "foule"), + ("Petit papa noel" , "papanoel"), + ("La marseillaise" , "marseillaise"), + ("A la claire fontaine" , "clairefontaine"), + ("Au clair de la lune" , "clairdelalune"), + ("Frere jacques" , "frerejacques"), + ("Le petit vin blanc" , "vinblanc"), + ("La vie en rose","vierose"), + ("Les feuilles mortes","feuillesmortes"), + ("Il pleut bergere","bergere"), + ("Le temps des cerises","cerises"), + ("La boheme","boheme"), + ("Chanson Test","test"), + ("Improvisation" , "none"), + ("Do/Do","C/C"), + ("Sol/Do","G/C"), + ("Oui","Yes"), + ("Non","No"), + ("Tres facile","veryEasy"), + ("Facile","easy"), + ("Normal","normal"), + ("Expert","expert")]) + +reversedReadabilityDict = dict(zip(readabilityDict.values(),readabilityDict.keys())) + +rangeDict = {"C/C":False,"G/C":True} + +cascadeDict = {"Yes":True,"No":False} + +modeDict = OrderedDict([("veryEasy",0),("easy",1),("normal",2),("expert",3)]) +print modeDict['veryEasy'] + +scaleDict = OrderedDict ([("majorScale" , [55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72]), + ("minorScale" , [55, 56, 58, 60, 62, 63, 65, 67, 68, 70, 72]), + ("myxolydianScale" , [55, 57, 58, 60, 62, 64, 65, 67, 69, 70, 72]), + ("dorianScale" , [55, 57, 58, 60, 62, 63, 65, 67, 69, 70, 72]), + ("spanishPhrygianScale" , [55,57,58,60,62,63,66,67,69,70,72]), + ("lydianScale" , [55, 57, 59, 60, 62, 64, 66, 67, 69, 71, 72]), + ("phrygianScale" , [55, 56, 58, 60, 61, 63, 65, 67, 68, 70, 72])]) + +songDict = OrderedDict([("jadbt" , Song(scaleDict["majorScale"],[3, 4, 5, 3, 4, 4, 5, 6, 6, 5, 5, 3, 4, 5, 3, 4, 4, 5, 6, 7, 3,7,7,6,5,4,5,6,7,4,7,7,6,5,4,5,6,7,4],False, + lyrics = ["J'ai","du","bon","ta-","-bac","dans","ma","ta-","-ba-","-tie-","-re","J'ai","du","bon","ta-","-bac","tu","n'en","au-","-ras","pas","j'en","ai","du","fin","et","du","bien","ra-","-pe","mais","ce","n'est","pas","pour","ton","vi-","-lain","nez"], + noteLengths = [1,1,1,1,2,1,1,2,2,2,2,1,1,1,1,2,1,1,2,2,4,2,1,1,2,1,1,2,2,4,2,1,1,2,1,1,2,2,4], + quarterNoteLength = 400)), + ("eauvive" , Song(scaleDict["majorScale"],[5,3,5,3,5,3,4,4,5,6,4,5,3,4,5,3,5,3,5,3,4,4,5,6,4,5,3,4,7,8,7,6,6,4,6,5,3,5,4,3,4,5,6,5,4,3,4,3,2,3], + True, + lyrics = ["Ma","pe-","-tite","est","co-","-mme","l'eau","elle","est","co-","-mme","l'eau","vi-","-ve","e-","-lle","court","comme","un","rui-","-sseau","que","les","en-","-fants","pour-","-sui-","-vent","ve-","-nez","ve-","-nez","mes","a-","-gneaux","mes","a-","-gne-","-lets","ja-","-mais","ja-","-mais","vous","ne","la","ra-","-ttra-","-pe-","-rez"], + noteLengths = [2,1,2,1,2,1,3,1,1,1,2,1,3,3,2,1,2,1,2,1,3,1,1,1,2,1,3,3,3,3,3,3,1,1,1,1,1,1,6,3,3,3,3,1,1,1,1,1,1,6], + quarterNoteLength = 300)), + ("penitencier" , + Song(scaleDict["dorianScale"],[3,3,3,5,7,6,3,3,10,10,10,9,7,6,7,10,10,10,3,5,6,7,6,3,5,3,3,3,3,2,2,3], + True, + alterationIndexes = [-2,-3], + alterations = [1,1], + lyrics = ["Les","por-","-tes","du","pe-","-ni-","-ten-","-cier","bien-","-tot","vont","se","re-","-fer-","-mer","et","c'est","la","que","je","fi-","-ni-","-rai","ma","vie","comme","d'au-","-tres","gars","l'ont","fi-","-nie"], + noteLengths =[1,5,1,5,1,1,6,4,1,5,1,4,1,1,10,1,1,5,1,4,1,1,5,1,5,1,1,1,4,5,1,12], + quarterNoteLength = 250)), + ("papanoel" , Song(scaleDict["myxolydianScale"],[3,6,6,6,7,6,6,7,8,8,8,9,8,7,6,6,6,6,5,4,3,3,3,6,6,6,7,7,6],False, + lyrics = ["pe-","-ti","Pa-","-pa","No-","-el","quand","tu","de-","-scen-","-dras","du","ciel","a-","-vec","tes","jou-","-ets","par","mi-","-lliers","n'ou-","-blie","pas","mes","pe-","-tits","sou-","-liers"], + noteLengths = [1,1,1,1,1,3,0.5,0.5,1,1,1,1,3,1,1.5,0.5,0.5,0.5,0.5,0.5,3,0.5,0.5,1,0.5,0.5,0.5,0.5,3], + quarterNoteLength = 500)), + ("foule" , Song(scaleDict["myxolydianScale"],[7,7,6,5,6,8,7,7,6,8,7,7,6,9,7,7,6,9,7,7,6,8,7,7,6,8,7,6,5,4,4,4,4,4,4,6,6,6,6,8,8,7,6,8,7,7,7,7,7,7,7,7,7,7,7,7,6,9,8,7,8,8,7,8,8,7,8,8,7,8,8,6,8,8,6,8,8,7],False,modulationIndexes = [28],modulationScales = [scaleDict["spanishPhrygianScale"]], + lyrics = ["Em-","-por-","-tes","par","la","fou-","-le","qui","nous","trai-","-ne","nous","en-","-trai-","-ne","e-","-cra-","-ses","l'un","con-","-tre","l'au-","-tre","nous","ne","for-","-mons","qu'un","seul","corps","et","le","flot","sans","e-","-ffort","nous","pousse","en-","-chai-","-nes","l'un","et","l'au-","-tre","et","nous","lai-","-sse","tous","deux","e-","-pa-","-nouis-","en-","-i-","-vres","et","heu-","-reux","ta-","-dam","ta","ta-","-dam","ta","ta-","-dam","ta","ta-","-dam","ta","ta-","-dam","ta","ta-","-dam","ta"], + noteLengths = [1,1.5,.5,.5,.5,1.5,.5,.5,.5,1.5,.5,.5,.5,1.5,.5,.5,.5,1.5,.5,.5,.5,1.5,.5,.5,.5,1.5,.5,.5,.5,3,.5,.5,.5,.5,.5,.5,.5,.5,.5,1,1,.5,.5,1.5,3,.5,.5,.5,.5,.5,.5,.5,.5,.5,.5,.5,.5,1,1,1.5,.5,1,1.5,.5,1,1.5,.5,1,1.5,.5,1,1.5,.5,1,1.5,.5,1,3], + quarterNoteLength = 400)), + ("clairefontaine" , Song(scaleDict["majorScale"], + [3,3,5,5,4,5,4,3,3,5,5,4,5,5,5,4,3,5,7,5,7,7,5,3,5,4,3,3,5,5,5,4,5,5,5,5,3,5,4,3], + False, + lyrics = ["A","la","clai-","-re","fon-","-tai-","-ne","m'en","a-","-llant","pro-","-me-","-ner","j'ai","trou-","-ve","l'eau","si","be-","-lle","que","je","m'y","suis","bai-","-gne","il","y-a","long-","-temps","que","je","t'aime","ja-","-mais","je","ne","t'ou-","-blie-","-rai"], + noteLengths = [2,1,1,1,1,1,1,2,1,1,1,1,2,2,1,1,1,1,1,1,2,1,1,1,1,2,2,1,1,1,0.5,0.5,2,2,1,0.5,0.5,1,1,4], + quarterNoteLength = 400)), + ("clairdelalune", Song(scaleDict["lydianScale"], [7,7,7,8,9,8,7,9,8,8,7,7,7,7,8,9,8,7,9,8,8,7,8,8,8,8,5,5,8,7,6,5,4,7,7,7,8,9,8,7,9,8,8,7],False, + lyrics = ["Au","clair","de","la","lu-","-ne","mon","a-","-mi","Pie-","-rrot","pre-","-te","moi","ta","plu-","-me","pour","e-","-crire","un","mot","ma","chan-","-delle","est","mor-","-te","je","n'ai","plus","de","feu","ou-","-vre","moi","ta","po-","-rte","pour","l'a-","-mour","de","Dieu"], + noteLengths = [1,1,1,1,2,2,1,1,1,1,4,1,1,1,1,2,2,1,1,1,1,4,1,1,1,1,2,2,1,1,1,1,4,1,1,1,1,2,2,1,1,1,1,4], + quarterNoteLength = 500)), + ("frerejacques" , + Song(scaleDict["majorScale"], + [3,4,5,3,3,4,5,3,5,6,7,5,6,7,7,8,7,6,5,3,7,8,7,6,5,3,3,0,3,3,0,3], + True, + lyrics = ["Fre-","-re","Ja-","-cques","fre-","-re","-Ja","-cques","dor-","-mez","vous","dor-","-mez","vous","so-","-nnez","les","ma-","-ti-","-nes","so-","-nnez","les","ma-","-ti-","-nes","ding","ding","dong","ding","ding","dong"], + noteLengths = [1,1,1,1,1,1,1,1,1,1,2,1,1,2,1.5,0.5,1,1,2,2,1.5,0.5,1,1,2,2,1,1,2,1,1,2], + quarterNoteLength = 600)), + ("marseillaise" , Song(scaleDict["majorScale"],[0, 0, 0, 3, 3, 4, 4, 7, 5, 3, 3, 5, 3, 1, 6, 4, 2, 3, 3, 4, 5, 5, 5, 6, 5, 5, 4, 4, 5, 6, 6, 6, 7, 6, 5, 7, 7, 7, 5, 3, 7, 5, 3, 0, 0, 0, 2, 4, 6, 4, 2, 4, 3, 2, 1, 3, 3, 3, 2, 3, 4, 4, 5, 5, 5, 5, 6, 7, 4, 5, 4, 3, 3, 3, 5, 4, 3, 3,2,7,7,7,5,3,4,7,7,7,5,3,4,0,3,4,5,6,7,8,4,8,7,5,6,4,3], True, modulationIndexes = [53,54,61,77], modulationScales = [scaleDict["dorianScale"],scaleDict["majorScale"],scaleDict["dorianScale"],scaleDict["majorScale"]], + lyrics = ["A-","-llons","en-","-fants","de","la","pa","tri-","-i-","-e","le","jour","de","gloire","est","a-","-rri-","-ve","con-","-tre","nous","de","la","ty-","-ra-","-nni-","-e","l'e-","-ten-","-dard","san-","-glant","est","le-","-ve","l'e-","-ten-","-dard","san-","-an-","-glant","est","le-","-ve","en-","-ten-","-dez","vous","dans","nos","cam-","-pa-","-gnes","mu-","-gir","ces","fe-","-ro-","-ces","sol-","-dats","qui","vie-","-nnent","ju-","-sque","dans","nos","bras","e-","-gor-","-ger","nos","fils","et","nos","com-","-pa-","-gnes","aux","ar-","-mes","ci-","-toy-","-yen","for-","-mez","vos","ba-","-ta-","-illons","mar-","-chons","mar-","-chons","qu'un","sang","im-","-pur","a-","-breu-","-ve","nos","si-","-illons","pon","pon","pon","pon"], + noteLengths = [1,2,1,3,3,3,3,5,1,2,1,2,1,3,6,2,1,9,2,1,3,3,3,2,1,3,6,2,1,3,3,3,2,1,6,2,1,3,2,1,3,2,1,6,1,2,1,6,3,2,1,3,3,6,3,2,1,3,2,1,6,3,5,1,2,1,2,1,6,2,1,5,1,2,1,2,1,6,5,1,7,1,2,1,8,1,7,1,2,1,8,3,9,3,9,6,3,3,9,3,8,1,2,1,2,1,2,1,8], + quarterNoteLength = 300)), + ("vinblanc" , + Song(scaleDict["phrygianScale"],[5, 5, 5, 3, 5, 6, 5, 5, 5, 3, 7, 6, 6, 6, 6, 4, 8, 7, 7, 7, 8, 9, 7, 5, 5, 5, 5, 3, 5, 6, 8, 9, 10, 9, 8, 10, 9, 8, 6, 6, 8, 7, 6, 8, 6, 5, 3, 5, 6, 3, 5, 6, 3, 5, 6, 3, 5, 6, 3, 5, 7, 6, 5, 7, 6, 5, 8], + False, + lyrics = ["Ah","le","pe-","-tit","vin","blanc","qu'on","boit","sous","les","to-","-nelles","quand","les","fi-","-lles","sont","belles","du","co-","-te","de","No-","-geant","et","puis","de","temps","en","temps","un","air","de","vie-","-lle","ro-","-man-","-ce","sem-","-ble","do-","-nner","la","ca-","-den-","-ce","pour","fau-","-ter","pour","fau-","-ter","dans","les","bois","dans","les","pres","du","co-","-te","du","co-","-te","de","No-","-geant"], + noteLengths = [1,1,1,2,1,6,1,1,1,2,1,6,1,1,1,2,1,6,1,1,1,2,1,6,1,1,1,2,1,6,1,1,1,1,1,1,3,3,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6], + quarterNoteLength = 300)), + ("none" , None)]) + +instrumentImagePathList = ["piano", "guitare", "accordeon", "violon", "flute", "tuba", "orgue", "violoncelle", "celesta"] +octaves = [0, -1, 0, 1, 1, -2, 0, -1, 0] + +defaultInstrumentChannel = 16 +defaultInstrumentNote = 60 +defaultCCHexCode = 0xB0+defaultInstrumentChannel - 1 +defaultNoteOnHexCode = 0x90+defaultInstrumentChannel - 1 + +songScaleFactor = 0.99 + +fileName = "../../../saves/22-01-2009-coll1-v65-" + +def noteNumberToName(noteNumber): + names = ["Do","Do#","R\xe9","Mib","Mi","Fa","Fa#","Sol","Sol#","La","Sib","Si"] + return(names[noteNumber%12]) + +if __name__ == "__main__": + key = "papanoel" + if songDict[key] != None : + songDict[key].save("../songs/smwis/"+str(key)+".smwi") diff --git a/src/instruments/Instrument.py b/src/instruments/Instrument.py new file mode 100755 index 0000000..fb54d3a --- /dev/null +++ b/src/instruments/Instrument.py @@ -0,0 +1,46 @@ +''' +Created on 15 juil. 2009 + +@author: Samuel Benveniste +''' + +class Instrument: + ''' + Object representing an instrument. + + notes: + The MIDI numbers of the notes played by this instrument (usually a scale) + channel: + The channel corresponding to the instrument in the synthesizer + image: + The image for the instrument + ''' + + def __init__(self, notes, channel, image, octave = 0): + ''' + Constructor + + notes: + The MIDI numbers of the notes played by this instrument (usually a scale) + channel: + The channel corresponding to the instrument in the synthesizer + image: + The image for the instrument + ''' + + self.notes = [loop+12*octave for loop in notes] + self.octave = octave + self.channel = channel + self.image = image + + def getNote(self,noteNumber): + if noteNumber == None : + return(None) + else : + return(self.notes[noteNumber]) + + def getNoteByNoteNumber(self,baseMidiNoteNumber): + if baseMidiNoteNumber == None: + return(None) + else : + return(baseMidiNoteNumber+self.octave*12) \ No newline at end of file diff --git a/src/instruments/__init__.py b/src/instruments/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/src/instruments/instrumentImages/accordeon.jpg b/src/instruments/instrumentImages/accordeon.jpg new file mode 100755 index 0000000000000000000000000000000000000000..015b1e0da827676f96634d73770ddc17e420cc6f GIT binary patch literal 31184 zcmbTd1yEc;*ETo=cL@a7!7VrpHn_WcaCevB0fI9)1b0tx56%EVg1Zh*AUMI7cje#u zw!Xi1|Lv+%x9Z-$UH#m?bdkdc=Gz`ZqAI934Qbrm29z(L2r!a&2p z!o&Ck`+ z*T~Ao;y;7H;o{*D5fFVOA^B(_As}J#zuaDX0k|k|K5*CYa5R8-xNz{eaIb>^N&o;3 z@jtVLg9H4Z4elL00wNMJ3Mv}RXZ@mNGo&ykY5%H)w#gX2t zn<3M<;d6yT3Q>R(^?d{y)919@=I&vrXdeiPh)L+^85o(Ed3gEw1wew5QqnTAa`FnA zTG~3gdin+ymR8m_ws!U&o?hNQzJC7UUm_x-zDCC+r=+H(XJlq&7ZsP3mX%jjRy8y> zHMg|3wRiLn3=R!LM@GkHX6NP?7MGS+ws&B=d;156N5>bJSJyYUcmM7m{(}n+0RMl$ z`X9*tAGmPeaJ@r7fJZ?74=%WOK5qt(i-1VYiG(Mvj%?=ko`x$F1z!SESl@>V9-|D9s=cqF;6x3_BrWcvgaP8SMqY}cFvw^T`stJH`Q6{a# zs$`{$m|yw-Y|j53j{nztNc^!DF{+p*_v-}wOlL%%&kn!vHvDW7@IwcaaR^;|K}Qn- zbT>Ktx9%%zOtz)QHE?}(G|ITwhAoCEyhG7I3*f2Q2yK2r(UCJRA%ks}zwQc8uC%4! z=XSIEEaBG2?yDpYk&|i9XN^@gF|#C>VTJc2uK<$KXs7)IdA30x6Z1cQWEti?>!yB` zV?|ngbr{UlX0zxq6ARHM!@7dmELh|kmc1GK4>3Jhr5N2on)kDsvG2pBSC}cA4HFuN zMQaebZZCycWZEIdF!hulHi-reiaa`qJ#jpK2^8D4OSfrq&;Gh>emfH?t7=)MKNGZc zgtU`zv@kAW0M|^;rlDaIJZ|ZS+#|PtzZ6WRYH3-81TXR{YGf|f2Q~Q)sgs3s z0CH4;4$*ds!M-W~Zh%irTod{ERM%7Fsy($Fg2tLdcdb66UL`XIMHTOOgQD8+YSvW; z{S%5ETkfVhc%7D)!&H9?F6eMZdO{^3&{u##$QSIiv5ViAA^`y&V(;0WM2RwTypU;YX7LLNa)MT zz#nCM_p9&&O=0^)PhhNTKSMvKZ;mMX&*2w1fE8ylxZuGug0K}S~HB#si z$3zT^e+4A{Q7j)ODuwIl3#*yNb9o zEu71Hal{blCY@L2!CHX@1(?4+kvh1REwm+=ozR*>?#-KPeo`s55vJQQJgW1}-jl%U zoc5YBhg=iie^eXDp?JRM2fmWa~l>TfF&VA&te{D{pgs*7cd& zP{)5bH}Dle(fUInxP#2*^29{Z!E#ZZCus`K)D>t4fYi@LR1~ya9dOFiatJ1TzFp$Z z3z;sUSe5oe;9qI^=9+%7sf+}RU}LucE;7XFj9fT(msdEX*!kcd(QJkP`~FXjd%B`d zg_3AIebmjbWUQVK?1vEpyFf+=;`Lq}de9!XR$7w@uNKA(y#dmM@E=xvc$m!cNTh#R z9zEU1c+vL7kr5v$KrD)31pKdBO|FActh`t?`kE2P*kEo{rAUN>4(4eM#5aBAJ{jb+ zjN#0AB^AKmc6us?Ki}MKFy5Nw=D_ki{}m+}T+P9{8B*=<97TS5;bQ9Vy}i>aj}aI(B~iY$VGjl*;T z$UZylUl)KDIoHIazSopxJ{h1m{Sxg%%Kvl)W(nS8cp%BsBSyi>6lomtSlLLreTa0_ zAu8VX-ueL~UY`nD^Vf9x>t#p*Z1<*IGfR6)aL7|&S~)PHDXYuhd=83|=uKPk(|lrY zN4~01E@6$QOrEaB;0Tilc_C-65v8_*KlT2)QN~*M)S;#Ei@ng*BF3o#iWb`PPUKv0 zHq7aWhPkiLcz6#}QhLUG3{$%x^_(W{^FWSi;D)~rXh!j!c{;;-j?)NbWH9AqXQijZ zi84q^mm?$eY0fecGta+XI6+lie_H=gZ5hrh;5IfA;cM;WpZA9$!Gb3->Lyq111!I` zWeI6Dq&dGPeeXYIpd19eh|RjIEZAO_gwNKSZ~g+Ox%8E<360=RbhkN{XcnXZ*Sx_B z9=78ik6%?E)#Nm&APWrHM&2%po&>ipwz;r2%od$`!AG0b8gDVd(NQ2j?Q4u@);_%q`>0DjoJl*NPtDpR+$oP!<(4~f-F zcaTLghYBHW==ISV^XbGlzWm!qyjGpPEK8y{BIOoI8A3Jdxq84#s2O{zBLz6k&!Ynm zmbY-vqzxBsj6|-?o)U}m(1_0v3bzsyozCqSW?3|~U4Ex>9TD@L8e2>Jb^|-o<#oXp ziTqAptYE1hVrvwPcYSbK%OAsL*xxwCg6h&Vyws4;APb3mI9J`1hK`+j@H)ae8?z4- z>BX@~4BdmghpUqg zoLh{1V;?BL*Fb%~*Kypym-u;EU#$x-7~c`pEBeLzwx-&GJ+bNoW(r0rIm*4InrrVv z_=L&%?pXF39(U0FuJ$J-4yuFes)xMAMfNY3j-NpPj*f$K$&szxr($^=0=aci9mm;r zzbX}6wbI7foL7_7*6{ztYnIB9VR$mi?%~IbE8RG5!^r)<|;q>l3CG3{T8a4tf@rzcUw64@=s#eKXBW`9r@Re ziLFL7jTi9C0Iq>O1eH6ay3@@l!}%UOI(KT(U(6;6X)h9X8rj!v=Dy=6p(_I4L#AjK zpmCJm-yNLAFv*)7y7HC^*y=Hdn$kOz)7u@@0?Ro@NedkLK|qm&6-A_!g<;2W(8&J5dJx{M#KhVP-C%}pf_l~b2U-Q+G)I-T^CsW|0A$lmYP za$l%g)&dI6d(nOg#ZgC$9NbNc=2knHh@heuKWS0h;dzKWa!;w-3r=isbWNs>J+fo| zowD^Y+kwf3LKm@(dqF_`5FwV1f8Dp*WqYfI^(8JZthQQ2E0>PmXH37SSgM36{REa^ zNJIy*_c_1E1P9$vdbmyX02Q8*oCWh3HoP~=Qw8pEs&0EX*KU0S#bAy>NwV#Z zyHmptKiS)K-kq(J`7EcJ{iDD>P&mS*zZHC75gpKL=%F^tz@xmkhGD(}7N1xoGQ(mR z3*P-tjTvMmr`8omAnPH9_r|~DeT0}3HQe;>1lv7Y-l+$7x6&?H?oKdF@Ml8{EJkbS zOjs;zr&IXZd8=*P5bSFcwDQhwjq}Xl72PeU9+Q`3LnxHwgwZvg;mxnvV5nX;q7cn@H6i(=0LW8 z1;h(JAVeO^NTcuPj>~$eb?nJtg0$_HZ5d~EI!S5i{j%L-YM{bs-DUeAIp;4FLRz?d zz&`q%WCF)9J6noaqFGsWnasYu7SLsu49&8$g44L*0NDwpnU)*_U;>bpLQ=Y z0lJ(I1*XG9Be%LaH{bwBT>50sfzGF5XPnM?B`{&V9{b~T*Pp~flC0c=N%I(sQ(br$ z3u*dzO)H=@DFhCD{$6ux>AOuJ)JUR~FE(VONN&K=KNzBa>R3+Wi!&IcYbygy6b&z& z6!_z2aDH?p|H~Qvc}?ro4zVysU)R%q+lul}$}=hQRjuhUn^HN7p=3(lB}LT~{cO7Lo*d zvTp(V$_UMJyUz^AE%vT=4O&bfgdwkASMoaSb>vz_>Uhb8&}C5a2eF94GIvDhFuwU5 zByh^nu_@Nub19a`(o3(lrozc1djKT| z4_8Avf;-$t?s6Ec{z2y924kb9FeY@CpzyEs^8Imf-iG?ZkJ6 z*xmZ5(3(ysG3XJ3E$maJ_Eg{LOeBmGaQBkBB*x{A3ZO{U`#iq6*eu{hZoXrggu4K7u#6vtlKLjy=r69l*-1snW2f1aP%3au-_`f(bMqQ>!+d-Wu- z|GSamRZ|03Rr+py?`WMuLsyN9f`~%dVE9iiweWcr&~3G=gJ5Y9Y*Ig!%v}56s^m(B ztAxM=22rvDAm&&l+D~XXSUYaz9nQC2Sbj$Tr4PKZypM2LIld+Iy>u?7eFdNjfNR~7 zWpdIfdBy1pgjD$jD3 zm61*Uv0g}$Kkh=cp-jW7%vKtm>#FLOeLy>T*V1+ztp*bck!i81JD32u)?nAEb7|;` zHmy!kSTtyccJ!u#V#AUwf$2Llt5D>2vjV9AmDhmjD?nxa zsLr}QT=6nZMmMZPGaUQVWDWW^yHK{YUSg|5?pg4&zov6tXOSzc1EK{re_7&}kH&o^nAD?j#z?z%0Vf%7#(VlZQ!v}Em$KuwMHe9NLM^H_Gotn&5|t*N0cT&TeCAMEKL!Dzcq zbqCFmr%DqMn1hor#5kdkV~!0UhgP>2D&a@@{j!ewpQ()ai*^h7A#7X|VAdo$3ap(2I{w8OS~!#099qmkP(lkzqXk-aO7|d(lev zA_5WZL_NlEhQ|QZL$QgGg&$*pk2P{5g^hb3%LQ%=eWSl_<%t%Bpad^CPl>56t|W69 zXrqUC4BILpn#($4m*QHm%1y#OF~X6Zxx2;PmQN%A4h1zWMw2M+r+5-p*YY*RuwByW zi2A@4g;+~D2a)$~4>JmW=!-6Zhndl|ctTPYuE1xe5HY07w{gG;0!0*7YrPy~IWvjr zYq^`BVel)pw&$#OkZRBMbn=$Cl&4C5D_4a-f0`h(U`(!ii+Uxo9oHXhcl%=flCRd0J17gNI^aeE#6;Chn?k5?z#;+f z`0_$Yp|v<%_-Tgq^Rl+t^UPo|`zs)l=oJ8r$&=el*q_-v<(!~R@|)!1$XnXFBVeDm z?jwaDaSTw+Da1gCH9b{R!lDvKc7sv{>)je9cQbfr>G&4S(#C0|Pxts#cU|pyeRtEs z+cX4FHd%sX$_yVfaR@K1;rwyb5(h1V(l9h+R8}8x%+q0$*?OUqYpy-)0XLJ}H@8%ajMweJ;jH^8`Xbv@jL_a=Oul6rzB{~V`mfI35t0BtcxVNE4L)ntw^V*W`cZzc zeHOc}IgF(`+k|8>Zjo~NigD#jjf&uwCsIe%-u3GJUtVl>Llj7Er>mlCQ4I4Je04cFc!p3hbZPE!3GQyUn+p1#mM`Qpm7+23c6{kuX}7GLXeIT% zrS9|9fghmS%sTV&?HNIb z83m8fg~~`ErGcLSbAV^Xqz|r9{Mv~DDpMa)S|yRQYJZ3iRe{wr(`cB~%Wl>a_A9`o zu7leNCCgb30md-X$dfU&2D!oN3Uv4+#Mc7`!YlmxrU_bSu%O@6t8b$s#=!C~8E`q7 zsVhN4WxDi1RHfY3|GRx?a=RnHp-NX`4jBj$V-QgZW}c~^)m4f&PjKN|(V?dYVzmDW zifr=SX%6Sorn^mA(oyt7m%`btq>2lig`6G>d6j;ZLBV@DNncTs`K|ivDk#^1Z&NqZ z9&FwbiXN?GVrfHm&{pfkJdTgs78fxk@SvHJqstoEZh4;+D_p-4ojcu&(2-Y+*#s*m z#|~;*9r-!!Xeo_$C?;?%Y@JppgS-b1L?(av*>rvH^&tYMiQ6!e3qH5@Fc5U4HD_Iy zl(M^?BwZ4}U2X=o|53jxp%{Uf=%FSu5YY#MB2`9bR$E?!sx`g@;S0&1O%S`Bdw*9+ zQ$AZS9e(@BrR%NCNQwY-&ryMzO6Og_Bx(FQy^uj_BBM)*1l1k8I=hHuE49`kG}YvNhL!hX@Z{VndCc)$ z0cHvGD;skC+!faFOM%n(By=cHA9pi;hN|C<1U2rg6D*A=y{5}>9I|G!SM-IE-hq4z z+<1Wvs9n>1@Nq#gLKqk@il*<8rk^~&P+&xPi-s3GAqs&Q7&f!hw1@PuwC2{AG6-2) zXO1=dFlHK3n)bp@$-JmMk(*`7cT+Z%-Ip+q;bf!Gsfd_Y)$<>-UcOl)VOn$OI(LaOt) z`g%|zM(=a)OOe1M;HZQEmB$&A8ENWwqG!9xkU^ZF;%4uh9ct=JEG++-F^(r#zJly4 zKrdiF-N?)>e>jAomnmtrUc!TT?1hI@Nc4~+egXe71VoyfGwI>SxrYfmpq~)SH2e*qVMUcZfMYQd2 z|9%ZudV3<#$o=`cz|E7JRE_?wX-wNY4#Kj4R{(gXJ+)o4RkO5@uj}i#Oe_IbyN0@V zGD47SNTj6{IWiA)Uq>WWN2ZtzIq9Qw`H?34UfAICbjmdWnY~g;UZ~wiOI(9au5_Y3 zagfaz@`HZqggz3DyGsVM5uXn``SOXK&lyw}gx6bKhcB!+%pXgPUrqC~VyDXF*UBq?dY zcQDtR%t^FX&XQw6&XnkWQOFnzIhoM&T&wH(TIDo$P){&0KDmd_Ryv-%#(oFxN+kM& z$pYU>Aa6L9CI{RD5nb03yBa~Jf0`*sH=DoXD$zt;E9?;rmQ+@gw}Su9^94;X#{66_ zh}W7$-VoVYv{_JJrUs*q`(E=$J49vq>047!f9tI?M)y~Nn%ndlfD9be2xET425+#Y z>m9SDq7U~?Mw(}5LyeA<6i73y-7H1JPIn^MR7XPiFvsOiqZtH+Al> zfIrzLJ@4%Kep4nywKQZAG2x)hszuzhnZIoREQn~~ zH|<8A8Dsa7FDO)1{R#rVu3`O6kZ7@9!rCccJTocb{&efJo6n=LbMC z63S;AqX&&&FF!644FK|-kVKWdRQV^WTXH+=(G=tgfXza(kqazA&|eMk3UC8}h$dLv zNU(~(&qV)xLFoga(LeT5pb*i7zzTOw9IBzI4cQM^J>v==Ms%Cve%q zS*+kjBl{3t-_^zTch)*Jv&nIYN-@~y9c-?&zv$p2gkc#z1S=e}i~TrPQs>It>&^%g zYDhR(Ew$0rDqgGb;ixI{J6QU1pCIw^rwX{%$Ggy?HEp(-L+TaaC4=bhkMXJJNi)hxFX=PW5QMmI^pRI;r_G^+L`f5&-w>ga8g)LaH;OpgT1q1f#>^JHye`Z`0ZE=L4wbkc|#A6VP76z4MSdctdWWV5eAy z4*mTvKHC(q^}T<}5TDL6A^edZDPG?gNMxlr&n7{7iObi--(&F}EgOM`S99@R$FE(! zt|UZeb<$gY=>R^lfVTwbZj@~G?`ju5ghav+ezW|#Ze=}`DtWkdLL z)#}$YZk*cT`zSn@kt5}2~dP!PZjY)JzZAl`*vG}5HVJ-f21hIT4p>PGui^>kDB6|qlx70m zlhKl8k=_Ak(bHk(h}y|{5Lz6n24HmLnR!Q*g>(1EDddGc_@}1s_uF{fARs+jz*A-{18g?}wapx3mhsfpkQp4kd zzzaEk#y@jn)J_jZ;t1`lgdMSIDcYZ;ah&LyPsm*lFb2#83_U36iR@~96I z;d~Gc!3wS{m*WTc&*a^a%u0#3byPphuAc4QmNBe*o?+wffsAk`4iS*MV&;ufyn&pp4@i71^- zH@(G5UVwHlTJbKtBk7k8bMa2S@n#HkqxZpiYa0A)q+4OViQ_g8I%yWQkC{Uo!rcif zI4uTMsOaWQ9P5e51i{0&Fax{Ldz*M#^)(EOSAbQ;XR$n;s!Mi`M@x!j${kFT3yG}j zQ?B!n$>~%dliaVAlO6cq8Gm(vPK#y1^!w80eIYQOdD0>QXIWZ`>n@_7XDEM9VKSN?GaweU1X zt}4NTSP12N0#gbAQW}dlUW|zRPBpD<3Mo91e^1yZ%+}=w%97ysE(H0lJj9)I0(-pM z#{=5^@u}tB?;u8i`xW4`|92$>_uT4aIG9{F~s^ zCu~C*foD|)HF3qRW&OmnRRN>jnpJ~mJc+vyLubb*C&S*8+B{LXS-m`1_1P)jTM3NY+z$&=SD0;=3Mqd-Crk4YS6<0ppuih~Zfd zRzQNtm7#P+-~B7#)4t`_9_?fBr(G`!k|@uVHQe5Qrf1dby2!?BInk*yiIUIb{H=2f z5#E|c^>VO^zx4evjMY^C@$dh!175wZ&RZ%sswtR$3e{yRKdIk{z%Wa}B5+Ka@#RBb zjS+R4j%s_iVj%Z~-#pN+$sfPew@i>6?@lw+#BN0(k&%vW^lsR*F}eIyi6=kO&z!UMkh0PqOP_c3=R&G;H`BE|!pMvEQU#25h#W~}JCeTdbkOCi zCYtm9VJ5De7Nl8D=shXOo4|jlpU41TS$&}z@-76s+#ptaW>vORoOk%&Cm}lL@;OR> zPdr1eIBQi`fv1x^H`|S)@@H_AkM92DH9*@Jy1iqkuNiX+l$?8*9iH zT1saJ&TNMe|NZRx=xh-3W~)1rP%(zZ(}N~kED!S}igOgOTM<>OoqAaPMTeqbZa~(Y zp?SFGVtfjRnJ!+OB~Mobd!M;>?Qi+|bAt@h*jCX2kKU>q`B!?FBE-F0H7tDoaN^sB{W$uylIoLqZE z3Cn%N4M2&+hGgOMEwB z5HV`1dI8vk8R{y^#M!o11uu%XuX2bMrN#x(M=v4+>&q!5cG@SyfVt&!WWU>J@&8^dM~^ER)!)0p+$uz!=ZaN$ zBnxV%dG|2NTD`f{HCvV77_RSAF54~#YQCn;llhf;IUK%vRX%J9od0&Juk|NzF2*A03u8&^JMBbHD$l)o4Ts~)J_~NiCZPV!-rtKjbtwrA%Se#;LXm|` zFiUKr^0Dw+eA$~y@VJWri` z=F|GaoANOmxqfIzX0E}v^`Hh{GL`3p<+0ig#88fSE4 zy~7cH;#j@%NSMR2x&P_x$5Wqp9YVN&kmygn?~;+wHUXfOXdzi-J z$MZMceb8V)J0K<+0NunhcLZyzLdx0CJgW`AD?6CTdgTd1k9+88D_(e8Vhw(P-O z4p^~xpVXW*v;0{GG7a8azBn^#jxZYkp)Q$V*jI#&S-9|x4qYd6w|h}zm_neA!8a#9 z1LyZE_3i=@-2bu5KtKZABo+? z9mK@Ov{F0#a~bS~nu#>hko7dG(7C$`V3yQKRWZUAtXbdj%lbNsy`nstL9x&vU(s1V zxyr|^A~-te1@+-(WUxWvz?z;?&qljiFqQp6te~`qPw5(96xV9SpGSG*sqvmfS+K8$ z{p`;!s}2ZHZ^_HE5B}cbyslDlt?|%oY`A5kYd%mlvXvajxNHb`^!aMC6MKtJ&+vzc?dQIc>NuZPHuS zVMyFB{%ZF|-_jQly$CD4JS@zU=F=RkSPSl5k#7~Em{`Edp(e~<&5>1$M z8X|ZoxhjM|Ni=!3(FRl)pN=P;4V;+(`VOwD?&|#nzg$>^91vX#$J80KE2Os&mv_$` zxKIAD2J3kk?k}vg5{N9Z!c!Wknef_x?Uy-FJ-M zNnyj2SiivdXP2vkEjUp0a8gk+FXh<`w4SZ+wr{24`*(Gvtg|%_7e7VpBARfIwQW6N zr|27l9hG}AWTWGw2Q}UB#pUUib#&0b`&L&_Ny@(<$BTQ7Uw4sOSjZ~ZfQB&o`yc-9 zLXXpZZKNuGFdk9i>DGkY0FC-rfIJ;E$V~}B#pYo5;Ibs~FQ;f!zQS9Tho0{mQZR{L z=*q6QNnTTkT<9t_xx{se3D6u1TeX%sbhlo#7%3@70tuM`RDgJdj9l%`q({j_NR|Wn zE0rTl0!!k)pZhUr)fR?>?qUVN>dK}F5e%@aE&8g84?#vu?SSN$f44v6y}4xdj0gFt z6K4LJJ9CBu*DBV@I6tX7SiOJuqr{Cs5HAbr*o=@ZVMy`SqBo*Zg5ALAQHcm+(B1Ww>esp$^`-u}^% znr|TIgHcJ^0y6i~kcaF}?s4s|$bmY507J_4EoJSeMz{2$e@%3)c@IwE>VZ=jWMHlbnY~tXY9R8vI&_3L&B~W##v77m=Fe)wzLi-5;1dd1 z=yV`)hwhV(c)tR=r}h?p&{9(0^0H?X)c&E_zsQt%DzSBg94nj2xc^h1*2tmkrnfjT zXrJ?vD~nbbfa^y(_S?-@TGZV>(Q2J-t*X1v&CSFrW}qx%j(7!pso9lqeEQ`lD?#?d z#T=7gac&~coL)B>4l1zm#Wkq8ypLrh%fPjnyC6g0JGiIyk?*?)o)Aj9Y8qikI{c5s&)-J?^d=)md9M za|=$p5U)kl-D6n>(I95b{IN0g%pr40!%U1cS(Ylhn-~w95wln^RjLs&yKu$S^tkCXkge{AsnP%JkMHW6`NMG6GsH+8uUd zFRoNLY&r!pAEV0&kBngK;`UA|G9LSDcM2soEw37dk3*{8|J{gcNG54s(^piBqg%xq zZk!8!+kJM>QL#w!5~i%RfXi@o_~0oO*gH|2SE|LoH~P#JCZK-00aZy}nb#fjGb~BK z+JI8z+&wY71L6(}x8`*WN2%qMe|4$hSwuOD^{3J1SByL?TxajOS@Y7|r$U6g%##;f zXm;f~snhg4fi#7&VN1IZqZ4J7`03xri;K5EoV8lTdQU+g!xKahZI1sX zD;k!7*#^;;Z{8f)0*k`f{VxO0+Hv%O9`Ypx9Db&@E8L0<7eE+e zQE7f>(za6`h_^+_*l?o`xgks3Q)#=@5K!VgMeJLHW=v5gZcGS2&uT4fOq;ePearYM zfgl%>stsm`^%0!~g%zdx{e7>H1|k@>-skyD225N`Jkc{@jCES$4jrt=fE;%PM|et0 z-PVS=kH|qCFTn<*i?dVH+c{ouXIo?_cMz2c?TT3HiX3XJ>t|fFu(P>|b*_nk-{k8#j%(Fu!1|IMt?4(kz1cQ%-b5#g z+J$&OA)>$T;P*kV0EwA1J+t9mfG0d)k(Yjx4P``R$ny%$ZL1Y+H> zMUp;@7qLwq*Ah*QY3yKbA$7NyRP>hK{%qecydG=K((9&3C3@2LsgekrO~r3YL7%%> zfLw54*!)*Mk4+vjObogbqymER$R~2TqMdUq1jBaEpeAl&n5sWF`(1<4a6(BBdL$JI zbz!c3g&w;g1TSKIfIHhHHex&e!uEUQ@9GNwF4b_Sz-g*Z4s3gCAEx2<rsfy^eF74L`unVvo;7x3`+ZuU@$viPzoa-nv+6)T%S5n&U}vQL&M+uZr#Vwkl_2&V-We> z>oDeu+mo^D*V2Y~8ip0^-4gfHNL?Kw3xetMzEHfGE#ISQ*15R*kGNOBrt&jOK?)TI zx!96ud8oSahBr@9O`VS4mamnbOSxh@?b7W@f9fCAebDWYo-3g}TBVD_-g<^9{|8nM zaMaT)fVrjJ+J@omx}utng|2}=4n#T^W)2UV3)QlTZe}z8rHY{iT05Ba0gs?Hvn#@_ zT|eZp5V-6$U7+;DE1qTu1!}n^jx`mMJ1gytO&{OZi#xpQdxrv34?)yupJB7^b_h?y zX!kOKr~FhajvdY8$2NExK&Bw0Fq&p|ns{FA?eqJX@5sk`b=x_w=j*9)x~gQ%rOF=V zAGx2?s4Y9ZZrwx&p-0A;(iF2JM9w#CbohB;?(S=ExrzCIi8zr*!oPez*=HxG=;|Px zR*oq|(fY^f+@^6Unvs-m#7l5o(=@mgU)C81*zij1NWRMgLSSaSmb4_>U!HRk?j=`b zMo!on5>}A1y-`Up8u{(F3)B9xmocTK>&r|&O7aN?(bTm@c?BxtDR%Z3xYv&leSHY+ zt=O7%Y3ddy(Tc0OBoi30$b;K&sr0d)#)lEDGkAM_Sg~rZF=bVJ^BnleZzZJBHB&ft zI-_=U*Eq}*C~JL42(g=@FE`ar6|3t~Bp_|W4$eMLzTA6LPOLT=Yb!T7VUiLSQxYH5?dwjkrtCR85LR;2c)DV7L z5C10(dtVEjM$F|YUL(Jn-gkOFl@_h8$4~&arp7`zYmboJ$wITDRcKy5ME9k@6Vknr2WghaMX+>xiEh?qF(5uOuIX{0V^-MCgp@8v5 z*V$T+lXg;B);s&|4*d!28Ld^EpqV@tcXI+B-F-RR5Vd4G4#e)(3saVvmo$Y ze4!vBclvKpiSAd8mkd`TU!shquaCBENy3cm(M#dzD*%dJe`**?^QDG^TJDFw?qfR$ zc*Sd={89Nm@x}s?zRIO!n$iPIpprTd9m>_`N~bkug(b5+iM_4PSMofwlfC9S-D$Vk zaRSNQ8w;7 zsEN7!as&lWmijt>j;;7etK&zZ3M^9qpltc;D5uiw!2Wy(vU-FyAcB2Ob97Q$`ADqh za9G(ty)ha&UhwD@c zAzrM;d?3mQaaKFp!y1J!w>I`2p#(7YLSwiaq*_7I_)80wbRXqMGS3^z!m34_`ws10 zfP2+YP?Zn%%y)U*NSO5~fiWC~-F#OTYvvw#Hi} znn9DWaK6O_`9v}G$9C9SJJjT7?nzldryqBo5blxGny-y!LJeGJ_0j{_blj2F}{ zSu_N97WOrFcMv$M+}E1d@UfE|>H!=?Jrs zfyoQLvp?H{5$L!J2#yV(FtVXN-B*kORjLmRqqS05FiXo5bj_OFyNUxxbH1R-KUG&R z7*AFf3Ffq>gMC#s+k!uyXs+74d_e3YW8YBqxJ<}55NT{a{cRLQ?qub`Wz^*c($mT! z!Xi8ouWvKvbRofGTT!m2mqES0sf&__NiOC)<5$ATnv|zpzoe1hYW6+2QxKmK?Ya_% z4}op}x^V0=uG!8kkCw{A9>g1QvuP` zs3)Va>#7#2m4AE>R(s_TvxC{6U;{-is&nJ(wc@q0`Y=_tk&y?l^5e?ALqXmsc{+=a z%8k-2bmNg4x#(ESPeZah6V-0zM+Kp`dPskj@`6k4KJ~K; z>zCX8qZhJWEY}dsd6D?xlGXeP*C_V20ok*3-wPT{-&{BzMalv6FAkJ~@yD*Dfl-9wsV zIGpv@(uWo^3ff(QId%UIgb2`$wOi)I(tsKH=Az%4_|>B1j(h=mt#}e;b)~tKT`xt5NvLN~Qy&vQhsyGE4?}pi#bbt~0llC}I{K%| z*_o&Yl~O*Gr*wm~DIV?DuYk=B!yG@IQYcOqu-)9r9TltCAj7X=x=Q`7q=>*SM0Z#S z7}6SG(`31FZGlo+4dq-4RF~n_8RccGM@%Yq0m3U47B1s8}DVh?}{CE$UCvS-6KD5$Pz*QjD>cbz%epAEMN7T3dWww zlk=;boQn0xyhCJS+*im*nAgL3qJJMhJb(90$8Nmv;Kbmn#2Q&T6Y}F}tz#SWo*U>D zz?GivfHu%V;$YKRQJk(Lm>FEKK!_do7vErnN1wc5sjvuXMgco(hRV*bKbWGf4)3N1 ztDw6$kx$2s9LM?El6r6}tBW|JinNll*H#NLS(tz5Ru2+!d9;kj8j&qY^R!R~5$9(% zFqM_z&wP>iR`&ijC521oSF+z^bh|T_Cb_SOP2YCP=|*bV$CQvJm2keNv_ntz*glO} z#?AQC_}dB=JC+0`;nFeJzukW~fyhsoWWh_%3u}vU?Uh%@H;P}V1mpN^c=BvFae`u1(8MJ2L z_XZyar!Or`aa)f_SX-VRgEaECF zd~;2CdpI(R=bb1P3%nyR%$gzA15)&EUW|0o0hRZ-Mq#LuvM6rW(^vjD@7?TuJ*@~u zeKSFa5wdp(d3V=WPvSJ^A-|RkQ^O&LGR>a~VLIl$7`` zQ*F2lrz!Q1&dGOvgumSD*5P+=qGtm-qqxb>!Lj=hS;G2{S5UQadNKii#NvY1CqJoA zx4x6x9a=O}9I+pKIp?6nxx0sdH9o(-u!CfwIFs_fq@!3{*DE)KTO<USD%g$^Mq1sp@N0dW#Ymdi9Sb~~d zYX*f6rW#8xd@^CU#$AwIiT>aO;t7F zadrF;aDw~`Cw^}%>b%+ti?Zk49hJoM0*)h7y}N5s3y^#arHBVV)pD{!MApiq^gsc= zFCY)rcd!MPv7MQnpgw4qIpA_bV&iC{AYR#rdX0Wm3*19lJG2mFmVW?Ni>FR(!THIs zse-VDTWcg2d3Rks5kqgC^|4hY@TerX!j+0>ArB6WnBcL zC3m)Uu1y+W6B}Pu8t`8im-JfHpWK!f&@hGXd$+sb66yW*Mr4GjMcxnAX&oqKpY?dN z@gHi}l>*1UX`sYm3clI>Hc0}K+*f){{9PI{47ASh>2jyssZ`z(;U$hti^O?F3**r! zA|NBs`jl7?vMdi;d6WzeGvdT1|L&Jh+4BqGL@?aCqS7K>JIvLC`hGnsyQhv}Zsi|9 zOFs-w^N%=+koN3dWv_I&RK8xJtK|E^`L^tdTu!wFb~WdS*15gQ+b^fIT%+V_U4l=n zaz?K2We^PzLZlyd+DgP3!Lu99I1XqEFZj)C9?AAwR#6&rLHdZy0*(gis9kG@9rzld z4taawSQV0y4HA|b0I(WzWYt(7cs8PM3c^I(ND;_?#60n7|6ZUArjFLjrxVc9RQYi? z$zuhHKAqEY0*Qu121xg5%PS{voh4#zyG%iWz`yv*9}^T?alQcc%QFTp#N3|FvjXN8 zuJh~U9M@O_b$pejo^c*kX6iY)!S>dPXKpD-%7=PwU(fo#E_}w-U8(=$CRA?a=d+uNwUy&UcwTF^s);i;fjL_5Ha>9A{*j)YAyX+PgfS zO=5gY{@TBt*&#L_#a>G@3MF}A93E#6G$uMJr;(Jryyl1Hls#K?G$puzS!8qgwNTIU znrIOw^>Xu=-fYK%CRzEeB!Si&tQ>5iTHW2`VAw`04(ro^;x4~%-+TSwttM8$C2$Gg z6Wlu7j2Ja}sg_x2xLsZ5K}}Yy&K>-qA0%*txsey^2Te-gN<|0x2PD0go_Nw{rAUK6 zCYuW_6FHmJyTX2T5jp>-3DJSjODB)~#@t#@se!6>k374#ymL`?E zfl2djb}<0T!}gU3+C~ayDVU2?i#-2|ol5z2LE0zQtbReU^I18VUTRcNi7KYFWiNK3 zRUfs#yR%k=oyOi5#>gRG{Ivc1ps>jFG=Uqb`HnI>+JLI{HFH9jMZP~;^T!Huk}Cw4 z#x*2X4R-UH?Ly9~k5s{0*b1a4&qKf-FZ)nq=cD`9aqqchkhD8O^(4bJeZgF6V|K0~ zaW4TK2WJ2>D%C`0tJm-3`u*!yvtsFt@4p%cPvhft8>zEVPh3LR%-k770!;LJIUmnu zyKi#U#=I^3pXam91FTzLg`C6XRM)mL{B-i5fUpxd#jvoY5(XCl+-j_R2PR6iJK-dY z)2KgqpF%WAazE0#6^~`>-4N}yTm@<{7Ljc#0#u~7?CmnqI9=K4wD~!8I^YjNLg`QT zl-SGkg(SXjZSs-)*efN#mv%}dOMw42T7$~wDSH>&@nV5}@nrOJGdfagw^$GCKy{P5 zyuszljf-aJ(-wz2kXJ!iA{;y%SN6tqXcsbR+xNib6}_PpcvDnU%|;23_~_}y30)9O z(C7M?wksrib-lb2YI(PH`^Mf~*+V5si>fy;cCx~f{ZSZS%4f!C zEihXNJlTnVM9Z`t{q;`!pgnsOaF6&8AgX9B=a8u^F|!EguzQm)HAUGXmL$?yIRr9_ zSd#X%D5_$zal~pd6@n&Jn4!eOgFp(hcu=G{X#N5*Q0q#eb}Mzinf5R{={q!OmN~8z zYr~S&*7hh5D@|j5Z~1*!J;eI_vJgVdTOTtWl_iMzcq|S1&imztkZt1NL`GbB>(k@x z`?D)$=f;^n#A2YE`6$5zm)N9N4fBt1np*&40dEoyz8&Jzs=4@i$j=ko(3}m!jNm_O zSYGp351IDi)ExR*G43@=ZvtpBm;uVSpH^SSDFS_)ozLHJg$F!l1b%X_F4(J%am+ z)-S(GaQ9zmrlko!hv2Ji{kS^u;#wX$%q$@ej}0Uns@-m4S~4DBuz^(ov%`9ZKByl z+QSCf?4A)Xx~80ZTxq{%M>qj!QZs!yq9^yWqfcH&)$U4@JDVgKx@G*5Q}}%!sFGS z`qsO)7}`1Ah+0$SDxjKy4gwI8>9^$B(I1AZ_Aw4!0>Ds|#f?mP$Hit)zSBs2EK;81 zkkM~52=iiGB(zan&3fU{9E^vy~-9%6w^^>Ml8j6^1ioI3ym*GW0et z@oBSqcO&SM%ptT%)fy>eKfe}HCLVyvOGiTud&T7Q2u2l}SV-Wu(sJ!Rcd1`AwigZt z1k@CNQfp&HougFk%Y8lOTzAx-%Uxz-d1ZUnUMfKb>FfHWLx0FbUTMR1!F2pC5_Tis@-9bLwJ&)R;%( zc_9pgW2Kdws*BI_g-_oV_ENawr9UMbc#hlHcuwgfV4MJHGZbS`&#?UNGO3xUssCb$ z$$JyN>kz$;>-~F>%RX@c(bnSLRLxxR_7)Kq0&$5tw|nq+m3s9Vf90g0g&UALd@TcA zxCOmy_?D@|jn<}2z1^8jtLdQnyE#3h0wfOk3TXCvdO)75?eM* z>QSM%vpK*y+G+2p%CcLRVGPYJ(d#+QKTZA^G*x3^B#G&tr02Cc4bf?LC%yj(PH2>s zjJ*$sjkyKw-!)$LO9mm3o?ZZ+)u`k|EGO6~x zLMrKsvR(oZDX!sxV5P2j2W<`dr21*Q1DB)o(}wxS!{LhekBhGo&Tu9Ke>l7|8}!!s zZ2pi&W>yK9oyZnsDd<1udH@gNJ`;PMNAUSCIs+rfkN=Q23Yc&os0lTS74eu)HmP3` z`~#$oVL!?4=I{@o?Dl`bFnjR_!So}e4O#cV&Fb<+ODFV=@xWH-i}j#M8%!T9XZQ9! zkYTwS*6%FLC{zBJ)#c?M%VTrFd(wKJ>)dG`IUIifJ_>7)hkunS0(nO`nthaEUXE&_ zhTWid8?_f}!&Vz4H7N~~w<&sWiY=;&pgf9>4GY)dM2BNjdF(-hn(}>rulb{8c7C15 z3WZrWf47eTY~V~D|B6Yd$ze31B`=(naG(FM;s?b1@3hIkz4XoDfe6ckk7W=J4@5>h zsRHhSq4%z|=$l;7KScF&Z;tTU{+Zy|GShs`Q|3pPz5DQ_(N$$n%Rd02 zA*kFBS0Hh z5bKC#Ta%~5c9y_h-m^ipgyUy;NV0baMAT}3X8*G_V_ z2ekd`kaIw!cJP(C2beHyMNtREUrjBn=}2BS<@#=Js%4xLJiC@2C&%(}6R?|$b^xhq z^`yIgw;!%5FWex;;wZY#%pH~GQAc$jEi6;*Gm$stHOI}Z7b;H4D+1U3Ovw_*#1mRM zz4{MO8R{AzYmkL96>KPfT_CMxr|E=Ov5a8Sh)4DC=iHFwx(F;-)279J=pFP!0w-N1 z%+v}-hwN&+BHWqYTz-=OW`@IHGbx}xZnwI2(E(Z4#~r|x^xvEii+epO>@0YzFjB3H zdK&!)pyH@9dI-_vmp*12&PZPn!ZkYjYs>4vp4=l~PL@vVzrGf0RQ1GtiN*Uy$Vg6L z&Lthh0m71cTEL7i`IE^(o!kUY)`a4{?LXYzRW=;NfI@df0%TXyQt}|2+54Jm$F8*| zmKUKxRko77d*Q2OC`#V3_6s(KbzE7Yjhe2s%4SfW1i_upPCj_La_eg=Xd}HTHMhmO zANTdc*+>b3=(uEOa5=b$1AMz3|0Ho7$LdvhB>yp2HL5YYnAHel|jH3gu`FYy|-f{pt9(Zk6ANQ;Gk9 z@&{>yu|-D+J43T4wJ;my6j3FYuQGh2zH6GuQ%O=R3D+)w2oEaV>&9Q zfYyY}=wn3a^~T2c4@7kx9W`Pd?i0@ZgA{P<&suKt`)0adk_?ix$Lr8DE+ktXU@qjQ z2s6Gc{DxKpHuM0$D9+ceGTxbi>6(zVTuezKVtcp4E963K-ztfD`_`njA+f6~sRxFm zv7$?fPnfz*x<`6J><4Nl0{549r`ow8G7&s1#%LAme|C1)zXPwv&2+Qtzlomnk*`eD z#;SDizmD6bP1)&DT&7AYzf+)mgvF(K9=j@|8#3uNWmS>cfeT|^C-h2&pN5{ez%HQbaahuP}SCmQg5_0wt{{Zbauo~hYfCHpJo&8S7 z7}=sjHCsv1dNQ!=5r$7j%9$*q=o~2qwfTG`71bV{6YshJYhQBlP~q}!5$hKJ1GqUH zE5f>MmBq-*g_eK&%w2(=4AsO`6&gNGp?Am$@ zPHdw~pVH~0NyNAx4isL@Z|?H5jZVwpZy~4+<9fUN`a(Fwz(>rrEk7QujWyzS9+L+- zGuPASAb&mmVdAB4p>8Uq-oF8pCUKpa`X1PJb+WP=v-MjDUYsPa$8OLz|84|P?uo0b{*k_~HQu}D#6+7W+cK2s|jrO%C`Kt6ZKA$(vBA0Kj9M!X&H zhtpf+)B5|_BFj96bFE2l@A42urCoN3mXmWx6*AaaeNeUX&3>FX`MezhlBCAyJsA{! zLsB6BL)n`Myy7!se^3iOxRy%*r|@e?vpNf^Konde-NPxbVaye=feNFeB1Ns1FDa09 zm<}lIAz@RbUpsV%h^kfl*BZvh13M=Atb)SyDX&XcskZ7{Dn_v+`Nj)n1nbLmr)+xU z`Ohe`39_sCtLK^v7nEbTe=+2?lq6J+NYFjCNrgM*R0 zek#aucU9O2mOy=e8HH_ky|WAtD^`mZHfXe!?}sFub4y2^-k>O7kF4wvWk>t7@ruyL z^ti!NdRXOz8>40sE`L{-BRS4IHQ$E$clyqzaHa-keu1d0XNAQ9_9ko>OI*` z$^|Xgh3#p~wIl=L16+o>UQg=woxOuq8qTY;Sh=HJXW;ioDe@dIIyk-q(CS>`o6QO| zcBb-Z@40VVcC7VAOgWYrv91v2d?iX8F-WCDheBrzjPW3HK>C`+_h_LiAVE?a&EegZ z^vt9m+n%lyC79!q&iU9%+cC>jyBdX)i4f*8E^Nu_A%+~3tA6=*a%2B!(21-1VAaDa#laJS6~N>{nQ2qlBjcxJ_sGD|LAdFO5#9)v_UTL1A43 zd;?$&-j)!wmqqG!wy@9MI*Mg6mK5_Bkg>(!sW$O?C9N0AqMbG0qr}cMnWjyK*0*&g zc2q3P_@X!+t32+kN$ddGMRljmpYO#+S~kSpF9c3!TF=jE(uT5Gtejkki8g2gKA^KT z|MDzZ%|4VayJ-G9_u^-%9resO_#YwnSa0O(sil4bMJZ2O*r9)7{1n92LF6XSTFp_& zwBvgCZo+?Z*I=Bd^X_-4%^5vs&U&d^tQwW~BM8d84tuQJchu{EXTy)L9sU&(Zkz=t z-B5?tRO*l5X8-6fCD^oAoNF={rijnZqIzOg{cs#_8wF(8@4{pm-gcqV(nTK-dR5(| ziPXcwP0#33R1S*Lqjobf-%J2oP-=Dvx z5YbiMA^*xcc_$!NpgMP#s@gE5C4jLA{%$)+CRv4YwNrP&Q$pJ?n-d_?QYYz|cRl9) zqGe<0p%wp=y?-f7j%OB4Z^LMz&^7xri-qpclSk!r#98}0TcF%UhI2c@31Ik5`PjgC zpv&X$nA|hktphz)^`kBK0HrwGbCx3Omj?~+5IPTOmk-zUiCOw$Ke_voS<)V)5#z#t zuGKoPw!%VajBQUpYeGLo{gwVub_do+iKf*~l2>Lj8@e>ggS|3ErqSvFO#a=~h>>CS zPW8OBmSuY;vGz#|d?YdE=W83l5JHOp4~^LYaG{2WsA(q87}0)wkizE7x%sYi<;R9} zvzVyYYh-iaX{@87hUWT@^>}spx8vmFIQTJV@k4^eZ?5m-Mmfn_`oWE_t0lCM$Grft zBo95GuZoFsF)j&rJkyF_3tmXHlNK_+XsAlNWd!~ow7UNjzYnj4bgR$4?#;(DrKMFx zNh%PY(;k@^|; z!&4wRl)kWFwN1K*nR$^xZmwz=59g%U>E<8{BHQH(xK(|##sWB{^)}_+DC_n_$xu%5 zKb0Zt(8z*xs48TaI5{X}c<>Z~yzhqY3Aix)XzG$5n6Ufp%;=y61pV!fmhN;lH^mmj z)c1R&6~B9nZBpu_c*-}_GItbwT8@3ii?{Y4ep*G z=HxNOY>Spv9QX~(o8OM33CTuXH;*ssYDDRBY)&zUPk9~)WYd36vG(uqUu<#`M@?u0 zQb(HYjR$05a_I~|cat3(D9+3FY4eUkYAmre0gR*#9-Sf^TQ z9LcEde&;cqOQc?gv`z2PWe400>K#!nC~s@xTV-WQSmH0`8duqcNb*fBsiMEkqfor( zGA7hyC?V$F7h|GIq6x=0sQ2`!k#j(5jTO|TrQ!qxHyzjC4H7^6{^euRR(q3ff6wuC zZJxP?lU|75+jf=l^Vi- zTR#4I5IKzjNym-C=1`=B1Jm~yPDR3-_whU@cIbztt{h;O0f4tjEEb~7cj;hIrKLFf zA6jG0J;DKprY7~()!Oa$^8HD1Oc7W$o}k6Lhucja`JgQP>`wK&;-I6S?#*9|E7IqJ zHE*{$WFn<#GiOqRVJW)ziFD_Y%hm6CF~=6$x2QWs<@)RNPpZ#OP};?8^FT6}>kO?_ z&kOyUNuFXRSXKg_aJelxzpP|y&xO>;(&5r@(s_FA#jdt;hUU&Ig;ZX596oJVJx= zmIrGL#unPIkk&^HAvM&^AvDfqOTK;$nJ&V!5UaF3#z4?LtN1NR@oL^ZVxa8OsIfb> zx@we%q(hB9b*Bno#Ht6rM!WNIg=Ky33}c{@=z?nY8g3M{ z`4veM6pW2d<6q+^<4^<6h5lSRW~)BWceGKXuK}3LP0TZ#!EszNDgq40@z3*3`}4ln zwiZiAwNkQuKknf(GN@mVi!QRB_zCDaPzuBcvU20T2uoh*dpCbDj{=#+S!6R*zmied z=muGIwti9>H7@}pj$sdZ2i~|H@>DP}wxwyra@AOltjW0}wZ2V>i!HQaCQVx7ICVfw z`6U8j(N61@s0~ayxdCfs5Y&Xj`Wb-#X=y5g#JHy4w9}guEiej{B{|jU+@^NUF2FLy z%+6lHN8VZxJC9@H7cDctM>UDpGG1|&+6VOri^>chvKh!HR3M3uv%UzD%WPsot&j!r z@Ym0zo8cxMMm4MEpzoHB=w{UfRz1_@P45K+taq1CibVWb(Ut_+Q>UIl1MfR8z)yGO z-&Ni0I^vVUF}Uqf*s)B77G{*V)GTcVR9ymRnh3_fK~_jEKbZddH7XRyK=Ey-;!lf^ z%u5?9pJmd0>}Z9lp>O2@2;!YVc=Ex(kA%Bak;hz-pZlU;wof&B-%Rxp%~hCoU(VH6 z(9a!FYnr8IxuvdGfYo0Qd}!@-k+CQwh+|T?!mk=@8&Aexx-^2bG`r=${t_{vj~{6e z)CZn{tfe{91xf9XqdS-^1&=gMMfhMM4mX?gA-6md8nX1&N^r;YXfGMYd_frDg%R;G z@FFdFXy?i$MEbWESH5`rrf>!lC1aj+aAI`}9HxGr+!iR&6H)WjFRP{J7^J zB(yH$I~WmW3VB{|HquXpGnr8>zyaNe|ye6t$@U7zeFja`0qScIF(1^b&hY)Z^ik^ z0+s%5Tl>5j>?q_>ewKw9gxaceQL$A<2P}e&iY+`P@3q|Df=dwK#lFQ2~og3mGb(#N`?+A`LmGA7nK+S>oaG6(hPYquuiz$7N z0jqxekf?e$6ALW5%vRCG;ZAz1#uzDNM82j(KMD*$6C=CSWK8|)0hp1SWu{3=@OxIa z39(?gR|awu@#lm5ZrZ?ZRsg~uroh!lW~@3JJ|e3!E2r(jn{mD7k*?A*V6t(W8PzAR z-Hn1J?nx|ti5Mj=5&vNxid&+4$ZET5xmu-%pii#|D)nME$~XhV+DSv6MGHQ*?x2fs zG82tN4`YH*AUS3GJ%z2r{IA&v*-1DM6a&YwO~t{N;Rt+_*qL3-T?r zghr+aFfco(gc%J8{H{U#w1n9iEs(YWK5&n6I9dDb)SR^oy zA7$`Zf`y^~emM7^hIPbxiQXTnV#poyXD)D8EN?Ig#gUc8rS%tpBQn$!m{?N_miz+G zi}+RV)+yp2wk_STTyW_h;t9O=sw?$XTKV*P4Cp_b_%z%NR-GzCxPcc@F&SzUq9>Y2 zYCoWG!J2~!y@<7^aWDi>`|X zC&?_Hwk;hE#O4$R2w5UGL$AdkL~=Kg_d2qcTypLfA2YMQuKC0i5!1-FE_}Ts1T)`qD!M@iL-p$R1&S;Sm`cyX| z1Xc*v`O@KiX1X>o)pwOfb}68S$$7j`9|2Lsq5q}OMzQAv-pfzRRR0DN`;JAfihBE!7;Q(k3Op?p zsVy7Tw&33#&r*~Lv!j3X%dJ;6r!n?O9Yl}GxjTIJWr4kq<<*nI*1X(?$Yl#6kWpEP+9T9LJqNNqj%J-}HB<^7lx(t^T0MC`;6~RPiLq5%`HsgLc;&O;xRl6Wcz~ z{}Q0Qt0atOSJ`#EP9ED^40X$gS)G|f%SZHngEyjl>N9RH#f7&X@;NDd`Vk1Q^+RW; z7dBAO&-X^hv$H_J46DtmD#|2L=a$=2Cq!ju!=KxM2rd+uTjH0)G>t{HRbYYs;W9^M z*3ud$Eu`P>34mL`%`=|vSFxtm?^fSBXk%?ePyD;f96w>SYG_qC5?YXviUSVgl)P>( zHQh($+?~+%iPe4nR`U<-8HYlR3KT?^bD3=`opn~0fEOM7Omy0aaed?%>BnY&&)cyl zdHM>$_#O{vL_fYQS1(g|lWx}4HPv+fG!DcYo?GFNys62f#kd>fS#!-`^-_GT<_=o! zbLl>S`~!R(&dL+E-(V)y^>IZS3ank6kl|!LN5Lk8-`K$v3Q|#2~Xv28K=( z{T!!y9Dlr(a{hk+TU|b?A+Q$dzUbT{LK0rbgotEOa`2T1BYH;3-_f_5Z@-i?_RhpS zfKhiBHuoE3S!Amo@jKQFpV{GrYI{Az;1*iNJ}4MjvGPZ=eX(lv9NC;HXo9;;+6-tb za(RQvlV9;+37f8KckS=;c;0-1gX>>ps(`_k^2quu6|76$DeR0r_tQ96A&;^d#e<<4 z%F5+JmLQ$o0vGA)BaedLT2yCmQ|03>I5BH!a@1*bXDA>Th`up&YlXE=IHKRx@2e1o zN!{i~h2tnE12yIyRRT6yBa(>gkCHbQT}`!hJT#xG7MvDNlTi8%5PTlOaMy9xop1`J z`Y`^q99f@u!f*7fwC6d=B_Z07RWA;6Q@GU_nGQj>*5-!hChyFvHGYWUx=xhKgg7}S zN&$bVgWa2->92IZi#~t57Tj?}X+%D_&uI!7-ju;nT7}u9qs8K3WU!uSb@}5pFoqy1 zS7wryJj1MMA=|xR?S!!A*LSrKkk{n1PvB#Jjfvt9zwQyRTc+t$vn-*GsP=s zf}G@5S7iiCF8{5R;Xg&o|ByLguYFFCoF0DApRKTJOy#p+_y_otTyHL5@1@Sd1mg0_ zlO682=3N*ebJX+{I617)E8QNsE&AC}IuEI(TW_nOYYZ|=GnEl70NEz4@YI1xtYd42 zUQ0Jq4?DOaUKw-4(ifo_$z$CuGnGIA#oE|=C9Hj2sD9rW1T-WV-P77D3j(1IJ(N=r zOs#ABD#;QIljLh5I+&f=m3V)#dYJ+#zvRZ-J0O_r%Va;;`bJ)8HyXxxAlygCV0T^U zU<()oaAqq>yq-L1h91GZ93=W8a^$;L6>|2wiEgOkUChk&jkN>WTxEk%;MroauXF1n z?jMvDQS(K;_|hY0&R1&9-p5Lv>X0UdtjCnR)nNG9lP$<_W+d)npx*X7!W23s-N5&Y zRa6D6u5J(_>iBMo6LlA_6F&TfP|Hr9J}-?)8)p^xPOdxa)tJs`^}p?h56Riy;oC3e zYN>%`|B2UwQRJNn$^nun@4m0iY^6z}vD+FPWyUlGDS6{mrD^(#O~u82gzn;j8Kuja zXfsVdLY%L(MkDXgbibVqw|uykP5v-0$L>EsRrcSK1+`;@VsymXCnIZGd-b~s(X3ak zy27>kPa&W4im%1H%>qws+L{DD54@Vge}C;9Brts6v!N8TRqoV4tNB3(!|lTRkX+-c zCtgU{xD59@|E_3o(P4TRrQtZuT+&d*VdyvNW=~5KXDxkq;6?0xEJfX*!A>e0Fh-YF z<84*m5CJaDQbeFI4z&qud696mfv? zihF^uv>kR+>OhZ4pu0K^vTR6DYf11M%`KE6J0>Cd1K> zx>;z8(I=1Z>~w$kK9@NJm2W==Zt~_J$_||I^b4Hb8sL6v7`8kkDqP*Essz9cP!R$~ z^9pY787OA=B(XMJ4P{O$x98j*ue4EG59hGDO1K}%zQ<6jQotYVwDsm~oUTQuMLT5o zq!{ySn0MrMv`v%#;!@-gqaf!MjJqP=sX!X^;(ejUQrzvhoX?5y5U)I^<(Np4 zTSg0ZnIPsspnf)0h_4^7@>5@!GuFbb4(wr681KJgz+Y_|py2i!vV}k$w&QVZM!%-4; z-#rB}>3EXFSQqU^D5zB%SmWn_(><8P`w1!f$km7+7`e88-a!-p3S|Z5shOwN9HGEx z{%j#n4&QQkk}V(3f$$K+g@Ukr%pYzK8tLg&c1w0392LaT0nela)vc$sJzsQXsm!TPMUuiWk$A9O@qO>R@3$=;4hv8*O6)!%Q7SzPz ze-uKJrmx?gQ3239b-C!3pn*iC5ssKVGRTXmp{7mI{1s6as%DF_d?LFIuzX)<`ftBm;-ra0oqY-{?H&rur6|2QP;45zgHNk>gMXgaQ%8XrI> z6qBXv`f|uERx4g zqhrI@g#5P}i~p=DpH<4wLEZ_<3eEf?-`hesn-5}g~qQKbEp+??RdAf#ce`Dh%0w2E&Vyrkulv)O0EJZx{Wdh~$1 zHTL<-@qC%ureb5$OG!&-`&xR7v>OObh*+S-k(-f%$>oc*Do{2beIpyh2-ke6$_26Y zQcyvpG-OE8;si0mH%G<5n7W>~B{i^%57`nMF)mYXR0UrmIK^>pvNDf{v%pIIjQD^x zHM0!$qkb05J#SxVy#wVuJ!3y1yhx@mYMvGKZce{k1gC-&AcuOrtwS_|m5A{FGROR% SUyAiV&p!WOeFy8`^8W(VD)N2+ literal 0 HcmV?d00001 diff --git a/src/instruments/instrumentImages/accordeonOld.jpg b/src/instruments/instrumentImages/accordeonOld.jpg new file mode 100755 index 0000000000000000000000000000000000000000..68ee03b922b6bafbdc9f294d93415da155763956 GIT binary patch literal 129956 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 XUdw;io&U+Q_5U_>{r_D3_v?QE24sx$ literal 0 HcmV?d00001 diff --git a/src/instruments/instrumentImages/celesta.jpg b/src/instruments/instrumentImages/celesta.jpg new file mode 100755 index 0000000000000000000000000000000000000000..2cb012b4b6382f5269b8baf5df36b6274291f527 GIT binary patch literal 44497 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�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 literal 0 HcmV?d00001 diff --git a/src/instruments/instrumentImages/celestaOld.jpg b/src/instruments/instrumentImages/celestaOld.jpg new file mode 100755 index 0000000000000000000000000000000000000000..fdec1540029f5fbebd88a67af16cc21ffce41799 GIT binary patch literal 269517 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 literal 0 HcmV?d00001 diff --git a/src/instruments/instrumentImages/guitare.jpg b/src/instruments/instrumentImages/guitare.jpg new file mode 100755 index 0000000000000000000000000000000000000000..33dcd50d5d733fa9fbdb40787c01e655f8b02317 GIT binary patch literal 20831 zcmb4qWmp_twr=ADcSz$92=4Cg?(PuWCAbsZf)fbt?(P!Y-8HzoUS`gD=1YeA>8)1OS+a0RVaJ*Cjvz01_M=90D8?0s`^_D7|wtvY1$VdcoC=m3hbbN&TXbg;yM8viNf=uXo8J|d)eURT~5fuEx z+ql8NApVsG!&xkvp6&Uh zprYX?6aXj~0PH^%0swNzdOn1<(HW?3p+G<(z(GO5{#Eb4LLQtM@1K*?(&QU`cFXnf)eRgQI;L1n*b~s1%@j0#!q@ z;W2s5I~D*1=lV1_U9%Halehey#Zm9viq8$>_S&j{PeNh1_6%WVjhRZ{y(ihK{rV{> zrTb@(*4~p~pciU;C2j)$p*`wfGf)X3kzziu#~Wpw!b&~o`%hJ;#&-tQ_&rbPPNxv za04?GX}nc=^$%VD$_L`}H8Q;!l`{6XMOu5>guOAc!2N0cuFen~CF8aAF_*VYK`9aX zj60srnAcxMg3BMyb{uYG#!CI;Eu*P-OAcftT&GKyHpW3D$%}P2I=lsaBk{s6xMP|9 z6SwC+e^d(+;L6haaKx$@>4`|P$L^w}07G)QW;4{9z_uXutm%%3J)IAvps8GPxo}*K zg8st^0HO|`twjVae?5IlFOJO$5=yxovluGpvL<2sy>Qo7s%At%L%;ICrH$#0^`{SK z;&;RGl!$ZM^Y8C-R>H8#N!WIqt=^0z%(F%`uK@pvRa-|@(476}C`P-9j6a?5$h$|4 zCfKdGo@-G{5}nd@N5461P2IVk9PkErwN>%GmcCn?{MatqT6S;a5s~}T3P(H`0h|dM zeFgMf70C-6x@=?|PG#?H71S%0y#f-eU51(s$Lb0hT=q{qfByB<1rgsBiAgBa85=yE zzdXswb$n)XSn-%&Vp>ZUn6I`Nn`qcwsr4mPF0Zv zM=KkQ{$9LbaOnBdqQT{&^Nfcru9P0OeXE(w{|PR)wwzpsnTpS^m^_iUJhlFsYy1xb zNdIt4yR0(FXTgE$+^zjAc@lJH%f`5DxSU`#Y89fD*2MB1Yu3F#91#9}PLAg1^9fkD zFS1U?481w1Dzhz>*>FV?#%M*qG^D?&vbr3&`ut(pBGoZ0&Sc2hW2<-MYDFvX6Bkxg zjLX+iG?F0ji}$0tvT^8b)%(W)`#EZ(UNUIDpAqkJ;56RngE+dda$J3o@+V0Pa-~{f zSajqiw-=c;ujqd~K;mD_SMrf|k(!a(Y54d`Fu^F&-{b04ST>5rbP%3_R*SYQ`=?Jo zH4U>pgp@xU9=N8irvH%>2j%{yEI3(RW^Le#W;hpI62ri1u6S<(yH;l@ADfHbnyofZ z>IdUVOSvke%A$lh!qC(uYb#gBe<}ds-SR3Unszl~lv|RY>aN3_>T|g3 z`cb+~GRd-bXu|MYHKWWgg1o}a6}K0WIqQu71OW7Nr5hK_wS^=MB|1NbmBEZ_l(XDC zX-AeeQ*$<1#_z3skvU9pC{iQJ@uP@I=Se*JTK~tBf?k$P+p8^1;kbdr`Ns-_ghZ%i zF*cbRSz$<#gtC!b&eDy&i}s7{Kj~mU$0apf8EiRwdFy!dO63X-z!1dpTQ39`5QNGT zjh@b)-`ubNBL_ufVlGXnTyP&doVUL!Du~OQ=KmC2Z|X+@ovTbb)$ZSXxLNRz9Kh}{ zR&2Wz);p8jxk4^a4nqo#R@xLx5t|a5(mvC_hr8? zh)}pCFd)xw(ETfCSsV4)A6fuCA}5nm#m4FA=224K1SqH)^^OUJq&j_*tIf@si|gU4 z&!1{I2Y+@&!_K`Uc8)>~Gl(KFwS@3E%bBpL0bGwX9yO<3y+73e(1{)#C#~OmBRhw! z#ZGGTVq>tJP75npYoa{XYL4HezM%Xi2Y~vgvlA<;_^QWaGdf#GggE|90{}2^2ES-N zLQL}gH}Tj1AaBcI=(hzk2n6U0IPW085&u&VcusE`iiQ)9L#hU)l~ta$8|M$l-MrrE zFGELJ3JIGPwO*gfm!@3hG2^6KlZ~e*}!kp74wT)9K|fcy+N^ zV70uV!!DWv1`tA1S4r|&?JQAJ;;0_17BS0-mZ6qrZaf5yZMCF&d3$=+YwRs5z)?fT^ov8||J6!Vu)(cI|rgdt$i!@@b&sgSq3~a1MwT$;w%_AGWmf2;U~WS5Ov;ZKHh! za4PIh$tu>A7YDxrMy4Cv0`0nRJToPdGQI}JpD!k|PAu9dYJGSG6uohwQWk9bFp3ks zw&p8+2U=^QUisuscc(8Vxg(RYy|f!|l&}|9McG@-{k2k0W!-T6hZV`x?DMjGB2eQD z)h(LBd5%O@8P8s~w4Axk0R_DStsU}h!m*?ZWgh+Vp4nWX>Bc6z+9KKR@7}?}UKDX8 z5t6Bggma1n4@K>Wj~a=rGqdyeyl1|redu?oE1iW7p1LpRR9v;t3>N1s&E{`4mi=;V zH22&oP~GUit))@lP0QzD9bQAVO^DGA{be`65w*=2CQp>9Is9dgO1LU^nrUwHAmWnw z1L_t_x{RFN-6)-J3yq{zLv1ia>D{Ixp1o4MS(R~rcrt!W$yBv5H{WzZb0J__9U-et zDW3d;!Z*C>;8W&bg-mk{BaEb+-Qqj0H6rq%lNOmvIposQ6 z2q%-%FGOEPar32wd>pVaPDr+n(42_DZ~I2%e{r-duAueZjfswEE6Tyc6D}3OSza4i z)2uGxakyqldZIT5zh!X~?BXbRY)~s4q(6+eF>^?#FOSx}!S-mO2rI=%uH0=?@u7yt z@Yq|bt%lN6F`p_K8(h@#U|ZU%!o7wEsAbl*Sne2lTSm6bZn`|xT~Fjdf@0v-Z>1UITNrxfxw>T6b`dM& zlz**x-N##rw1tbkHi1UNZsOc@Ngh4zSeR_9{D?-Ecx&um#lUCBkB@HU)i$v@>0FPv zk7ZZbl7^XVurE=9BD_Uu8E*VMw|GJrv?TE&q{MKv+Z;jNpVqpcb8M;KTi_9a86&*l zeHF(pJSMpeN0N1%A_cN?{E3d3T2f4`VB|y@=GJ(1D#MRShF`@*qMp+Ywt#X4B?4dW zlB8-Jx2wLH^4cy>sR;lgh{qtB7cx3{TxCm9;j*XI6k4bg*O;D|fZVX9f`$JehfiC4eYX3OiJR{P8F zu07ZWaA%pI5|AQA`Q_M~x00u^;kH?!2Epx%mA`KpDR+!&$5ki3 z?v;1pk=wexJHv0gpIiqw*$L6w-~E8JTvU)?h~}cpycYM*kuY}9IfazcIA3#h@Y8qj z<|k(w9W8<_VAmN~Z$IGX@=U7yrsxuEDZX)tPG}+#X;?dwk->h{lLlu%?m0f7IouHo7RY)I-lMOW<@&SbKO>?R49D<(G^^N^FI$-w=!A6W(W6-`tNXnjQQ+iCVUKkLa&;4&MV;GZov~8p5^qV{(@y6iQWp(d$Z; zrbZxbxy!SQQ0~V^pl$9C)2m9AnC5q4r4UmB$&2Op`N3zFw< z&RO zPpg=}0D#!79;t$YF6G}r7vFZjn@!;2i9=6_wZ}-haTcD(u7EFzYj6?x^A~|G>RSS- zfs5udHFK78rsJk^V0YgCo@cOsFG%n;RoM{==zzHuY`D@)94WZUg}%`T1`&91rBX0V z9C}WSVjWl0r{Zj=FP+H6zC~8WUqI`C^Ntmamh9Mvp(&Gqp=#7nj%^K_T&F=hQLSRU zCL)hFV8=yRhHUr^DBCOS_{|pCs52o9@r4I9&5?iWGvP!8Twa`gUJxZu3R{ljuM+Cu z%&;c5PAJ0cz+UUjL!aIi91}LnV&#gD7&J`!p>AL5zMy7>hwMj(E~$(P?}eF$;C(pz zA$>(3)6(B<$HD>QLA=q#%>)ut`C~t%zud<|l;i$9%&>z^C(JLbMvIMgin!GgmCu9% zeFaTBD?8DOz|F{|JRK{t5nh*0Jg1hQnB(DoBg|C>8{WCNRy$ME12qFqbANk<1KX1; zCE^O%-%EOCFXH-whCR!FTjeBjvc;H#T;j91VB%S5N7gkuY92`!83(0p@$80nr}l>M zmaypmPBSPdBroXAMoW5=w!#dxVoBj5?$rMtfd66A5*U6pQ-w7(A){T~en7A>-mQ!yI>FQPpd1>B!0kS};&htg&>tina5e1BWO1M@+#)W; z8sccV#1v^kAW4Rm<$W@w%=$497|{eB3RWlNb`OD;s)`CM3$4cQ|ENpKh@5`Mye?D$ z3Qszv{2|YS>!7U&4ji>6W8kQ5uL%@c08Pa%9GG==cHl!jX8`pun3f(Lq&a$^Fi`Zf z7K*7iFFTw{;O3MtWO8>H+$4bS~uMu|?X?C{-R9=kvY^}eXO(TT0;V|rk zjFj0=TI=?_0UI62y&m3}T4uu!!5pjWAwW8hHirzwlcNV&M_n-%lGA8XE~k##tlvBIDa$!t@H}m z)?z)c&jw15_pMheh6PY&Vlm<5MnH*?X$0@TDW{8fHnMAk59tf>&2xH;_RK3*9|>)ME`Z+b>!=#ORCELe`@ z_2JS7qv2*fD`uQ5=DKyFx$vc_jG11Rb(Xi;H@(spCLiKLg&cN*m^QKStb@Kg0;vS= z+`fB|$Ue1xoeH5%b?i6_>RHGjec5WI8mYMZZhdxxdy6{ZB#Q~`pgB40`=RrVRNF9Z z9~cxjGy+%d5p-49^{6F=#?%kAv$7~V1rp-9O*fA@v@)tsCYQ?K%jz(;QgbB%#(bknvH*6QzXWDP9MQ!F02Aq4 zG35di(J6NcGBa%;G1)$S0e)ZJu@8kG$t-HaAfq2+^~c$AvTGchGoMSEF2l76rb%^b zw4iG(F%Tzxw!@OEZ!bdKLW|9Dj<03{XNLvQu&QIR(^?uSl~KCzbFo#jo83(3dv}dN zHmS(+qjbcRyhlG~%c3nIb)No%mwEJp>*$0c(0I)jl_i9o0is(gk-8Fh{wB(e%&jcI z9Lt+&G34kJTLS-!(` z{?hh0Ub=9SJ1`M$jhcjUm^L_mlc_Xn{+fK9DLS`00V4_Z^#6{)kpi1`Z34agojO%} zY0Xg%VwB+&+P7K9oGy=*3$eRC?tsoIG%6=Ou4QA10#RZ=-CW&hHj=am0yD z!ti75f?hQ73V{!DkGG9(k|m{yW3g+$%-t!#4Gz1&%fT6a=Q zMCSzuT3m)??0r5o8Vvl>m!vC;r4#J-!t(TEj+_$DfJ%Q|vN(<`5 z@RHxWL|OA8Z-lhf?HwyFX1h#&Wp(9zU*nc=2`hy{M#2`G&OjK*!5REWhc&v_6KE2O zh+DK&6i=T}(L-=@1_e?w_~X&sI<}qiWit0}OktBtx6n%_my#c+mp4I^@k%iyE7dSi znE9>m+AvRAIZY*(jX9uuH;JpcBtXZ3=%|)p$!f>JzCPoHEveMQce4(A zd5|bum3m`AwQ;k2C@fhTBNUbFm@|XCEU?cdGOmx&ekxvvv$Vr+J-WOR?j;P5EX|d*-JTY7mUg}8+0(2Oka3*5pBeQ`T{1)F%Xe_*o;g}3`ApTjV z+mwM5@?>fN-XhK-KmV56FT0Oq=|iSARE^x1wHc}bGo|cs9I|-__?JCinlej!SO}Zi zOPT4&0W;-=oT3VNT^nnOBE|F{$j6RCu?H8Zk7w;+?YNd zb=pjd-90`bJ1Y*}|E{eX0h?!)m<`a@+f!1=8gS>{tl!8~Fv#^*S#R!hgKCc%0?{l0 zP8mo33WBFdj8H1|MW-E%d%GYZdux=l|6tNWSjrTFkI%cW&a*>=N0UUdK2d1DXZvWG z_f6^=u`dvTaP%S-ngz+oNq(TBOA+em~Ri+s8I zXJ!M2e-5Dc{YBc@|FOjQ|t5Bo_r!7&aRHRJN zKKb*18ggJDyo9fS4WL-8z+rAbLD|O%DcxW`RiTcHLiWtM1vlUeEB4ON%=$#lD?oAj zs26H|>&Agl!osK~ETMVsWJe+r^?v5VuuNCf!M7lxQdx}lFU12?FhW#_uL=x+R;Ytx{e6}!-y=-p}j2Nj>WVfy7@vR?u6 z@rTMr)w+zBO6utAq0+B_WGhT}@vZXJCdDS3AM3#xx zghz;td~B6d?q~k_s6PnI-}Mc+H<|DXI;U*tkRc z!G4aj--~kb$8c>5*J+{6?jqfhw`qAVcjX90-<&;c9@SGviM{i;Dl_QIWeHzuV}O1N znuEkdL^%}oY1>X(z@#|d&v&EOwcok1c z>o{5G8L|rpU$1uOhY$z51;sSmRDfH4g*1na5ZK!T4QdcJ7HKMg>7t^82AW;OL9UG* z2!Kg7cUK@L(Mos)pbuYn?P|zrKN#OgmhyXEr5X8uDL3_RQR3sli!{Tz2RFLH?klvu z=5e6Cu)*Lt{heZB-l+$c_)MHQbC*GXnYpqd2CZb_>0CU*yW8~r(}s~V9X9ET`T|^a z-F8h=9_!%<5DXCW9lvYWa_Go8#{Pof5%DycL(;bw9pb8oJKOx)TMQy5aN&Swn^>J) z{*1)k53I6Ere%m^pEQH#R!$RaUuO6G+ZIrBH^74!Z3r3*bVj;fS4_~dcJCE{s-vG* zv3ZiUhRGnHKBv@v;rN|6eoxdL=qQ<@zxri9NczjT+pj4qoulI$eyVTOdA$=wXAFIc z$6s#fL~K`Pj^sO?I7XfcQpmA6UI7b%9Z=02-*&*atgOuTbB;_Qn)#eN(3b=uDQ-7-MaPQ>F|-{j*W*#X;*w|A0&dTJ1xg5&jAI4hmLz5(UsKtSk99`rDdJy zI&7wWl-_*~@6qQ*miU4>or$34Z--N2U=XMjMbxVIOK_M%_%XS<=xd;QNLde2dO?HnJsGrZSlO1TxSUa@w(9j&cR*xvM zk{i7hd3dn43i0I-HdF9JJo`m5rzg@`0Lqz#Vhk?HQa!hRTFoD|k6|Z7Ph-C-5S8y5 z=u}dugg3f3ABLyaqr@R7K z*hv%&oOG8MB%vNb3m?D{hz>D`X21*3h5^k@xImtPa_dZ4StXT4m@;0N(fDnZQr$J` z_-hVV;uh=H4TT!mY+v;ChP-{nw`AG zQnkpJ_n;xP{Ku})I6x1ALYio6rVUGLc~kg6EbYHW1uZ3{CdS4vznt3K_1NTg558nJ zOX9^Pw~N;>r4nX;OB9|(#g3lwn)s!vJya5&{J)F*&=^f zi?-9imjPWn+WVCtHPnVc52J_e`cD-(6)9h@QSm=bhW0wY0tVbPqD0yuRn&|9D=c)E z9zzO?nk@uduM;|3iRp}!Y7#A&?L-iM#!U?uxUWs)Y0Caw11o7cgdUhh2nhR+FC)k8VRFDFIJHF}2&8mK#Be7RWi;F8dtU%LL7{y8U4vbG?&3IJ2PY#`|b5>6RlLBY92x6j3o7 ziIZNKTHkquwgjbbXC|!N`a8UH+FCkOlJNNKj3Qg${z^qd z+)}paCMqlP+=#y?hh1sANMhm%G`{{)32z5<4&7(8?7p+YygW*|kM;;JAG92bIHRj( zTcK>bJ)DXzASr7%WW8P=QBMq+q4(muAenBK;)<(S!_fyk?l+R&~xKpu-Y$`THenS)}~K^Uo{`K`~qBFk#!g>8Wby zs8ht-f#A`##aF=KM$M$_63Ymf!8bl8Kh>N?4K7SY*;T}-1E7)DE1;liq#Cm4790sa zPk@Ffxo44m#cSAu_jDeL>PtPAtrj-rQR{peK~dg>F>&rtPrVGT+1Ayd4vl+}`CJc! zStMyGO*#0q-2S&|l@*t;d9P)31U`_|8~;}TiLJH{VjHTk?aS(seSvf)q!Ie8iTVpr z@{p_eWe8W#U}BXc5t&31M!Py!#548C+<5Jx(|8IO=qvgQle1Yw@Q-r*Tq4H^#SYram-KRZ=7MI*juqm5 z`tu#mZ!1j@Im0cfiSiz!NA z?$)Ji5T3T^xW;FVRzp4v1>7^J;(XjNuK@S;j@!iZpL1x%uK)s2Ev*@r)aEWbJikm( z{}QPkq9s2i^91BtsWYZv+DAD2_S-$&Jgf1c9>+Acug;%c`*Aaw6Co$fqu?EcRyl?e z&PJT}BxJTvUI7~3ZB{X>u|MxbhV#5X6}&W9F$?#Db{X^>cL|m(YTEA%r4VM1y&YRV zY&sQhy+#E~i4+`@yF+nl$P9s3lKSpnWvpB--;{W9SLB7098>J=!#l`=(WG^0D43M? zh|s0)Yxs(2J5NkFG9I<6KpLW@yS=T#dukc^p@nA8mgJ^9$QMhNwM3p6PBCrhZ*^6{NU)vU)oq5;1kV z>|4?{%J%O}Lvzn)>0IJ#D!1C>0x8eb(=uxl@fA6n21D24yEe^U*o+-*5y|R1wj}D= zDSINytE#Zt#2UuihqRa?+t+hT(?!}h7dLX8)?d5?V`!)`F)r^dg1&np{?_KW zz&smRxIYYvnYF?nwxF|#DbVufww>e{$?lMncv4R1JD+^(I%>g5QiZ`jnQw5nGCwXjnUHBR1-6z>ph znHF4}>Ka=_3Ei9{e&?X86%$z5m;ddU|L-LmI%UcakyY)1>uYeNbk>E=MuK6ey z;*m&e2Zz)j%Nrik8(P!5zggK-nb{k=?vug`wMH9cfjb)r)GsVDJ#HwC$`zDnb5h;C zs9dyXDC+{MpPQg?9evigJ{E4+y-*~!e}>t_3r4>)|JpvFN`iA%@EeKpeEO_0^B$L7 z$Y$jsWUM~Lmv^i3&_^1EhpI-y- zEl}O>K|ZXDcfq4A@=)G^F)0x5Y9Nq2uYV725NW*wK~Kv5FZINTz5~SqSd!m?AQ4FK zD;K)xdRJtulup%qkUH&MJ)dIi!{39!=tl2BEyj2Ch?Dw!d=FwKyf0F`An$!WQZ-fY zLGqdRslVG;z6XP^x8H-~4)5zB%{F@vGP=J{EtaqH9)wjxc?U*|hrUl83ZnPlpylt87^VbCY z2}bjqZARd!2K_Zfsg`Mp0fl}Rf6WHwY|?rHYTo@{;KYMr#3h-;pQ*(`9kZ196P*4o zlBqmo0mO*x&(yJEgkl15SyX=?GBNwd$>1}`zfU#?;f+xd43Hmx+WmG%DObtL6aK0k zX^TbGG24{w&mu_+-FmaVUjfU1ji<07Gd|!@d>{D_DWWYS^TC00e`n)AU^K|d<+HeD z7*Y7ZKOk~Ze4`J-W)3{ZA0wAm=>)kNK4&$%_y;7u!;=6&c{t5UgRv&GByOJwa>CZDGn!+H9c)#-2_Kz%| zqRqm9ZHxVx;D3Q%WZLX=Tt57f?|)m~1hW6> zt0KMiRWZh}OzF%^KDIZk$8|-Bge-5LmW*0-{Rot24rHunl%t-6qS=D!aX}zBHK^NG zwo>**;gYbP(#XtGv8Ai8q0A!kKfoO|!k{498g0rFB=em6A4|NxK z`$kuO22w3%Kuo~mkGZ`l#`s`3i|%W0kEO7yq`&N)LZvJk$;Q^=ehq{JKL*jbrUYP_5cT zmAL~bMSwkJleXllryR!!KzpKfO3Z!N0(Zl_Ruf$@yMV9>4gT|}iVvtlah&wdlaH{8 zny4~+l)}fbxZ*E*c=|bVTBv|(f+r!6;9Y9a4j(CEEF{(qE5BbChLe#2qZt!^2LuZS z8I{#i!7ze!kwKUh`8m^ScuJQLO*BLbnxq)1OcfBRggmtuXGcCJDvyM{@n5VY!xroc z5y)p8I@ZgxsZD98l6CHA$XLRxOZp286iK);7`l!&hDY4^N~Ix7Jo;Xc;!PC`V11>A zdfR<`+fwwd@i)utDYEz1a?bC^G6)mlVXWf*tP$31S;*8x2 zfvu(>mUp}YDrgY{xd#*T8QUGl2Wo+W@y;cZ(!HYD5n#aUq_dgw#o1^3F#kS5K@GQ- zk>{+|Yy$egm-?GTkMgriau-L0xyQF?y%98h>^{!Y@V+RHl<4+Um2tKE)&!X^7{T@vwq-l&%x6w2V+g7IT+^&E#EaTb- zeO9A(hPCN~r&xhxuBHtmZ;eAE#+*?0qzZAoTsBNB+qgBfXo0Yt#J#rC!o+aW%eYhp zn{%D2qn@-fy3TE|o|WiuqOR{^y3s!7DzPI&g(QWpn2V?>V5-$rBM$5msdz4IQvq9K zMUqyLYhWVm7&@Uw84VR6ix%h)(E&}PTW}J4Q79^1gg3b>6YlLQ`XvdyFTYwSM}2)K z@8TvLWhJwn_lB_gMtrycWgV_6aJ&JYT*kNs#S|$nB|m4cy}8Vf>bDqUpPq>96WJaT zS9TMRfgE*m8@TzPOLnimHcFsQQB8p7rbhn zw%Mmnz9N5$ee6#kl<;=O?|li>pyb>uabw`YDridD7Ng|a9RY$RXwq=yQo`oxaa}*! z%5sY|z`3BH61J&I2Ur^SP{lNdnj=oAgz~MA-afm^?ru_+@YZw|GdZTn@VByLjYs5w zkk|}bq|hE|T8ax82UpjtSkz_((QJ!`1HB^P>%N2G2TSoxicvhP7d~p0Q4S&(Kl2`6 z%Zdp)Nr(5DrxW)3s3$NRR1EYrkGQqk$;S;3_AuqWSC?pfy9W^Sdd7V-hc1WtlUz4A;Qw2M+z(DDtn=NEw-UV@ihk z7h#LZfuMt`$-(+`!im!dTu0h!x`1y?b=V;7tosm%@;+Spl(-$oyVfjN?#*CR987|~ zhgfavLB&uQ2xtADE511~@6)d~7goqynS9pbweLh#F!Q8A8x-WW%=dQa@FR$b6xuG1 z+)(fbYg$hTDdp4gyFufW>I|45E&X0{E$4^QJm;s|AF*-}QP?!d0q-GVUim}R&j6Ts@8+*oFd&bTw$(?W!;_IFiNU@F(MOl2_4o+$EU*PMB|Z2^to!@x^^oK>+&2DrNk`@Tv`Rb_#vxHIGo zOik<0P)x4?<|x?St78r@>1bpd{<3NYrqZdXJ9Z-InHW@);>~AaPGT}U)l#rqgvl&b z8C@hOy{mpP3>!)%KE8~syqtNcGHc*T>Y%q;kY}8Vz6GE=8lxt?Jcr!OXIGP`m6+p@ z?7)|=Rvn3(B?V?#6i$Mq+2tIgv-nx6GHJ!eTkJ}WUUS`^&(<+sRD5O};8C$M?#FR6 zhj)oggG=TW+vAAm6rml;;wccQYh{;Ipb09dDJAULp&{>*?UjDi<~|<=i)&fd=<(G@ z&kQE-BST@eFu(CGyXIv5Dida&S|r2GE~AUDeRqfmiMNtEKynp*wWrri1J~2|!UO1k zvmKn#L?R{cU$lm|g(ET&?5Lw;*yu9(jizteeC!%c#mbuUVBi*2aBXCG(wA?>5mCk5 z&xegt7?fn@YdJl@-NzrlD0~V?r3sseiT1+Oj_wKQYY{;M zA7j*T-6YW*_iOTLmC_U zh?3F9<1+cDTlFbszLcNv8qJDW$W-&2=5uzN?dg`}NZWdf3hsUY1s!fGY@Xb^Suusm zw-p1yu-DF9D`{Yw^eZl=IcqmJ0)pgeb0!)46t=vYEjWgcMI7wPy=b;Mg7PP zhYYSrwVFMU!0wnUc4#0LW+KAxw%FewlF+v#N1Cn&(dyJABtQ4Ln4aK)8EGto_!mn7 zHGj2ssQhX*;}IuYUYfmrH(1lJ@JQVPndrQ$zLyZ8Oc7t@DgJ63I{3W!IQ9vTpJFWW&Cxi2w^DpvnH5k8_*>jL?Ut=OFd8SFYVmm1@44r;P@Un~Shu@hV z&s@>z6@ql^nWq!=UhA(Ri37$#Y>ae}mA0pJ$pLkYv#W(#Aid=}%uff>u#i%|IGAn& zb~h797X?N?>Wx+%N0yyaFK&H!Ja*y435lGhF3gJxw_71eheMU>1#f^WHw|s5KlDME z>rp|7pgP3R#&(ljn26ozHuIlVv@k8feQRIng71T1k*UQeyQDn3ubP4zoOn&sTNG$&?(R)d^ijX*QHO%X(Vrb!2=d zf!o77p+E8P{pITI;>9m#XA{^aTuH;ZCH%YAu^QC(>x#*`O1IR~ZT z{48WX%^i4#f4ZedVMUEOVe5vZ2vRl-FXB+O?TsU$jeB^F#H6nJRKV?$*1io9sBE!H zQmpgyo?3z;+^Xg#(Ncx7;x^zHqzej*hOcoJORyPqR@lW$)+c4uVhn*J?^fNM_TzYo zr$H#bA>vF&9dlNkSpYq&rhoZ!;!m+k$H%DKc-To2gkDW%U5bs8VN??)96~A%T_Ai2=mM)Lv*Sc>|hUkV_yaF8a5XTZZ4%XtW(Vx+~dB_F0FEuol&1 z!usg36rUAUVi=M?X>X|OYoUx5NnseO1AFjILquKy(1pp%0hW+5!vgwCt01m}LRM$X zGVT?FbrIZ%*DtqbA|$18cmp5p6Fz+Tjh_|w5yL{GL!thyL%m=&PJ3U2>izK*Q2lmH zM8yyBiOq8!Dshre)O-!mlZ>vdi|7<@?SqLtUS8m0Kaq|~p%jj!qCa539Z<~y8) z2D0RD+2!$-bnhcFcR$b0pC4_aA6@}pskL?G(W*q7G?J1(YrhakF|1-{Q04{5AjoR^ znO|KZW#%ks4664PAch3>&yoX9-G_;rSIrRw4wTA`LnwNGHdtA-5~;9P;}XFMf$pX0 zDx7IIeBmEG6Rl9*TjmLDZC|^L#ZFCo|FS&}_%Xf-%>pKP7z-abee z2la6hG6GD%FguqmQC0EV_4q3qmv{SG7T6y3a^Z5v0nAP4RqziJc{nD7Uyt%2ZrUhk zv{GARUqe-H=UxFs8dnH0iFvKYSn~#%QmwfG(u&-6AM^yv)*3k5Jo)^d$xciF z@I_^MUrM!(gPhj5p) zRx30C6j6fmYH~wHw))MA04Wzj-~Sj892i2ufZt-NZU%oVLY zr)~G_ZQGkPGwqe7So&M=MT&Y0PcKNVIPOFx8cPKxVB9H?jI~s#qNZSaYF4|LTR#)> zSdM#hR{I;lb7hCx9vT?nQTi7E20=`1iF7B`j~-2m7{OG4e%uo8v8(>+K3>~G*FF$! zk2Uzj;QSCOD_6~NL60N_vb==JX()$Freut$7Z~_<8zKh+nzMZ!pJ9}7!?`ULFJ{au z51Wv+03bgQj6!+|eN=<&jtqt{QoAwzaQuPB6Vd)>@NO@McZYDE^V)_T*aS;?Zznsg z9HQNYB){hL+zgMNQYo0O{KKcN1v8cWz{*p=r-Mpe*F!T~;Q1n^K%~NY@U<@nPk@Y) zBQY^pjpW1IZHNi9?D=r?)EYT8&LRE=q~)~C4v7B~#|Sw0c7O#1a?q$>Nd5Z=tNI{+ zq9KoBev?fsKm4En+5iXv0s{d*5dQ$-7cO5kY|+Ny%-+0SW+12$agK|FT*;E7IyGxE z8`3)uX^CkpDchOi+!o`;YRm{X%vMtbU%C*mnjx3vQ07ABvot|P6BA3!u4|YCQdJ(T zZ~&na**TCh(SnhrsF87VQ^z!GM0XivsD@n8E_gxoi{`1A62AGN9bq5eG$pPB9%v@0 zN17347ZK~t391q1gtg4Xd7(8zJkXZ7Tu$=2nKeQ@(1S1~IibN$3+7}Qhc;Q6l)&bz zl!MI%U~^JhQz}<7R6^WDxopoeQG|F>9Jy*eGVo$tsaTY7au$fj(FeQ{)0I~g%Yz0H zXo2W3tTLrzgkv(PA)3hR3|W(t)cQy$!v(ZPaOx62V~JRUke37J@j+Kgci7(2%$)fmeF z)9uCKa@FukWnvT3cpf)CukVta#Dg)}ZrmXj94%i-Qxz;uq*k6ALx+?+lw_E(6)$u& zhYI1TU@(+HDr7JMI{yGaj6tV?!iTOIfIFC;qHAykK?2XS)L7_Zct_O<-m+TD9>bK*A5km@AV!+ z96d3~jtiF$^GPoQ|SA za)WHXVZxU|%s4Nv7!P&SkYuOM-Z6?=Wet-7#>2Z+LbpQ)qc^(qcxO)$9X zl9^JtB=lF;Aa=$xC~cNk7lA4qXUu_=ZTg8biGI^G7y#0L7mvq7%l`h+jMZ+0Me3Es zf^?c%o3Kop+cdIv5}Ah$Xb~1ei@;Fw{{X+DF_%ubguWz5^(K%93z@?>1lCevHBEU- z<5IX*yMMo?F`n>$9X}*Ntk)nq76$@8DAkH(@TpRzN{D?-3dj5UBN(tca97~Eo8Y_x zB&d?1#-lAyZbT$M1V03o!lgnd3g8?of+{s(2;>AyjAA`_D~d{$9t3pbP$f!?t-ZG+ zOP8L9?pGR>9uF5z6)IGzLR#C{Z8?rLAQHw1GNXt7N_Af zP;kC!fBYx^+5iXv0|Nm+5dQ$-17pz>no?UT1Ys+g5P(+_4ri&B=!7^W+{lIjV{$Yb zpr&_-0Mugjb1`^|ggM1RWJIoF5S%uKu-T0Q>lL!KmJ#SKJjo1RC-sifE>AFBc;&=3`C7L_!{DIEyb4 z=9(G01a;XOF*V@xO4AyGbc@Y5NA(Ev zN336|d3@085%`vg%@luJHs*q3;#txyoYnn7M5CH0t)3w^=4g_W7DKWvoXX}_vjuF_ zKswA-r|usYdrE( zg@h%7{{Zp9;uk4@SSBOU6YEA1j7j%7G@_?l4>T{7pxIy1&fHX z)OqB!DA!DKj?Og+Qk^x6m#nuD7g0lexU z-l6pZZ4*}qSOQW108-`c#Az)J_T=@EB1@V)NV`HyC0|$!D{(E-08zo=a}Cq&$!$~! zlM>}iv~+`r(vZ@)0A*_lQ6}607K~+Ea!L#9#jV%%4Pyd4HKFzW!$+Cc4mj-s69WGL zha|w`ZLRe2D?Cmbkox}NqtEVc%^Y^&P$q?=laW(yu;7G0@d1IPB|=vXXnlWkXP?~O z3~@LdGJEnM5Q{~}rE8yQK`o)O0QYDIM6$7-o_ECkYtU*I-dMYjI{-*h1c44$it z!GdT?l`39%vba~_SvtR5fMU2$z5W`T$NUB@(2nbn?ZJ;TrxU^8#s~OWV`F|qHN&NK zA5h@_4*>rF56I6>NHr_EA`;1R{{RZ$eqb$VmUKG*09=@0*RlP7fc#W4%x+JJu3ns= yQL+}t?ZTygdiU)*KY6MzmSG$wt#F+OyzZXy4M)EK6G3CN2h7$-{{Wx=0RP$1+2>gR literal 0 HcmV?d00001 diff --git a/src/instruments/instrumentImages/orgue.jpg b/src/instruments/instrumentImages/orgue.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ea4e1b59dc74f10414515951b467f74759ab9cf1 GIT binary patch literal 23105 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 literal 0 HcmV?d00001 diff --git a/src/instruments/instrumentImages/piano.jpg b/src/instruments/instrumentImages/piano.jpg new file mode 100755 index 0000000000000000000000000000000000000000..ef109bcfd50551fb02643a0e99021fcbfcb219d3 GIT binary patch literal 56087 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 WZ`x9RoqP9zwS2_Iv literal 0 HcmV?d00001 diff --git a/src/instruments/instrumentImages/tuba.jpg b/src/instruments/instrumentImages/tuba.jpg new file mode 100755 index 0000000000000000000000000000000000000000..453d3bd8f0a7c69d56cf0e176782eef6d3284f95 GIT binary patch literal 16913 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 T>!fs1U6^evN7TZ<@Y(;_KD|mN literal 0 HcmV?d00001 diff --git a/src/launcher/__init__.py b/src/launcher/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/src/logging/EventLog.py b/src/logging/EventLog.py new file mode 100755 index 0000000..3e11f25 --- /dev/null +++ b/src/logging/EventLog.py @@ -0,0 +1,69 @@ +''' +Created on 21 aout 2009 + +@author: Samuel Benveniste +''' +import time + +class EventLog(): + ''' + classdocs + ''' + + def __init__(self,eventGroups = [], times = []): + ''' + Constructor + ''' + self.eventGroups = eventGroups + self.times = times + self.rate = 1 + self.yielder = self.eventGroupYielder() + self.yieldPointer = 0 + + self._timeCounter = 0 + + def __getstate__(self): + d = [] + d.append(self.eventGroups) + d.append(self.times) + return d + + def __setstate__(self,d): + self.eventGroups = d[0] + self.times = d[1] + self.yielder = self.eventGroupYielder() + + self._timeCounter = 0 + + def appendEventGroup(self, eventGroup): + t = time.clock()*1000 + self.times.append(t) + self.eventGroups.append(eventGroup) + + def update(self,timePassed): + self._timeCounter += timePassed + + def setReplayRate(self,rate): + self.rate = rate + self.yielder = self.eventGroupYielder() + + def getPickledEvents(self): + return(self.yielder.next()) + + def getCurrentTime(self): + return(self.times[self.yieldPointer]) + + def eventGroupYielder(self): + ''' + Will return the next event to post if enough time has passed and [] otherwise + ''' + i = 0 + while i in range(len(self.eventGroups)): + print "rate is " + str(self.rate) + if self._timeCounter*self.rate>self.times[i]: + print str(self._timeCounter*self.rate)+" > "+ str(self.times[i]) + self.yieldPointer = i + yield self.eventGroups[i] + i += 1 + else: + yield [] diff --git a/src/logging/FamiliarizerLog.py b/src/logging/FamiliarizerLog.py new file mode 100644 index 0000000..e84d1c2 --- /dev/null +++ b/src/logging/FamiliarizerLog.py @@ -0,0 +1,100 @@ +''' +Created on 28 aout 2009 + +@author: Samuel Benveniste +''' + +import os +import sys +import subprocess +import re + +import pygame +import pygame.midi +import pickle + +from gui.constants import * + +from gui.PlayingScreen import PlayingScreen +from gui.InstrumentChoice import InstrumentChoice +from instruments.Instrument import Instrument +from cursor.WarpingCursor import * +from controllers.Wiimote import Wiimote +from songs.Song import Song +from gui.StaticFamiliarizer import StaticFamiliarizer +from gui.SongFamiliarizer import SongFamiliarizer +from gui.SongPlayingScreen import SongPlayingScreen +from gui.DummyInstrumentChoice import DummyInstrumentChoice + +class FamiliarizerLog(): + ''' + classdocs + ''' + + def __init__(self,eventLog,level,activeWiimotes): + ''' + Constructor + ''' + self.eventLog = eventLog + self.level = level + self.activeWiimotes = activeWiimotes + self.scale = scaleDict["majorScale"] + +if __name__ == '__main__': + + f = file('../../../saves/19-01-2009-testcoll1-v65-1.fmwi', 'r') + unpickler = pickle.Unpickler(f) + log = unpickler.load() + f.close() + + pygame.init() + modeResolution = (1024,768) + window = pygame.display.set_mode(modeResolution,pygame.FULLSCREEN) + pygame.midi.init() + instruments = [Instrument(log.scale, i + 1, "".join(["../instruments/instrumentImages/", instrumentImagePathList[i], ".jpg"]), octaves[i]) for i in range(9)] + + joys = [[id,pygame.joystick.Joystick(id).get_name()] for id in range(pygame.joystick.get_count())] + for joy in joys: + if joy[1] in joyNames: + pygame.joystick.Joystick(joy[0]).init() + + ports = [pygame.midi.get_device_info(id)[1] for id in range(pygame.midi.get_count())] + portOffset = ports.index(portNames[0]) + print(portOffset) + + screen = pygame.display.get_surface() + clock = pygame.time.Clock() + cursorImages=[['../cursor/cursorImages/black/10.png'],['../cursor/cursorImages/red/10.png'],['../cursor/cursorImages/blue/10.png'],['../cursor/cursorImages/green/10.png']] + durations = [75 for i in range(len(cursorImages))] + + extsc = True + casc = False + easyMode = True + + song = Song(scaleDict["majorScale"],[3,9,6,4,1,8,5,7,2,10],True) + + wiimoteCount = 4 + + cursors = [WarpingCursor(None, cursorImages[i], durations, (300 * i, 300 * i),'../cursor/cursorImages/black/flash.png') for i in range(wiimoteCount)] + wiimotes = [Wiimote(i, i + portOffset, None, instruments[0], cursors[i]) for i in range(wiimoteCount)] + dummyInstrumentChoice = DummyInstrumentChoice(wiimotes, window, screen, clock, joys, portOffset, log.activeWiimotes) + if log.level < 2 : + familiarize = StaticFamiliarizer(wiimotes, window, screen, clock, joys, portOffset,log.activeWiimotes,level = log.level,eventLog = log.eventLog,replay = True) + elif log.level == 2 : + familiarize = SongFamiliarizer(wiimotes, window, screen, clock, joys, portOffset,song,log.activeWiimotes,casc,extsc,easyMode,eventLog = log.eventLog,replay = True) + else : + familiarize = SongPlayingScreen(dummyInstrumentChoice,songDict["clairdelalune"],easyMode = True,eventLog = log.eventLog,replay = True) + + while familiarize.nextLevel != None : + if familiarize.nextLevel < 2 : + familiarize = StaticFamiliarizer(wiimotes, window, screen, clock, joys, portOffset,log.activeWiimotes,level = familiarize.nextLevel,eventLog = familiarize.eventLog,replay = True) + elif familiarize.nextLevel == 2 : + familiarize = SongFamiliarizer(wiimotes, window, screen, clock, joys, portOffset,song,log.activeWiimotes,casc,extsc,easyMode,eventLog = familiarize.eventLog,replay = True) + else : + familiarize = SongPlayingScreen(dummyInstrumentChoice,songDict["clairdelalune"],easyMode = True,eventLog = familiarize.eventLog,replay = True) + + for wiimote in wiimotes: + del wiimote.port + + pygame.midi.quit() + pygame.quit() \ No newline at end of file diff --git a/src/logging/Log.py b/src/logging/Log.py new file mode 100755 index 0000000..4aef88b --- /dev/null +++ b/src/logging/Log.py @@ -0,0 +1,135 @@ +''' +Created on 28 aout 2009 + +@author: Samuel Benveniste +''' + +import os +import sys +import subprocess +import re + +import pygame +import pygame.midi +import pickle + +from gui.constants import * + +from gui.PlayingScreen import PlayingScreen +from gui.SongPlayingScreen import SongPlayingScreen +from gui.InstrumentChoice import InstrumentChoice +from instruments.Instrument import Instrument +from cursor.WarpingCursor import * +from controllers.Wiimote import Wiimote +from songs.Song import Song + + +class Log(): + ''' + classdocs + ''' + + + def __init__(self,eventLog,scale,extendedScale,cascade,song,mode,activeWiimotes,easyMode = True): + ''' + Constructor + ''' + self.eventLog = eventLog + self.scale = scale + self.extendedScale = extendedScale + self.cascade = cascade + self.song = song + self.activeWiimotes = activeWiimotes + self.mode = mode + +if __name__ == '__main__': + + f = file('../../saves/4-12-2009-B1-v50-1.mwi', 'r') + unpickler = pickle.Unpickler(f) + log = unpickler.load() + f.close() + + pygame.init() + pygame.midi.init() + instruments = [Instrument(scaleDict["majorScale"], i + 1, "".join(["../instruments/instrumentImages/", instrumentImagePathList[i], ".jpg"]), octaves[i]) for i in range(9)] + + joys = [[id,pygame.joystick.Joystick(id).get_name()] for id in range(pygame.joystick.get_count())] + for joy in joys: + if joy[1] in joyNames: + pygame.joystick.Joystick(joy[0]).init() + + ports = [pygame.midi.get_device_info(id)[1] for id in range(pygame.midi.get_count())] + portOffset = ports.index(portNames[0]) + print(portOffset) + + modeResolution = (1024,768) + window = pygame.display.set_mode(modeResolution,pygame.FULLSCREEN) + screen = pygame.display.get_surface() + clock = pygame.time.Clock() + cursorImages=[['../cursor/cursorImages/black/10.png'],['../cursor/cursorImages/red/10.png'],['../cursor/cursorImages/blue/10.png'],['../cursor/cursorImages/green/10.png']] + durations = [75 for i in range(len(cursorImages[0]))] + + wiimoteCount = 4 + cursors = [WarpingCursor(None, cursorImages[i], durations, (300 * i, 300 * i),flashImage = '../cursor/cursorImages/black/flash.png' ) for i in range(wiimoteCount)] + wiimotes = [Wiimote(i, i + portOffset, None, None, cursors[i]) for i in range(wiimoteCount)] + + if log.song != None : + + if log.mode == 0 : + log.extendedScale = log.song.requiresExtendedScale + log.cascade = True + log.easyMode = True + elif log.mode == 1 : + log.extendedScale = log.song.requiresExtendedScale + log.cascade = True + log.easyMode = True + elif log.mode == 2: + log.extendedScale = log.song.requiresExtendedScale + log.cascade = False + log.easyMode = True + elif log.mode == 3: + log.extendedScale = True + log.cascade = False + log.easyMode = False + + choice = InstrumentChoice(instruments, wiimotes, window, screen, clock, joys, portOffset,log.activeWiimotes, eventLog = log.eventLog,scaleFactor = songScaleFactor,replay = True) + play = SongPlayingScreen(choice, log.song,log.cascade, log.extendedScale,log.easyMode) + + else: + + if log.mode == 0 : + log.extendedScale = False + log.cascade = False + elif log.mode == 1 : + log.extendedScale = True + log.cascade = False + elif log.mode == 2: + log.extendedScale = False + log.cascade = True + elif log.mode == 3: + log.extendedScale = True + log.cascade = True + + choice = InstrumentChoice(instruments, wiimotes, window, screen, clock, joys, portOffset,log.activeWiimotes,eventLog = log.eventLog,replay = True) + play = PlayingScreen(choice, None,log.cascade, log.extendedScale) + + while play.backToInstrumentChoice == True : + + for wiimote in wiimotes: + del wiimote.port + + wiimotes = [Wiimote(i, i + portOffset, None, None, cursors[i]) for i in range(wiimoteCount)] + previousEventLog = play.eventLog + + if log.song != None : + choice = InstrumentChoice(instruments, wiimotes,window, screen, clock, joys, portOffset, log.activeWiimotes,eventLog = previousEventLog, replay = True, scaleFactor = songScaleFactor) + play = SongPlayingScreen(choice, log.song, False, log.extendedScale,log.easyMode) + else: + choice = InstrumentChoice(instruments, wiimotes, log.window, screen, clock, joys, portOffset,log.activeWiimotes, eventLog = previousEventLog, replay = True) + play = PlayingScreen(choice, None, log.cascade, log.extendedScale) + + for wiimote in wiimotes: + del wiimote.port + + pygame.midi.quit() + pygame.quit() \ No newline at end of file diff --git a/src/logging/LogPGUAnalyzer.py b/src/logging/LogPGUAnalyzer.py new file mode 100644 index 0000000..a3551fd --- /dev/null +++ b/src/logging/LogPGUAnalyzer.py @@ -0,0 +1,42 @@ +''' +Created on 25 janv. 2010 + +@author: Samuel Benveniste +''' + +from LogPGUPlayer import LogPGUPlayer + +class LogPGUAnalyzer(LogPGUPlayer): + ''' + classdocs + ''' + + + def __init__(self): + ''' + Constructor + ''' + + self.firstStepDurations = [] + self.firstStepClicks = [] + self.firstStepClicksIn = [] + + self.secondStepDurations = [] + self.secondStepClicks = [] + self.secondStepClicksIn = [] + + self.thirdStepDurations = [] + self.thirdStepClicks = [] + self.thirdStepClicksIn = [] + + self.songDurations = [] + self.songClicks = [] + self.songClicksIn = [] + self.songClicksPerMinute = [] + self.songClicksInPerMinute = [] + self.songTotalDurations = [] + + self.meanTimeBetweenNotes = [] + + LogPGUPlayer.__init__(self,20) + \ No newline at end of file diff --git a/src/logging/LogPGUPlayer.py b/src/logging/LogPGUPlayer.py new file mode 100644 index 0000000..cf1a670 --- /dev/null +++ b/src/logging/LogPGUPlayer.py @@ -0,0 +1,237 @@ +''' +Created on 25 janv. 2010 + +@author: Samuel Benveniste +''' + +import pygame +import pickle + +from pgu import gui as pguGui + +from gui import constants + +from instruments.Instrument import Instrument +from songs.Song import Song +from cursor.WarpingCursor import * +from gui.StaticFamiliarizer import StaticFamiliarizer +from gui.SongFamiliarizer import SongFamiliarizer +from gui.SongPlayingScreen import SongPlayingScreen +from gui.DummyInstrumentChoice import DummyInstrumentChoice +from controllers.Wiimote import Wiimote + +class LogPGUPlayer(pguGui.Desktop): + ''' + classdocs + ''' + + + def __init__(self,rate): + ''' + Constructor + ''' + self.firstStepDurations = [] + self.firstStepClicks = [] + self.firstStepClicksIn = [] + + self.secondStepDurations = [] + self.secondStepClicks = [] + self.secondStepClicksIn = [] + + self.thirdStepDurations = [] + self.thirdStepClicks = [] + self.thirdStepClicksIn = [] + + self.songDurations = [] + self.songClicks = [] + self.songClicksIn = [] + self.songClicksPerMinute = [] + self.songClicksInPerMinute = [] + self.songTotalDurations = [] + + self.meanTimeBetweenNotes = [] + + pguGui.Desktop.__init__(self) + + self.replayRate = rate + #pguGui.theme.load('../data/themes/default') + + self.connect(pguGui.QUIT,self.quit,None) + + main = pguGui.Container(width=500, height=400) #, background=(220, 220, 220) ) + + + main.add(pguGui.Label("File Dialog Example", cls="h1"), 20, 20) + + + td_style = {'padding_right': 10} + t = pguGui.Table() + t.tr() + t.td( pguGui.Label('File Name:') , style=td_style ) + self.input_file = pguGui.Input() + t.td( self.input_file, style=td_style ) + self.browseButton = pguGui.Button("Browse...") + t.td( self.browseButton, style=td_style ) + self.browseButton.connect(pguGui.CLICK, self.open_file_browser, None) + + self.goButton = pguGui.Button("Go") + + self.goButton.connect(pguGui.CLICK, self.goButtonClicked,None) + + self.quitButton = pguGui.Button("Fin") + self.quitButton.connect(pguGui.CLICK,self.quit,None) + + t.td( self.browseButton, style=td_style ) + t.td( self.goButton, style=td_style ) + t.td( self.quitButton, style=td_style ) + + main.add(t, 20, 100) + + self.run(main) + #import profile + #profile.run('app.run(main)') + + def open_file_browser(self,data=None): + d = pguGui.FileDialog(path = "../../../saves") + d.connect(pguGui.CHANGE, self.handle_file_browser_closed, d) + d.open() + + + def handle_file_browser_closed(self,dlg): + if dlg.value: self.input_file.value = dlg.value + + def goButtonClicked(self,data=None): + if self.input_file.value.endswith(".fmwi"): + f = file(self.input_file.value, 'r') + unpickler = pickle.Unpickler(f) + log = unpickler.load() + f.close() + + log.eventLog.setReplayRate(self.replayRate) + + pygame.midi.init() + instruments = [Instrument(log.scale, i + 1, "".join(["../instruments/instrumentImages/", constants.instrumentImagePathList[i], ".jpg"]), constants.octaves[i]) for i in range(9)] + + joys = [[id,pygame.joystick.Joystick(id).get_name()] for id in range(pygame.joystick.get_count())] + for joy in joys: + if joy[1] in constants.joyNames: + pygame.joystick.Joystick(joy[0]).init() + + ports = [pygame.midi.get_device_info(id)[1] for id in range(pygame.midi.get_count())] + portOffset = ports.index(constants.portNames[0]) + print(portOffset) + + screen = pygame.display.get_surface() + clock = pygame.time.Clock() + cursorImages=[['../cursor/cursorImages/black/10.png'],['../cursor/cursorImages/red/10.png'],['../cursor/cursorImages/blue/10.png'],['../cursor/cursorImages/green/10.png']] + durations = [75 for i in range(len(cursorImages))] + + extsc = True + casc = False + easyMode = True + + song = Song(constants.scaleDict["majorScale"],[3,9,6,4,1,8,5,7,2,10],True) + + wiimoteCount = 4 + + cursors = [WarpingCursor(None, cursorImages[i], durations, (300 * i, 300 * i),'../cursor/cursorImages/black/flash.png') for i in range(wiimoteCount)] + wiimotes = [Wiimote(i, i + portOffset, None, instruments[0], cursors[i]) for i in range(wiimoteCount)] + dummyInstrumentChoice = DummyInstrumentChoice(wiimotes, window, screen, clock, joys, portOffset, log.activeWiimotes) + if log.level < 2 : + familiarize = StaticFamiliarizer(wiimotes, window, screen, clock, joys, portOffset,log.activeWiimotes,level = log.level,eventLog = log.eventLog,replay = True) + self.fillStaticFamiliarizerStats(familiarize) + elif log.level == 2 : + familiarize = SongFamiliarizer(wiimotes, window, screen, clock, joys, portOffset,song,log.activeWiimotes,casc,extsc,easyMode,eventLog = log.eventLog,replay = True) + self.fillSongFamiliarizerStats(familiarize) + else : + familiarize = SongPlayingScreen(dummyInstrumentChoice,constants.songDict["clairdelalune"],easyMode = True,eventLog = log.eventLog,replay = True) + self.fillSongStats(familiarize) + + while familiarize.nextLevel != None : + if familiarize.nextLevel < 2 : + familiarize = StaticFamiliarizer(wiimotes, window, screen, clock, joys, portOffset,log.activeWiimotes,level = familiarize.nextLevel,eventLog = familiarize.eventLog,replay = True) + self.fillStaticFamiliarizerStats(familiarize) + elif familiarize.nextLevel == 2 : + familiarize = SongFamiliarizer(wiimotes, window, screen, clock, joys, portOffset,song,log.activeWiimotes,casc,extsc,easyMode,eventLog = familiarize.eventLog,replay = True) + self.fillSongFamiliarizerStats(familiarize) + else : + familiarize = SongPlayingScreen(dummyInstrumentChoice,constants.songDict["clairdelalune"],easyMode = True,eventLog = familiarize.eventLog,replay = True) + self.fillSongStats(familiarize) + + for wiimote in wiimotes: + del wiimote.port + + pygame.midi.quit() + self.printStatsToFile() + + def fillStaticFamiliarizerStats(self,familiarizer): + if familiarizer.level == 0 : + self.firstStepClicks.append(familiarizer.clicks) + self.firstStepClicksIn.append(familiarizer.clicksIn) + self.firstStepDurations.append(familiarizer.duration) + + if familiarizer.level == 1 : + self.secondStepClicks.append(familiarizer.clicks) + self.secondStepClicksIn.append(familiarizer.clicksIn) + self.secondStepDurations.append(familiarizer.duration) + + def fillSongFamiliarizerStats(self,familiarizer): + self.thirdStepClicks.append(familiarizer.clicks) + self.thirdStepClicksIn.append(familiarizer.clicksIn) + self.thirdStepDurations.append(familiarizer.duration) + + def fillSongStats(self,familiarizer): + self.songClicks.append(familiarizer.clicks) + self.songClicksIn.append(familiarizer.clicksIn) + self.songClicksPerMinute.append(familiarizer.clicksPerMinute) + self.songClicksInPerMinute.append(familiarizer.clicksInPerMinute) + self.songDurations.append(familiarizer.songDurations) + self.songTotalDurations.append(familiarizer.totalDuration) + + def statsToFormattedString(self): + return("First step durations :\n"+"\n"+ + str(self.firstStepDurations)+"\n"+"\n"+ + "First step clicks :\n"+"\n"+ + str(self.firstStepClicks)+"\n"+"\n"+ + "First step clicksIn :\n"+"\n"+ + str(self.firstStepClicksIn)+"\n"+"\n"+ + "Second step durations :\n"+"\n"+ + str(self.secondStepDurations)+"\n"+"\n"+ + "Second step clicks :\n"+"\n"+ + str(self.secondStepClicks)+"\n"+"\n"+ + "Second step clicksIn :\n"+"\n"+ + str(self.secondStepClicksIn)+"\n"+"\n"+ + "Third step durations :\n"+"\n"+ + str(self.thirdStepDurations)+"\n"+"\n"+ + "Third step clicks :\n"+"\n"+ + str(self.thirdStepClicks)+"\n"+"\n"+ + "Third step clicksIn :\n"+"\n"+ + str(self.thirdStepClicksIn)+"\n"+"\n"+ + "song durations :\n"+"\n"+ + str(self.songDurations)+"\n"+"\n"+ + "song clicks :\n"+"\n"+ + str(self.songClicks)+"\n"+"\n"+ + "song clicksIn :\n"+"\n"+ + str(self.songClicksIn)+"\n"+"\n"+ + "song clicks per minute:\n"+"\n"+ + str(self.songClicksPerMinute)+"\n"+"\n"+ + "song clicksIn per minute :\n"+"\n"+ + str(self.songClicksInPerMinute)+"\n"+"\n"+ + "song total durations :\n"+"\n"+ + str(self.songTotalDurations)+"\n"+"\n") + + def printStatsToFile(self,path=None): + if path == None : + path = self.input_file.value.replace(".fmwi",".txt") + file = open(path,"w") + file.write("Log ID : "+self.input_file.value+"\n"+"\n") + file.write(self.statsToFormattedString()) + file.close() + +if __name__ == "__main__": + pygame.init() + modeResolution = (1024,768) + window = pygame.display.set_mode(modeResolution,pygame.FULLSCREEN) + logConfig = LogPGUPlayer(10000) + pygame.quit() + \ No newline at end of file diff --git a/src/logging/PickleableEvent.py b/src/logging/PickleableEvent.py new file mode 100755 index 0000000..ab218f8 --- /dev/null +++ b/src/logging/PickleableEvent.py @@ -0,0 +1,24 @@ +import pygame +import copy +import pickle + +from pygame.event import Event + +class PickleableEvent(object): + "A pygame.Event that can be serialized." + + def __init__(self,type,dict): + self.__dict__ = copy.copy(dict) + self.type = type + self.event = Event(self.type,dict) + + def __getstate__(self): + d = [] + d.append(self.type) + d.append(copy.copy(self.event.dict)) + return d + + def __setstate__(self, d): + self.__dict__ = copy.copy(d[1]) + self.type = d[0] + self.event = Event(d[0],d[1]) \ No newline at end of file diff --git a/src/logging/__init__.py b/src/logging/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/src/mxmMidi/DataTypeConverters.py b/src/mxmMidi/DataTypeConverters.py new file mode 100644 index 0000000..25115de --- /dev/null +++ b/src/mxmMidi/DataTypeConverters.py @@ -0,0 +1,217 @@ +# -*- coding: ISO-8859-1 -*- + +from struct import pack, unpack + +""" +This module contains functions for reading and writing the special data types +that a midi file contains. +""" + +""" +nibbles are four bits. A byte consists of two nibles. +hiBits==0xF0, loBits==0x0F Especially used for setting +channel and event in 1. byte of musical midi events +""" + + + +def getNibbles(byte): + """ + Returns hi and lo bits in a byte as a tuple + >>> getNibbles(142) + (8, 14) + + Asserts byte value in byte range + >>> getNibbles(256) + Traceback (most recent call last): + ... + ValueError: Byte value out of range 0-255: 256 + """ + if not 0 <= byte <= 255: + raise ValueError('Byte value out of range 0-255: %s' % byte) + return (byte >> 4 & 0xF, byte & 0xF) + + +def setNibbles(hiNibble, loNibble): + """ + Returns byte with value set according to hi and lo bits + Asserts hiNibble and loNibble in range(16) + >>> setNibbles(8, 14) + 142 + + >>> setNibbles(8, 16) + Traceback (most recent call last): + ... + ValueError: Nible value out of range 0-15: (8, 16) + """ + if not (0 <= hiNibble <= 15) or not (0 <= loNibble <= 15): + raise ValueError('Nible value out of range 0-15: (%s, %s)' % (hiNibble, loNibble)) + return (hiNibble << 4) + loNibble + + + +def readBew(value): + """ + Reads string as big endian word, (asserts len(value) in [1,2,4]) + >>> readBew('aáâã') + 1642193635L + >>> readBew('aá') + 25057 + """ + return unpack('>%s' % {1:'B', 2:'H', 4:'L'}[len(value)], value)[0] + + +def writeBew(value, length): + """ + Write int as big endian formatted string, (asserts length in [1,2,4]) + Difficult to print the result in doctest, so I do a simple roundabout test. + >>> readBew(writeBew(25057, 2)) + 25057 + >>> readBew(writeBew(1642193635L, 4)) + 1642193635L + """ + return pack('>%s' % {1:'B', 2:'H', 4:'L'}[length], value) + + + +""" +Variable Length Data (varlen) is a data format sprayed liberally throughout +a midi file. It can be anywhere from 1 to 4 bytes long. +If the 8'th bit is set in a byte another byte follows. The value is stored +in the lowest 7 bits of each byte. So max value is 4x7 bits = 28 bits. +""" + + +def readVar(value): + """ + Converts varlength format to integer. Just pass it 0 or more chars that + might be a varlen and it will only use the relevant chars. + use varLen(readVar(value)) to see how many bytes the integer value takes. + asserts len(value) >= 0 + >>> readVar('€@') + 64 + >>> readVar('áâãa') + 205042145 + """ + sum = 0 + for byte in unpack('%sB' % len(value), value): + sum = (sum << 7) + (byte & 0x7F) + if not 0x80 & byte: break # stop after last byte + return sum + + + +def varLen(value): + """ + Returns the the number of bytes an integer will be when + converted to varlength + """ + if value <= 127: + return 1 + elif value <= 16383: + return 2 + elif value <= 2097151: + return 3 + else: + return 4 + + +def writeVar(value): + "Converts an integer to varlength format" + sevens = to_n_bits(value, varLen(value)) + for i in range(len(sevens)-1): + sevens[i] = sevens[i] | 0x80 + return fromBytes(sevens) + + +def to_n_bits(value, length=1, nbits=7): + "returns the integer value as a sequence of nbits bytes" + bytes = [(value >> (i*nbits)) & 0x7F for i in range(length)] + bytes.reverse() + return bytes + + +def toBytes(value): + "Turns a string into a list of byte values" + return unpack('%sB' % len(value), value) + + +def fromBytes(value): + "Turns a list of bytes into a string" + if not value: + return '' + return pack('%sB' % len(value), *value) + + + +if __name__ == '__main__': + +# print to7bits(0, 3) +# print to7bits(127, 3) +# print to7bits(255, 3) +# print to7bits(65536, 3) + + # simple test cases + +# print 'getHiLoHex', getNibbles(16) +# print 'setHiLoHex', setNibbles(1,0) +# +# print 'readBew', readBew('aáâã') +# print 'writeBew', writeBew(1642193635, 4) +# +# print 'varLen', varLen(1) +# + print 'readVar', readVar('€@') + print 'writeVar', writeVar(8192) + + print 'readVar', readVar('áâãa') + print 'writeVar', writeVar(205058401) +# +# vartest = '\x82\xF7\x80\x00' +# print 'toBytes', toBytes(vartest) +# print 'fromBytes', fromBytes([48, 49, 50,]) + + +# instr = '\xFF\xFF\xFF\x00' +# print 'readVar', readVar(instr) +# inst2 = 268435455 +# print inst2 +# print writeVar(inst2) +# print writeVar(readVar(instr)) + + s1 = 0x00000000 + print '%08X -' % s1, '00', writeVar(s1) + s2 = 0x00000040 + print '%08X -' % s2, '40', writeVar(s2) + s3 = 0x0000007F + print '%08X -' % s3, '7F', writeVar(s3) + s4 = 0x00000080 + print '%08X -' % s4, '81 00', writeVar(s4) + s5 = 0x00002000 + print '%08X -' % s5, 'C0 00', writeVar(s5) + s6 = 0x00003FFF + print '%08X -' % s6, 'FF 7F', writeVar(s6) + s7 = 0x00004000 + print '%08X -' % s7, '81 80 00', writeVar(s7) + s8 = 0x00100000 + print '%08X -' % s8, 'C0 80 00', writeVar(s8) + s9 = 0x001FFFFF + print '%08X -' % s9, 'FF FF 7F', writeVar(s9) + s10 = 0x00200000 + print '%08X -' % s10, '81 80 80 00', writeVar(s10) + s11 = 0x08000000 + print '%08X -' % s11, 'C0 80 80 00', writeVar(s11) + s12 = 0x0FFFFFFF + print '%08X -' % s12, 'FF FF FF 7F', writeVar(s12) + + + + + + + + + + + + \ No newline at end of file diff --git a/src/mxmMidi/DataTypeConverters.pyc b/src/mxmMidi/DataTypeConverters.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5ef8c80dc90cc6617a0484e53237de5375e8dee GIT binary patch literal 5803 zcmc&&TXPi06+W}Nt}ZMRy5iWhLljnyQ0)py$doN)NdcT-$~8+MwHBp}c3RSy-5D`G zi%b=U7%!hR73 zC>#)BkitO`iWK5+h{9p|7Sll(k@jH-K*1{dsRE(UMH!3hQcY*XK3nXI4wgV+nHvlUJ_-Am9th^a?0~mKP$?!tbETZ z^F92C>SLlDW99o+Ip#)=Q+-^N{6RiBPRpy^^ zk?ND8oMh!sta8$=IY;#=QBJY)r&c-Tl$WSJEy`(DmaTHyDd(v^Bgz?8eq@z1PWdyc z&x&%El?zrmYn8DFAY7(ec@bcVUgB24>-SJ#IlP6vbR8JmU=h`R0UO|jjEDJ$6n?(W z+G%XmVWfgMRLw-~MVV1itOB+7B-1J|kh1nsQ%nE#^>uZivpdn=UQ?TLb$MxC+RJMT zs=91tY52?-onj`LugIat9FLFY0%Jnu!SnO5|gP^H*}n-M$l}k zW?-`UYqAD^z~bVf$oF`OpQmY(UQ?UAal2;H&Q!9mWJy)IytJ}%O<@@s62TJi1>568 z6hAO(&P432sDz@-?#YHwoGfeGxC?(|88t~^egkRi+Rk>;Xt(ecuqO;%(^(e92WF=h zwA#9-U_&pOZ7Pt1Q2J8^hi_s)AAhGTRH9+x37hk0~}JXv5eTLpQ6v{sQC zkrY=m;Xkn3>=fAS1-cBOth(w%a?+`|Kp#RY!}3>gReb ztyEU7ir(~KTkCTMI|sQ$LK$4#iiG)Dylp83lJ%c2op>DYPhQwWveDD_-~bkOpSJ?h z@TO_7LnR&8eT3%!?m93*?zCE&L1_l?X=0=MX#}c{!0oSkYd=X_L6+&zIrCM|9e_Aq z_u6)}zaKT)&5Y^e2mpX^sNqP%ZRi~)jZB+tL77B-jyDx36Sa`nRGPHoFxcZ%!98p~ z=|;gZ?~>sl&RtMT^A-^&zJ6=(F2F3PWjCg)@fDQ#Y#0HF&zKgB_?%(7;v8=dCnJ#L z$N-$c8mEm7-fM1@4agQ8MTu)hZzs=ui5CR*GmpO65|k9E6UZ)(w;z=0S%Gs6f`0ue z0=t(srZED+kGGAZKJvbNq{zc_AHCcO=F=QPE)N={lGIv5S@bXv00VuX(?#`*HjWWT zh<+7is-luqwUSh;#$k{e042!88LjBxFjIRt^|;w2$za5Bgp)@SH=n4s(GFNm{W#!5 z2~S}$!#eEZHe#0}=U$LHj+y7Z7_HS|a;#cG{6r2yys&_uw}^p!M#_SR+RgSBs#^b4 zRb-<%-gt>i&o>{DMb$C7Ece6CL$bvYy9qkqNQID>+Q`@Qqj?~QxIR6I#6OjcXmXB`Efem&xYGoXaz zQj?=`Pp75Vwe)pb`q6@6b!C$VXu`w)_~ ze&49q=eeiwX88N)h}-}NbfO-ao7td38K?kP7LV^oaL){??FTcC3K00S@YE*M5I=de zK=*M~vYl%JM>#5WV!zAk-KKR+Ahc?M&1oxRg3XfMc$e=wJ|C7dZkGe30A70Rr%8+N z1f~oAa(U7?soSg`owg4Ku}vXf#K19R!x@4KlioC9V9K)}%5l$Pp+FPY;f#&(M`QHc9(o1}?&GZV0yk1fH6aGGim6g}aeR}) zf}l2~3jNkj6d6Xt|gQuze0}@raC+JM!*V)d&7`-Y#>U zvhDqISe>KP9%KtwyrC1m=_EYaqVP=z@h;Cf+s$K!yK?0Y@`Eap6rV<#xc%ikVzYtC z>G^d&erFuO{>l=Gia)R^pZC-;!$rIx>N$4Z+~QZ1pjc4XjbExVq}2&^G!%q36m4xl4UYC8{LBmw3 lI941l4i_hj=ZdA`U}>P(R~#H2D|w{?o-_U4wD-S1{{aAoJ)i&p literal 0 HcmV?d00001 diff --git a/src/mxmMidi/EventDispatcher.py b/src/mxmMidi/EventDispatcher.py new file mode 100644 index 0000000..3c07a33 --- /dev/null +++ b/src/mxmMidi/EventDispatcher.py @@ -0,0 +1,287 @@ +# -*- coding: ISO-8859-1 -*- + +# std library +from struct import unpack + +# custom +from DataTypeConverters import readBew, readVar, varLen, toBytes + +# uhh I don't really like this, but there are so many constants to +# import otherwise +from constants import * + + +class EventDispatcher: + + + def __init__(self, outstream): + + """ + + The event dispatcher generates events on the outstream. + + """ + + # internal values, don't mess with 'em directly + self.outstream = outstream + + # public flags + + # A note_on with a velocity of 0x00 is actually the same as a + # note_off with a velocity of 0x40. When + # "convert_zero_velocity" is set, the zero velocity note_on's + # automatically gets converted into note_off's. This is a less + # suprising behaviour for those that are not into the intimate + # details of the midi spec. + self.convert_zero_velocity = 1 + + # If dispatch_continuos_controllers is true, continuos + # controllers gets dispatched to their defined handlers. Else + # they just trigger the "continuous_controller" event handler. + self.dispatch_continuos_controllers = 1 # NOT IMPLEMENTED YET + + # If dispatch_meta_events is true, meta events get's dispatched + # to their defined events. Else they all they trigger the + # "meta_event" handler. + self.dispatch_meta_events = 1 + + + + def header(self, format, nTracks, division): + "Triggers the header event" + self.outstream.header(format, nTracks, division) + + + def start_of_track(self, current_track): + "Triggers the start of track event" + + # I do this twice so that users can overwrite the + # start_of_track event handler without worrying whether the + # track number is updated correctly. + self.outstream.set_current_track(current_track) + self.outstream.start_of_track(current_track) + + + def sysex_event(self, data): + "Dispatcher for sysex events" + self.outstream.sysex_event(data) + + + def eof(self): + "End of file!" + self.outstream.eof() + + + def update_time(self, new_time=0, relative=1): + "Updates relative/absolute time." + self.outstream.update_time(new_time, relative) + + + def reset_time(self): + "Updates relative/absolute time." + self.outstream.reset_time() + + + # Event dispatchers for similar types of events + + + def channel_messages(self, hi_nible, channel, data): + + "Dispatches channel messages" + + stream = self.outstream + data = toBytes(data) + + if (NOTE_ON & 0xF0) == hi_nible: + note, velocity = data + # note_on with velocity 0x00 are same as note + # off with velocity 0x40 according to spec! + if velocity==0 and self.convert_zero_velocity: + stream.note_off(channel, note, 0x40) + else: + stream.note_on(channel, note, velocity) + + elif (NOTE_OFF & 0xF0) == hi_nible: + note, velocity = data + stream.note_off(channel, note, velocity) + + elif (AFTERTOUCH & 0xF0) == hi_nible: + note, velocity = data + stream.aftertouch(channel, note, velocity) + + elif (CONTINUOUS_CONTROLLER & 0xF0) == hi_nible: + controller, value = data + # A lot of the cc's are defined, so we trigger those directly + if self.dispatch_continuos_controllers: + self.continuous_controllers(channel, controller, value) + else: + stream.continuous_controller(channel, controller, value) + + elif (PATCH_CHANGE & 0xF0) == hi_nible: + program = data[0] + stream.patch_change(channel, program) + + elif (CHANNEL_PRESSURE & 0xF0) == hi_nible: + pressure = data[0] + stream.channel_pressure(channel, pressure) + + elif (PITCH_BEND & 0xF0) == hi_nible: + hibyte, lobyte = data + value = (hibyte<<7) + lobyte + stream.pitch_bend(channel, value) + + else: + + raise ValueError, 'Illegal channel message!' + + + + def continuous_controllers(self, channel, controller, value): + + "Dispatches channel messages" + + stream = self.outstream + + # I am not really shure if I ought to dispatch continuous controllers + # There's so many of them that it can clutter up the OutStream + # classes. + + # So I just trigger the default event handler + stream.continuous_controller(channel, controller, value) + + + + def system_commons(self, common_type, common_data): + + "Dispatches system common messages" + + stream = self.outstream + + # MTC Midi time code Quarter value + if common_type == MTC: + data = readBew(common_data) + msg_type = (data & 0x07) >> 4 + values = (data & 0x0F) + stream.midi_time_code(msg_type, values) + + elif common_type == SONG_POSITION_POINTER: + hibyte, lobyte = toBytes(common_data) + value = (hibyte<<7) + lobyte + stream.song_position_pointer(value) + + elif common_type == SONG_SELECT: + data = readBew(common_data) + stream.song_select(data) + + elif common_type == TUNING_REQUEST: + # no data then + stream.tuning_request(time=None) + + + + def meta_event(self, meta_type, data): + + "Dispatches meta events" + + stream = self.outstream + + # SEQUENCE_NUMBER = 0x00 (00 02 ss ss (seq-number)) + if meta_type == SEQUENCE_NUMBER: + number = readBew(data) + stream.sequence_number(number) + + # TEXT = 0x01 (01 len text...) + elif meta_type == TEXT: + stream.text(data) + + # COPYRIGHT = 0x02 (02 len text...) + elif meta_type == COPYRIGHT: + stream.copyright(data) + + # SEQUENCE_NAME = 0x03 (03 len text...) + elif meta_type == SEQUENCE_NAME: + stream.sequence_name(data) + + # INSTRUMENT_NAME = 0x04 (04 len text...) + elif meta_type == INSTRUMENT_NAME: + stream.instrument_name(data) + + # LYRIC = 0x05 (05 len text...) + elif meta_type == LYRIC: + stream.lyric(data) + + # MARKER = 0x06 (06 len text...) + elif meta_type == MARKER: + stream.marker(data) + + # CUEPOINT = 0x07 (07 len text...) + elif meta_type == CUEPOINT: + stream.cuepoint(data) + + # PROGRAM_NAME = 0x08 (05 len text...) + elif meta_type == PROGRAM_NAME: + stream.program_name(data) + + # DEVICE_NAME = 0x09 (09 len text...) + elif meta_type == DEVICE_NAME: + stream.device_name(data) + + # MIDI_CH_PREFIX = 0x20 (20 01 channel) + elif meta_type == MIDI_CH_PREFIX: + channel = readBew(data) + stream.midi_ch_prefix(channel) + + # MIDI_PORT = 0x21 (21 01 port (legacy stuff)) + elif meta_type == MIDI_PORT: + port = readBew(data) + stream.midi_port(port) + + # END_OFF_TRACK = 0x2F (2F 00) + elif meta_type == END_OF_TRACK: + stream.end_of_track() + + # TEMPO = 0x51 (51 03 tt tt tt (tempo in us/quarternote)) + elif meta_type == TEMPO: + b1, b2, b3 = toBytes(data) + # uses 3 bytes to represent time between quarter + # notes in microseconds + stream.tempo((b1<<16) + (b2<<8) + b3) + + # SMTP_OFFSET = 0x54 (54 05 hh mm ss ff xx) + elif meta_type == SMTP_OFFSET: + hour, minute, second, frame, framePart = toBytes(data) + stream.smtp_offset( + hour, minute, second, frame, framePart) + + # TIME_SIGNATURE = 0x58 (58 04 nn dd cc bb) + elif meta_type == TIME_SIGNATURE: + nn, dd, cc, bb = toBytes(data) + stream.time_signature(nn, dd, cc, bb) + + # KEY_SIGNATURE = 0x59 (59 02 sf mi) + elif meta_type == KEY_SIGNATURE: + sf, mi = toBytes(data) + stream.key_signature(sf, mi) + + # SPECIFIC = 0x7F (Sequencer specific event) + elif meta_type == SPECIFIC: + meta_data = toBytes(data) + stream.sequencer_specific(meta_data) + + # Handles any undefined meta events + else: # undefined meta type + meta_data = toBytes(data) + stream.meta_event(meta_type, meta_data) + + + + + +if __name__ == '__main__': + + + from MidiToText import MidiToText + + outstream = MidiToText() + dispatcher = EventDispatcher(outstream) + dispatcher.channel_messages(NOTE_ON, 0x00, '\x40\x40') \ No newline at end of file diff --git a/src/mxmMidi/EventDispatcher.pyc b/src/mxmMidi/EventDispatcher.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2657b04e982e9438f23993a204c9b4a1739cbc76 GIT binary patch literal 7056 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 Mnkmi|aNx533FbO8cmMzZ literal 0 HcmV?d00001 diff --git a/src/mxmMidi/MidiFileParser.py b/src/mxmMidi/MidiFileParser.py new file mode 100644 index 0000000..2b447bc --- /dev/null +++ b/src/mxmMidi/MidiFileParser.py @@ -0,0 +1,192 @@ +# -*- coding: ISO-8859-1 -*- + +# std library +from struct import unpack + +# uhh I don't really like this, but there are so many constants to +# import otherwise +from constants import * + +from EventDispatcher import EventDispatcher + +class MidiFileParser: + + """ + + The MidiFileParser is the lowest level parser that see the data as + midi data. It generates events that gets triggered on the outstream. + + """ + + def __init__(self, raw_in, outstream): + + """ + raw_data is the raw content of a midi file as a string. + """ + + # internal values, don't mess with 'em directly + self.raw_in = raw_in + self.dispatch = EventDispatcher(outstream) + + # Used to keep track of stuff + self._running_status = None + + + + + def parseMThdChunk(self): + + "Parses the header chunk" + + raw_in = self.raw_in + + header_chunk_type = raw_in.nextSlice(4) + header_chunk_zise = raw_in.readBew(4) + + # check if it is a proper midi file + if header_chunk_type != 'MThd': + raise TypeError, "It is not a valid midi file!" + + # Header values are at fixed locations, so no reason to be clever + self.format = raw_in.readBew(2) + self.nTracks = raw_in.readBew(2) + self.division = raw_in.readBew(2) + + # Theoretically a header larger than 6 bytes can exist + # but no one has seen one in the wild + # But correctly ignore unknown data if it is though + if header_chunk_zise > 6: + raw_in.moveCursor(header_chunk_zise-6) + + # call the header event handler on the stream + self.dispatch.header(self.format, self.nTracks, self.division) + + + + def parseMTrkChunk(self): + + "Parses a track chunk. This is the most important part of the parser." + + # set time to 0 at start of a track + self.dispatch.reset_time() + + dispatch = self.dispatch + raw_in = self.raw_in + + # Trigger event at the start of a track + dispatch.start_of_track(self._current_track) + # position cursor after track header + raw_in.moveCursor(4) + # unsigned long is 4 bytes + tracklength = raw_in.readBew(4) + track_endposition = raw_in.getCursor() + tracklength # absolute position! + + while raw_in.getCursor() < track_endposition: + + # find relative time of the event + time = raw_in.readVarLen() + dispatch.update_time(time) + + # be aware of running status!!!! + peak_ahead = raw_in.readBew(move_cursor=0) + if (peak_ahead & 0x80): + # the status byte has the high bit set, so it + # was not running data but proper status byte + status = self._running_status = raw_in.readBew() + else: + # use that darn running status + status = self._running_status + # could it be illegal data ?? Do we need to test for that? + # I need more example midi files to be shure. + + # Also, while I am almost certain that no realtime + # messages will pop up in a midi file, I might need to + # change my mind later. + + # we need to look at nibbles here + hi_nible, lo_nible = status & 0xF0, status & 0x0F + + # match up with events + + # Is it a meta_event ?? + # these only exists in midi files, not in transmitted midi data + # In transmitted data META_EVENT (0xFF) is a system reset + if status == META_EVENT: + meta_type = raw_in.readBew() + meta_length = raw_in.readVarLen() + meta_data = raw_in.nextSlice(meta_length) + dispatch.meta_event(meta_type, meta_data) + + + # Is it a sysex_event ?? + elif status == SYSTEM_EXCLUSIVE: + # ignore sysex events + sysex_length = raw_in.readVarLen() + # don't read sysex terminator + sysex_data = raw_in.nextSlice(sysex_length-1) + # only read last data byte if it is a sysex terminator + # It should allways be there, but better safe than sorry + if raw_in.readBew(move_cursor=0) == END_OFF_EXCLUSIVE: + eo_sysex = raw_in.readBew() + dispatch.sysex_event(sysex_data) + # the sysex code has not been properly tested, and might be fishy! + + + # is it a system common event? + elif hi_nible == 0xF0: # Hi bits are set then + data_sizes = { + MTC:1, + SONG_POSITION_POINTER:2, + SONG_SELECT:1, + } + data_size = data_sizes.get(hi_nible, 0) + common_data = raw_in.nextSlice(data_size) + common_type = lo_nible + dispatch.system_common(common_type, common_data) + + + # Oh! Then it must be a midi event (channel voice message) + else: + data_sizes = { + PATCH_CHANGE:1, + CHANNEL_PRESSURE:1, + NOTE_OFF:2, + NOTE_ON:2, + AFTERTOUCH:2, + CONTINUOUS_CONTROLLER:2, + PITCH_BEND:2, + } + data_size = data_sizes.get(hi_nible, 0) + channel_data = raw_in.nextSlice(data_size) + event_type, channel = hi_nible, lo_nible + dispatch.channel_messages(event_type, channel, channel_data) + + + def parseMTrkChunks(self): + "Parses all track chunks." + for t in range(self.nTracks): + self._current_track = t + self.parseMTrkChunk() # this is where it's at! + self.dispatch.eof() + + + +if __name__ == '__main__': + + # get data + test_file = 'test/midifiles/minimal.mid' + test_file = 'test/midifiles/cubase-minimal.mid' + test_file = 'test/midifiles/Lola.mid' +# f = open(test_file, 'rb') +# raw_data = f.read() +# f.close() +# +# +# # do parsing + from MidiToText import MidiToText + from RawInstreamFile import RawInstreamFile + + midi_in = MidiFileParser(RawInstreamFile(test_file), MidiToText()) + midi_in.parseMThdChunk() + midi_in.parseMTrkChunks() + \ No newline at end of file diff --git a/src/mxmMidi/MidiFileParser.pyc b/src/mxmMidi/MidiFileParser.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6a716540c77f0fd418baf83c1d43bf662a5a657 GIT binary patch literal 4233 zcmc&%UvDEx5wDqX?AVDDC)sRvk2^H?fMlISka##GK&Ra}-dl^riN;QrjRMWA-HB&y z&xGlAl0DfHV)-BliFZB#UxG&-_zs9C-r!f&c9Oe&;f1?6(^LJgy8isCs^@S2s#gB- z_xKk*n*S~1{S1%!3z|OuJsJ{?JUa8peXf&}kV1hHB?E{rz0vLt~*dY)C+82Z{jew3Y?^*v4UO9G@{H4tZoZ zY}xQqr#g?VHX(MWmKkE>rDiHmE-!Vi`(c&}n`~l@&2>E9y_c#NKuCUkJPkbN2WX}q zO^Fmt3c_cXa96Zv0!n+ZK5sECG{TM*&Ep#-!p=2AKkQ|xg=ArN5yqhie*t^5I&lbb zlJwGv!~5G}IPoL1O45kWunf}v+;6skPCHArWtXaalBQsxjE(KY)L9c*Vf5%C;-$8X z=1%iEIwXxb2i5rL`F_@$jKy+s+7CP0TCg+cop?NfH}-T2vnIys^P4Om0y;f?e%NZi zN|Mu`oSVFNKE55ZSI@uh+TE*nBDI1JiB)PFhZ%+^mCD|F&|`eDbo_|b{|W-8O^9YN zwnqs7=ds~uzI4U*+zr?v0N>kyvMPBNNDS!rK5!C4l69S-i<7MFjAx`SS-=o z0%hBdMQJ|t1m}6e7lJKQQWgop6kRYvi)iI!Py`rCP{8bdI*2`x?TZ!@5@x*+RiBHY0F0f&iy@oBVO*l zyVA`(&vF6KMV60aD~r-@j+|iTIJ!(qhBRPf14QN6ebyijoM&4bNHIaXsA&3*MYUFR}D5j{FbWTwnHAf=?-}* zEbWj7%)LjRbsdHwJm4I!N^ntb)!&(l=nWGb_;Ts?W>aP=Vee z82|0bre!{D<`4;JEiq~r+<@W$)7}j51oHwt%XSu%*j1PTqlo?rr4=V|g?OmMNPfnz zB0ckG%QOSy64@20OFw(SVOHTd0;*Yt6`@yYit>UG1A#!Q(iCe}xeR%~{WZ3N&zkUg z?fAI8SOz}Wf^t|Q4w>1S3_2(T`dgv+MjKHqhTWd+_F{T(;|v$ce>3()%<1S z;H1+!ZA!vvw)fT1ix&?@`3UpQ=-c_$0R6*m!*bQ>9JRkx$48x3w{_G8(Q0>_kq9L- zo#sKa(M1&@f(Dk=0Vk`+s+Wz&NRuqu@$+uurE0u<-u|*FaxvL%9;oA}+3B1_P06h7 zqi&N0la%W^ZBg|33mn-!I%&KVi5f@kZmWHAbkb2wMn?w+kcj^a-9f904f9S>E^*<2F7 zyE=#pgG8mtn~|2zD4Tcq1|g1-oG(aYH_Z>co8^m-n9I3hJ}p=m-^e^y6rCwqBEs;f zGRarC0Wzn%uDHngK(15|`yvNBW?>;=%_j+TTy0{U&F8;%{QE=sj9; zeIC0XuX;TWaE@* z$$bJoi(EAtJ_V>0f?!;%vFY1%45vUz znTOrEW6Ym1WEeK&*Qn@~y){qnaRPs((s-ZNvf1#cijC>ivgj6yLN`_vyvonr&wzN&1W( z%uISV0_92xzL=1c@G&P}KcZmNT1>J4iZzH1F%-3VoL$0-@duN5>> test_file = 'C:/Documents and Settings/maxm/Desktop/temp/midi/src/midi/tests/midifiles/minimal-cubase-type0.mid' + + Do parsing, and generate events with MidiToText, + so we can see what a minimal midi file contains + >>> from MidiToText import MidiToText + >>> midi_in = MidiInFile(MidiToText(), test_file) + >>> midi_in.read() + format: 0, nTracks: 1, division: 480 + ---------------------------------- + + Start - track #0 + sequence_name: Type 0 + tempo: 500000 + time_signature: 4 2 24 8 + note_on - ch:00, note:48, vel:64 time:0 + note_off - ch:00, note:48, vel:40 time:480 + End of track + + End of file + + + """ + + def __init__(self, outStream, infile): + # these could also have been mixins, would that be better? Nah! + self.raw_in = RawInstreamFile(infile) + self.parser = MidiFileParser(self.raw_in, outStream) + + + def read(self): + "Start parsing the file" + p = self.parser + p.parseMThdChunk() + p.parseMTrkChunks() + + + def setData(self, data=''): + "Sets the data from a plain string" + self.raw_in.setData(data) + + diff --git a/src/mxmMidi/MidiInFile.pyc b/src/mxmMidi/MidiInFile.pyc new file mode 100644 index 0000000000000000000000000000000000000000..182efaa1e219ebbb979ee947f070628ed50b7942 GIT binary patch literal 2252 zcmcgtUvC>l5TCpJDT#pg0r7@32#H=LCpN`xqf@aUNkLH?3)vQbB1@<3-P&I4+cUT8 zIF-s%_<}t0!iV4sz|5=@M<|FVa`LU`W@l%9^Shb3-~N1W_mAJz%N$nM7X5!ow|hoQ zLB9y505gCyfQX-Cm_{&*;4Gr&4Jfvu*o0pJE&+Z#i=o(pesYh_n!o5uB9i=lT6$`E zVx6zGD!(=}9X8&ljZ;$?)_kjKr)$5vQk_^eMq-!(4q-V#Naqy#KF%9NG!r8 zFepMq2)CfuPdFi$Z2;^dU9w0hhYCxIjU$TFKxGT`wHc3f?a)tj*wg3QdWV%2RkiSa z$so9?UjL+XzrXhTjrOQ7R5_n%ER(H}%!L>2*18az;&8=RsgMWJNmm z#gYKo3*q+so4Ic7)Aqx44#ySF=}nOPz{wR*Tu~u#Ps!t;8t4n(kdv;$rN&%YbXwzb zqWo=HV_sRWjCFE`(-eNz&d`+es`j|nTw4-IlNn2N@Mb8EWNnu`YOFbX^v_fKRCPrX z)T62{l~1wNKs%^aK6NR6*1*D?8)qt;V*8*a=lA~e60_%rufFQOe09=&(UIrASCqjX z)e`x}Pl7L}e_m*t>&&WBr#K+qG3@Y5t5ST@;!7NOQ|io_u~mLilW`j#_zLEu(Z8CvTfzJ)=@(R8)hK|!HNBMqmy_(T zmz-J*uI?jlx`Y-F@HU3a2;Kr@5%`z|Lyr+$icFnJjog=c&`mb!NRMvt+qBebN$I6p5dXk)a=H2JzQ4x z)Xi0{ho>jq?~VEH*^pXlSYDJ|al>^5?$6)&cgT50FpbZ$Pf2!+4C4Dy&bWDQ@xKuA zF$tVLz%Rl8@o-7o#DyV_c)mu&1Rrr9(h^E()r~TMIIphc-{UBr=ckZzI+zqklZBni ztX-+TI?C~7*3}t>-%rHdmJRaGO-yg&~(QZT~0g!W+SGSP!0Vx7GtMcIQ%QYWN z9gV#(ns3h5`HUtC(uaj6RySn2LAIVhK~DQ)8pAj8XGnbdjwtBy3;LXqaHjnr+ buk@%irkLI(Hlgo%Agse!q~RV!4>tY={Ut*b literal 0 HcmV?d00001 diff --git a/src/mxmMidi/MidiInStream.py b/src/mxmMidi/MidiInStream.py new file mode 100644 index 0000000..22f7e09 --- /dev/null +++ b/src/mxmMidi/MidiInStream.py @@ -0,0 +1,52 @@ +# -*- coding: ISO-8859-1 -*- + +from MidiOutStream import MidiOutStream + +class MidiInStream: + + """ + Takes midi events from the midi input and calls the apropriate + method in the eventhandler object + """ + + def __init__(self, midiOutStream, device): + + """ + + Sets a default output stream, and sets the device from where + the input comes + + """ + + if midiOutStream is None: + self.midiOutStream = MidiOutStream() + else: + self.midiOutStream = midiOutStream + + + def close(self): + + """ + Stop the MidiInstream + """ + + + def read(self, time=0): + + """ + + Start the MidiInstream. + + "time" sets timer to specific start value. + + """ + + + def resetTimer(self, time=0): + """ + + Resets the timer, probably a good idea if there is some kind + of looping going on + + """ + diff --git a/src/mxmMidi/MidiOutFile.py b/src/mxmMidi/MidiOutFile.py new file mode 100644 index 0000000..a39bc9f --- /dev/null +++ b/src/mxmMidi/MidiOutFile.py @@ -0,0 +1,448 @@ +# -*- coding: ISO-8859-1 -*- + +from MidiOutStream import MidiOutStream +from RawOutstreamFile import RawOutstreamFile + +from constants import * +from DataTypeConverters import fromBytes, writeVar + +class MidiOutFile(MidiOutStream): + + + """ + MidiOutFile is an eventhandler that subclasses MidiOutStream. + """ + + + def __init__(self, raw_out=''): + + self.raw_out = RawOutstreamFile(raw_out) + MidiOutStream.__init__(self) + + + def write(self): + self.raw_out.write() + + + def event_slice(self, slc): + """ + Writes the slice of an event to the current track. Correctly + inserting a varlen timestamp too. + """ + trk = self._current_track_buffer + trk.writeVarLen(self.rel_time()) + trk.writeSlice(slc) + + + ##################### + ## Midi events + + + def note_on(self, channel=0, note=0x40, velocity=0x40): + + """ + channel: 0-15 + note, velocity: 0-127 + """ + slc = fromBytes([NOTE_ON + channel, note, velocity]) + self.event_slice(slc) + + + def note_off(self, channel=0, note=0x40, velocity=0x40): + + """ + channel: 0-15 + note, velocity: 0-127 + """ + slc = fromBytes([NOTE_OFF + channel, note, velocity]) + self.event_slice(slc) + + + def aftertouch(self, channel=0, note=0x40, velocity=0x40): + + """ + channel: 0-15 + note, velocity: 0-127 + """ + slc = fromBytes([AFTERTOUCH + channel, note, velocity]) + self.event_slice(slc) + + + def continuous_controller(self, channel, controller, value): + + """ + channel: 0-15 + controller, value: 0-127 + """ + slc = fromBytes([CONTINUOUS_CONTROLLER + channel, controller, value]) + self.event_slice(slc) + # These should probably be implemented + # http://users.argonet.co.uk/users/lenny/midi/tech/spec.html#ctrlnums + + + def patch_change(self, channel, patch): + + """ + channel: 0-15 + patch: 0-127 + """ + slc = fromBytes([PATCH_CHANGE + channel, patch]) + self.event_slice(slc) + + + def channel_pressure(self, channel, pressure): + + """ + channel: 0-15 + pressure: 0-127 + """ + slc = fromBytes([CHANNEL_PRESSURE + channel, pressure]) + self.event_slice(slc) + + + def pitch_bend(self, channel, value): + + """ + channel: 0-15 + value: 0-16383 + """ + msb = (value>>7) & 0xFF + lsb = value & 0xFF + slc = fromBytes([PITCH_BEND + channel, msb, lsb]) + self.event_slice(slc) + + + + + ##################### + ## System Exclusive + +# def sysex_slice(sysex_type, data): +# "" +# sysex_len = writeVar(len(data)+1) +# self.event_slice(SYSTEM_EXCLUSIVE + sysex_len + data + END_OFF_EXCLUSIVE) +# + def system_exclusive(self, data): + + """ + data: list of values in range(128) + """ + sysex_len = writeVar(len(data)+1) + self.event_slice(chr(SYSTEM_EXCLUSIVE) + sysex_len + data + chr(END_OFF_EXCLUSIVE)) + + + ##################### + ## Common events + + def midi_time_code(self, msg_type, values): + """ + msg_type: 0-7 + values: 0-15 + """ + value = (msg_type<<4) + values + self.event_slice(fromBytes([MIDI_TIME_CODE, value])) + + + def song_position_pointer(self, value): + + """ + value: 0-16383 + """ + lsb = (value & 0x7F) + msb = (value >> 7) & 0x7F + self.event_slice(fromBytes([SONG_POSITION_POINTER, lsb, msb])) + + + def song_select(self, songNumber): + + """ + songNumber: 0-127 + """ + self.event_slice(fromBytes([SONG_SELECT, songNumber])) + + + def tuning_request(self): + + """ + No values passed + """ + self.event_slice(chr(TUNING_REQUEST)) + + + ######################### + # header does not really belong here. But anyhoo!!! + + def header(self, format=0, nTracks=1, division=96): + + """ + format: type of midi file in [0,1,2] + nTracks: number of tracks. 1 track for type 0 file + division: timing division ie. 96 ppq. + + """ + raw = self.raw_out + raw.writeSlice('MThd') + bew = raw.writeBew + bew(6, 4) # header size + bew(format, 2) + bew(nTracks, 2) + bew(division, 2) + + + def eof(self): + + """ + End of file. No more events to be processed. + """ + # just write the file then. + self.write() + + + ##################### + ## meta events + + + def meta_slice(self, meta_type, data_slice): + "Writes a meta event" + slc = fromBytes([META_EVENT, meta_type]) + \ + writeVar(len(data_slice)) + data_slice + self.event_slice(slc) + + + def meta_event(self, meta_type, data): + """ + Handles any undefined meta events + """ + self.meta_slice(meta_type, fromBytes(data)) + + + def start_of_track(self, n_track=0): + """ + n_track: number of track + """ + self._current_track_buffer = RawOutstreamFile() + self.reset_time() + self._current_track += 1 + + + def end_of_track(self): + """ + Writes the track to the buffer. + """ + raw = self.raw_out + raw.writeSlice(TRACK_HEADER) + track_data = self._current_track_buffer.getvalue() + # wee need to know size of track data. + eot_slice = writeVar(self.rel_time()) + fromBytes([META_EVENT, END_OF_TRACK, 0]) + raw.writeBew(len(track_data)+len(eot_slice), 4) + # then write + raw.writeSlice(track_data) + raw.writeSlice(eot_slice) + + + + def sequence_number(self, value): + + """ + value: 0-65535 + """ + self.meta_slice(meta_type, writeBew(value, 2)) + + + def text(self, text): + """ + Text event + text: string + """ + self.meta_slice(TEXT, text) + + + def copyright(self, text): + + """ + Copyright notice + text: string + """ + self.meta_slice(COPYRIGHT, text) + + + def sequence_name(self, text): + """ + Sequence/track name + text: string + """ + self.meta_slice(SEQUENCE_NAME, text) + + + def instrument_name(self, text): + + """ + text: string + """ + self.meta_slice(INSTRUMENT_NAME, text) + + + def lyric(self, text): + + """ + text: string + """ + self.meta_slice(LYRIC, text) + + + def marker(self, text): + + """ + text: string + """ + self.meta_slice(MARKER, text) + + + def cuepoint(self, text): + + """ + text: string + """ + self.meta_slice(CUEPOINT, text) + + + def midi_ch_prefix(self, channel): + + """ + channel: midi channel for subsequent data + (deprecated in the spec) + """ + self.meta_slice(MIDI_CH_PREFIX, chr(channel)) + + + def midi_port(self, value): + + """ + value: Midi port (deprecated in the spec) + """ + self.meta_slice(MIDI_CH_PREFIX, chr(value)) + + + def tempo(self, value): + + """ + value: 0-2097151 + tempo in us/quarternote + (to calculate value from bpm: int(60,000,000.00 / BPM)) + """ + hb, mb, lb = (value>>16 & 0xff), (value>>8 & 0xff), (value & 0xff) + self.meta_slice(TEMPO, fromBytes([hb, mb, lb])) + + + def smtp_offset(self, hour, minute, second, frame, framePart): + + """ + hour, + minute, + second: 3 bytes specifying the hour (0-23), minutes (0-59) and + seconds (0-59), respectively. The hour should be + encoded with the SMPTE format, just as it is in MIDI + Time Code. + frame: A byte specifying the number of frames per second (one + of : 24, 25, 29, 30). + framePart: A byte specifying the number of fractional frames, + in 100ths of a frame (even in SMPTE-based tracks + using a different frame subdivision, defined in the + MThd chunk). + """ + self.meta_slice(SMTP_OFFSET, fromBytes([hour, minute, second, frame, framePart])) + + + + def time_signature(self, nn, dd, cc, bb): + + """ + nn: Numerator of the signature as notated on sheet music + dd: Denominator of the signature as notated on sheet music + The denominator is a negative power of 2: 2 = quarter + note, 3 = eighth, etc. + cc: The number of MIDI clocks in a metronome click + bb: The number of notated 32nd notes in a MIDI quarter note + (24 MIDI clocks) + """ + self.meta_slice(TIME_SIGNATURE, fromBytes([nn, dd, cc, bb])) + + + + + def key_signature(self, sf, mi): + + """ + sf: is a byte specifying the number of flats (-ve) or sharps + (+ve) that identifies the key signature (-7 = 7 flats, -1 + = 1 flat, 0 = key of C, 1 = 1 sharp, etc). + mi: is a byte specifying a major (0) or minor (1) key. + """ + self.meta_slice(KEY_SIGNATURE, fromBytes([sf, mi])) + + + + def sequencer_specific(self, data): + + """ + data: The data as byte values + """ + self.meta_slice(SEQUENCER_SPECIFIC, data) + + + + + +# ##################### +# ## realtime events + +# These are of no use in a midi file, so they are ignored!!! + +# def timing_clock(self): +# def song_start(self): +# def song_stop(self): +# def song_continue(self): +# def active_sensing(self): +# def system_reset(self): + + + +if __name__ == '__main__': + + out_file = 'test/midifiles/midiout.mid' + midi = MidiOutFile(out_file) + +#format: 0, nTracks: 1, division: 480 +#---------------------------------- +# +#Start - track #0 +#sequence_name: Type 0 +#tempo: 500000 +#time_signature: 4 2 24 8 +#note_on - ch:00, note:48, vel:64 time:0 +#note_off - ch:00, note:48, vel:40 time:480 +#End of track +# +#End of file + + + midi.header(0, 1, 480) + + midi.start_of_track() + midi.sequence_name('Type 0') + midi.tempo(750000) + midi.time_signature(4, 2, 24, 8) + ch = 0 + for i in range(127): + midi.note_on(ch, i, 0x64) + midi.update_time(96) + midi.note_off(ch, i, 0x40) + midi.update_time(0) + + midi.update_time(0) + midi.end_of_track() + + midi.eof() # currently optional, should it do the write instead of write?? + + + midi.write() \ No newline at end of file diff --git a/src/mxmMidi/MidiOutStream.py b/src/mxmMidi/MidiOutStream.py new file mode 100644 index 0000000..c128fa6 --- /dev/null +++ b/src/mxmMidi/MidiOutStream.py @@ -0,0 +1,471 @@ +# -*- coding: ISO-8859-1 -*- + +class MidiOutStream: + + + """ + + MidiOutstream is Basically an eventhandler. It is the most central + class in the Midi library. You use it both for writing events to + an output stream, and as an event handler for an input stream. + + This makes it extremely easy to take input from one stream and + send it to another. Ie. if you want to read a Midi file, do some + processing, and send it to a midiport. + + All time values are in absolute values from the opening of a + stream. To calculate time values, please use the MidiTime and + MidiDeltaTime classes. + + """ + + def __init__(self): + + # the time is rather global, so it needs to be stored + # here. Otherwise there would be no really simple way to + # calculate it. The alternative would be to have each event + # handler do it. That sucks even worse! + self._absolute_time = 0 + self._relative_time = 0 + self._current_track = 0 + self._running_status = None + + # time handling event handlers. They should be overwritten with care + + def update_time(self, new_time=0, relative=1): + """ + Updates the time, if relative is true, new_time is relative, + else it's absolute. + """ + if relative: + self._relative_time = new_time + self._absolute_time += new_time + else: + self._relative_time = new_time - self._absolute_time + self._absolute_time = new_time + + def reset_time(self): + """ + reset time to 0 + """ + self._relative_time = 0 + self._absolute_time = 0 + + def rel_time(self): + "Returns the relative time" + return self._relative_time + + def abs_time(self): + "Returns the absolute time" + return self._absolute_time + + # running status methods + + def reset_run_stat(self): + "Invalidates the running status" + self._running_status = None + + def set_run_stat(self, new_status): + "Set the new running status" + self._running_status = new_status + + def get_run_stat(self): + "Set the new running status" + return self._running_status + + # track handling event handlers + + def set_current_track(self, new_track): + "Sets the current track number" + self._current_track = new_track + + def get_current_track(self): + "Returns the current track number" + return self._current_track + + + ##################### + ## Midi events + + + def channel_message(self, message_type, channel, data): + """The default event handler for channel messages""" + pass + + + def note_on(self, channel=0, note=0x40, velocity=0x40): + + """ + channel: 0-15 + note, velocity: 0-127 + """ + pass + + + def note_off(self, channel=0, note=0x40, velocity=0x40): + + """ + channel: 0-15 + note, velocity: 0-127 + """ + pass + + + def aftertouch(self, channel=0, note=0x40, velocity=0x40): + + """ + channel: 0-15 + note, velocity: 0-127 + """ + pass + + + def continuous_controller(self, channel, controller, value): + + """ + channel: 0-15 + controller, value: 0-127 + """ + pass + + + def patch_change(self, channel, patch): + + """ + channel: 0-15 + patch: 0-127 + """ + pass + + + def channel_pressure(self, channel, pressure): + + """ + channel: 0-15 + pressure: 0-127 + """ + pass + + + def pitch_bend(self, channel, value): + + """ + channel: 0-15 + value: 0-16383 + + """ + pass + + + + + ##################### + ## System Exclusive + + def system_exclusive(self, data): + + """ + data: list of values in range(128) + """ + pass + + + ##################### + ## Common events + + def song_position_pointer(self, value): + + """ + value: 0-16383 + """ + pass + + + def song_select(self, songNumber): + + """ + songNumber: 0-127 + """ + pass + + + def tuning_request(self): + + """ + No values passed + """ + pass + + + def midi_time_code(self, msg_type, values): + """ + msg_type: 0-7 + values: 0-15 + """ + pass + + + ######################### + # header does not really belong here. But anyhoo!!! + + def header(self, format=0, nTracks=1, division=96): + + """ + format: type of midi file in [1,2] + nTracks: number of tracks + division: timing division + """ + pass + + + def eof(self): + + """ + End of file. No more events to be processed. + """ + pass + + + ##################### + ## meta events + + + def meta_event(self, meta_type, data): + + """ + Handles any undefined meta events + """ + pass + + + def start_of_track(self, n_track=0): + + """ + n_track: number of track + """ + pass + + + def end_of_track(self): + + """ + n_track: number of track + """ + pass + + + def sequence_number(self, value): + + """ + value: 0-16383 + """ + pass + + + def text(self, text): + + """ + Text event + text: string + """ + pass + + + def copyright(self, text): + + """ + Copyright notice + text: string + """ + pass + + + def sequence_name(self, text): + + """ + Sequence/track name + text: string + """ + pass + + + def instrument_name(self, text): + + """ + text: string + """ + pass + + + def lyric(self, text): + + """ + text: string + """ + pass + + + def marker(self, text): + + """ + text: string + """ + pass + + + def cuepoint(self, text): + + """ + text: string + """ + pass + + + def midi_ch_prefix(self, channel): + + """ + channel: midi channel for subsequent data (deprecated in the spec) + """ + pass + + + def midi_port(self, value): + + """ + value: Midi port (deprecated in the spec) + """ + pass + + + def tempo(self, value): + + """ + value: 0-2097151 + tempo in us/quarternote + (to calculate value from bpm: int(60,000,000.00 / BPM)) + """ + pass + + + def smtp_offset(self, hour, minute, second, frame, framePart): + + """ + hour, + minute, + second: 3 bytes specifying the hour (0-23), minutes (0-59) and + seconds (0-59), respectively. The hour should be + encoded with the SMPTE format, just as it is in MIDI + Time Code. + frame: A byte specifying the number of frames per second (one + of : 24, 25, 29, 30). + framePart: A byte specifying the number of fractional frames, + in 100ths of a frame (even in SMPTE-based tracks + using a different frame subdivision, defined in the + MThd chunk). + """ + pass + + + + def time_signature(self, nn, dd, cc, bb): + + """ + nn: Numerator of the signature as notated on sheet music + dd: Denominator of the signature as notated on sheet music + The denominator is a negative power of 2: 2 = quarter + note, 3 = eighth, etc. + cc: The number of MIDI clocks in a metronome click + bb: The number of notated 32nd notes in a MIDI quarter note + (24 MIDI clocks) + """ + pass + + + + def key_signature(self, sf, mi): + + """ + sf: is a byte specifying the number of flats (-ve) or sharps + (+ve) that identifies the key signature (-7 = 7 flats, -1 + = 1 flat, 0 = key of C, 1 = 1 sharp, etc). + mi: is a byte specifying a major (0) or minor (1) key. + """ + pass + + + + def sequencer_specific(self, data): + + """ + data: The data as byte values + """ + pass + + + + + ##################### + ## realtime events + + def timing_clock(self): + + """ + No values passed + """ + pass + + + + def song_start(self): + + """ + No values passed + """ + pass + + + + def song_stop(self): + + """ + No values passed + """ + pass + + + + def song_continue(self): + + """ + No values passed + """ + pass + + + + def active_sensing(self): + + """ + No values passed + """ + pass + + + + def system_reset(self): + + """ + No values passed + """ + pass + + + +if __name__ == '__main__': + + midiOut = MidiOutStream() + midiOut.update_time(0,0) + midiOut.note_on(0, 63, 127) + midiOut.note_off(0, 63, 127) + + \ No newline at end of file diff --git a/src/mxmMidi/MidiOutStream.pyc b/src/mxmMidi/MidiOutStream.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53ceb24f634236178aaa89b66a063f9618c13b86 GIT binary patch literal 15350 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 literal 0 HcmV?d00001 diff --git a/src/mxmMidi/MidiToText.py b/src/mxmMidi/MidiToText.py new file mode 100644 index 0000000..7a35ff3 --- /dev/null +++ b/src/mxmMidi/MidiToText.py @@ -0,0 +1,184 @@ +# -*- coding: ISO-8859-1 -*- + +from MidiOutStream import MidiOutStream +class MidiToText(MidiOutStream): + + + """ + This class renders a midi file as text. It is mostly used for debugging + """ + + ############################# + # channel events + + def channel_message(self, message_type, channel, data): + """The default event handler for channel messages""" + print 'message_type:%X, channel:%X, data size:%X' % (message_type, channel, len(data)) + + + def note_on(self, channel=0, note=0x40, velocity=0x40): + print 'note_on - ch:%02X, note:%02X, vel:%02X time:%s' % (channel, note, velocity, self.timeInMs()) + + def note_off(self, channel=0, note=0x40, velocity=0x40): + print 'note_off - ch:%02X, note:%02X, vel:%02X time:%s' % (channel, note, velocity, self.abs_time()) + + def aftertouch(self, channel=0, note=0x40, velocity=0x40): + print 'aftertouch', channel, note, velocity + + + def continuous_controller(self, channel, controller, value): + print 'controller - ch: %02X, cont: #%02X, value: %02X' % (channel, controller, value) + + + def patch_change(self, channel, patch): + print 'patch_change - ch:%02X, patch:%02X' % (channel, patch) + + + def channel_pressure(self, channel, pressure): + print 'channel_pressure', channel, pressure + + + def pitch_bend(self, channel, value): + print 'pitch_bend ch:%s, value:%s' % (channel, value) + + + + ##################### + ## Common events + + + def system_exclusive(self, data): + print 'system_exclusive - data size: %s' % len(data) + + + def song_position_pointer(self, value): + print 'song_position_pointer: %s' % value + + + def song_select(self, songNumber): + print 'song_select: %s' % songNumber + + + def tuning_request(self): + print 'tuning_request' + + + def midi_time_code(self, msg_type, values): + print 'midi_time_code - msg_type: %s, values: %s' % (msg_type, values) + + + + ######################### + # header does not really belong here. But anyhoo!!! + + def header(self, format=0, nTracks=1, division=96): + print 'format: %s, nTracks: %s, division: %s' % (format, nTracks, division) + print '----------------------------------' + print '' + print division + self.division = division + + def eof(self): + print 'End of file' + + + def start_of_track(self, n_track=0): + print 'Start - track #%s' % n_track + + + def end_of_track(self): + print 'End of track' + print '' + + + + ############### + # sysex event + + def sysex_event(self, data): + print 'sysex_event - datasize: %X' % len(data) + + + ##################### + ## meta events + + def meta_event(self, meta_type, data): + print 'undefined_meta_event:', meta_type, len(data) + + + def sequence_number(self, value): + print 'sequence_number', value + + + def text(self, text): + print 'text', text + + + def copyright(self, text): + print 'copyright', text + + + def sequence_name(self, text): + print 'sequence_name:', text + + + def instrument_name(self, text): + print 'instrument_name:', text + + + def lyric(self, text): + print 'lyric', text + + + def marker(self, text): + print 'marker', text + + + def cuepoint(self, text): + print 'cuepoint', text + + + def midi_ch_prefix(self, channel): + print 'midi_ch_prefix', channel + + + def midi_port(self, value): + print 'midi_port:', value + + + def tempo(self, value): + print 'tempo:', value + self.tempo = value + + + def smtp_offset(self, hour, minute, second, frame, framePart): + print 'smtp_offset', hour, minute, second, frame, framePart + + + def time_signature(self, nn, dd, cc, bb): + print 'time_signature:', nn, dd, cc, bb + + + def key_signature(self, sf, mi): + print 'key_signature', sf, mi + + + def sequencer_specific(self, data): + print 'sequencer_specific', len(data) + + def timeInMs(self): + return(long(self.abs_time())*1000000000/(long(self.tempo)*long(self.division))) + + + +if __name__ == '__main__': + + # get data + test_file = '../songs/midis/test.mid' + f = open(test_file, 'rb') + + # do parsing + from MidiInFile import MidiInFile + midiIn = MidiInFile(MidiToText(), f) + midiIn.read() + f.close() diff --git a/src/mxmMidi/RawInstreamFile.py b/src/mxmMidi/RawInstreamFile.py new file mode 100644 index 0000000..0c2eba6 --- /dev/null +++ b/src/mxmMidi/RawInstreamFile.py @@ -0,0 +1,108 @@ +# -*- coding: ISO-8859-1 -*- + +# standard library imports +from types import StringType +from struct import unpack + +# custom import +from DataTypeConverters import readBew, readVar, varLen + + +class RawInstreamFile: + + """ + + It parses and reads data from an input file. It takes care of big + endianess, and keeps track of the cursor position. The midi parser + only reads from this object. Never directly from the file. + + """ + + def __init__(self, infile=''): + """ + If 'file' is a string we assume it is a path and read from + that file. + If it is a file descriptor we read from the file, but we don't + close it. + Midi files are usually pretty small, so it should be safe to + copy them into memory. + """ + if infile: + if isinstance(infile, StringType): + infile = open(infile, 'rb') + self.data = infile.read() + infile.close() + else: + # don't close the f + self.data = infile.read() + else: + self.data = '' + # start at beginning ;-) + self.cursor = 0 + + + # setting up data manually + + def setData(self, data=''): + "Sets the data from a string." + self.data = data + + # cursor operations + + def setCursor(self, position=0): + "Sets the absolute position if the cursor" + self.cursor = position + + + def getCursor(self): + "Returns the value of the cursor" + return self.cursor + + + def moveCursor(self, relative_position=0): + "Moves the cursor to a new relative position" + self.cursor += relative_position + + # native data reading functions + + def nextSlice(self, length, move_cursor=1): + "Reads the next text slice from the raw data, with length" + c = self.cursor + slc = self.data[c:c+length] + if move_cursor: + self.moveCursor(length) + return slc + + + def readBew(self, n_bytes=1, move_cursor=1): + """ + Reads n bytes of date from the current cursor position. + Moves cursor if move_cursor is true + """ + return readBew(self.nextSlice(n_bytes, move_cursor)) + + + def readVarLen(self): + """ + Reads a variable length value from the current cursor position. + Moves cursor if move_cursor is true + """ + MAX_VARLEN = 4 # Max value varlen can be + var = readVar(self.nextSlice(MAX_VARLEN, 0)) + # only move cursor the actual bytes in varlen + self.moveCursor(varLen(var)) + return var + + + +if __name__ == '__main__': + + test_file = 'test/midifiles/minimal.mid' + fis = RawInstreamFile(test_file) + print fis.nextSlice(len(fis.data)) + + test_file = 'test/midifiles/cubase-minimal.mid' + cubase_minimal = open(test_file, 'rb') + fis2 = RawInstreamFile(cubase_minimal) + print fis2.nextSlice(len(fis2.data)) + cubase_minimal.close() diff --git a/src/mxmMidi/RawInstreamFile.pyc b/src/mxmMidi/RawInstreamFile.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d05bf3b8d46642edef7ce802961b6c4dfdd3957 GIT binary patch literal 4140 zcmc&%+io015bc@uuDxqJw&OqoM56PQl`xBhKmmjz5{HXLY^2$cz{+UUJJYs1p35@b zW5-hbl>8s!k%#;QKLDqy_m+eQ9>7`8w5z*oditEIuB!R{&(+S0Kh*b$82?)M{}pcg z8=4eXAdZE|0x<|gK>bi0hazi;LBsbO;&?%1O)+SStR)65ku8eBBIXuEx-8PBcrL^< zA$}e#3EdWHOFRxmSz;b)9icJW5znyvve3)ItO&iz!X+BS_3d}*5-YBeV%iqZLNQq9 z=hpeT4WTzC&q0_yr`LtKOs@_K+ImOyyDPwC{=%;tKyn>4eOH;{@WI(g`!T{_7bBG% zcN?U$h^Epiy{k{B@<$oDXfEL{*B4>lulaXE^Z4Fg%-pjNF0R3 zE2w-9;0=}=EQ2##;0)tUA`9e!QW{+3!9@W&zyc{i@K;AX2Pq(Tne{s&@=)yyytE_n z<7UUnk*ch=QWdErP*$eODS1$pImVyD86*dQA_>vZO=NH5wi%kIfhd0v0W=^v_!8W13;mG#U?2VS zfMnAkCwVGFyujTi`^>Mg2ws^iI&dRA&YEe11-4DU+oZQjIF*M+l4rrOS6jA*#S?Og79=PF1WG3K-&Id|6ZBE1cmb_p$~wtjot67 zyw;h#tBVs|80+-@X;~dx1OvUlyR-Mmn1{FaZI$fjPjX^w|CLkU8=bi&ydjQFVO$)) z1=+5n5$(lbJy^rvrN(C14yPVVTV{`4g#dRW-{P3tXEgRYhOs@IFPxycvpROC-W~_7 zXc=n!Ky(R`??SjR&}2fZ-94D5M6H%}+nCY|S?E4sqw5zMa+xSFfHHX_-9Q7t< zth5%J_`=~GPT+lxEll7MO1c}k8QvxYz*_)5IPX75gT%CfWCOS0+=QZsE0(7V6DRo$OGKQmiMc{QL2jnTW+p*Or0h)-l{)1Zu_aFp za!RI)LwCegOhn$pVIg`O5~nNnBaV_@(NPc~V6hLUNST1+2#?K@3wJm|*(ZGWXahvL z2;0GxU@_PTm}J`6lw?9hnI0T+P6wyR?_hF#%xcU}6P>5Bki#gE^hC- zO%7Bq5&9`6Q6!;4nx_@jkEivV%OLnG{DZjWQaymwXN2|~k54)9d@G4^*{C6E7VmKA zQ>>f1?|;g>A=lsp)Fmk*aBKlS01=JN*@E0__s&o8!#mOaulLyJvDu5X2p2$9X3K3YF_P<|pDfFVi}sE~S<@PRk^YBdR$f3Y8H>O8vCQnD)nxb6_mf%pG{T54)^K=iYBI9&eG$RXp)= oM4zS?ZV%@BOYcIr37Mrxv>vQCt~WLxt%j{&CAf-qjs6FJ10tUC4FCWD literal 0 HcmV?d00001 diff --git a/src/mxmMidi/RawOutstreamFile.py b/src/mxmMidi/RawOutstreamFile.py new file mode 100644 index 0000000..73eed31 --- /dev/null +++ b/src/mxmMidi/RawOutstreamFile.py @@ -0,0 +1,69 @@ +# -*- coding: ISO-8859-1 -*- + +# standard library imports +import sys +from types import StringType +from struct import unpack +from cStringIO import StringIO + +# custom import +from DataTypeConverters import writeBew, writeVar, fromBytes + +class RawOutstreamFile: + + """ + + Writes a midi file to disk. + + """ + + def __init__(self, outfile=''): + self.buffer = StringIO() + self.outfile = outfile + + + # native data reading functions + + + def writeSlice(self, str_slice): + "Writes the next text slice to the raw data" + self.buffer.write(str_slice) + + + def writeBew(self, value, length=1): + "Writes a value to the file as big endian word" + self.writeSlice(writeBew(value, length)) + + + def writeVarLen(self, value): + "Writes a variable length word to the file" + var = self.writeSlice(writeVar(value)) + + + def write(self): + "Writes to disc" + if self.outfile: + if isinstance(self.outfile, StringType): + outfile = open(self.outfile, 'wb') + outfile.write(self.getvalue()) + outfile.close() + else: + self.outfile.write(self.getvalue()) + else: + sys.stdout.write(self.getvalue()) + + def getvalue(self): + return self.buffer.getvalue() + + +if __name__ == '__main__': + + out_file = 'test/midifiles/midiout.mid' + out_file = '' + rawOut = RawOutstreamFile(out_file) + rawOut.writeSlice('MThd') + rawOut.writeBew(6, 4) + rawOut.writeBew(1, 2) + rawOut.writeBew(2, 2) + rawOut.writeBew(15360, 2) + rawOut.write() diff --git a/src/mxmMidi/__init__.py b/src/mxmMidi/__init__.py new file mode 100644 index 0000000..b2d2031 --- /dev/null +++ b/src/mxmMidi/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: ISO-8859-1 -*- + +#import MidiOutStream +#import MidiInStream +#import MidiInFile +#import MidiToText \ No newline at end of file diff --git a/src/mxmMidi/changes.txt b/src/mxmMidi/changes.txt new file mode 100644 index 0000000..8b6670a --- /dev/null +++ b/src/mxmMidi/changes.txt @@ -0,0 +1,45 @@ +------------------------------------------------------------------------ +r409 | maxm | 2006-01-05 16:37:29 +0100 (to, 05 jan 2006) | 1 line + +Made RawOutstreamFile.py write to std out if no outfile is given. +------------------------------------------------------------------------ +r403 | maxm | 2006-01-05 13:34:11 +0100 (to, 05 jan 2006) | 1 line + + +------------------------------------------------------------------------ +r402 | maxm | 2006-01-05 13:33:56 +0100 (to, 05 jan 2006) | 1 line + +- Fixed minor bugs, added coding headers +------------------------------------------------------------------------ +r401 | maxm | 2006-01-01 23:09:17 +0100 (s_, 01 jan 2006) | 1 line + +Fixed sysex dispathcer bug. +------------------------------------------------------------------------ +r268 | maxm | 2005-02-04 12:26:59 +0100 (fr, 04 feb 2005) | 1 line + + +------------------------------------------------------------------------ +r128 | maxm | 2004-12-18 14:05:27 +0100 (l_, 18 dec 2004) | 1 line + +Fixed bug when using relative time +------------------------------------------------------------------------ +r15 | maxm | 2004-03-09 15:01:41 +0100 (ti, 09 mar 2004) | 1 line + +made a copy to meta folder +------------------------------------------------------------------------ +r13 | maxm | 2004-03-09 09:17:23 +0100 (ti, 09 mar 2004) | 1 line + +Deleted .pyc files +------------------------------------------------------------------------ +r12 | maxm | 2004-03-09 09:15:54 +0100 (ti, 09 mar 2004) | 1 line + +Removed file/folder +------------------------------------------------------------------------ +r3 | maxm | 2004-03-08 23:16:25 +0100 (ma, 08 mar 2004) | 1 line + +Adde midi +------------------------------------------------------------------------ +r1 | maxm | 2004-03-08 22:49:23 +0100 (ma, 08 mar 2004) | 1 line + +Initial Import +------------------------------------------------------------------------ diff --git a/src/mxmMidi/constants.py b/src/mxmMidi/constants.py new file mode 100644 index 0000000..81b91bc --- /dev/null +++ b/src/mxmMidi/constants.py @@ -0,0 +1,210 @@ +# -*- coding: ISO-8859-1 -*- + +################################################### +## Definitions of the different midi events + + + +################################################### +## Midi channel events (The most usual events) +## also called "Channel Voice Messages" + +NOTE_OFF = 0x80 +# 1000cccc 0nnnnnnn 0vvvvvvv (channel, note, velocity) + +NOTE_ON = 0x90 +# 1001cccc 0nnnnnnn 0vvvvvvv (channel, note, velocity) + +AFTERTOUCH = 0xA0 +# 1010cccc 0nnnnnnn 0vvvvvvv (channel, note, velocity) + +CONTINUOUS_CONTROLLER = 0xB0 # see Channel Mode Messages!!! +# 1011cccc 0ccccccc 0vvvvvvv (channel, controller, value) + +PATCH_CHANGE = 0xC0 +# 1100cccc 0ppppppp (channel, program) + +CHANNEL_PRESSURE = 0xD0 +# 1101cccc 0ppppppp (channel, pressure) + +PITCH_BEND = 0xE0 +# 1110cccc 0vvvvvvv 0wwwwwww (channel, value-lo, value-hi) + + +################################################### +## Channel Mode Messages (Continuous Controller) +## They share a status byte. +## The controller makes the difference here + +# High resolution continuous controllers (MSB) + +BANK_SELECT = 0x00 +MODULATION_WHEEL = 0x01 +BREATH_CONTROLLER = 0x02 +FOOT_CONTROLLER = 0x04 +PORTAMENTO_TIME = 0x05 +DATA_ENTRY = 0x06 +CHANNEL_VOLUME = 0x07 +BALANCE = 0x08 +PAN = 0x0A +EXPRESSION_CONTROLLER = 0x0B +EFFECT_CONTROL_1 = 0x0C +EFFECT_CONTROL_2 = 0x0D +GEN_PURPOSE_CONTROLLER_1 = 0x10 +GEN_PURPOSE_CONTROLLER_2 = 0x11 +GEN_PURPOSE_CONTROLLER_3 = 0x12 +GEN_PURPOSE_CONTROLLER_4 = 0x13 + +# High resolution continuous controllers (LSB) + +BANK_SELECT = 0x20 +MODULATION_WHEEL = 0x21 +BREATH_CONTROLLER = 0x22 +FOOT_CONTROLLER = 0x24 +PORTAMENTO_TIME = 0x25 +DATA_ENTRY = 0x26 +CHANNEL_VOLUME = 0x27 +BALANCE = 0x28 +PAN = 0x2A +EXPRESSION_CONTROLLER = 0x2B +EFFECT_CONTROL_1 = 0x2C +EFFECT_CONTROL_2 = 0x2D +GENERAL_PURPOSE_CONTROLLER_1 = 0x30 +GENERAL_PURPOSE_CONTROLLER_2 = 0x31 +GENERAL_PURPOSE_CONTROLLER_3 = 0x32 +GENERAL_PURPOSE_CONTROLLER_4 = 0x33 + +# Switches + +SUSTAIN_ONOFF = 0x40 +PORTAMENTO_ONOFF = 0x41 +SOSTENUTO_ONOFF = 0x42 +SOFT_PEDAL_ONOFF = 0x43 +LEGATO_ONOFF = 0x44 +HOLD_2_ONOFF = 0x45 + +# Low resolution continuous controllers + +SOUND_CONTROLLER_1 = 0x46 # (TG: Sound Variation; FX: Exciter On/Off) +SOUND_CONTROLLER_2 = 0x47 # (TG: Harmonic Content; FX: Compressor On/Off) +SOUND_CONTROLLER_3 = 0x48 # (TG: Release Time; FX: Distortion On/Off) +SOUND_CONTROLLER_4 = 0x49 # (TG: Attack Time; FX: EQ On/Off) +SOUND_CONTROLLER_5 = 0x4A # (TG: Brightness; FX: Expander On/Off)75 SOUND_CONTROLLER_6 (TG: Undefined; FX: Reverb OnOff) +SOUND_CONTROLLER_7 = 0x4C # (TG: Undefined; FX: Delay OnOff) +SOUND_CONTROLLER_8 = 0x4D # (TG: Undefined; FX: Pitch Transpose OnOff) +SOUND_CONTROLLER_9 = 0x4E # (TG: Undefined; FX: Flange/Chorus OnOff) +SOUND_CONTROLLER_10 = 0x4F # (TG: Undefined; FX: Special Effects OnOff) +GENERAL_PURPOSE_CONTROLLER_5 = 0x50 +GENERAL_PURPOSE_CONTROLLER_6 = 0x51 +GENERAL_PURPOSE_CONTROLLER_7 = 0x52 +GENERAL_PURPOSE_CONTROLLER_8 = 0x53 +PORTAMENTO_CONTROL = 0x54 # (PTC) (0vvvvvvv is the source Note number) (Detail) +EFFECTS_1 = 0x5B # (Ext. Effects Depth) +EFFECTS_2 = 0x5C # (Tremelo Depth) +EFFECTS_3 = 0x5D # (Chorus Depth) +EFFECTS_4 = 0x5E # (Celeste Depth) +EFFECTS_5 = 0x5F # (Phaser Depth) +DATA_INCREMENT = 0x60 # (0vvvvvvv is n/a; use 0) +DATA_DECREMENT = 0x61 # (0vvvvvvv is n/a; use 0) +NON_REGISTERED_PARAMETER_NUMBER = 0x62 # (LSB) +NON_REGISTERED_PARAMETER_NUMBER = 0x63 # (MSB) +REGISTERED_PARAMETER_NUMBER = 0x64 # (LSB) +REGISTERED_PARAMETER_NUMBER = 0x65 # (MSB) + +# Channel Mode messages - (Detail) + +ALL_SOUND_OFF = 0x78 +RESET_ALL_CONTROLLERS = 0x79 +LOCAL_CONTROL_ONOFF = 0x7A +ALL_NOTES_OFF = 0x7B +OMNI_MODE_OFF = 0x7C # (also causes ANO) +OMNI_MODE_ON = 0x7D # (also causes ANO) +MONO_MODE_ON = 0x7E # (Poly Off; also causes ANO) +POLY_MODE_ON = 0x7F # (Mono Off; also causes ANO) + + + +################################################### +## System Common Messages, for all channels + +SYSTEM_EXCLUSIVE = 0xF0 +# 11110000 0iiiiiii 0ddddddd ... 11110111 + +MTC = 0xF1 # MIDI Time Code Quarter Frame +# 11110001 + +SONG_POSITION_POINTER = 0xF2 +# 11110010 0vvvvvvv 0wwwwwww (lo-position, hi-position) + +SONG_SELECT = 0xF3 +# 11110011 0sssssss (songnumber) + +#UNDEFINED = 0xF4 +## 11110100 + +#UNDEFINED = 0xF5 +## 11110101 + +TUNING_REQUEST = 0xF6 +# 11110110 + +END_OFF_EXCLUSIVE = 0xF7 # terminator +# 11110111 # End of system exclusive + + +################################################### +## Midifile meta-events + +SEQUENCE_NUMBER = 0x00 # 00 02 ss ss (seq-number) +TEXT = 0x01 # 01 len text... +COPYRIGHT = 0x02 # 02 len text... +SEQUENCE_NAME = 0x03 # 03 len text... +INSTRUMENT_NAME = 0x04 # 04 len text... +LYRIC = 0x05 # 05 len text... +MARKER = 0x06 # 06 len text... +CUEPOINT = 0x07 # 07 len text... +PROGRAM_NAME = 0x08 # 08 len text... +DEVICE_NAME = 0x09 # 09 len text... + +MIDI_CH_PREFIX = 0x20 # MIDI channel prefix assignment (unofficial) + +MIDI_PORT = 0x21 # 21 01 port, legacy stuff but still used +END_OF_TRACK = 0x2F # 2f 00 +TEMPO = 0x51 # 51 03 tt tt tt (tempo in us/quarternote) +SMTP_OFFSET = 0x54 # 54 05 hh mm ss ff xx +TIME_SIGNATURE = 0x58 # 58 04 nn dd cc bb +KEY_SIGNATURE = 0x59 # ??? len text... +SPECIFIC = 0x7F # Sequencer specific event + +FILE_HEADER = 'MThd' +TRACK_HEADER = 'MTrk' + +################################################### +## System Realtime messages +## I don't supose these are to be found in midi files?! + +TIMING_CLOCK = 0xF8 +# undefined = 0xF9 +SONG_START = 0xFA +SONG_CONTINUE = 0xFB +SONG_STOP = 0xFC +# undefined = 0xFD +ACTIVE_SENSING = 0xFE +SYSTEM_RESET = 0xFF + + +################################################### +## META EVENT, it is used only in midi files. +## In transmitted data it means system reset!!! + +META_EVENT = 0xFF +# 11111111 + + +################################################### +## Helper functions + +def is_status(byte): + return (byte & 0x80) == 0x80 # 1000 0000 + + diff --git a/src/mxmMidi/constants.pyc b/src/mxmMidi/constants.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ce9fecea7b9f08d07346880b3a90cdaf0ccaee6 GIT binary patch literal 3692 zcmcJRTXz)45y$@$AaTDM8yjo{<|1=P7X%n%jb?jy2hGkbGqbuB3xiPYNjA2G4?83# z_XmG~e1yE^H6J10AogQkeDVHKC8P(UmPAOp}r$RKnFWCwI7WG8eNWEXS@G6Wrl3`2KAc0>0- z_CWVS_CohT_CfbU_CpUq4nPk=4nhw>4nYq?4nvPXjzEt>jzW(?jzQmoyahcDISzdr z@;3AxXa9t=|E{zDp0j__*+1p%zwhjS;Ow7v_D7ukGtT~5Xa7UUJJ55G6VUUJccB*` z??Ep@PC`c^r=TA}-iKa-d;q-+ISsu68G&AfoPl10oP}P8d(G0U8_-W6H=*|-W6)0_6k=R7%PyJ~7tJa(g9I+74_r)VT}(q4)0&HE1Z_ZK7pXebM(QDS z4wAUFr*6F&bRN=xECY}&E@swC1o)KCGm>*G4T`Pr^L^QpA)|z z{zUwl_>TAs@mJz+#13K)ah+Ho7A*>fqLzJMdyN;Lwg1k(e-Qs9{zd$o_>aXhgUE+* zkurG3H!60Ci`p*8dS4FEUqP#P2;oohRo-e;#X{{EWk)>4~ zNn1tHUj1IDnJ%roY<)g5(^~yuYqi}eTFoClfALx8i>2jOvlc}2?e^SMv-4uPx$@;o zt*!0m^7GYBv1ILB`{GsM*4oLfpm^E&J!hj=7>Gu>$;EDqD9%hCm&*n7ulo`e%s{W4 znIwxFeziDmU;Q}Bf~XNU(wxmC4nva^OwhWQ`PJO7dQrs`%u_Za6Xx~Aq-i5D&Rjj9 z){Kct1yg&*i)QoGgvQU@m|9$FgkBcJQ9fTaCM=liGl}ssYkGaYLsnXjL~*J+r%61!>HX&2Mqz9_ z3**}21=TLU$;G$WIJU>$<39)X1bnU&16N(8c|?%6Z5cP(#%y%TVCnv z2Gj1qQNtFxwe90|mzjmk#mA59i%C$aX5AzFTGj4&!NEb4W{ItsQIusSdfeTJT2|*WZ8)7Rmi#;oDv_7*x?!AV&Ef_L-An7n56aeUdQ%QUlUI#b zvc5BjZkA1gz}~Kv+_#xA>+Y}a=4YPuj`rOv6UN?&#(CdUi0jTJ&(CaN?F|>D){dK_ z7j>6~&ZJFgdqK_disB8l{!QRo|JM%#Zpgir=lb&V)_tzO^R30ujt&3&h6c9$-??S) oz|hA2jqR 127: + note = 127 + return note + + + def note_on(self, channel=0, note=0x40, velocity=0x40): + note = self._transp(channel, note) + MidiOutFile.note_on(self, channel, note, velocity) + + + def note_off(self, channel=0, note=0x40, velocity=0x40): + note = self._transp(channel, note) + MidiOutFile.note_off(self, channel, note, velocity) + + +out_file = 'midiout/transposed.mid' +midi_out = Transposer(out_file) + +#in_file = 'midiout/minimal_type0.mid' +#in_file = 'test/midifiles/Lola.mid' +in_file = 'test/midifiles/tennessee_waltz.mid' +midi_in = MidiInFile(midi_out, in_file) +midi_in.read() + diff --git a/src/mxmMidi/experimental/EventDispatcherBase.py b/src/mxmMidi/experimental/EventDispatcherBase.py new file mode 100644 index 0000000..71bde62 --- /dev/null +++ b/src/mxmMidi/experimental/EventDispatcherBase.py @@ -0,0 +1,76 @@ +class EventDispatcherBase: + + + def __init__(self, outstream): + """ + The event dispatcher generates events on the outstream. This + is the base implementation. It is more like an interface for + how the EventDispatcher. It has the methods that are used by + the Midi Parser. + """ + # internal values, don't mess with 'em directly + self.outstream = outstream + + + def eof(self): + "End of file!" + self.outstream.eof() + + + def update_time(self, new_time=0, relative=1): + "Updates relative/absolute time." + self.outstream.update_time(new_time, relative) + + # 'official' midi events + + def header(self, format, nTracks, division): + "Triggers the header event" + self.outstream.header(format, nTracks, division) + + + def start_of_track(self, current_track): + "Triggers the start of track event" + + # I do this twice so that users can overwrite the + # start_of_track event handler without worrying whether the + # track number is updated correctly. + self.outstream.set_current_track(current_track) + self.outstream.start_of_track(current_track) + + # Event dispatchers for midi events + + def channel_messages(self, hi_nible, channel, data): + "Dispatches channel messages" + self.outstream.channel_message(hi_nible, channel, data) + + + def continuous_controllers(self, channel, controller, value): + "Dispatches channel messages" + self.outstream.continuous_controller(channel, controller, value) + + + def system_commons(self, common_type, common_data): + "Dispatches system common messages" + self.outstream.system_common(common_type, common_data) + + + def meta_event(self, meta_type, data): + "Dispatches meta events" + self.outstream.meta_event(meta_type, data) + + + def sysex_events(self, data): + "Dispatcher for sysex events" + self.outstream.sysex_event(data) + + + +if __name__ == '__main__': + + + from MidiToText import MidiToText + from constants import NOTE_ON + + outstream = MidiToText() + dispatcher = EventDispatcherBase(outstream) + dispatcher.channel_messages(NOTE_ON, 0x00, '\x40\x40') \ No newline at end of file diff --git a/src/mxmMidi/experimental/MidiOutPassThrough.py b/src/mxmMidi/experimental/MidiOutPassThrough.py new file mode 100644 index 0000000..25ceed4 --- /dev/null +++ b/src/mxmMidi/experimental/MidiOutPassThrough.py @@ -0,0 +1,182 @@ +from MidiOutStream import MidiOutStream + +class MidiOutPassThrough(MidiOutStream): + + + """ + + This class i mainly used for testing the event dispatcher. The + methods just returns the passed parameters as a tupple. + + """ + + + ##################### + ## Midi channel events + + + def note_on(self, channel, note, velocity, time=None): + return channel, note, velocity, time + + + def note_off(self, channel, note, velocity, time=None): + return channel, note, velocity, time + + + def aftertouch(self, channel, note, velocity, time=None): + return channel, note, velocity, time + + + def continuous_controller(self, channel, controller, value, time=None): + return channel, controller, value, time + + + def patch_change(self, channel, patch, time=None): + return channel, patch, time + + + def channel_pressure(self, channel, pressure, time=None): + return channel, pressure, time + + + ##################### + ## defined continuous controller events + +# def cc_ + + ##################### + ## Common events + + def system_exclusive(self, data, time=None): + return data, time + + + def song_position_pointer(self, hiPos, loPos, time=None): + return hiPos, loPos, time + + + def song_select(self, songNumber, time=None): + return songNumber, time + + + def tuning_request(self, time=None): + return time + + + + ######################### + # header does not really belong here. But anyhoo!!! + + def header(self, format, nTracks, division): + return format, nTracks, division + + + def eof(self): + return 'eof' + + + ##################### + ## meta events + + def start_of_track(self, n_track=0): + return n_track + + + def end_of_track(self, n_track=0, time=None): + return n_track, time + + + def sequence_number(self, hiVal, loVal, time=None): + return hiVal, loVal, time + + + def text(self, text, time=None): + return text, time + + + def copyright(self, text, time=None): + return text, time + + + def sequence_name(self, text, time=None): + return text, time + + + def instrument_name(self, text, time=None): + return text, time + + + def lyric(self, text, time=None): + return text, time + + + def marker(self, text, time=None): + return text, time + + + def cuepoint(self, text, time=None): + return text, time + + + def midi_port(self, value, time=None): + return value, time + + + def tempo(self, value, time=None): + return value, time + + def smtp_offset(self, hour, minute, second, frame, framePart, time=None): + return hour, minute, second, frame, framePart, time + + + def time_signature(self, nn, dd, cc, bb, time=None): + return nn, dd, cc, bb, time + + + def key_signature(self, sf, mi, time=None): + return sf, mi, time + + + def sequencer_specific(self, data, time=None): + return data, time + + + + + ##################### + ## realtime events + + def timing_clock(self, time=None): + return time + + + def song_start(self, time=None): + return time + + + def song_stop(self, time=None): + return time + + + def song_continue(self, time=None): + return time + + + def active_sensing(self, time=None): + return time + + + def system_reset(self, time=None): + return time + + + + + +if __name__ == '__main__': + + midiOut = MidiOutStream() + midiOut.note_on(0, 63, 127, 0) + midiOut.note_off(0, 63, 127, 384) + + \ No newline at end of file diff --git a/src/mxmMidi/experimental/MidiOutStreamBase.py b/src/mxmMidi/experimental/MidiOutStreamBase.py new file mode 100644 index 0000000..1abada0 --- /dev/null +++ b/src/mxmMidi/experimental/MidiOutStreamBase.py @@ -0,0 +1,135 @@ +class MidiOutStreamBase: + + + """ + + MidiOutStreamBase is Basically an eventhandler. It is the most central + class in the Midi library. You use it both for writing events to + an output stream, and as an event handler for an input stream. + + This makes it extremely easy to take input from one stream and + send it to another. Ie. if you want to read a Midi file, do some + processing, and send it to a midiport. + + All time values are in absolute values from the opening of a + stream. To calculate time values, please use the MidiTime and + MidiDeltaTime classes. + + """ + + def __init__(self): + + # the time is rather global, so it needs to be stored + # here. Otherwise there would be no really simple way to + # calculate it. The alternative would be to have each event + # handler do it. That sucks even worse! + self._absolute_time = 0 + self._relative_time = 0 + self._current_track = 0 + + # time handling event handlers. They should overwritten with care + + def update_time(self, new_time=0, relative=1): + """ + Updates the time, if relative is true, new_time is relative, + else it's absolute. + """ + if relative: + self._relative_time = new_time + self._absolute_time += new_time + else: + self._absolute_time = new_time + self._relative_time = new_time - self._absolute_time + + def rel_time(self): + "Returns the relative time" + return self._relative_time + + def abs_time(self): + "Returns the absolute time" + return self._absolute_time + + # track handling event handlers + + def set_current_track(self, new_track): + "Sets the current track number" + self._current_track = new_track + + def get_current_track(self): + "Returns the current track number" + return self._current_track + + + ##################### + ## Midi events + + + def channel_message(self, message_type, channel, data): + """The default event handler for channel messages""" + pass + + + ##################### + ## Common events + + def system_exclusive(self, data): + + """The default event handler for system_exclusive messages""" + pass + + + def system_common(self, common_type, common_data): + + """The default event handler for system common messages""" + pass + + + ######################### + # header does not really belong here. But anyhoo!!! + + def header(self, format, nTracks, division): + + """ + format: type of midi file in [1,2] + nTracks: number of tracks + division: timing division + """ + pass + + + def start_of_track(self, n_track=0): + + """ + n_track: number of track + """ + pass + + + def eof(self): + + """ + End of file. No more events to be processed. + """ + pass + + + ##################### + ## meta events + + + def meta_event(self, meta_type, data, time): + + """The default event handler for meta_events""" + pass + + + + +if __name__ == '__main__': + + midiOut = MidiOutStreamBase() + midiOut.update_time(0,0) + midiOut.note_on(0, 63, 127) + midiOut.note_off(0, 63, 127) + + \ No newline at end of file diff --git a/src/mxmMidi/experimental/readme.txt b/src/mxmMidi/experimental/readme.txt new file mode 100644 index 0000000..4234118 --- /dev/null +++ b/src/mxmMidi/experimental/readme.txt @@ -0,0 +1 @@ +Stuff that I am just playing around with \ No newline at end of file diff --git a/src/mxmMidi/midiout/minimal_type0.mid b/src/mxmMidi/midiout/minimal_type0.mid new file mode 100644 index 0000000000000000000000000000000000000000..ffdfcda3ee633017534da66d7ac09a53c7f2b5e5 GIT binary patch literal 35 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 G?*9kCU(Ry? literal 0 HcmV?d00001 diff --git a/src/mxmMidi/readme.txt b/src/mxmMidi/readme.txt new file mode 100644 index 0000000..d3c7431 --- /dev/null +++ b/src/mxmMidi/readme.txt @@ -0,0 +1,50 @@ +This is the documentation for the midi package +============================================== + + +The modules follows the following naming convention: + + +MidiIn.py +--------------------- + +The MidiIn modules reads midi content for a specific type of stream. Ie. a file or a midi port. It then generates events and triggers them on a MidiOutStream. + + +MidiOut.py +---------------------- + +The MidiOut modules are event handlers, that reacts to events generated by a a Midi in module. + + +MidiInBase.py +--------------- + +The base class for input streams. + + +MidiOutBase.py +---------------- + +The base class for the output streams. + + + + + + +Internal modules +================ + + +DataTypeConverters.py +--------------------- + +A collection of functions that converts the special data types used in midi files to and from strings. + + +constants.py +------------ + +A collection of constants from the midi spec. + diff --git a/src/mxmMidi/test/midifiles/midiout.mid b/src/mxmMidi/test/midifiles/midiout.mid new file mode 100644 index 0000000000000000000000000000000000000000..eff8ffa745aa66aee6c7f6a8817bbcb94843c51e GIT binary patch literal 1067 zcmWN?RaR92006)XJQ@TEX(^Rdx{*#5sYgq9cO%CouoRc%PH;Zv%vgADD+q!ZA|n2c zg)a_+Ae0%rM#Y5h&$f$dgV)KZ#Ph$w>wG8_nH?9r1Y2u=f}Y?d!V!*iq@x_=kVB4k zv|}9OSjRffagKMq6P(~gCpyVVPIj{2_>EJX;#8;lt=~G$X-;>#Go0Z}XZoGrIm=nj zcD8ez<6P%D&w0*wz6)I7_kQm}7rMwrE_Sg?T;fuf`h!3Cqd)qSKe^0hE_b;rT;WPr zy2@3qcC|nIv%mO@Yh2@6*SgMiu6Ml~+~7txy2(v$cC%aD;#Rl1&24UXyF1+BPIvmN zzq-p^?sm6(+~Z#Ny3c*?cfSWb;6V?1$U`3Xutz-NQIGnYzxlhr`-gvc%wzuPpC0$P zCp_UvPkPEzp7ylE4tvHkp7pHfJm-1Od%+7{^rDx%A#!4H1)qo4fb-~R1qKlcQ$HNk%<%Tkg6 literal 0 HcmV?d00001 diff --git a/src/mxmMidi/test/midifiles/minimal-cubase-type0.mid b/src/mxmMidi/test/midifiles/minimal-cubase-type0.mid new file mode 100644 index 0000000000000000000000000000000000000000..dcea0cfc9201f12b23d44979b809d8e68832e59e GIT binary patch literal 59 zcmeYb$w*;fU|<7cM#cxeAw}6hmMX)4X10*Zf>Z?qhW~-g>r*n0=uv!R$)T}?81iFg|Yk65W6o8vHQ{xyDtsFz61bmRcOQj literal 0 HcmV?d00001 diff --git a/src/mxmMidi/test/midifiles/minimal.mid b/src/mxmMidi/test/midifiles/minimal.mid new file mode 100644 index 0000000000000000000000000000000000000000..c4567b22536c36d0d1bd7f0ef4a2fad0b2a0b63d GIT binary patch literal 96 zcmeYb$w*;fU|?flWMHyk@C_--2J*xh{ztH|FiCJQ{10SiU#QUZy@BDsK1^1J;XgBb iaAjUehJqo(e-;E&k&%UAf=Ye!1BM0_hNjO8Kzaa7eHu3a literal 0 HcmV?d00001 diff --git a/src/mxmMidi/test/midifiles/minimal.txt b/src/mxmMidi/test/midifiles/minimal.txt new file mode 100644 index 0000000..dd9f61e --- /dev/null +++ b/src/mxmMidi/test/midifiles/minimal.txt @@ -0,0 +1,26 @@ +MThd | Format=1 | # of Tracks=2 | Division=15360 + + + + +Track #0 ****************************************** + Time Event + + 1: 1: 0 |Time Sig | 4/4 | MIDI-clocks\click=24 | 32nds\quarter=8 + |Tempo | BPM=120 | micros\quarter=500000 + 101: 1: 0 |End of track| + + + + + +Track #1 ****************************************** + Time Event + + 1: 1: 0 |Track Name | len=7 | + 0x53 0x79 0x6E 0x74 0x68 0x20 0x31 + |Instrument | len=7 | + 0x53 0x79 0x6E 0x74 0x68 0x20 0x31 + |On Note | chan= 1 | pitch=C 1 | vol=127 + 2: 1: 0 |Off Note | chan= 1 | pitch=c 1 | vol=0 + 101: 1: 0 |End of track| diff --git a/src/mxmMidi/test/midifiles/minimal_analyse.txt b/src/mxmMidi/test/midifiles/minimal_analyse.txt new file mode 100644 index 0000000..498dfe9 --- /dev/null +++ b/src/mxmMidi/test/midifiles/minimal_analyse.txt @@ -0,0 +1,54 @@ +4D 54 68 64 MThd +00 00 00 06 len: 6 +00 01 Type: 1 +00 02 tracks: 2 +3C 00 tempo: 15360 + + + +4D 54 72 6B MTrk +00 00 00 16 len: 22 + +00 time + FF 58 04 Time Signature + 04 02 18 08 4/4 24 8 + +00 time + FF 51 03 TEMPO: + 07 A1 20 500.000 mySec + +82 F7 80 00 time ## oh bugger, it's buggy. + FF 2F 00 End Of Track + + + +4D 54 72 6B MTrk +00 00 00 2C len: 44 + +00 time + FF 03 Sequence/Track Name + 07 len: 7 + 53 79 6E 74 + 68 20 31 'Synth 1' + +00 time + FF 04 Instrument + 07 len: 7 + 53 79 6E 74 + 68 20 31 'Synth 1' + +00 time + FF 21 01 Midi port + 04 Port #5 + +00 time + 90 24 7F Note ON + 83 E0 00 Note OFF + +00 time + 80 24 00 Note OFF + +00 82 F3 A0 + +00 + FF 2F 00 End Of Track \ No newline at end of file diff --git a/src/mxmMidi/test/midifiles/readme.txt b/src/mxmMidi/test/midifiles/readme.txt new file mode 100644 index 0000000..f3f59cd --- /dev/null +++ b/src/mxmMidi/test/midifiles/readme.txt @@ -0,0 +1,7 @@ +These files are used for testing the midi package +================================================= + +minimal.mid +----------- + +A minimal working midifile. Plays a one bar "middle C" at 120 bpm. The absolute simplest file I could get to play in midi devices. \ No newline at end of file diff --git a/src/mxmMidi/test/readme.txt b/src/mxmMidi/test/readme.txt new file mode 100644 index 0000000..c40adf3 --- /dev/null +++ b/src/mxmMidi/test/readme.txt @@ -0,0 +1,3 @@ +Embarrasingly empty. + +Why don't you write some tests? \ No newline at end of file diff --git a/src/mxmMidi/version.txt b/src/mxmMidi/version.txt new file mode 100644 index 0000000..446ba66 --- /dev/null +++ b/src/mxmMidi/version.txt @@ -0,0 +1 @@ +0.1.4 \ No newline at end of file diff --git a/src/pgu/__init__.py b/src/pgu/__init__.py new file mode 100644 index 0000000..5cc6d1c --- /dev/null +++ b/src/pgu/__init__.py @@ -0,0 +1,7 @@ +"""Phil's pyGame Utilities + + +""" +__version__ = '0.12.3' + +# vim: set filetype=python sts=4 sw=4 noet si : diff --git a/src/pgu/algo.py b/src/pgu/algo.py new file mode 100644 index 0000000..993eab0 --- /dev/null +++ b/src/pgu/algo.py @@ -0,0 +1,143 @@ +"""Some handy algorithms for use in games, etc. + +

please note that this file is alpha, and is subject to modification in +future versions of pgu!

+""" + +# The manhattan distance metric +def manhattan_dist(a,b): + return abs(a[0]-b[0]) + abs(a[1]-b[1]) + +class node: + def __init__(self, prev, pos, dest, dist): + self.prev,self.pos,self.dest = prev,pos,dest + if self.prev == None: self.g = 0 + else: self.g = self.prev.g + 1 + self.h = dist(pos,dest) + self.f = self.g+self.h + + +def astar(start,end,layer,dist=manhattan_dist): + """uses the a* algorithm to find a path + +
astar(start,end,layer,dist): return [list of positions]
+ +
+
start
start position +
end
end position +
layer
a grid where zero cells are open and non-zero cells are walls +
dist
a distance function dist(a,b) - manhattan distance is used by default +
+ +

returns a list of positions from start to end

+ """ + + w,h = len(layer[0]),len(layer) + if start[0] < 0 or start[1] < 0 or start[0] >= w or start[1] >= h: + return [] #start outside of layer + if end[0] < 0 or end[1] < 0 or end[0] >= w or end[1] >= h: + return [] #end outside of layer + + if layer[start[1]][start[0]]: + return [] #start is blocked + if layer[end[1]][end[0]]: + return [] #end is blocked + + opens = [] + open = {} + closed = {} + cur = node(None, start, end, dist) + open[cur.pos] = cur + opens.append(cur) + while len(open): + cur = opens.pop(0) + if cur.pos not in open: continue + del open[cur.pos] + closed[cur.pos] = cur + if cur.pos == end: break + for dx,dy in [(0,-1),(1,0),(0,1),(-1,0)]:#(-1,-1),(1,-1),(-1,1),(1,1)]: + pos = cur.pos[0]+dx,cur.pos[1]+dy + # Check if the point lies in the grid + if (pos[0] < 0 or pos[1] < 0 or + pos[0] >= w or pos[1] >= h or + layer[pos[0]][pos[1]]): + continue + #check for blocks of diagonals + if layer[cur.pos[1]+dy][cur.pos[0]]: continue + if layer[cur.pos[1]][cur.pos[0]+dx]: continue + new = node(cur, pos, end, dist) + if pos in open and new.f >= open[pos].f: continue + if pos in closed and new.f >= closed[pos].f: continue + if pos in open: del open[pos] + if pos in closed: del closed[pos] + open[pos] = new + lo = 0 + hi = len(opens) + while lo < hi: + mid = (lo+hi)/2 + if new.f < opens[mid].f: hi = mid + else: lo = mid + 1 + opens.insert(lo,new) + + if cur.pos != end: + return [] + + path = [] + while cur.prev != None: + path.append(cur.pos) + cur = cur.prev + path.reverse() + return path + + +def getline(a,b): + """returns a path of points from a to b + +
getline(a,b): return [list of points]
+ +
+
a
starting point +
b
ending point +
+ +

returns a list of points from a to b

+ """ + + path = [] + + x1,y1 = a + x2,y2 = b + dx,dy = abs(x2-x1),abs(y2-y1) + + if x2 >= x1: xi1,xi2 = 1,1 + else: xi1,xi2 = -1,-1 + + if y2 >= y1: yi1,yi2 = 1,1 + else: yi1,yi2 = -1,-1 + + if dx >= dy: + xi1,yi2 = 0,0 + d = dx + n = dx/2 + a = dy + p = dx + else: + xi2,yi1 = 0,0 + d = dy + n = dy/2 + a = dx + p = dy + + x,y = x1,y1 + c = 0 + while c <= p: + path.append((x,y)) + n += a + if n > d: + n -= d + x += xi1 + y += yi1 + x += xi2 + y += yi2 + c += 1 + return path diff --git a/src/pgu/ani.py b/src/pgu/ani.py new file mode 100644 index 0000000..c33d380 --- /dev/null +++ b/src/pgu/ani.py @@ -0,0 +1,90 @@ +"""animation loading and manipulating functions. + +

please note that this file is alpha, and is subject to modification in +future versions of pgu!

+""" + +print 'pgu.ani','This module is alpha, and is subject to change.' + +import math +import pygame + +def _ani_load(tv,name,parts,frames,shape): + l = len(frames) + #print name,parts,l + n = parts.pop() + if len(parts): + s = l/n + for i in xrange(0,n): + _ani_load(tv,name + ".%d"%i,parts[:],frames[s*i:s*(i+1)],shape) + return + + for i in xrange(0,n): + tv.images[name+".%d"%i] = frames[i],shape + +def ani_load(tv,name,img,size,shape,parts): + """load an animation from an image + +
ani_load(tv,name,image,size,shape,parts)
+ +
+
tv
vid to load into +
name
prefix name to give the images +
image
image to load anis from +
size
w,h size of image +
shape
shape of image (usually a subset of 0,0,w,h) used for collision detection +
parts
list of parts to divide the animation into +
for example parts = [4,5] would yield 4 animations 5 frames long, 20 total +
for example parts = [a,b,c] would yield ... images['name.a.b.c'] ..., a*b*c total +
+ + """ + parts = parts[:] + parts.reverse() + w,h = size + frames = [] + for y in xrange(0,img.get_height(),h): + for x in xrange(0,img.get_width(),w): + frames.append(img.subsurface(x,y,w,h)) + _ani_load(tv,name,parts,frames,shape) + + +def image_rotate(tv,name,img,shape,angles,diff=0): + """rotate an image and put it into tv.images + +
image_rotate(tv,name,image,shape,angles,diff=0)
+ +
+
tv
vid to load into +
name
prefix name to give the images +
image
image to load anis from +
shape
shape fimage (usually a subset of 0,0,w,h) used for collision detection +
angles
a list of angles to render in degrees +
diff
a number to add to the angles, to correct for source image not actually being at 0 degrees +
+ """ + w1,h1 = img.get_width(),img.get_height() + shape = pygame.Rect(shape) + ps = shape.topleft,shape.topright,shape.bottomleft,shape.bottomright + for a in angles: + img2 = pygame.transform.rotate(img,a+diff) + w2,h2 = img2.get_width(),img2.get_height() + minx,miny,maxx,maxy = 1024,1024,0,0 + for x,y in ps: + x,y = x-w1/2,y-h1/2 + a2 = math.radians(a+diff) + #NOTE: the + and - are switched from the normal formula because of + #the weird way that pygame does the angle... + x2 = x*math.cos(a2) + y*math.sin(a2) + y2 = y*math.cos(a2) - x*math.sin(a2) + x2,y2 = x2+w2/2,y2+h2/2 + minx = min(minx,x2) + miny = min(miny,y2) + maxx = max(maxx,x2) + maxy = max(maxy,y2) + r = pygame.Rect(minx,miny,maxx-minx,maxy-miny) + #print r + #((ww-w)/2,(hh-h)/2,w,h) + tv.images["%s.%d"%(name,a)] = img2,r + + diff --git a/src/pgu/engine.py b/src/pgu/engine.py new file mode 100644 index 0000000..76be583 --- /dev/null +++ b/src/pgu/engine.py @@ -0,0 +1,154 @@ +"""a state engine. +""" +import pygame +from pygame.locals import * + +class State: + """Template Class -- for a state. + +
State(game,value...)
+ +
+
game
The state engine. +
value
I usually pass in a custom value to a state +
+ +

For all of the template methods, they should return None unless they return + a new State to switch the engine to.

+ """ + def __init__(self,game,value=None): + self.game,self.value = game,value + def init(self): + """Template Method - Initialize the state, called once the first time a state is selected. + +
State.init()
+ """ + return + def paint(self,screen): + """Template Method - Paint the screen. Called once after the state is selected. + +

State is responsible for calling pygame.display.flip() or whatever.

+ +
State.paint(screen)
+ """ + return + + def repaint(self): + """Template Method - Request a repaint of this state. + +
State.repaint()
+ """ + self._paint = 1 + def update(self,screen): + """Template Method - Update the screen. + +

State is responsible for calling pygame.display.update(updates) or whatever.

+ +
State.update(screen)
+ """ + return + def loop(self): + """Template Method - Run a logic loop, called once per frame. + +
State.loop()
+ """ + return + def event(self,e): + """Template Method - Recieve an event. + +
State.event(e)
+ """ + return + +class Quit(State): + """A state to quit the state engine. + +
Quit(game,value)
+ """ + + def init(self): + self.game.quit = 1 + +class Game: + """Template Class - The state engine. + """ + def fnc(self,f,v=None): + s = self.state + if not hasattr(s,f): return 0 + f = getattr(s,f) + if v != None: r = f(v) + else: r = f() + if r != None: + self.state = r + self.state._paint = 1 + return 1 + return 0 + + def run(self,state,screen=None): + """Run the state engine, this is a infinite loop (until a quit occurs). + +
Game.run(state,screen=None)
+ +
+
game
a state engine +
screen
the screen +
+ """ + self.quit = 0 + self.state = state + if screen != None: self.screen = screen + + self.init() + + while not self.quit: + self.loop() + + def loop(self): + s = self.state + if not hasattr(s,'_init') or s._init: + s._init = 0 + if self.fnc('init'): return + else: + if self.fnc('loop'): return + if not hasattr(s,'_paint') or s._paint: + s._paint = 0 + if self.fnc('paint',self.screen): return + else: + if self.fnc('update',self.screen): return + + for e in pygame.event.get(): + #NOTE: this might break API? + #if self.event(e): return + if not self.event(e): + if self.fnc('event',e): return + + self.tick() + return + + def init(self): + """Template Method - called at the beginning of State.run() to initialize things. + +
Game.init()
+ """ + return + + def tick(self): + """Template Method - called once per frame, usually for timer purposes. + +
Game.tick()
+ """ + pygame.time.wait(10) + + def event(self,e): + """Template Method - called with each event, so the engine can capture special events. + +
Game.event(e): return captured
+ +

return a True value if the event is captured and does not need to be passed onto the current + state

+ """ + if e.type is QUIT: + self.state = Quit(self) + return 1 + +# vim: set filetype=python sts=4 sw=4 noet si : diff --git a/src/pgu/fonts.py b/src/pgu/fonts.py new file mode 100644 index 0000000..ab6f73d --- /dev/null +++ b/src/pgu/fonts.py @@ -0,0 +1,130 @@ +"""Some handy font-like objects. + +

please note that this file is alpha, and is subject to modification in +future versions of pgu!

+""" + +print 'pgu.fonts','This module is alpha, and is subject to change.' + +import pygame +from pygame.locals import * + +class TileFont: + """Creates an instance of the TileFont class. Interface compatible with pygame.Font + +

TileFonts are fonts that are stored in a tiled image. Where the image opaque, it assumed that the font is visible. Font color is changed automatically, so it does not work with + fonts with stylized coloring.

+ +
TileFont(fname,size,hints,scale=None,sensitive=False)
+ +
+
size
the dimensions of the characters +
hints
a string of hints "abcdefg..." +
scale
size to scale font to +
sensitive
case sensitivity +
+ """ + + def __init__(self,fname,size,hints,scale=None,sensitive=False): + + self.image = pygame.image.load(fname) + + w,h = self.image.get_width(),self.image.get_height() + tw,th = size + if not scale: scale = size + self._size = size + self.scale = scale + + self.chars = {} + x,y = 0,0 + self.sensitive = sensitive + if not self.sensitive: hints = hints.lower() + for c in hints: + if c not in ('\r','\n','\t'): + img = self.image.subsurface(x,y,tw,th) + self.chars[c] = img + x += tw + if x >= w: x,y = 0,y+th + + self.colors = {} + + def size(self,text): + tw,th = self.scale + return len(text)*tw,th + + def render(self,text,antialias=0,color=(255,255,255),background=None): + size = self.size(text) + scale = self.scale + tw,th = self._size + if background == None: + s = pygame.Surface(size).convert_alpha() + s.fill((0,0,0,0)) + else: + s = pygame.Surface(size).convert() + s.fill(background) + + if not self.sensitive: text = text.lower() + + if color not in self.colors: self.colors[color] = {} + colored = self.colors[color] + + x,y = 0,0 + for c in text: + if c in self.chars: + if c not in colored: + img = self.chars[c].convert_alpha() + for yy in xrange(0,th): + for xx in xrange(0,tw): + r,g,b,a = img.get_at((xx,yy)) + if a > 128: + img.set_at((xx,yy),color) + colored[c] = img + img = colored[c] + if scale != (tw,th): img = pygame.transform.scale(img,scale) + s.blit(img,(x,y)) + x += scale[0] + return s + + +class BorderFont: + """a decorator for normal fonts, adds a border. Interface compatible with pygame.Font. + +
BorderFont(font,size=1,color=(0,0,0))
+ +
+
size
width of border; defaults 0 +
color
color of border; default (0,0,0) +
+ """ + def __init__(self,font,size=1,color=(0,0,0)): + + self.font = font + self._size = size + self.color = color + + def size(self,text): + w,h = self.font.size(text) + s = self._size + return w+s*2,h+s*2 + + def render(self,text,antialias=0,color=(255,255,255),background=None): + size = self.size(text) + + if background == None: + s = pygame.Surface(size).convert_alpha() + s.fill((0,0,0,0)) + else: + s = pygame.Surface(size).convert() + s.fill(background) + + bg = self.font.render(text,antialias,self.color) + fg = self.font.render(text,antialias,color) + + si = self._size + dirs = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)] + for dx,dy in dirs: s.blit(bg,(si+dx*si,si+dy*si)) + s.blit(fg,(si,si)) + + return s + + diff --git a/src/pgu/gui/__init__.py b/src/pgu/gui/__init__.py new file mode 100644 index 0000000..256fb63 --- /dev/null +++ b/src/pgu/gui/__init__.py @@ -0,0 +1,32 @@ +import pygame +from pygame.locals import * + +from theme import Theme +from style import Style +from widget import Widget +from surface import subsurface, ProxySurface +from const import * + +from container import Container +from app import App, Desktop +from table import Table +from document import Document +#html +from area import SlideBox, ScrollArea, List + +from form import Form +from group import Group + +from basic import Spacer, Color, Label, Image, parse_color +from button import Icon, Button, Switch, Checkbox, Radio, Tool, Link +from input import Input, Password +from keysym import Keysym +from slider import VSlider, HSlider, VScrollBar, HScrollBar +from select import Select +from misc import ProgressBar + +from menus import Menus +from dialog import Dialog, FileDialog +from textarea import TextArea + +from deprecated import Toolbox, action_open, action_setvalue, action_quit, action_exec diff --git a/src/pgu/gui/app.py b/src/pgu/gui/app.py new file mode 100644 index 0000000..857af98 --- /dev/null +++ b/src/pgu/gui/app.py @@ -0,0 +1,279 @@ +""" +""" +import pygame +from pygame.locals import * + +import pguglobals +import container +from const import * + +class App(container.Container): + """The top-level widget for an application. + +
App(theme=None)
+ +
+
theme
an instance of a Theme, optional as it will use the default Theme class. +
+ + Basic Example + + app = gui.App() + app.run(widget=widget,screen=screen) + + + Integrated Example + + app = gui.App() + gui.init(widget=widget) + while 1: + for e in pygame.event.get(): + app.event(e) + app.update(screen) + + + + + """ + def __init__(self,theme=None,**params): + self.set_global_app() + + if theme == None: + from theme import Theme + theme = Theme() + self.theme = theme + + params['decorate'] = 'app' + container.Container.__init__(self,**params) + self._quit = False + self.widget = None + self._chsize = False + self._repaint = False + + self.screen = None + self.container = None + self.events = [] + + def set_global_app(self): + # Keep a global reference to this application instance so that PGU + # components can easily find it. + pguglobals.app = self + # For backwards compatibility we keep a reference in the class + # itself too. + App.app = self + + def resize(self): + + screen = self.screen + w = self.widget + wsize = 0 + + #5 cases + + #input screen is already set use its size + if screen: + self.screen = screen + width,height = screen.get_width(),screen.get_height() + + #display.screen + elif pygame.display.get_surface(): + screen = pygame.display.get_surface() + self.screen = screen + width,height = screen.get_width(),screen.get_height() + + #app has width,height + elif self.style.width != 0 and self.style.height != 0: + screen = pygame.display.set_mode((self.style.width,self.style.height),SWSURFACE) + self.screen = screen + width,height = screen.get_width(),screen.get_height() + + #widget has width,height, or its own size.. + else: + wsize = 1 + width,height = w.rect.w,w.rect.h = w.resize() + #w._resize() + screen = pygame.display.set_mode((width,height),SWSURFACE) + self.screen = screen + + #use screen to set up size of this widget + self.style.width,self.style.height = width,height + self.rect.w,self.rect.h = width,height + self.rect.x,self.rect.y = 0,0 + + w.rect.x,w.rect.y = 0,0 + w.rect.w,w.rect.h = w.resize(width,height) + + for w in self.windows: + w.rect.w,w.rect.h = w.resize() + + self._chsize = False + + + def init(self,widget=None,screen=None): #TODO widget= could conflict with module widget + """Initialize the application. + +
App.init(widget=None,screen=None)
+ +
+
widget
main widget +
screen
pygame.Surface to render to +
+ """ + + self.set_global_app() + + if widget: self.widget = widget + if screen: self.screen = screen + + self.resize() + + w = self.widget + + self.widgets = [] + self.widgets.append(w) + w.container = self + self.focus(w) + + pygame.key.set_repeat(500,30) + + self._repaint = True + self._quit = False + + self.send(INIT) + + def event(self,e): + """Pass an event to the main widget. + +
App.event(e)
+ +
+
e
event +
+ """ + self.set_global_app() + + #NOTE: might want to deal with ACTIVEEVENT in the future. + self.send(e.type,e) + container.Container.event(self,e) + if e.type == MOUSEBUTTONUP: + if e.button not in (4,5): #ignore mouse wheel + sub = pygame.event.Event(CLICK,{ + 'button':e.button, + 'pos':e.pos}) + self.send(sub.type,sub) + container.Container.event(self,sub) + + + def loop(self): + self.set_global_app() + + s = self.screen + for e in pygame.event.get(): + if not (e.type == QUIT and self.mywindow): + self.event(e) + us = self.update(s) + pygame.display.update(us) + + + def paint(self,screen): + self.screen = screen + if self._chsize: + self.resize() + self._chsize = False + if hasattr(self,'background'): + self.background.paint(screen) + container.Container.paint(self,screen) + + def update(self,screen): + """Update the screen. + +
+
screen
pygame surface +
+ """ + self.screen = screen + if self._chsize: + self.resize() + self._chsize = False + if self._repaint: + self.paint(screen) + self._repaint = False + return [pygame.Rect(0,0,screen.get_width(),screen.get_height())] + else: + us = container.Container.update(self,screen) + return us + + def run(self,widget=None,screen=None): + """Run an application. + +

Automatically calls App.init and then forever loops App.event and App.update

+ +
+
widget
main widget +
screen
pygame.Surface to render to +
+ """ + self.init(widget,screen) + while not self._quit: + self.loop() + pygame.time.wait(10) + + def reupdate(self,w=None): pass + def repaint(self,w=None): self._repaint = True + def repaintall(self): self._repaint = True + def chsize(self): + self._chsize = True + self._repaint = True + + def quit(self,value=None): self._quit = True + + def open(self, w, pos=None): + w.container = self + + if (w.rect.w == 0 or w.rect.h == 0): + w.rect.size = w.resize() + + if (not pos): + # Auto-center the window + w.rect.center = self.rect.center + #w.rect.topleft = ((self.rect.w - w.rect.w)/2, + # (self.rect.h - w.rect.h)/2) + else: + # Show the window in a particular location + w.rect.topleft = pos + + self.windows.append(w) + self.mywindow = w + self.focus(w) + self.repaint(w) + w.send(OPEN) + + def close(self, w): + if self.myfocus is w: self.blur(w) + + if w not in self.windows: return #no need to remove it twice! happens. + + self.windows.remove(w) + + self.mywindow = None + if self.windows: + self.mywindow = self.windows[-1] + self.focus(self.mywindow) + + if not self.mywindow: + self.myfocus = self.widget #HACK: should be done fancier, i think.. + if not self.myhover: + self.enter(self.widget) + + self.repaintall() + w.send(CLOSE) + + +class Desktop(App): + """Create an App using the desktop theme class. + +
Desktop()
+ """ + def __init__(self,**params): + params.setdefault('cls','desktop') + App.__init__(self,**params) diff --git a/src/pgu/gui/area.py b/src/pgu/gui/area.py new file mode 100644 index 0000000..64074d6 --- /dev/null +++ b/src/pgu/gui/area.py @@ -0,0 +1,454 @@ +""" +""" +import os + +import pguglobals +from const import * +import surface +import container, table +import group +import basic, button, slider +from pygame.font import Font + +class SlideBox(container.Container): + """A scrollable area with no scrollbars. + +
SlideBox(widget,width,height)
+ +
+
widget
widget to be able to scroll around +
width, height
size of scrollable area +
+ + Example + + c = SlideBox(w,100,100) + c.offset = (10,10) + c.repaint() + + + """ + + def __init__(self, widget, width, height, **params): + params.setdefault('width', width) + params.setdefault('height', height) + container.Container.__init__(self, **params) + self.offset = [0, 0] + self.widget = widget + + def __setattr__(self,k,v): + if k == 'widget': + if hasattr(self,'widget'): + self.remove(self.widget) + self.add(v,0,0) + self.__dict__[k] = v + + + def paint(self, s): + #if not hasattr(self,'surface'): + self.surface = pygame.Surface((self.max_rect.w,self.max_rect.h),0,s) + #self.surface.fill((0,0,0,0)) + pguglobals.app.theme.render(self.surface,self.style.background,pygame.Rect(0,0,self.max_rect.w,self.max_rect.h)) + self.bkgr = pygame.Surface((s.get_width(),s.get_height()),0,s) + self.bkgr.blit(s,(0,0)) + container.Container.paint(self,self.surface) + s.blit(self.surface,(-self.offset[0],-self.offset[1])) + self._offset = self.offset[:] + return + + def paint_for_when_pygame_supports_other_tricks(self,s): + #this would be ideal if pygame had support for it! + #and if pgu also had a paint(self,s,rect) method to paint small parts + sr = (self.offset[0],self.offset[1],self.max_rect.w,self.max_rect.h) + cr = (-self.offset[0],-self.offset[1],s.get_width(),s.get_height()) + s2 = s.subsurface(sr) + s2.set_clip(cr) + container.Container.paint(self,s2) + + def proxy_paint(self, s): + container.Container.paint(self, surface.ProxySurface(parent=None, + rect=self.max_rect, + real_surface=s, + offset=self.offset)) + def update(self, s): + rects = container.Container.update(self,self.surface) + + rets = [] + s_rect = pygame.Rect(0,0,s.get_width(),s.get_height()) + + if self.offset == self._offset: + for r in rects: + r2 = r.move((-self.offset[0],-self.offset[1])) + if r2.colliderect(s_rect): + s.blit(self.surface.subsurface(r),r2) + rets.append(r2) + else: + s.blit(self.bkgr,(0,0)) + sub = pygame.Rect(self.offset[0],self.offset[1],min(s.get_width(),self.max_rect.w-self.offset[0]),min(s.get_height(),self.max_rect.h-self.offset[1])) +# print sub +# print self.surface.get_width(),self.surface.get_height() +# print s.get_width(),s.get_height() +# print self.offset +# print self.style.width,self.style.height + s.blit(self.surface.subsurface(sub),(0,0)) + rets.append(s_rect) + self._offset = self.offset[:] + return rets + + def proxy_update(self, s): + rects = container.Container.update(self, surface.ProxySurface(parent=None, + rect=self.max_rect, + real_surface=s, + offset=self.offset)) + result = [] + for r in rects: result.append(pygame.Rect(r).move(self.offset)) + return result + + def resize(self, width=None, height=None): + container.Container.resize(self) + self.max_rect = pygame.Rect(self.widget.rect) + #self.max_rect.w = max(self.max_rect.w,self.style.width) + #self.max_rect.h = max(self.max_rect.h,self.style.height) + return self.style.width,self.style.height + #self.rect = pygame.Rect(self.rect[0], self.rect[1], self.style.width, self.style.height) + + def event(self, e): + if e.type in [MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION]: + pos = (e.pos[0] + self.offset[0], e.pos[1] + self.offset[1]) + if self.max_rect.collidepoint(pos): + e_params = {'pos': pos } + if e.type == MOUSEMOTION: + e_params['buttons'] = e.buttons + e_params['rel'] = e.rel + else: + e_params['button'] = e.button + e = pygame.event.Event(e.type, e_params) + container.Container.event(self, e) + +#class SlideBox(Area): +# def __init__(self,*args,**params): +# print 'gui.SlideBox','Scheduled to be renamed to Area.' +# Area.__init__(self,*args,**params) + +class ScrollArea(table.Table): + """A scrollable area with scrollbars. + +
ScrollArea(widget,width,height,hscrollbar=True)
+ +
+
widget
widget to be able to scroll around +
width, height
size of scrollable area. Set either to 0 to default to size of widget. +
hscrollbar
set to False if you do not wish to have a horizontal scrollbar +
vscrollbar
set to False if you do not wish to have a vertical scrollbar +
step
set to how far clicks on the icons will step +
+ """ + def __init__(self, widget, width=0, height=0, hscrollbar=True, vscrollbar=True,step=24, **params): + w= widget + params.setdefault('cls', 'scrollarea') + table.Table.__init__(self, width=width,height=height,**params) + + self.sbox = SlideBox(w, width=width, height=height, cls=self.cls+".content") + self.widget = w + self.vscrollbar = vscrollbar + self.hscrollbar = hscrollbar + + self.step = step + + def __setattr__(self,k,v): + if k == 'widget': + self.sbox.widget = v + self.__dict__[k] = v + + def resize(self,width=None,height=None): + widget = self.widget + box = self.sbox + + #self.clear() + table.Table.clear(self) + #print 'resize',self,self._rows + + self.tr() + self.td(box) + + widget.rect.w, widget.rect.h = widget.resize() + my_width,my_height = self.style.width,self.style.height + if not my_width: + my_width = widget.rect.w + self.hscrollbar = False + if not my_height: + my_height = widget.rect.h + self.vscrollbar = False + + box.style.width,box.style.height = my_width,my_height #self.style.width,self.style.height + + box.rect.w,box.rect.h = box.resize() + + #print widget.rect + #print box.rect + #r = table.Table.resize(self,width,height) + #print r + #return r + + #print box.offset + +# #this old code automatically adds in a scrollbar if needed +# #but it doesn't always work +# self.vscrollbar = None +# if widget.rect.h > box.rect.h: +# self.vscrollbar = slider.VScrollBar(box.offset[1],0, 65535, 0,step=self.step) +# self.td(self.vscrollbar) +# self.vscrollbar.connect(CHANGE, self._vscrollbar_changed, None) +# +# vs = self.vscrollbar +# vs.rect.w,vs.rect.h = vs.resize() +# box.style.width = self.style.width - vs.rect.w +# +# +# self.hscrollbar = None +# if widget.rect.w > box.rect.w: +# self.hscrollbar = slider.HScrollBar(box.offset[0], 0,65535, 0,step=self.step) +# self.hscrollbar.connect(CHANGE, self._hscrollbar_changed, None) +# self.tr() +# self.td(self.hscrollbar) +# +# hs = self.hscrollbar +# hs.rect.w,hs.rect.h = hs.resize() +# box.style.height = self.style.height - hs.rect.h + + xt,xr,xb,xl = pguglobals.app.theme.getspacing(box) + + + if self.vscrollbar: + self.vscrollbar = slider.VScrollBar(box.offset[1],0, 65535, 0,step=self.step) + self.td(self.vscrollbar) + self.vscrollbar.connect(CHANGE, self._vscrollbar_changed, None) + + vs = self.vscrollbar + vs.rect.w,vs.rect.h = vs.resize() + if self.style.width: + box.style.width = self.style.width - (vs.rect.w + xl+xr) + + if self.hscrollbar: + self.hscrollbar = slider.HScrollBar(box.offset[0], 0,65535, 0,step=self.step) + self.hscrollbar.connect(CHANGE, self._hscrollbar_changed, None) + self.tr() + self.td(self.hscrollbar) + + hs = self.hscrollbar + hs.rect.w,hs.rect.h = hs.resize() + if self.style.height: + box.style.height = self.style.height - (hs.rect.h + xt + xb) + + if self.hscrollbar: + hs = self.hscrollbar + hs.min = 0 + hs.max = widget.rect.w - box.style.width + hs.style.width = box.style.width + hs.size = hs.style.width * box.style.width / max(1,widget.rect.w) + else: + box.offset[0] = 0 + + if self.vscrollbar: + vs = self.vscrollbar + vs.min = 0 + vs.max = widget.rect.h - box.style.height + vs.style.height = box.style.height + vs.size = vs.style.height * box.style.height / max(1,widget.rect.h) + else: + box.offset[1] = 0 + + #print self.style.width,box.style.width, hs.style.width + + r = table.Table.resize(self,width,height) + return r + + def x_resize(self, width=None, height=None): + w,h = table.Table.resize(self, width, height) + if self.hscrollbar: + if self.widget.rect.w <= self.sbox.rect.w: + self.hscrollbar.size = self.hscrollbar.style.width + else: + self.hscrollbar.size = max(20,self.hscrollbar.style.width * self.sbox.rect.w / self.widget.rect.w) + self._hscrollbar_changed(None) + if self.widget.rect.h <= self.sbox.rect.h: + self.vscrollbar.size = self.vscrollbar.style.height + else: + self.vscrollbar.size = max(20,self.vscrollbar.style.height * self.sbox.rect.h / self.widget.rect.h) + self._vscrollbar_changed(None) + return w,h + + def _vscrollbar_changed(self, xxx): + #y = (self.widget.rect.h - self.sbox.rect.h) * self.vscrollbar.value / 1000 + #if y >= 0: self.sbox.offset[1] = -y + self.sbox.offset[1] = self.vscrollbar.value + self.sbox.reupdate() + + def _hscrollbar_changed(self, xxx): + #x = (self.widget.rect.w - self.sbox.rect.w) * self.hscrollbar.value / 1000 + #if x >= 0: self.sbox.offset[0] = -x + self.sbox.offset[0] = self.hscrollbar.value + self.sbox.reupdate() + + + def set_vertical_scroll(self, percents): + #if not self.vscrollbar: return + if not hasattr(self.vscrollbar,'value'): return + self.vscrollbar.value = percents #min(max(percents*10, 0), 1000) + self._vscrollbar_changed(None) + + def set_horizontal_scroll(self, percents): + #if not self.hscrollbar: return + if not hasattr(self.hscrollbar,'value'): return + self.hscrollbar.value = percents #min(max(percents*10, 0), 1000) + self._hscrollbar_changed(None) + + def event(self, e): + #checking for event recipient + if (table.Table.event(self, e)): + return True + + #mouse wheel scrolling + if self.vscrollbar: + if not hasattr(self.vscrollbar,'value'): + return False + + if e.type == pygame.locals.MOUSEBUTTONDOWN: + if e.button == 4: #wheel up + self.vscrollbar._click(-1) + return True + elif e.button == 5: #wheel down + self.vscrollbar._click(1) + return True + return False + + + + +class _List_Item(button._button): + def __init__(self,label=None,image=None,value=None,**params): #TODO label= could conflict with the module label + #param image: an imagez.Image object (optional) + #param text: a string object + params.setdefault('cls','list.item') + button._button.__init__(self,**params) + self.group = None + self.value = value #(self, value) + self.widget = None + + if type(label) == str: + label = basic.Label(label, cls=self.cls+".label") + + if image and label: + self.widget = container.Container() + self.widget.add(image, 0, 0) + #HACK: improper use of .resize() + image.rect.w,image.rect.h = image.resize() + self.widget.add(label, image.rect.w, 0) + elif image: self.widget = image + elif label: self.widget = label + + self.pcls = "" + + def resize(self,width=None,height=None): + self.widget.rect.w,self.widget.rect.h = self.widget.resize() + return self.widget.rect.w,self.widget.rect.h +# self.widget._resize() +# self.rect.w,self.rect.h = self.widget.rect_margin.w,self.widget.rect_margin.h + + def event(self,e): + button._button.event(self,e) + if self.group.value == self.value: self.pcls = "down" + + def paint(self,s): + if self.group.value == self.value: self.pcls = "down" + self.widget.paint(surface.subsurface(s,self.widget.rect)) + + def click(self): + self.group.value = self.value + for w in self.group.widgets: + if w != self: w.pcls = "" + + + +class List(ScrollArea): + """A list of items in an area. + +

This widget can be a form element, it has a value set to whatever item is selected.

+ +
List(width,height)
+ """ + def _change(self, value): + self.value = self.group.value + self.send(CHANGE) + + def __init__(self, width, height, **params): + params.setdefault('cls', 'list') + self.table = table.Table(width=width) + ScrollArea.__init__(self, self.table, width, height,hscrollbar=False ,**params) + + self.items = [] + + g = group.Group() + self.group = g + g.connect(CHANGE,self._change,None) + self.value = self.group.value = None + + self.add = self._add + self.remove = self._remove + + def clear(self): + """Clear the list. + +
List.clear()
+ """ + self.items = [] + self.group = group.Group() + self.group.connect(CHANGE,self._change,None) + self.table.clear() + self.set_vertical_scroll(0) + self.blur(self.myfocus) + + def _docs(self): #HACK: nasty hack to get the docs in "my way" + def add(self, label, image=None, value=None): + """Add an item to the list. + +
List.add(label,image=None,value=None)
+ +
+
label
a label for the item +
image
an image for the item +
value
a value for the item +
+ """ + + def remove(self,value): + """Remove an item from the list. + +
List.remove(value)
+ +
+
value
a value of an item to remove from the list +
+ """ + + def _add(self, label, image = None, value=None): + item = _List_Item(label,image=image,value=value) + self.table.tr() + self.table.add(item) + self.items.append(item) + item.group = self.group + item.group.add(item) + + def _remove(self, item): + for i in self.items: + if i.value == item: item = i + if item not in self.items: return + item.blur() + self.items.remove(item) + self.group.widgets.remove(item) + self.table.remove_row(item.style.row) + +#class List(ListArea): +# def __init__(self,*args,**params): +# print 'gui.List','Scheduled to be renamed to ListArea. API may also be changed in the future.' +# ListArea.__init__(self,*args,**params) diff --git a/src/pgu/gui/basic.py b/src/pgu/gui/basic.py new file mode 100644 index 0000000..3800440 --- /dev/null +++ b/src/pgu/gui/basic.py @@ -0,0 +1,136 @@ +"""These widgets are all grouped together because they are non-interactive widgets. +""" + +import pygame + +from const import * +import widget + +# Turns a descriptive string or a tuple into a pygame color +def parse_color(desc): + if (is_color(desc)): + # Already a color + return desc + elif (desc and desc[0] == "#"): + # Because of a bug in pygame 1.8.1 we need to explicitly define the + # alpha value otherwise it will default to transparent. + if (len(desc) == 7): + desc += "FF" + return pygame.Color(desc) + +# Determines if the given object is a pygame-compatible color or not +def is_color(col): + # In every version of pygame (up to 1.8.1 so far) will interpret + # a tuple as a color. + if (type(col) == tuple): + return col + if (hasattr(pygame, "Color") and type(pygame.Color) == type): + # This is a recent version of pygame that uses a proper type + # instance for colors. + return (isinstance(col, pygame.Color)) + # Otherwise, this version of pygame only supports tuple colors + return False + +class Spacer(widget.Widget): + """A invisible space. + +
Spacer(width,height)
+ + """ + def __init__(self,width,height,**params): + params.setdefault('focusable',False) + widget.Widget.__init__(self,width=width,height=height,**params) + + +class Color(widget.Widget): + """A block of color. + +

The color can be changed at run-time.

+ +
Color(value=None)
+ + Example + + c = Color() + c.value = (255,0,0) + c.value = (0,255,0) + + """ + + + def __init__(self,value=None,**params): + params.setdefault('focusable',False) + if value != None: params['value']=value + widget.Widget.__init__(self,**params) + + def paint(self,s): + if hasattr(self,'value'): s.fill(self.value) + + def __setattr__(self,k,v): + if k == 'value' and type(v) == str: + v = parse_color(v) + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and _v != NOATTR and _v != v: + self.send(CHANGE) + self.repaint() + +class Label(widget.Widget): + """A text label. + +
Label(value)
+ +
+
value
text to be displayed +
+ + Example + + w = Label(value="I own a rubber chicken!") + + w = Label("3 rubber chickens") + + """ + def __init__(self,value,**params): + params.setdefault('focusable',False) + params.setdefault('cls','label') + widget.Widget.__init__(self,**params) + self.value = value + self.font = self.style.font + self.style.width, self.style.height = self.font.size(self.value) + + def paint(self,s): + s.blit(self.font.render(self.value, 1, self.style.color),(0,0)) + +class Image(widget.Widget): + """An image. + +
Image(value)
+ +
+
value
a file name or a pygame.Surface +
+ + """ + def __init__(self,value,**params): + params.setdefault('focusable',False) + widget.Widget.__init__(self,**params) + if type(value) == str: value = pygame.image.load(value) + + ow,oh = iw,ih = value.get_width(),value.get_height() + sw,sh = self.style.width,self.style.height + + if sw and not sh: + iw,ih = sw,ih*sw/iw + elif sh and not sw: + iw,ih = iw*sh/ih,sh + elif sw and sh: + iw,ih = sw,sh + + if (ow,oh) != (iw,ih): + value = pygame.transform.scale(value,(iw,ih)) + self.style.width,self.style.height = iw,ih + self.value = value + + def paint(self,s): + s.blit(self.value,(0,0)) diff --git a/src/pgu/gui/button.py b/src/pgu/gui/button.py new file mode 100644 index 0000000..90cdd1e --- /dev/null +++ b/src/pgu/gui/button.py @@ -0,0 +1,351 @@ +""" +""" + +from pygame.locals import * + +from const import * +import widget, surface +import basic + +class _button(widget.Widget): + def __init__(self,**params): + widget.Widget.__init__(self,**params) + self.state = 0 + + def event(self,e): + if e.type == ENTER: self.repaint() + elif e.type == EXIT: self.repaint() + elif e.type == FOCUS: self.repaint() + elif e.type == BLUR: self.repaint() + elif e.type == KEYDOWN: + if e.key == K_SPACE or e.key == K_RETURN: + self.state = 1 + self.repaint() + elif e.type == MOUSEBUTTONDOWN: + self.state = 1 + self.repaint() + elif e.type == KEYUP: + if self.state == 1: + sub = pygame.event.Event(CLICK,{'pos':(0,0),'button':1}) + #self.send(sub.type,sub) + self._event(sub) + + self.state = 0 + self.repaint() + elif e.type == MOUSEBUTTONUP: + self.state = 0 + self.repaint() + elif e.type == CLICK: + self.click() + + self.pcls = "" + if self.state == 0 and self.container.myhover is self: + self.pcls = "hover" + if self.state == 1 and self.container.myhover is self: + self.pcls = "down" + + def click(self): + pass + + +class Button(_button): + """A button, buttons can be clicked, they are usually used to set up callbacks. + +
Button(value=None)
+ +
+
value
either a widget or a string +
+ + Example + + w = gui.Button("Click Me") + w.connect(gui.CLICK,fnc,value) + + """ + def __init__(self,value=None,**params): + params.setdefault('cls','button') + _button.__init__(self,**params) + self.value = value + + def __setattr__(self,k,v): + if k == 'value' and type(v) == str: v = basic.Label(v,cls=self.cls+".label") + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and v != None: + pass + + if k == 'value' and _v != NOATTR and _v != None and _v != v: + self.send(CHANGE) + self.chsize() + + def resize(self,width=None,height=None): + self.value.rect.x,self.value.rect.y = 0,0 + self.value.rect.w,self.value.rect.h = self.value.resize(width,height) + return self.value.rect.w,self.value.rect.h +# +# self.value._resize() +# self.rect.w,self.rect.h = self.value.rect_margin.w,self.value.rect_margin.h +# +# if self.style.width: self.rect.w = max(self.rect.w,self.style.width) +# if self.style.height: self.rect.w = max(self.rect.w,self.style.height) +# +# xt,xr,xb,xl = self.value.getspacing() +# +# self.value._resize(self.rect.w-(xl+xr),self.rect.h-(xt+xb)) +# + def paint(self,s): + self.value.pcls = self.pcls + self.value.paint(surface.subsurface(s,self.value.rect)) + +class Switch(_button): + """A switch can have two states, True or False. + +
Switch(value=False)
+ +
+
value
initial value, (True, False) +
+ + Example + + w = gui.Switch(True) + w.connect(gui.CHANGE,fnc,value) + + """ + def __init__(self,value=False,**params): + params.setdefault('cls','switch') + _button.__init__(self,**params) + self.value = value + + img = self.style.off + self.style.width = img.get_width() + self.style.height = img.get_height() + + def paint(self,s): + #self.pcls = "" + #if self.container.myhover is self: self.pcls = "hover" + if self.value: img = self.style.on + else: img = self.style.off + s.blit(img,(0,0)) + + def __setattr__(self,k,v): + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and _v != NOATTR and _v != v: + self.send(CHANGE) + self.repaint() + + def click(self): + self.value = not self.value + +class Checkbox(_button): + """Within a Group of Checkbox widgets several may be selected at a time. + +
Checkbox(group,value=None)
+ +
+
group
a gui.Group for the Checkbox to belong to +
value
the value +
+ + Example + + g = gui.Group(name='colors',value=['r','b']) + + t = gui.Table() + t.tr() + t.td(gui.Label('Red')) + t.td(gui.Checkbox(g,'r')) + t.tr() + t.td(gui.Label('Green')) + t.td(gui.Checkbox(g,'g')) + t.tr() + t.td(gui.Label('Blue')) + t.td(gui.Checkbox(g,'b')) + + """ + + def __init__(self,group,value=None,**params): + params.setdefault('cls','checkbox') + _button.__init__(self,**params) + self.group = group + self.group.add(self) + if self.group.value == None: + self.group.value = [] + self.value = value + + img = self.style.off + self.style.width = img.get_width() + self.style.height = img.get_height() + + def paint(self,s): + #self.pcls = "" + #if self.container.myhover is self: self.pcls = "hover" + if self.value in self.group.value: img = self.style.on + else: img = self.style.off + + s.blit(img,(0,0)) + + def click(self): + if self.value in self.group.value: + self.group.value.remove(self.value) + else: + self.group.value.append(self.value) + self.group._change() + +class Radio(_button): + """Within a Group of Radio widgets only one may be selected at a time. + +
Radio(group,value=None)
+ +
+
group
a gui.Group for the Radio to belong to +
value
the value +
+ + Example + + g = gui.Group(name='colors',value='g') + + t = gui.Table() + t.tr() + t.td(gui.Label('Red')) + t.td(gui.Radio(g,'r')) + t.tr() + t.td(gui.Label('Green')) + t.td(gui.Radio(g,'g')) + t.tr() + t.td(gui.Label('Blue')) + t.td(gui.Radio(g,'b')) + + """ + + + def __init__(self,group=None,value=None,**params): + params.setdefault('cls','radio') + _button.__init__(self,**params) + self.group = group + self.group.add(self) + self.value = value + + img = self.style.off + self.style.width = img.get_width() + self.style.height = img.get_height() + + def paint(self,s): + #self.pcls = "" + #if self.container.myhover is self: self.pcls = "hover" + if self.group.value == self.value: img = self.style.on + else: img = self.style.off + s.blit(img,(0,0)) + + def click(self): + self.group.value = self.value + +class Tool(_button): + """Within a Group of Tool widgets only one may be selected at a time. + +
Tool(group,widget=None,value=None)
+ +
+
group
a gui.Group for the Tool to belong to +
widget
a widget to appear on the Tool (similar to a Button) +
value
the value +
+ + Example + + g = gui.Group(name='colors',value='g') + + t = gui.Table() + t.tr() + t.td(gui.Tool(g,'Red','r')) + t.tr() + t.td(gui.Tool(g,'Green','g')) + t.tr() + t.td(gui.Tool(g,'Blue','b')) + + """ + + def __init__(self,group,widget=None,value=None,**params): #TODO widget= could conflict with module widget + params.setdefault('cls','tool') + _button.__init__(self,**params) + self.group = group + self.group.add(self) + self.value = value + + if widget: + self.setwidget(widget) + + if self.group.value == self.value: self.pcls = "down" + + def setwidget(self,w): + self.widget = w + + def resize(self,width=None,height=None): + self.widget.rect.w,self.widget.rect.h = self.widget.resize() + #self.widget._resize() + #self.rect.w,self.rect.h = self.widget.rect_margin.w,self.widget.rect_margin.h + + return self.widget.rect.w,self.widget.rect.h + + def event(self,e): + _button.event(self,e) + if self.group.value == self.value: self.pcls = "down" + + def paint(self,s): + if self.group.value == self.value: self.pcls = "down" + self.widget.paint(surface.subsurface(s,self.widget.rect)) + + def click(self): + self.group.value = self.value + for w in self.group.widgets: + if w != self: w.pcls = "" + + +class Icon(_button): + """TODO - might be deprecated + """ + def __init__(self,cls,**params): + params['cls'] = cls + _button.__init__(self,**params) + s = self.style.image + self.style.width = s.get_width() + self.style.height = s.get_height() + self.state = 0 + + def paint(self,s): + #self.pcls = "" + #if self.state == 0 and hasattr(self.container,'myhover') and self.container.myhover is self: self.pcls = "hover" + #if self.state == 1 and hasattr(self.container,'myhover') and self.container.myhover is self: self.pcls = "down" + s.blit(self.style.image,(0,0)) + +class Link(_button): + """A link, links can be clicked, they are usually used to set up callbacks. + Basically the same as the button widget, just text only with a different cls. Made for + convenience. + +
Link(value=None)
+ +
+
value
a string +
+ + Example + + w = gui.Link("Click Me") + w.connect(gui.CLICK,fnc,value) + + """ + def __init__(self,value,**params): + params.setdefault('focusable',True) + params.setdefault('cls','link') + _button.__init__(self,**params) + self.value = value + self.font = self.style.font + self.style.width, self.style.height = self.font.size(self.value) + + def paint(self,s): + s.blit(self.font.render(self.value, 1, self.style.color),(0,0)) + diff --git a/src/pgu/gui/const.py b/src/pgu/gui/const.py new file mode 100644 index 0000000..c865cd8 --- /dev/null +++ b/src/pgu/gui/const.py @@ -0,0 +1,45 @@ +"""Constants. +

+Event Types + +

from pygame

+
+
QUIT +
MOUSEBUTTONDOWN +
MOUSEBUTTONUP +
MOUSEMOTION +
KEYDOWN +
+ +

gui specific

+
+
ENTER +
EXIT +
BLUR +
FOCUS +
CLICK +
CHANGE +
OPEN +
CLOSE +
INIT +
+ +Other +
+
NOATTR +
+""" +import pygame + +from pygame.locals import QUIT, MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION, KEYDOWN, USEREVENT +ENTER = pygame.locals.USEREVENT + 0 +EXIT = pygame.locals.USEREVENT + 1 +BLUR = pygame.locals.USEREVENT + 2 +FOCUS = pygame.locals.USEREVENT + 3 +CLICK = pygame.locals.USEREVENT + 4 +CHANGE = pygame.locals.USEREVENT + 5 +OPEN = pygame.locals.USEREVENT + 6 +CLOSE = pygame.locals.USEREVENT + 7 +INIT = 'init' + +class NOATTR: pass \ No newline at end of file diff --git a/src/pgu/gui/container.py b/src/pgu/gui/container.py new file mode 100644 index 0000000..73a8e68 --- /dev/null +++ b/src/pgu/gui/container.py @@ -0,0 +1,414 @@ +""" +""" +import pygame +from pygame.locals import * + +from const import * +import widget, surface +import pguglobals + +class Container(widget.Widget): + """The base container widget, can be used as a template as well as stand alone. + +
Container()
+ """ + def __init__(self,**params): + widget.Widget.__init__(self,**params) + self.myfocus = None + self.mywindow = None + self.myhover = None + #self.background = 0 + self.widgets = [] + self.windows = [] + self.toupdate = {} + self.topaint = {} + + def update(self,s): + updates = [] + + if self.myfocus: self.toupdate[self.myfocus] = self.myfocus + + for w in self.topaint: + if w is self.mywindow: + continue + else: + sub = surface.subsurface(s,w.rect) + #if (hasattr(w, "_container_bkgr")): + # sub.blit(w._container_bkgr,(0,0)) + w.paint(sub) + updates.append(pygame.rect.Rect(w.rect)) + + for w in self.toupdate: + if w is self.mywindow: + continue + else: + us = w.update(surface.subsurface(s,w.rect)) + if us: + for u in us: + updates.append(pygame.rect.Rect(u.x + w.rect.x,u.y+w.rect.y,u.w,u.h)) + + for w in self.topaint: + if w is self.mywindow: + w.paint(self.top_surface(s,w)) + updates.append(pygame.rect.Rect(w.rect)) + else: + continue + + for w in self.toupdate: + if w is self.mywindow: + us = w.update(self.top_surface(s,w)) + else: + continue + if us: + for u in us: + updates.append(pygame.rect.Rect(u.x + w.rect.x,u.y+w.rect.y,u.w,u.h)) + + self.topaint = {} + self.toupdate = {} + + return updates + + def repaint(self,w=None): + if not w: + return widget.Widget.repaint(self) + self.topaint[w] = w + self.reupdate() + + def reupdate(self,w=None): + if not w: + return widget.Widget.reupdate(self) + self.toupdate[w] = w + self.reupdate() + + def paint(self,s): + self.toupdate = {} + self.topaint = {} + for w in self.widgets: + try: + sub = surface.subsurface(s, w.rect) + except: + print 'container.paint(): %s not inside %s' % ( + w.__class__.__name__,self.__class__.__name__) + print s.get_width(), s.get_height(), w.rect + print "" + else: +# if (not hasattr(w,'_container_bkgr') or +# w._container_bkgr.get_size() != sub.get_size()): +# #w._container_bkgr.get_width() == sub.get_width() and +# #w._container_bkgr.get_height() == sub.get_height())): +# w._container_bkgr = sub.copy() +# w._container_bkgr.fill((0,0,0,0)) +# w._container_bkgr.blit(sub,(0,0)) + w.paint(sub) + + for w in self.windows: + w.paint(self.top_surface(s,w)) + + def top_surface(self,s,w): + x,y = s.get_abs_offset() + s = s.get_abs_parent() + return surface.subsurface(s,(x+w.rect.x,y+w.rect.y,w.rect.w,w.rect.h)) + + def event(self,e): + used = False + + if self.mywindow and e.type == MOUSEBUTTONDOWN: + w = self.mywindow + if self.myfocus is w: + if not w.rect.collidepoint(e.pos): self.blur(w) + if not self.myfocus: + if w.rect.collidepoint(e.pos): self.focus(w) + + if not self.mywindow: + #### by Gal Koren + ## + ## if e.type == FOCUS: + if e.type == FOCUS and not self.myfocus: + #self.first() + pass + elif e.type == EXIT: + if self.myhover: self.exit(self.myhover) + elif e.type == BLUR: + if self.myfocus: self.blur(self.myfocus) + elif e.type == MOUSEBUTTONDOWN: + h = None + for w in self.widgets: + if not w.disabled: #focusable not considered, since that is only for tabs + if w.rect.collidepoint(e.pos): + h = w + if self.myfocus is not w: self.focus(w) + if not h and self.myfocus: + self.blur(self.myfocus) + elif e.type == MOUSEMOTION: + if 1 in e.buttons: + if self.myfocus: ws = [self.myfocus] + else: ws = [] + else: ws = self.widgets + + h = None + for w in ws: + if w.rect.collidepoint(e.pos): + h = w + if self.myhover is not w: self.enter(w) + if not h and self.myhover: + self.exit(self.myhover) + w = self.myhover + + if w and w is not self.myfocus: + sub = pygame.event.Event(e.type,{ + 'buttons':e.buttons, + 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y), + 'rel':e.rel}) + used = w._event(sub) + + w = self.myfocus + if w: + sub = e + + if e.type == MOUSEBUTTONUP or e.type == MOUSEBUTTONDOWN: + sub = pygame.event.Event(e.type,{ + 'button':e.button, + 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y)}) + used = w._event(sub) + elif e.type == CLICK and self.myhover is w: + sub = pygame.event.Event(e.type,{ + 'button':e.button, + 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y)}) + used = w._event(sub) + elif e.type == CLICK: #a dead click + pass + elif e.type == MOUSEMOTION: + sub = pygame.event.Event(e.type,{ + 'buttons':e.buttons, + 'pos':(e.pos[0]-w.rect.x,e.pos[1]-w.rect.y), + 'rel':e.rel}) + used = w._event(sub) + else: + used = w._event(sub) + + if not used: + if e.type is KEYDOWN: + if e.key is K_TAB and self.myfocus: + if (e.mod&KMOD_SHIFT) == 0: + self.myfocus.next() + else: + self.myfocus.previous() + return True + elif e.key == K_UP: + self._move_focus(0,-1) + return True + elif e.key == K_RIGHT: + self._move_focus(1,0) + return True + elif e.key == K_DOWN: + self._move_focus(0,1) + return True + elif e.key == K_LEFT: + self._move_focus(-1,0) + return True + return used + + def _move_focus(self,dx_,dy_): + myfocus = self.myfocus + if not self.myfocus: return + + widgets = self._get_widgets(pguglobals.app) + #if myfocus not in widgets: return + #widgets.remove(myfocus) + if myfocus in widgets: + widgets.remove(myfocus) + rect = myfocus.get_abs_rect() + fx,fy = rect.centerx,rect.centery + + def sign(v): + if v < 0: return -1 + if v > 0: return 1 + return 0 + + dist = [] + for w in widgets: + wrect = w.get_abs_rect() + wx,wy = wrect.centerx,wrect.centery + dx,dy = wx-fx,wy-fy + if dx_ > 0 and wrect.left < rect.right: continue + if dx_ < 0 and wrect.right > rect.left: continue + if dy_ > 0 and wrect.top < rect.bottom: continue + if dy_ < 0 and wrect.bottom > rect.top: continue + dist.append((dx*dx+dy*dy,w)) + if not len(dist): return + dist.sort() + d,w = dist.pop(0) + w.focus() + + def _get_widgets(self,c): + widgets = [] + if c.mywindow: + widgets.extend(self._get_widgets(c.mywindow)) + else: + for w in c.widgets: + if isinstance(w,Container): + widgets.extend(self._get_widgets(w)) + elif not w.disabled and w.focusable: + widgets.append(w) + return widgets + + def remove(self,w): + """Remove a widget from the container. + +
Container.remove(w)
+ """ + self.blur(w) + self.widgets.remove(w) + #self.repaint() + self.chsize() + + def add(self,w,x,y): + """Add a widget to the container. + +
Container.add(w,x,y)
+ +
+
x, y
position of the widget +
+ """ + w.style.x = x + w.style.y = y + w.container = self + #NOTE: this might fix it, sort of... + #but the thing is, we don't really want to resize + #something if it is going to get resized again later + #for no reason... + #w.rect.x,w.rect.y = w.style.x,w.style.y + #w.rect.w, w.rect.h = w.resize() + self.widgets.append(w) + self.chsize() + + def open(self,w=None,x=None,y=None): + if (not w): + w = self + + if (x != None): + # The position is relative to this container + rect = self.get_abs_rect() + pos = (rect.x + x, rect.y + y) + else: + pos = None + # Have the application open the window + pguglobals.app.open(w, pos) + + def focus(self,w=None): + widget.Widget.focus(self) ### by Gal koren +# if not w: +# return widget.Widget.focus(self) + if not w: return + if self.myfocus: self.blur(self.myfocus) + if self.myhover is not w: self.enter(w) + self.myfocus = w + w._event(pygame.event.Event(FOCUS)) + + #print self.myfocus,self.myfocus.__class__.__name__ + + def blur(self,w=None): + if not w: + return widget.Widget.blur(self) + if self.myfocus is w: + if self.myhover is w: self.exit(w) + self.myfocus = None + w._event(pygame.event.Event(BLUR)) + + def enter(self,w): + if self.myhover: self.exit(self.myhover) + self.myhover = w + w._event(pygame.event.Event(ENTER)) + + def exit(self,w): + if self.myhover and self.myhover is w: + self.myhover = None + w._event(pygame.event.Event(EXIT)) + + +# def first(self): +# for w in self.widgets: +# if w.focusable: +# self.focus(w) +# return +# if self.container: self.container.next(self) + +# def next(self,w): +# if w not in self.widgets: return #HACK: maybe. this happens in windows for some reason... +# +# for w in self.widgets[self.widgets.index(w)+1:]: +# if w.focusable: +# self.focus(w) +# return +# if self.container: return self.container.next(self) + + + def _next(self,orig=None): + start = 0 + if orig in self.widgets: start = self.widgets.index(orig)+1 + for w in self.widgets[start:]: + if not w.disabled and w.focusable: + if isinstance(w,Container): + if w._next(): + return True + else: + self.focus(w) + return True + return False + + def _previous(self,orig=None): + end = len(self.widgets) + if orig in self.widgets: end = self.widgets.index(orig) + ws = self.widgets[:end] + ws.reverse() + for w in ws: + if not w.disabled and w.focusable: + if isinstance(w,Container): + if w._previous(): + return True + else: + self.focus(w) + return True + return False + + def next(self,w=None): + if w != None and w not in self.widgets: return #HACK: maybe. this happens in windows for some reason... + + if self._next(w): return True + if self.container: return self.container.next(self) + + + def previous(self,w=None): + if w != None and w not in self.widgets: return #HACK: maybe. this happens in windows for some reason... + + if self._previous(w): return True + if self.container: return self.container.previous(self) + + def resize(self,width=None,height=None): + #r = self.rect + #r.w,r.h = 0,0 + ww,hh = 0,0 + if self.style.width: ww = self.style.width + if self.style.height: hh = self.style.height + + for w in self.widgets: + #w.rect.w,w.rect.h = 0,0 + w.rect.x,w.rect.y = w.style.x,w.style.y + w.rect.w, w.rect.h = w.resize() + #w._resize() + + ww = max(ww,w.rect.right) + hh = max(hh,w.rect.bottom) + return ww,hh + + # Returns the widget with the given name + def find(self, name): + for w in self.widgets: + if (w.name == name): + return w + elif (isinstance(w, Container)): + tmp = w.find(name) + if (tmp): return tmp + return None + diff --git a/src/pgu/gui/deprecated.py b/src/pgu/gui/deprecated.py new file mode 100644 index 0000000..8d53515 --- /dev/null +++ b/src/pgu/gui/deprecated.py @@ -0,0 +1,76 @@ +import pygame + +from const import * +import table +import group +import button, basic +import pguglobals + +def action_open(value): + print 'gui.action_open',"Scheduled to be deprecated." + value.setdefault('x',None) + value.setdefault('y',None) + value['container'].open(value['window'],value['x'],value['y']) + +def action_setvalue(value): + print 'gui.action_setvalue',"Scheduled to be deprecated." + a,b = value + b.value = a.value + +def action_quit(value): + print 'gui.action_quit',"Scheduled to be deprecated." + value.quit() + +def action_exec(value): + print 'gui.action_exec',"Scheduled to be deprecated." + exec(value['script'],globals(),value['dict']) + +class Toolbox(table.Table): + def __setattr__(self,k,v): + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and _v != NOATTR and _v != v: + self.group.value = v + for w in self.group.widgets: + if w.value != v: w.pcls = "" + else: w.pcls = "down" + self.repaint() + + def _change(self,value): + self.value = self.group.value + self.send(CHANGE) + + def __init__(self,data,cols=0,rows=0,tool_cls='tool',value=None,**params): + print 'gui.Toolbox','Scheduled to be deprecated.' + params.setdefault('cls','toolbox') + table.Table.__init__(self,**params) + + if cols == 0 and rows == 0: cols = len(data) + if cols != 0 and rows != 0: rows = 0 + + self.tools = {} + + _value = value + + g = group.Group() + self.group = g + g.connect(CHANGE,self._change,None) + self.group.value = _value + + x,y,p,s = 0,0,None,1 + for ico,value in data: + #from __init__ import theme + img = pguglobals.app.theme.get(tool_cls+"."+ico,"","image") + if img: + i = basic.Image(img) + else: i = basic.Label(ico,cls=tool_cls+".label") + p = button.Tool(g,i,value,cls=tool_cls) + self.tools[ico] = p + #p.style.hexpand = 1 + #p.style.vexpand = 1 + self.add(p,x,y) + s = 0 + if cols != 0: x += 1 + if cols != 0 and x == cols: x,y = 0,y+1 + if rows != 0: y += 1 + if rows != 0 and y == rows: x,y = x+1,0 diff --git a/src/pgu/gui/dialog.py b/src/pgu/gui/dialog.py new file mode 100644 index 0000000..0d30b34 --- /dev/null +++ b/src/pgu/gui/dialog.py @@ -0,0 +1,168 @@ +""" +""" +import os + +from const import * +import table, area +import basic, input, button +import pguglobals + +class Dialog(table.Table): + """A dialog window with a title bar and an "close" button on the bar. + +
Dialog(title,main)
+ +
+
title
title widget, usually a label +
main
main widget, usually a container +
+ + Example + + title = gui.Label("My Title") + main = gui.Container() + #add stuff to the container... + + d = gui.Dialog(title,main) + d.open() + + """ + def __init__(self,title,main,**params): + params.setdefault('cls','dialog') + table.Table.__init__(self,**params) + + + self.tr() + self.td(title,align=-1,cls=self.cls+'.bar') + clos = button.Icon(self.cls+".bar.close") + clos.connect(CLICK,self.close,None) + self.td(clos,align=1,cls=self.cls+'.bar') + + self.tr() + self.td(main,colspan=2,cls=self.cls+".main") + + +# self.tr() +# +# +# t = table.Table(cls=self.cls+".bar") +# t.tr() +# t.td(title) +# clos = button.Icon(self.cls+".bar.close") +# t.td(clos,align=1) +# clos.connect(CLICK,self.close,None) +# self.add(t,0,0) +# +# main.rect.w,main.rect.h = main.resize() +# clos.rect.w,clos.rect.h = clos.resize() +# title.container.style.width = main.rect.w - clos.rect.w +# +# self.tr() +# self.td(main,cls=self.cls+".main") +# + + +class FileDialog(Dialog): + """A file picker dialog window. + +
FileDialog()
+

Some optional parameters:

+
+
title_txt
title text +
button_txt
button text +
path
initial path +
+ """ + + def __init__(self, title_txt="File Browser", button_txt="Okay", cls="dialog", folderText = "Folder", fileText = "File", path=None, customFont = None, showCurDir = True, customWidth = 350, customHeight = 150): + + self.customFont = customFont + self.showCurDir= showCurDir + cls1 = 'filedialog' + if not path: self.curdir = os.getcwd() + else: self.curdir = path + self.dir_img = basic.Image( + pguglobals.app.theme.get(cls1+'.folder', '', 'image')) + td_style = {'padding_left': 4, + 'padding_right': 4, + 'padding_top': 2, + 'padding_bottom': 2} + self.title = basic.Label(title_txt, cls=cls+".title.label") + self.body = table.Table() + self.list = area.List(width=customWidth, height=customHeight) + self.input_dir = input.Input(customFont = self.customFont) + self.input_file = input.Input(customFont = self.customFont) + self._list_dir_() + self.button_ok = button.Button(button_txt) + self.body.tr() + if self.showCurDir : + self.body.td(basic.Label(folderText), style=td_style, align=-1) + self.body.td(self.input_dir, style=td_style) + self.body.tr() + self.body.td(self.list, colspan=3, style=td_style) + self.list.connect(CHANGE, self._item_select_changed_, None) + self.button_ok.connect(CLICK, self._button_okay_clicked_, None) + self.body.tr() + self.body.td(basic.Label(fileText), style=td_style, align=-1) + self.body.td(self.input_file, style=td_style) + self.body.td(self.button_ok, style=td_style) + self.value = None + Dialog.__init__(self, self.title, self.body) + + def _list_dir_(self): + self.input_dir.value = self.curdir + self.input_dir.pos = len(self.curdir) + self.input_dir.vpos = 0 + dirs = [] + files = [] + try: + for i in os.listdir(self.curdir): + if os.path.isdir(os.path.join(self.curdir, i)): dirs.append(i) + else: files.append(i) + except: + self.input_file.value = "Opps! no access" + #if '..' not in dirs: dirs.append('..') + dirs.sort() + dirs = ['..'] + dirs + + files.sort() + for i in dirs: + #item = ListItem(image=self.dir_img, text=i, value=i) + if self.customFont == None : + self.list.add(i,image=self.dir_img,value=i) + else : + label = basic.Label(i,font = self.customFont) + self.list.add(label,image=self.dir_img,value=i) + for i in files: + #item = ListItem(image=None, text=i, value=i) + if self.customFont == None : + self.list.add(i,value=i) + else: + label = basic.Label(i,font = self.customFont) + self.list.add(label,value=i) + #self.list.resize() + self.list.set_vertical_scroll(0) + #self.list.repaintall() + + + def _item_select_changed_(self, arg): + self.input_file.value = self.list.value + fname = os.path.abspath(os.path.join(self.curdir, self.input_file.value)) + if os.path.isdir(fname): + self.input_file.value = "" + self.curdir = fname + self.list.clear() + self._list_dir_() + + + def _button_okay_clicked_(self, arg): + if self.input_dir.value != self.curdir: + if os.path.isdir(self.input_dir.value): + self.input_file.value = "" + self.curdir = os.path.abspath(self.input_dir.value) + self.list.clear() + self._list_dir_() + else: + self.value = os.path.join(self.curdir, self.input_file.value) + self.send(CHANGE) + self.close() diff --git a/src/pgu/gui/document.py b/src/pgu/gui/document.py new file mode 100644 index 0000000..1bd96df --- /dev/null +++ b/src/pgu/gui/document.py @@ -0,0 +1,112 @@ +""" +""" +import pygame + +import container +import layout + +class _document_widget: + def __init__(self,w,align=None): + #w.rect.w,w.rect.h = w.resize() + #self.rect = w.rect + self.widget = w + if align != None: self.align = align + +class Document(container.Container): + """A document container contains many widgets strung together in a document format. (How informative!) + +
Document()
+ + """ + def __init__(self,**params): + params.setdefault('cls','document') + container.Container.__init__(self,**params) + self.layout = layout.Layout(pygame.Rect(0,0,self.rect.w,self.rect.h)) + + def add(self,e,align=None): + """Add a widget. + +
Document.add(e,align=None)
+ +
+
e
widget +
align
alignment (None,-1,0,1) +
+ """ + dw = _document_widget(e,align) + self.layout.add(dw) + e.container = self + e._c_dw = dw + self.widgets.append(e) + self.chsize() + + def remove(self,e): + self.layout._widgets.remove(e._c_dw) + self.widgets.remove(e) + self.chsize() + + + def block(self,align): + """Start a new block. + +
Document.block(align)
+ +
+
align
alignment of block (-1,0,1) +
+ """ + self.layout.add(align) + + def space(self,e): + """Add a spacer. + +
Document.space(e)
+ +
+
e
a (w,h) size for the spacer +
+ """ + self.layout.add(e) + + def br(self,height): + """Add a line break. + +
Document.br(height)
+ +
+
height
height of line break +
+ """ + self.layout.add((0,height)) + + def resize(self,width=None,height=None): + if self.style.width: width = self.style.width + if self.style.height: height = self.style.height + + for w in self.widgets: + w.rect.w,w.rect.h = w.resize() + + if (width != None and w.rect.w > width) or (height != None and w.rect.h > height): + w.rect.w,w.rect.h = w.resize(width,height) + + dw = w._c_dw + dw.rect = pygame.Rect(0,0,w.rect.w,w.rect.h) + + if width == None: width = 65535 + self.layout.rect = pygame.Rect(0,0,width,0) + self.layout.resize() + + _max_w = 0 + + for w in self.widgets: + #xt,xl,xb,xr = w.getspacing() + dw = w._c_dw + w.style.x,w.style.y,w.rect.w,w.rect.h = dw.rect.x,dw.rect.y,dw.rect.w,dw.rect.h + #w.resize() + w.rect.x,w.rect.y = w.style.x,w.style.y + _max_w = max(_max_w,w.rect.right) + + #self.rect.w = _max_w #self.layout.rect.w + #self.rect.h = self.layout.rect.h + #print 'document',_max_w,self.layout.rect.h + return _max_w,self.layout.rect.h diff --git a/src/pgu/gui/form.py b/src/pgu/gui/form.py new file mode 100644 index 0000000..9a874f9 --- /dev/null +++ b/src/pgu/gui/form.py @@ -0,0 +1,79 @@ +""" +""" +import widget + +class Form(widget.Widget): + """A form that automatically will contain all named widgets. + +

After a form is created, all named widget that are subsequently created are added + to that form. You may use dict style access to access named widgets.

+ +
Form()
+ + Example + + f = gui.Form() + + w = gui.Input("Phil",name="firstname") + w = gui.Input("Hassey",name="lastname") + + print f.results() + print '' + print f.items() + print '' + print f['firstname'].value + print f['lastname'].value + + """ + + def __init__(self): + widget.Widget.__init__(self,decorate=False) + self._elist = [] + self._emap = {} + self._dirty = 0 + Form.form = self + + def add(self,e,name=None,value=None): + if name != None: e.name = name + if value != None: e.value = value + self._elist.append(e) + self._dirty = 1 + + def _clean(self): + for e in self._elist[:]: + if not hasattr(e,'name') or e.name == None: + self._elist.remove(e) + self._emap = {} + for e in self._elist: + self._emap[e.name] = e + self._dirty = 0 + + def __getitem__(self,k): + if self._dirty: self._clean() + return self._emap[k] + + def __contains__(self,k): + if self._dirty: self._clean() + if k in self._emap: return True + return False + + def results(self): + """Return a dict of name => values. + +
Form.results(): return dict
+ """ + if self._dirty: self._clean() + r = {} + for e in self._elist: + r[e.name] = e.value + return r + + def items(self): + """Return a list of name, value keys. + +
Form.items(): return list
+ """ + return self.results().items() + + #def start(self): + # Object.start(self,-1) diff --git a/src/pgu/gui/group.py b/src/pgu/gui/group.py new file mode 100644 index 0000000..bcb231a --- /dev/null +++ b/src/pgu/gui/group.py @@ -0,0 +1,43 @@ +""" +""" +from const import * +import widget + +class Group(widget.Widget): + """An object for grouping together Form elements. + +
Group(name=None,value=None)
+ +
+
name
name as used in the Form +
value
values that are currently selected in the group +
+ +

See [[gui-button]] for several examples.

+ +

When the value changes, an gui.CHANGE event is sent. + Although note, that when the value is a list, it may have to be sent by hand via + g.send(gui.CHANGE)

+ """ + + def __init__(self,name=None,value=None): + widget.Widget.__init__(self,name=name,value=value) + self.widgets = [] + + def add(self,w): + """Add a widget to this group. + +
Group.add(w)
+ """ + self.widgets.append(w) + + def __setattr__(self,k,v): + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k] = v + if k == 'value' and _v != NOATTR and _v != v: + self._change() + + def _change(self): + self.send(CHANGE) + for w in self.widgets: + w.repaint() diff --git a/src/pgu/gui/input.py b/src/pgu/gui/input.py new file mode 100644 index 0000000..3f3f653 --- /dev/null +++ b/src/pgu/gui/input.py @@ -0,0 +1,169 @@ +""" +""" +import pygame +from pygame.locals import * + +from const import * +import widget + +class Input(widget.Widget): + """A single line text input. + +
Input(value="",size=20)
+ +
+
value
initial text +
size
size for the text box, in characters +
+ + Example + + w = Input(value="Cuzco the Goat",size=20) + + w = Input("Marbles") + + + """ + def __init__(self,value="",size=20,customFont = None,**params): + params.setdefault('cls','input') + widget.Widget.__init__(self,**params) + self.value = value + self.pos = len(str(value)) + self.vpos = 0 + if customFont != None: + self.font = customFont + else: + self.font = self.style.font + w,h = self.font.size("e"*size) + if not self.style.height: self.style.height = h + if not self.style.width: self.style.width = w + #self.style.height = max(self.style.height,h) + #self.style.width = max(self.style.width,w) + #self.rect.w=w+self.style.padding_left+self.style.padding_right; + #self.rect.h=h+self.style.padding_top+self.style.padding_bottom; + + def paint(self,s): + + r = pygame.Rect(0,0,self.rect.w,self.rect.h) + + cs = 2 #NOTE: should be in a style + + w,h = self.font.size(self.value[0:self.pos]) + x = w-self.vpos + if x < 0: self.vpos -= -x + if x+cs > s.get_width(): self.vpos += x+cs-s.get_width() + + s.blit(self.font.render(self.value, 1, self.style.color),(-self.vpos,0)) + + if self.container.myfocus is self: + w,h = self.font.size(self.value[0:self.pos]) + r.x = w-self.vpos + r.w = cs + r.h = h + s.fill(self.style.color,r) + + def _setvalue(self,v): + self.__dict__['value'] = v + self.send(CHANGE) + + def event(self,e): + used = None + if e.type == KEYDOWN: + if e.key == K_BACKSPACE: + if self.pos: + self._setvalue(self.value[:self.pos-1] + self.value[self.pos:]) + self.pos -= 1 + elif e.key == K_DELETE: + if len(self.value) > self.pos: + self._setvalue(self.value[:self.pos] + self.value[self.pos+1:]) + elif e.key == K_HOME: + self.pos = 0 + elif e.key == K_END: + self.pos = len(self.value) + elif e.key == K_LEFT: + if self.pos > 0: self.pos -= 1 + used = True + elif e.key == K_RIGHT: + if self.pos < len(self.value): self.pos += 1 + used = True + elif e.key == K_RETURN: + self.next() + elif e.key == K_TAB: + pass + else: + #c = str(e.unicode) + try: + c = (e.unicode).encode('latin-1') + if c: + self._setvalue(self.value[:self.pos] + c + self.value[self.pos:]) + self.pos += 1 + except: #ignore weird characters + pass + self.repaint() + elif e.type == FOCUS: + self.repaint() + elif e.type == BLUR: + self.repaint() + + self.pcls = "" + if self.container.myfocus is self: self.pcls = "focus" + + return used + + def __setattr__(self,k,v): + if k == 'value': + if v == None: v = '' + v = str(v) + self.pos = len(v) + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and _v != NOATTR and _v != v: + self.send(CHANGE) + self.repaint() + +class Password(Input): + """A password input, text is *-ed out. + +
Password(value="",size=20)
+ +
+
value
initial text +
size
size for the text box, in characters +
+ + Example + + w = Password(value="password",size=20) + + w = Password("53[r3+") + + + """ + + def paint(self,s): + hidden="*" + show=len(self.value)*hidden + + #print "self.value:",self.value + + if self.pos == None: self.pos = len(self.value) + + r = pygame.Rect(0,0,self.rect.w,self.rect.h) + + cs = 2 #NOTE: should be in a style + + w,h = self.font.size(show) + x = w-self.vpos + if x < 0: self.vpos -= -x + if x+cs > s.get_width(): self.vpos += x+cs-s.get_width() + + s.blit(self.font.render(show, 1, self.style.color),(-self.vpos,0)) + + if self.container.myfocus is self: + #w,h = self.font.size(self.value[0:self.pos]) + w,h = self.font.size(show[0:self.pos]) + r.x = w-self.vpos + r.w = cs + r.h = h + s.fill(self.style.color,r) + diff --git a/src/pgu/gui/keysym.py b/src/pgu/gui/keysym.py new file mode 100644 index 0000000..cc24089 --- /dev/null +++ b/src/pgu/gui/keysym.py @@ -0,0 +1,72 @@ +""" +""" +import pygame +from pygame.locals import * + +from const import * +import widget + +class Keysym(widget.Widget): + """A keysym input. + +

This widget records the keysym of the key pressed while this widget is in focus.

+ +
Keysym(value=None)
+ +
+
value
initial keysym, see pygame keysyms
+ + Example + + w = Input(value=pygame.locals.K_g) + + w = Input(pygame.locals.K_g) + + w = Input() + + + """ + + def __init__(self,value=None,**params): + params.setdefault('cls','keysym') + widget.Widget.__init__(self,**params) + self.value = value + + self.font = self.style.font + w,h = self.font.size("Right Super") #"Right Shift") + self.style.width,self.style.height = w,h + #self.rect.w=w+self.style.padding_left+self.style.padding_right + #self.rect.h=h+self.style.padding_top+self.style.padding_bottom + + def event(self,e): + used = None + if e.type == FOCUS or e.type == BLUR: self.repaint() + elif e.type == KEYDOWN: + if e.key != K_TAB: + self.value = e.key + self.repaint() + self.send(CHANGE) + used = True + self.next() + self.pcls = "" + if self.container.myfocus is self: self.pcls = "focus" + return used + + def paint(self,s): + r = pygame.rect.Rect(0,0,self.rect.w,self.rect.h) + #render_box(s,self.style.background,r) + if self.value == None: return + name = "" + for p in pygame.key.name(self.value).split(): name += p.capitalize()+" " + #r.x = self.style.padding_left; + #r.y = self.style.padding_bottom; + s.blit(self.style.font.render(name, 1, self.style.color), r) + + def __setattr__(self,k,v): + if k == 'value' and v != None: + v = int(v) + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and _v != NOATTR and _v != v: + self.send(CHANGE) + self.repaint() diff --git a/src/pgu/gui/layout.py b/src/pgu/gui/layout.py new file mode 100644 index 0000000..01fe0cb --- /dev/null +++ b/src/pgu/gui/layout.py @@ -0,0 +1,172 @@ +"""document layout engine.""" +class Layout: + """the document layout engine + + .widgets -- elements are kept in this list. read-only, use add to add items to it. + """ + + def __init__(self,rect=None): + """initialize the object with the size of the box.""" + self._widgets = [] + self.rect = rect + + def add(self,e): + """add a document element to the layout. + + a document element may be + - a tuple (w,h) if it is a whitespace element + - a tuple (0,h) if it is a linebreak element + - an integer -1,0,1 if it is a command to start a new block of elements that are aligned either left,center, or right. + - an object with a .rect (for size) -- such as a word element + - an object with a .rect (for size) and .align -- such as an image element + """ + + self._widgets.append(e) + + + def resize(self): + """resize the layout + this method recalculates the position of all document elements + after they have been added to the document. .rect.x,y will be updated for all + objects. + """ + self.init() + self.widgets = [] + for e in self._widgets: + if type(e) is tuple and e[0] != 0: + self.do_space(e) + elif type(e) is tuple and e[0] == 0: + self.do_br(e[1]) + elif type(e) is int: + self.do_block(align=e) + elif hasattr(e,'align'): + self.do_align(e) + else: + self.do_item(e) + self.line() + self.rect.h = max(self.y,self.left_bottom,self.right_bottom) + + def init(self): + self.x,self.y = self.rect.x,self.rect.y + self.left = self.rect.left + self.right = self.rect.right + self.left_bottom = 0 + self.right_bottom = 0 + self.y = self.rect.y + self.x = self.rect.x + self.h = 0 + + self.items = [] + self.align = -1 + + def getleft(self): + if self.y > self.left_bottom: + self.left = self.rect.left + return self.left + + def getright(self): + if self.y > self.right_bottom: + self.right = self.rect.right + return self.right + + def do_br(self,h): + self.line() + self.h = h + + def do_block(self,align=-1): + self.line() + self.align = align + + def do_align(self,e): + align = e.align + ox,oy,oh = self.x,self.y,self.h + w,h = e.rect.w,e.rect.h + + if align == 0: + self.line() + self.x = self.rect.left + (self.rect.width-w)/2 + self.fit = 0 + elif align == -1: + self.line() + self.y = max(self.left_bottom,self.y + self.h) + self.h = 0 + self.x = self.rect.left + elif align == 1: + self.line() + self.y = max(self.right_bottom,self.y + self.h) + self.h = 0 + self.x = self.rect.left + (self.rect.width-w) + + e.rect.x,e.rect.y = self.x,self.y + + self.x = self.x + w + self.y = self.y + + if align == 0: + self.h = max(self.h,h) + self.y = self.y + self.h + self.x = self.getleft() + self.h = 0 + elif align == -1: + self.left = self.x + self.left_bottom = self.y + h + self.x,self.y,self.h = ox + w,oy,oh + elif align == 1: + self.right = self.x - w + self.right_bottom = self.y + h + self.x,self.y,self.h = ox,oy,oh + + self.widgets.append(e) + + def do_space(self,e): + w,h = e + if self.x+w >= self.getright(): + self.line() + else: + self.items.append(e) + self.h = max(self.h,h) + self.x += w + + def do_item(self,e): + w,h = e.rect.w,e.rect.h + if self.x+w >= self.getright(): + self.line() + self.items.append(e) + self.h = max(self.h,h) + self.x += w + + def line(self): + x1 = self.getleft() + x2 = self.getright() + align = self.align + y = self.y + + if len(self.items) != 0 and type(self.items[-1]) == tuple: + del self.items[-1] + + w = 0 + for e in self.items: + if type(e) == tuple: w += e[0] + else: w += e.rect.w + + if align == -1: x = x1 + elif align == 0: + x = x1 + ((x2-x1)-w)/2 + self.fit = 0 + elif align == 1: x = x2 - w + + for e in self.items: + if type(e) == tuple: x += e[0] + else: + e.rect.x,e.rect.y = x,y + self.widgets.append(e) + x += e.rect.w + + self.items = [] + self.y = self.y + self.h + self.x = self.getleft() + self.h = 0 + + + +# vim: set filetype=python sts=4 sw=4 noet si : diff --git a/src/pgu/gui/menus.py b/src/pgu/gui/menus.py new file mode 100644 index 0000000..b850b6c --- /dev/null +++ b/src/pgu/gui/menus.py @@ -0,0 +1,119 @@ +""" +""" +from const import * +import table +import basic, button + +class _Menu_Options(table.Table): + def __init__(self,menu,**params): + table.Table.__init__(self,**params) + + self.menu = menu + + def event(self,e): + handled = False + arect = self.get_abs_rect() + + if e.type == MOUSEMOTION: + abspos = e.pos[0]+arect.x,e.pos[1]+arect.y + for w in self.menu.container.widgets: + if not w is self.menu: + mrect = w.get_abs_rect() + if mrect.collidepoint(abspos): + self.menu._close(None) + w._open(None) + handled = True + + if not handled: table.Table.event(self,e) + +class _Menu(button.Button): + def __init__(self,parent,widget=None,**params): #TODO widget= could conflict with module widget + params.setdefault('cls','menu') + button.Button.__init__(self,widget,**params) + + self.parent = parent + + self._cls = self.cls + self.options = _Menu_Options(self, cls=self.cls+".options") + + self.connect(CLICK,self._open,None) + + self.pos = 0 + + def _open(self,value): + self.parent.value = self + self.pcls = 'down' + + self.repaint() + self.container.open(self.options,self.rect.x,self.rect.bottom) + self.options.connect(BLUR,self._close,None) + self.options.focus() + self.repaint() + + def _pass(self,value): + pass + + def _close(self,value): + self.pcls = '' + self.parent.value = None + self.repaint() + self.options.close() + + def _value(self,value): + self._close(None) + if value['fnc'] != None: + value['fnc'](value['value']) + + def event(self,e): + button.Button.event(self,e) + + if self.parent.value == self: + self.pcls = 'down' + + def add(self,w,fnc=None,value=None): + w.style.align = -1 + b = button.Button(w,cls=self.cls+".option") + b.connect(CLICK,self._value,{'fnc':fnc,'value':value}) + + self.options.tr() + self.options.add(b) + + return b + +class Menus(table.Table): + """A drop down menu bar. + +
Menus(data)
+ +
+
data
Menu data, a list of (path,fnc,value), see example below +
+ + Example + + data = [ + ('File/Save',fnc_save,None), + ('File/New',fnc_new,None), + ('Edit/Copy',fnc_copy,None), + ('Edit/Cut',fnc_cut,None), + ('Help/About',fnc_help,help_about_content), + ('Help/Reference',fnc_help,help_reference_content), + ] + w = Menus(data) + """ + + def __init__(self,data,menu_cls='menu',**params): + params.setdefault('cls','menus') + table.Table.__init__(self,**params) + + self.value = None + + n,m,mt = 0,None,None + for path,cmd,value in data: + parts = path.split("/") + if parts[0] != mt: + mt = parts[0] + m = _Menu(self,basic.Label(mt,cls=menu_cls+".label"),cls=menu_cls) + self.add(m,n,0) + n += 1 + m.add(basic.Label(parts[1],cls=m.cls+".option.label"),cmd,value) diff --git a/src/pgu/gui/misc.py b/src/pgu/gui/misc.py new file mode 100644 index 0000000..afb10c5 --- /dev/null +++ b/src/pgu/gui/misc.py @@ -0,0 +1,43 @@ +from const import * +import widget +import pguglobals + +class ProgressBar(widget.Widget): + """A progress bar. + +
ProgressBar(value,min,max)
+ +
+
value
starting value +
min
minimum value rendered on the screen (usually 0) +
max
maximum value +
+ + Example + + w = gui.ProgressBar(0,0,100) + w.value = 25 + + """ + + def __init__(self,value,min,max,**params): + params.setdefault('cls','progressbar') + widget.Widget.__init__(self,**params) + self.min,self.max,self.value = min,max,value + + def paint(self,s): + r = pygame.rect.Rect(0,0,self.rect.w,self.rect.h) + r.w = r.w*(self.value-self.min)/(self.max-self.min) + self.bar = r + pguglobals.app.theme.render(s,self.style.bar,r) + + def __setattr__(self,k,v): + if k == 'value': + v = int(v) + v = max(v,self.min) + v = min(v,self.max) + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and _v != NOATTR and _v != v: + self.send(CHANGE) + self.repaint() diff --git a/src/pgu/gui/pguglobals.py b/src/pgu/gui/pguglobals.py new file mode 100644 index 0000000..dc0e673 --- /dev/null +++ b/src/pgu/gui/pguglobals.py @@ -0,0 +1,7 @@ +# pguglobals.py - A place to stick global variables that need to be accessed +# from other modules. To avoid problems with circular imports +# this module should not import any other PGU module. + +# A global reference to the application instance (App class) +app = None + diff --git a/src/pgu/gui/select.py b/src/pgu/gui/select.py new file mode 100644 index 0000000..0ee39e9 --- /dev/null +++ b/src/pgu/gui/select.py @@ -0,0 +1,180 @@ +""" +""" + +import traceback + +from const import * +from button import Button +from basic import Label, Image +from table import Table + +class Select(Table): + """A select input. + +
Select(value=None)
+ +
+
value
initial value +
+ + Example + + w = Select(value="goats") + w.add("Cats","cats") + w.add("Goats","goats") + w.add("Dogs","Dogs") + + w.value = 'dogs' #changes the value from goats to dogs + + + """ + + # The drop-down arrow button for the selection widget + top_arrow = None + # A button displaying the currently selected item + top_selection = None + # The first option added to the selector + firstOption = None + # The PGU table of options + options = None + + def __init__(self,value=None,**params): + params.setdefault('cls','select') + Table.__init__(self,**params) + + label = Label(" ",cls=self.cls+".option.label") + self.top_selected = Button(label, cls=self.cls+".selected") + Table.add(self,self.top_selected) #,hexpand=1,vexpand=1)#,0,0) + + self.top_arrow = Button(Image(self.style.arrow), cls=self.cls+".arrow") + Table.add(self,self.top_arrow) #,hexpand=1,vexpand=1) #,1,0) + + self.options = Table(cls=self.cls+".options") + self.options.connect(BLUR,self._close,None) + self.options.name = "pulldown-table" + + self.values = [] + self.value = value + + def resize(self,width=None,height=None): + max_w,max_h = 0,0 + for w in self.options.widgets: + w.rect.w,w.rect.h = w.resize() + max_w,max_h = max(max_w,w.rect.w),max(max_h,w.rect.h) + + #xt,xr,xb,xl = self.top_selected.getspacing() + self.top_selected.style.width = max_w #+ xl + xr + self.top_selected.style.height = max_h #+ xt + xb + + self.top_arrow.connect(CLICK,self._open,None) + self.top_selected.connect(CLICK,self._open,None) + + w,h = Table.resize(self,width,height) + + self.options.style.width = w + #HACK: sort of, but not a big one.. + self.options.resize() + + return w,h + + def _open(self,value): + opts = self.options + + opts.rect.w, opts.rect.h = opts.resize() + +# y = self.rect.y +# c = self.container +# while hasattr(c, 'container'): +# y += c.rect.y +# if (not c.container): +# break +# c = c.container + +# if y + self.rect.h + opts.rect.h <= c.rect.h: #down +# dy = self.rect.y + self.rect.h +# else: #up +# dy = self.rect.y - self.rect.h + + opts.rect.w, opts.rect.h = opts.resize() + + # TODO - make sure there is enough space to open down + # ... + yp = self.rect.bottom-1 + + self.container.open(opts, self.rect.x, yp) + self.firstOption.focus() + + # TODO - this is a hack + for opt in self.options.widgets: + opt.repaint() + + def _close(self,value): + self.options.close() + self.top_selected.focus() + + def _setvalue(self,value): + self.value = value._value + if hasattr(self,'container'): + #self.chsize() + #HACK: improper use of resize() + #self.resize() #to recenter the new value, etc. + pass + # #self._resize() + + self._close(None) + #self.repaint() #this will happen anyways + + + + def __setattr__(self,k,v): + mywidget = None + if k == 'value': + for w in self.values: + if w._value == v: + mywidget = w + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and _v != NOATTR and _v != v: + self.send(CHANGE) + self.repaint() + if k == 'value': + if not mywidget: + mywidget = Label(" ",cls=self.cls+".option.label") + self.top_selected.value = mywidget + + def add(self,w,value=None): + """Add a widget, value item to the Select. + +
Select.add(widget,value=None)
+ +
+
widget
Widget or string to represent the item +
value
value for this item +
+ + Example + + w = Select() + w.add("Goat") #adds a Label + w.add("Goat","goat") #adds a Label with the value goat + w.add(gui.Label("Cuzco"),"goat") #adds a Label with value goat + + """ + + if type(w) == str: w = Label(w,cls=self.cls+".option.label") + + w.style.align = -1 + btn = Button(w,cls=self.cls+".option") + btn.connect(CLICK,self._setvalue,w) + + self.options.tr() + self.options.add(btn) + + if (not self.firstOption): + self.firstOption = btn + + if value != None: w._value = value + else: w._value = w + if self.value == w._value: + self.top_selected.value = w + self.values.append(w) diff --git a/src/pgu/gui/slider.py b/src/pgu/gui/slider.py new file mode 100644 index 0000000..f4fa623 --- /dev/null +++ b/src/pgu/gui/slider.py @@ -0,0 +1,279 @@ +"""All sliders and scroll bar widgets have the same parameters. + +
Slider(value,min,max,size)
+
+
value
initial value +
min
minimum value +
max
maximum value +
size
size of bar in pixels +
+""" +import pygame +from pygame.locals import * + +from const import * +import widget +import table +import basic +import pguglobals + +_SLIDER_HORIZONTAL = 0 +_SLIDER_VERTICAL = 1 + +class _slider(widget.Widget): + def __init__(self,value,orient,min,max,size,step=1,**params): + params.setdefault('cls','slider') + widget.Widget.__init__(self,**params) + self.min,self.max,self.value,self.orient,self.size,self.step = min,max,value,orient,size,step + + + def paint(self,s): + + self.value = self.value + r = pygame.rect.Rect(0,0,self.style.width,self.style.height) + if self.orient == _SLIDER_HORIZONTAL: + r.x = (self.value-self.min) * (r.w-self.size) / max(1,self.max-self.min); + r.w = self.size; + else: + r.y = (self.value-self.min) * (r.h-self.size) / max(1,self.max-self.min); + r.h = self.size; + + self.bar = r + + pguglobals.app.theme.render(s,self.style.bar,r) + + def event(self,e): + used = None + r = pygame.rect.Rect(0,0,self.style.width,self.style.height) + adj = 0 + if e.type == ENTER: self.repaint() + elif e.type == EXIT: self.repaint() + elif e.type == MOUSEBUTTONDOWN: + if self.bar.collidepoint(e.pos): + self.grab = e.pos[0],e.pos[1] + self.grab_value = self.value + else: + x,y,adj = e.pos[0],e.pos[1],1 + self.grab = None + self.repaint() + elif e.type == MOUSEBUTTONUP: + #x,y,adj = e.pos[0],e.pos[1],1 + self.repaint() + elif e.type == MOUSEMOTION: + if 1 in e.buttons and self.container.myfocus is self: + if self.grab != None: + rel = e.pos[0]-self.grab[0],e.pos[1]-self.grab[1] + if self.orient == _SLIDER_HORIZONTAL: + d = (r.w - self.size) + if d != 0: self.value = self.grab_value + ((self.max-self.min) * rel[0] / d) + else: + d = (r.h - self.size) + if d != 0: self.value = self.grab_value + ((self.max-self.min) * rel[1] / d) + else: + x,y,adj = e.pos[0],e.pos[1],1 + + elif e.type is KEYDOWN: + if self.orient == _SLIDER_HORIZONTAL and e.key == K_LEFT: + self.value -= self.step + used = True + elif self.orient == _SLIDER_HORIZONTAL and e.key == K_RIGHT: + self.value += self.step + used = True + elif self.orient == _SLIDER_VERTICAL and e.key == K_UP: + self.value -= self.step + used = True + elif self.orient == _SLIDER_VERTICAL and e.key == K_DOWN: + self.value += self.step + used = True + + if adj: + if self.orient == _SLIDER_HORIZONTAL: + d = self.size/2 - (r.w/(self.max-self.min+1))/2 + self.value = (x-d) * (self.max-self.min) / (r.w-self.size+1) + self.min + else: + d = self.size/2 - (r.h/(self.max-self.min+1))/2 + self.value = (y-d) * (self.max-self.min) / (r.h-self.size+1) + self.min + + self.pcls = "" + if self.container.myhover is self: self.pcls = "hover" + if (self.container.myfocus is self and 1 in pygame.mouse.get_pressed()): self.pcls = "down" + + return used + + + def __setattr__(self,k,v): + if k == 'value': + v = int(v) + v = max(v,self.min) + v = min(v,self.max) + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and _v != NOATTR and _v != v: + self.send(CHANGE) + self.repaint() + + if hasattr(self,'size'): + sz = min(self.size,max(self.style.width,self.style.height)) + sz = max(sz,min(self.style.width,self.style.height)) + self.__dict__['size'] = sz + + if hasattr(self,'max') and hasattr(self,'min'): + if self.max < self.min: self.max = self.min + +class VSlider(_slider): + """A verticle slider. + +
VSlider(value,min,max,size)
+ """ + def __init__(self,value,min,max,size,step=1,**params): + params.setdefault('cls','vslider') + _slider.__init__(self,value,_SLIDER_VERTICAL,min,max,size,step,**params) + +class HSlider(_slider): + """A horizontal slider. + +
HSlider(value,min,max,size)
+ """ + def __init__(self,value,min,max,size,step=1,**params): + params.setdefault('cls','hslider') + _slider.__init__(self,value,_SLIDER_HORIZONTAL,min,max,size,step,**params) + +class HScrollBar(table.Table): + """A horizontal scroll bar. + +
HScrollBar(value,min,max,size,step=1)
+ """ + def __init__(self,value,min,max,size,step=1,**params): + params.setdefault('cls','hscrollbar') + + table.Table.__init__(self,**params) + + self.slider = _slider(value,_SLIDER_HORIZONTAL,min,max,size,step=step,cls=self.cls+'.slider') + + self.minus = basic.Image(self.style.minus) + self.minus.connect(MOUSEBUTTONDOWN,self._click,-1) + self.slider.connect(CHANGE,self.send,CHANGE) + + self.minus2 = basic.Image(self.style.minus) + self.minus2.connect(MOUSEBUTTONDOWN,self._click,-1) + + self.plus = basic.Image(self.style.plus) + self.plus.connect(MOUSEBUTTONDOWN,self._click,1) + + self.size = size + + def _click(self,value): + self.slider.value += self.slider.step*value + + def resize(self,width=None,height=None): + self.clear() + self.tr() + + w = self.style.width + h = self.slider.style.height + ww = 0 + + if w > (h*2 + self.minus.style.width+self.plus.style.width): + self.td(self.minus) + ww += self.minus.style.width + + self.td(self.slider) + + if w > (h*2 + self.minus.style.width+self.minus2.style.width+self.plus.style.width): + self.td(self.minus2) + ww += self.minus2.style.width + + if w > (h*2 + self.minus.style.width+self.plus.style.width): + self.td(self.plus) + ww += self.plus.style.width + + + #HACK: handle theme sizing properly + xt,xr,xb,xl = pguglobals.app.theme.getspacing(self.slider) + ww += xr+xl + + self.slider.style.width = self.style.width - ww + setattr(self.slider,'size',self.size * self.slider.style.width / max(1,self.style.width)) + return table.Table.resize(self,width,height) + + + def __setattr__(self,k,v): + if k in ('min','max','value','step'): + return setattr(self.slider,k,v) + self.__dict__[k]=v + + def __getattr__(self,k): + if k in ('min','max','value','step'): + return getattr(self.slider,k) + return table.Table.__getattr__(self,k) #self.__dict__[k] + +class VScrollBar(table.Table): + """A vertical scroll bar. + +
VScrollBar(value,min,max,size,step=1)
+ """ + def __init__(self,value,min,max,size,step=1,**params): + params.setdefault('cls','vscrollbar') + + table.Table.__init__(self,**params) + + self.minus = basic.Image(self.style.minus) + self.minus.connect(MOUSEBUTTONDOWN,self._click,-1) + + self.minus2 = basic.Image(self.style.minus) + self.minus2.connect(MOUSEBUTTONDOWN,self._click,-1) + + self.plus = basic.Image(self.style.plus) + self.plus.connect(MOUSEBUTTONDOWN,self._click,1) + + self.slider = _slider(value,_SLIDER_VERTICAL,min,max,size,step=step,cls=self.cls+'.slider') + self.slider.connect(CHANGE,self.send,CHANGE) + + self.size = size + + def _click(self,value): + self.slider.value += self.slider.step*value + + def resize(self,width=None,height=None): + self.clear() + + h = self.style.height + w = self.slider.style.width + hh = 0 + + if h > (w*2 + self.minus.style.height+self.plus.style.height): + self.tr() + self.td(self.minus) + hh += self.minus.style.height + + self.tr() + self.td(self.slider) + + if h > (w*2 + self.minus.style.height+self.minus2.style.height+self.plus.style.height): + self.tr() + self.td(self.minus2) + hh += self.minus2.style.height + + if h > (w*2 + self.minus.style.height+self.plus.style.height): + self.tr() + self.td(self.plus) + hh += self.plus.style.height + + + #HACK: handle theme sizing properly + xt,xr,xb,xl = pguglobals.app.theme.getspacing(self.slider) + hh += xt+xb + + self.slider.style.height = self.style.height - hh + setattr(self.slider,'size',self.size * self.slider.style.height / max(1,self.style.height)) + return table.Table.resize(self,width,height) + + def __setattr__(self,k,v): + if k in ('min','max','value','step'): + return setattr(self.slider,k,v) + self.__dict__[k]=v + + def __getattr__(self,k): + if k in ('min','max','value','step'): + return getattr(self.slider,k) + return table.Table.__getattr__(self,k) diff --git a/src/pgu/gui/style.py b/src/pgu/gui/style.py new file mode 100644 index 0000000..3060928 --- /dev/null +++ b/src/pgu/gui/style.py @@ -0,0 +1,41 @@ +""" +""" + +import pguglobals + +class Style: + """The class used by widget for the widget.style + +

This object is used mainly as a dictionary, accessed via widget.style.attr, as opposed to + widget.style['attr']. It automatically grabs information from the theme via value = theme.get(widget.cls,widget.pcls,attr).

+ + """ + def __init__(self,o,dict): + self.obj = o + for k,v in dict.items(): self.__dict__[k]=v + self._cache = {} + + def __getattr__(self,k): + key = self.obj.cls,self.obj.pcls,k + if key not in self._cache: + self._cache[key] = Style_get(self.obj.cls,self.obj.pcls,k) + v = self._cache[key] + if k in ( + 'border_top','border_right','border_bottom','border_left', + 'padding_top','padding_right','padding_bottom','padding_left', + 'margin_top','margin_right','margin_bottom','margin_left', + 'align','valign','width','height', + ): self.__dict__[k] = v + return v + + def __setattr__(self,k,v): + self.__dict__[k] = v + + +Style_cache = {} +def Style_get(cls,pcls,k): + key = cls,pcls,k + if key not in Style_cache: + Style_cache[key] = pguglobals.app.theme.get(cls,pcls,k) + return Style_cache[key] + diff --git a/src/pgu/gui/surface.py b/src/pgu/gui/surface.py new file mode 100644 index 0000000..9bd064d --- /dev/null +++ b/src/pgu/gui/surface.py @@ -0,0 +1,143 @@ +""" +""" +import pygame + +def subsurface(s,r): + """Return the subsurface of a surface, with some help, checks. + +
subsurface(s,r): return surface
+ """ + r = pygame.Rect(r) + if r.x < 0 or r.y < 0: + raise "gui.subsurface: %d %d %s"%(s.get_width(),s.get_height(),r) + w,h = s.get_width(),s.get_height() + if r.right > w: + r.w -= r.right-w + if r.bottom > h: + r.h -= r.bottom-h + assert(r.w >= 0 and r.h >= 0) + return s.subsurface(r) + +class ProxySurface: + """ + A surface-like object which smartly handle out-of-area blitting. + +
ProxySurface(parent, rect, real_surface=None, offset=(0, 0))
+ +

only one of parent and real_surface should be supplied (non None)

+
+
parent
a ProxySurface object +
real_surface
a pygame Surface object +
+ + Variables + +
+
mysubsurface
a real and valid pygame.Surface object to be used + for blitting. +
x, y
if the proxy surface is lefter or higher than the parent, + x, y hold the diffs. +
offset
an optional feature which let you scroll the whole blitted + content. +
+ """ + def __init__(self, parent, rect, real_surface, offset=(0, 0)): + self.offset = offset + self.x = self.y = 0 + if rect.x < 0: self.x = rect.x + if rect.y < 0: self.y = rect.y + self.real_surface = real_surface + if real_surface == None: + self.mysubsurface = parent.mysubsurface.subsurface( + parent.mysubsurface.get_rect().clip(rect)) + else: + self.mysubsurface = real_surface.subsurface( + real_surface.get_rect().clip(rect)) + rect.topleft = (0, 0) + self.rect = rect + + def blit(self, s, pos, rect=None): + if rect == None: rect = s.get_rect() + pos = (pos[0] + self.offset[0] + self.x, pos[1] + self.offset[1] + self.y) + self.mysubsurface.blit(s, pos, rect) + + def subsurface(self, rect): + r = pygame.Rect(rect).move(self.offset[0] + self.x, + self.offset[1] + self.y) + return ProxySurface(self, r, self.real_surface) + + def fill(self, color, rect=None): + if rect != None: self.mysubsurface.fill(color, rect) + else: self.mysubsurface.fill(color) + def get_rect(self): return self.rect + def get_width(self): return self.rect[2] + def get_height(self): return self.rect[3] + def get_abs_offset(): return self.rect[:2] + def get_abs_parent(): return self.mysubsurface.get_abs_parent() + def set_clip(self, rect=None): + if rect == None: self.mysubsurface.set_clip() + else: + rect = [rect[0] + self.offset[0] + self.x, rect[1] + self.offset[0] + self.y, rect[2], rect[3]] + self.mysubsurface.set_clip(rect) + + + + + + +class xProxySurface: + """ + A surface-like object which smartly handle out-of-area blitting. + +
ProxySurface(parent, rect, real_surface=None, offset=(0, 0))
+ +

only one of parent and real_surface should be supplied (non None)

+
+
parent
a ProxySurface object +
real_surface
a pygame Surface object +
+ + Variables + +
+
mysubsurface
a real and valid pygame.Surface object to be used + for blitting. +
x, y
if the proxy surface is lefter or higher than the parent, + x, y hold the diffs. +
offset
an optional feature which let you scroll the whole blitted + content. +
+ """ + def __init__(self, parent, rect, real_surface, offset=(0, 0)): + self.offset = offset + self.x = self.y = 0 + if rect[0] < 0: self.x = rect[0] + if rect[1] < 0: self.y = rect[1] + self.real_surface = real_surface + if real_surface == None: + self.mysubsurface = parent.mysubsurface.subsurface(parent.mysubsurface.get_rect().clip(rect)) + else: + self.mysubsurface = real_surface.subsurface(real_surface.get_rect().clip(rect)) + rect[0], rect[1] = 0, 0 + self.rect = rect + + def blit(self, s, pos, rect=None): + if rect == None: rect = s.get_rect() + pos = (pos[0] + self.offset[0] + self.x, pos[1] + self.offset[1] + self.y) + self.mysubsurface.blit(s, pos, rect) + + def subsurface(self, rect): return ProxySurface(self, pygame.Rect(rect).move(self.offset[0] + self.x, self.offset[1] + self.y),self.real_surface) + def fill(self, color, rect=None): + if rect != None: self.mysubsurface.fill(color, rect) + else: self.mysubsurface.fill(color) + def get_rect(self): return self.rect + def get_width(self): return self.rect[2] + def get_height(self): return self.rect[3] + def get_abs_offset(): return self.rect[:2] + def get_abs_parent(): return self.mysubsurface.get_abs_parent() + def set_clip(self, rect=None): + if rect == None: self.mysubsurface.set_clip() + else: + rect = [rect[0] + self.offset[0] + self.x, rect[1] + self.offset[0] + self.y, rect[2], rect[3]] + self.mysubsurface.set_clip(rect) + diff --git a/src/pgu/gui/table.py b/src/pgu/gui/table.py new file mode 100644 index 0000000..6ff6c74 --- /dev/null +++ b/src/pgu/gui/table.py @@ -0,0 +1,331 @@ +""" +""" +from const import * +import container + +class Table(container.Container): + """A table style container. + +

If you know HTML, this should all work roughly how you would expect. If you are not + familiar with HTML, please read Tables in HTML Documents. Pay attention to TABLE, TR, TD related parts of the document.

+ +
Table()
+ + Example + + t = gui.Table() + + t.tr() + t.td(gui.Label("First Name"), align=-1) + t.td(gui.Input()) + + t.tr() + t.td(gui.Label("Last Name"), align=-1) + t.td(gui.Input()) + + + """ + + + def __init__(self, **params): + params.setdefault('cls','table') + container.Container.__init__(self, **params) + self._rows = [] + self._curRow = 0 + self._trok = False + + def getRows(self): + return len(self._rows) + + def getColumns(self): + if self._rows: + return len(self._rows[0]) + else: + return 0 + + def remove_row(self, n): #NOTE: won't work in all cases. + if n >= self.getRows(): + print "Trying to remove a nonexistant row:", n, "there are only", self.getRows(), "rows" + return + + for cell in self._rows[n]: + if isinstance(cell, dict) and cell["widget"] in self.widgets: + #print 'removing widget' + self.widgets.remove(cell["widget"]) + del self._rows[n] + #print "got here" + + for w in self.widgets: + if w.style.row > n: w.style.row -= 1 + + if self._curRow >= n: + self._curRow -= 1 + + #self.rect.w, self.rect.h = self.resize() + #self.repaint() + + self.chsize() + + def clear(self): + self._rows = [] + self._curRow = 0 + self._trok = False + + self.widgets = [] + + self.chsize() + + #print 'clear',self,self._rows + + def _addRow(self): + self._rows.append([None for x in xrange(self.getColumns())]) + + def tr(self): + """Start on the next row.""" + if not self._trok: + self._trok = True + return + self._curRow += 1 + if self.getRows() <= self._curRow: + self._addRow() + + def _addColumn(self): + if not self._rows: + self._addRow() + for row in self._rows: + row.append(None) + + def _setCell(self, w, col, row, colspan=1, rowspan=1): + #make room for the widget by adding columns and rows + while self.getColumns() < col + colspan: + self._addColumn() + while self.getRows() < row + rowspan: + self._addRow() + + #print w.__class__.__name__,col,row,colspan,rowspan + + #actual widget setting and modification stuff + w.container = self + w.style.row = row #HACK - to work with gal's list + w.style.col = col #HACK - to work with gal's list + self._rows[row][col] = {"widget":w, "colspan":colspan, "rowspan":rowspan} + self.widgets.append(self._rows[row][col]["widget"]) + + #set the spanned columns + #for acell in xrange(col + 1, col + colspan): + # self._rows[row][acell] = True + + #set the spanned rows and the columns on them + #for arow in xrange(row + 1, row + rowspan): + # for acell in xrange(col, col + colspan): #incorrect? + # self._rows[arow][acell] = True + + for arow in xrange(row, row + rowspan): + for acell in xrange(col, col + colspan): #incorrect? + if row != arow or col != acell: + self._rows[arow][acell] = True + + + def td(self, w, col=None, row=None, colspan=1, rowspan=1, **params): + """Add a widget to a table after wrapping it in a TD container. + +
Table.td(w,col=None,row=None,colspan=1,rowspan=1,**params)
+ +
+
w
widget +
col
column +
row
row +
colspan
colspan +
rowspan
rowspan +
align
horizontal alignment (-1,0,1) +
valign
vertical alignment (-1,0,1) +
params
other params for the TD container, style information, etc +
+ """ + + Table.add(self,_Table_td(w, **params), col=col, row=row, colspan=colspan, rowspan=rowspan) + + def add(self, w, col=None, row=None, colspan=1, rowspan=1): + """Add a widget directly into the table, without wrapping it in a TD container. + +
Table.add(w,col=None,row=None,colspan=1,rowspan=1)
+ +

See Table.td for an explanation of the parameters.

+ """ + self._trok = True + #if no row was specifically specified, set it to the current row + if row is None: + row = self._curRow + #print row + + #if its going to be a new row, have it be on the first column + if row >= self.getRows(): + col = 0 + + #try to find an open cell for the widget + if col is None: + for cell in xrange(self.getColumns()): + if col is None and not self._rows[row][cell]: + col = cell + break + + #otherwise put the widget in a new column + if col is None: + col = self.getColumns() + + self._setCell(w, col, row, colspan=colspan, rowspan=rowspan) + + self.chsize() + return + + def remove(self,w): + if hasattr(w,'_table_td'): w = w._table_td + row,col = w.style.row,w.style.col + cell = self._rows[row][col] + colspan,rowspan = cell['colspan'],cell['rowspan'] + + for arow in xrange(row , row + rowspan): + for acell in xrange(col, col + colspan): #incorrect? + self._rows[arow][acell] = False + self.widgets.remove(w) + self.chsize() + + + + def resize(self, width=None, height=None): + #if 1 or self.getRows() == 82: + #print '' + #print 'resize',self.getRows(),self.getColumns(),width,height + #import inspect + #for obj,fname,line,fnc,code,n in inspect.stack()[9:20]: + # print fname,line,':',fnc,code[0].strip() + + + #resize the widgets to their smallest size + for w in self.widgets: + w.rect.w, w.rect.h = w.resize() + + #calculate row heights and column widths + rowsizes = [0 for y in xrange(self.getRows())] + columnsizes = [0 for x in xrange(self.getColumns())] + for row in xrange(self.getRows()): + for cell in xrange(self.getColumns()): + if self._rows[row][cell] and self._rows[row][cell] is not True: + if not self._rows[row][cell]["colspan"] > 1: + columnsizes[cell] = max(columnsizes[cell], self._rows[row][cell]["widget"].rect.w) + if not self._rows[row][cell]["rowspan"] > 1: + rowsizes[row] = max(rowsizes[row], self._rows[row][cell]["widget"].rect.h) + + #distribute extra space if necessary for wide colspanning/rowspanning + for row in xrange(self.getRows()): + for cell in xrange(self.getColumns()): + if self._rows[row][cell] and self._rows[row][cell] is not True: + if self._rows[row][cell]["colspan"] > 1: + columns = xrange(cell, cell + self._rows[row][cell]["colspan"]) + totalwidth = 0 + for acol in columns: + totalwidth += columnsizes[acol] + if totalwidth < self._rows[row][cell]["widget"].rect.w: + for acol in columns: + columnsizes[acol] += _table_div(self._rows[row][cell]["widget"].rect.w - totalwidth, self._rows[row][cell]["colspan"],acol) + if self._rows[row][cell]["rowspan"] > 1: + rows = xrange(row, row + self._rows[row][cell]["rowspan"]) + totalheight = 0 + for arow in rows: + totalheight += rowsizes[arow] + if totalheight < self._rows[row][cell]["widget"].rect.h: + for arow in rows: + rowsizes[arow] += _table_div(self._rows[row][cell]["widget"].rect.h - totalheight, self._rows[row][cell]["rowspan"],arow) + + #make everything fill out to self.style.width, self.style.heigh, not exact, but pretty close... + w, h = sum(columnsizes), sum(rowsizes) + if w > 0 and w < self.style.width and len(columnsizes): + d = (self.style.width - w) + for n in xrange(0, len(columnsizes)): + v = columnsizes[n] + columnsizes[n] += v * d / w + if h > 0 and h < self.style.height and len(rowsizes): + d = (self.style.height - h) / len(rowsizes) + for n in xrange(0, len(rowsizes)): + v = rowsizes[n] + rowsizes[n] += v * d / h + + #set the widget's position by calculating their row/column x/y offset + cellpositions = [[[sum(columnsizes[0:cell]), sum(rowsizes[0:row])] for cell in xrange(self.getColumns())] for row in xrange(self.getRows())] + for row in xrange(self.getRows()): + for cell in xrange(self.getColumns()): + if self._rows[row][cell] and self._rows[row][cell] is not True: + x, y = cellpositions[row][cell] + w = sum(columnsizes[cell:cell+self._rows[row][cell]["colspan"]]) + h = sum(rowsizes[row:row+self._rows[row][cell]["rowspan"]]) + + widget = self._rows[row][cell]["widget"] + widget.rect.x = x + widget.rect.y = y + if 1 and (w,h) != (widget.rect.w,widget.rect.h): +# if h > 20: +# print widget.widget.__class__.__name__, (widget.rect.w,widget.rect.h),'=>',(w,h) + widget.rect.w, widget.rect.h = widget.resize(w, h) + + #print self._rows[row][cell]["widget"].rect + + #print columnsizes + #print sum(columnsizes) + #size = sum(columnsizes), sum(rowsizes); print size + + #return the tables final size + return sum(columnsizes),sum(rowsizes) + + +def _table_div(a,b,c): + v,r = a/b, a%b + if r != 0 and (c%b) self.style.width) or (self.style.height!=0 and w.rect.h > self.style.height): +# ww,hh = None,None +# if self.style.width: ww = self.style.width +# if self.style.height: hh = self.style.height +# w.rect.w,w.rect.h = w.resize(ww,hh) + + + #in the case that the widget is too big, we try to resize it + if (width != None and width < w.rect.w) or (height != None and height < w.rect.h): + w.rect.w,w.rect.h = w.resize(width,height) + + width = max(width,w.rect.w,self.style.width) #,self.style.cell_width) + height = max(height,w.rect.h,self.style.height) #,self.style.cell_height) + + dx = width-w.rect.w + dy = height-w.rect.h + w.rect.x = (self.style.align+1)*dx/2 + w.rect.y = (self.style.valign+1)*dy/2 + + return width,height diff --git a/src/pgu/gui/textarea.py b/src/pgu/gui/textarea.py new file mode 100644 index 0000000..667076a --- /dev/null +++ b/src/pgu/gui/textarea.py @@ -0,0 +1,287 @@ +""" +""" +import pygame +from pygame.locals import * + +from const import * +import widget + +class TextArea(widget.Widget): + """A multi-line text input. + +
TextArea(value="",width = 120, height = 30, size=20)
+ +
+
value
initial text +
size
size for the text box, in characters +
+ + Example + + w = TextArea(value="Cuzco the Goat",size=20) + + w = TextArea("Marbles") + + w = TextArea("Groucho\nHarpo\nChico\nGummo\nZeppo\n\nMarx", 200, 400, 12) + + + """ + def __init__(self,value="",width = 120, height = 30, size=20,**params): + params.setdefault('cls','input') + params.setdefault('width', width) + params.setdefault('height', height) + + widget.Widget.__init__(self,**params) + self.value = value # The value of the TextArea + self.pos = len(str(value)) # The position of the cursor + self.vscroll = 0 # The number of lines that the TextArea is currently scrolled + self.font = self.style.font # The font used for rendering the text + self.cursor_w = 2 # Cursor width (NOTE: should be in a style) + w,h = self.font.size("e"*size) + if not self.style.height: self.style.height = h + if not self.style.width: self.style.width = w + + def resize(self,width=None,height=None): + if (width != None) and (height != None): + self.rect = pygame.Rect(self.rect.x, self.rect.y, width, height) + return self.rect.w, self.rect.h + + def paint(self,s): + + # TODO: What's up with this 20 magic number? It's the margin of the left and right sides, but I'm not sure how this should be gotten other than by trial and error. + max_line_w = self.rect.w - 20 + + # Update the line allocation for the box's value + self.doLines(max_line_w) + + # Make sure that the vpos and hpos of the cursor is set properly + self.updateCursorPos() + + # Make sure that we're scrolled vertically such that the cursor is visible + if (self.vscroll < 0): + self.vscroll = 0 + if (self.vpos < self.vscroll): + self.vscroll = self.vpos + elif ((self.vpos - self.vscroll + 1) * self.line_h > self.rect.h): + self.vscroll = - (self.rect.h / self.line_h - self.vpos - 1) + + # Blit each of the lines in turn + cnt = 0 + for line in self.lines: + line_pos = (0, (cnt - self.vscroll) * self.line_h) + if (line_pos[1] >= 0) and (line_pos[1] < self.rect.h): + s.blit( self.font.render(line, 1, self.style.color), line_pos ) + cnt += 1 + + # If the textarea is focused, then also show the cursor + if self.container.myfocus is self: + r = self.getCursorRect() + s.fill(self.style.color,r) + + # This function updates self.vpos and self.hpos based on self.pos + def updateCursorPos(self): + self.vpos = 0 # Reset the current line that the cursor is on + self.hpos = 0 + + line_cnt = 0 + char_cnt = 0 + + for line in self.lines: + line_char_start = char_cnt # The number of characters at the start of the line + + # Keep track of the character count for words + char_cnt += len(line) + + # If our cursor count is still less than the cursor position, then we can update our cursor line to assume that it's at least on this line + if (char_cnt > self.pos): + self.vpos = line_cnt + self.hpos = self.pos - line_char_start + + break # Now that we know where our cursor is, we exit the loop + + line_cnt += 1 + + if (char_cnt <= self.pos) and (len(self.lines) > 0): + self.vpos = len(self.lines) - 1 + self.hpos = len(self.lines[ self.vpos ] ) + + # Returns a rectangle that is of the size and position of where the cursor is drawn + def getCursorRect(self): + lw = 0 + if (len(self.lines) > 0): + lw, lh = self.font.size( self.lines[ self.vpos ][ 0:self.hpos ] ) + + r = pygame.Rect(lw, (self.vpos - self.vscroll) * self.line_h, self.cursor_w, self.line_h) + return r + + # This function sets the cursor position according to an x/y value (such as by from a mouse click) + def setCursorByXY(self, (x, y)): + self.vpos = ((int) (y / self.line_h)) + self.vscroll + if (self.vpos >= len(self.lines)): + self.vpos = len(self.lines) - 1 + + currentLine = self.lines[ self.vpos ] + + for cnt in range(0, len(currentLine) ): + self.hpos = cnt + lw, lh = self.font.size( currentLine[ 0:self.hpos + 1 ] ) + if (lw > x): + break + + lw, lh = self.font.size( currentLine ) + if (lw < x): + self.hpos = len(currentLine) + + self.setCursorByHVPos() + + # This function sets the cursor position by the horizontal/vertical cursor position. + def setCursorByHVPos(self): + line_cnt = 0 + char_cnt = 0 + + for line in self.lines: + line_char_start = char_cnt # The number of characters at the start of the line + + # Keep track of the character count for words + char_cnt += len(line) + + # If we're on the proper line + if (line_cnt == self.vpos): + # Make sure that we're not trying to go over the edge of the current line + if ( self.hpos >= len(line) ): + self.hpos = len(line) - 1 + # Set the cursor position + self.pos = line_char_start + self.hpos + break # Now that we've set our cursor position, we exit the loop + + line_cnt += 1 + + # Splits up the text found in the control's value, and assigns it into the lines array + def doLines(self, max_line_w): + self.line_h = 10 + self.lines = [] # Create an empty starter list to start things out. + + inx = 0 + line_start = 0 + while inx >= 0: + # Find the next breakable whitespace + # HACK: Find a better way to do this to include tabs and system characters and whatnot. + prev_word_start = inx # Store the previous whitespace + spc_inx = self.value.find(' ', inx+1) + nl_inx = self.value.find('\n', inx+1) + + if (min(spc_inx, nl_inx) == -1): + inx = max(spc_inx, nl_inx) + else: + inx = min(spc_inx, nl_inx) + + # Measure the current line + lw, self.line_h = self.font.size( self.value[ line_start : inx ] ) + + # If we exceeded the max line width, then create a new line + if (lw > max_line_w): + #Fall back to the previous word start + self.lines.append(self.value[ line_start : prev_word_start + 1 ]) + line_start = prev_word_start + 1 + # TODO: Check for extra-long words here that exceed the length of a line, to wrap mid-word + + # If we reached the end of our text + if (inx < 0): + # Then make sure we added the last of the line + if (line_start < len( self.value ) ): + self.lines.append( self.value[ line_start : len( self.value ) ] ) + # If we reached a hard line break + elif (self.value[inx] == "\n"): + # Then make a line break here as well. + newline = self.value[ line_start : inx + 1 ] + newline = newline.replace("\n", " ") # HACK: We know we have a newline character, which doesn't print nicely, so make it into a space. Comment this out to see what I mean. + self.lines.append( newline ) + + line_start = inx + 1 + else: + # Otherwise, we just continue progressing to the next space + pass + + def _setvalue(self,v): + self.__dict__['value'] = v + self.send(CHANGE) + + def event(self,e): + used = None + if e.type == KEYDOWN: + if e.key == K_BACKSPACE: + if self.pos: + self._setvalue(self.value[:self.pos-1] + self.value[self.pos:]) + self.pos -= 1 + elif e.key == K_DELETE: + if len(self.value) > self.pos: + self._setvalue(self.value[:self.pos] + self.value[self.pos+1:]) + elif e.key == K_HOME: + # Find the previous newline + newPos = self.value.rfind('\n', 0, self.pos) + if (newPos >= 0): + self.pos = newPos + elif e.key == K_END: + # Find the previous newline + newPos = self.value.find('\n', self.pos, len(self.value) ) + if (newPos >= 0): + self.pos = newPos + elif e.key == K_LEFT: + if self.pos > 0: self.pos -= 1 + used = True + elif e.key == K_RIGHT: + if self.pos < len(self.value): self.pos += 1 + used = True + elif e.key == K_UP: + self.vpos -= 1 + self.setCursorByHVPos() + elif e.key == K_DOWN: + self.vpos += 1 + self.setCursorByHVPos() + # The following return/tab keys are standard for PGU widgets, but I took them out here to facilitate multi-line text editing +# elif e.key == K_RETURN: +# self.next() +# elif e.key == K_TAB: +# pass + else: + #c = str(e.unicode) + try: + if (e.key == K_RETURN): + c = "\n" + elif (e.key == K_TAB): + c = " " + else: + c = (e.unicode).encode('latin-1') + if c: + self._setvalue(self.value[:self.pos] + c + self.value[self.pos:]) + self.pos += len(c) + except: #ignore weird characters + pass + self.repaint() + elif e.type == MOUSEBUTTONDOWN: + self.setCursorByXY(e.pos) + self.repaint() + + elif e.type == FOCUS: + self.repaint() + elif e.type == BLUR: + self.repaint() + + self.pcls = "" + if self.container.myfocus is self: self.pcls = "focus" + + return used + + def __setattr__(self,k,v): + if k == 'value': + if v == None: v = '' + v = str(v) + self.pos = len(v) + _v = self.__dict__.get(k,NOATTR) + self.__dict__[k]=v + if k == 'value' and _v != NOATTR and _v != v: + self.send(CHANGE) + self.repaint() + +# The first version of this code was done by Clint Herron, and is a modified version of input.py (by Phil Hassey). +# It is under the same license as the rest of the PGU library. \ No newline at end of file diff --git a/src/pgu/gui/theme.py b/src/pgu/gui/theme.py new file mode 100644 index 0000000..283c287 --- /dev/null +++ b/src/pgu/gui/theme.py @@ -0,0 +1,485 @@ +# theme.py + +""" +""" +import os, re +import pygame + +from const import * +import widget +import surface +from basic import parse_color, is_color + +__file__ = os.path.abspath(__file__) + +def _list_themes(dir): + d = {} + for entry in os.listdir(dir): + if os.path.exists(os.path.join(dir, entry, 'config.txt')): + d[entry] = os.path.join(dir, entry) + return d + +class Theme: + """Theme interface. + +

If you wish to create your own theme, create a class with this interface, and + pass it to gui.App via gui.App(theme=MyTheme()).

+ + Default Theme + +
Theme(dirs='default')
+
+
dirs
Name of the theme dir to load a theme from. May be an absolute path to a theme, if pgu is not installed, or if you created your own theme. May include several dirs in a list if data is spread across several themes. +
+ + Example + + + theme = gui.Theme("default") + theme = gui.Theme(["mytheme","mytheme2"]) + + """ + def __init__(self,dirs='default'): + self.config = {} + self.dict = {} + self._loaded = [] + self.cache = {} + self._preload(dirs) + pygame.font.init() + + def _preload(self,ds): + if not isinstance(ds, list): + ds = [ds] + for d in ds: + if d not in self._loaded: + self._load(d) + self._loaded.append(d) + + def _load(self, name): + #theme_dir = themes[name] + + #try to load the local dir, or absolute path + dnames = [name] + + #if the package isn't installed and people are just + #trying out the scripts or examples + dnames.append(os.path.join(os.path.dirname(__file__),"..","..","data","themes",name)) + + #if the package is installed, and the package is installed + #in /usr/lib/python2.3/site-packages/pgu/ + #or c:\python23\lib\site-packages\pgu\ + #the data is in ... lib/../share/ ... + dnames.append(os.path.join(os.path.dirname(__file__),"..","..","..","..","share","pgu","themes",name)) + dnames.append(os.path.join(os.path.dirname(__file__),"..","..","..","..","..","share","pgu","themes",name)) + dnames.append(os.path.join(os.path.dirname(__file__),"..","..","share","pgu","themes",name)) + for dname in dnames: + if os.path.isdir(dname): break + if not os.path.isdir(dname): + raise 'could not find theme '+name + + fname = os.path.join(dname,"config.txt") + if os.path.isfile(fname): + try: + f = open(fname) + for line in f.readlines(): + vals = line.strip().split() + if len(vals) < 3: continue + cls = vals[0] + del vals[0] + pcls = "" + if cls.find(":")>=0: + cls,pcls = cls.split(":") + attr = vals[0] + del vals[0] + self.config[cls+":"+pcls+" "+attr] = (dname, vals) + finally: + f.close() + fname = os.path.join(dname,"style.ini") + if os.path.isfile(fname): + import ConfigParser + cfg = ConfigParser.ConfigParser() + f = open(fname,'r') + cfg.readfp(f) + for section in cfg.sections(): + cls = section + pcls = '' + if cls.find(":")>=0: + cls,pcls = cls.split(":") + for attr in cfg.options(section): + vals = cfg.get(section,attr).strip().split() + self.config[cls+':'+pcls+' '+attr] = (dname,vals) + + is_image = re.compile('\.(gif|jpg|bmp|png|tga)$', re.I) + def _get(self,key): + if not key in self.config: return + if key in self.dict: return self.dict[key] + dvals = self.config[key] + dname, vals = dvals + #theme_dir = themes[name] + v0 = vals[0] + if v0[0] == '#': + v = parse_color(v0) + #if (len(v0) == 7): + # # Due to a bug in pygame 1.8 (?) we need to explicitly + # # specify the alpha value (otherwise it defaults to zero) + # v0 += "FF" + #v = pygame.color.Color(v0) + elif v0.endswith(".ttf") or v0.endswith(".TTF"): + v = pygame.font.Font(os.path.join(dname, v0),int(vals[1])) + elif self.is_image.search(v0) is not None: + v = pygame.image.load(os.path.join(dname, v0)) + else: + try: v = int(v0) + except: v = pygame.font.SysFont(v0, int(vals[1])) + self.dict[key] = v + return v + + def get(self,cls,pcls,attr): + """Interface method -- get the value of a style attribute. + +
Theme.get(cls,pcls,attr): return value
+ +
+
cls
class, for example "checkbox", "button", etc. +
pcls
pseudo class, for example "hover", "down", etc. +
attr
attribute, for example "image", "background", "font", "color", etc. +
+ +

returns the value of the attribute.

+ +

This method is called from [[gui-style]].

+ """ + + if not self._loaded: self._preload("default") + + o = cls+":"+pcls+" "+attr + + #if not hasattr(self,'_count'): + # self._count = {} + #if o not in self._count: self._count[o] = 0 + #self._count[o] += 1 + + if o in self.cache: + return self.cache[o] + + v = self._get(cls+":"+pcls+" "+attr) + if v: + self.cache[o] = v + return v + + pcls = "" + v = self._get(cls+":"+pcls+" "+attr) + if v: + self.cache[o] = v + return v + + cls = "default" + v = self._get(cls+":"+pcls+" "+attr) + if v: + self.cache[o] = v + return v + + v = 0 + self.cache[o] = v + return v + + def box(self,w,s): + style = w.style + + c = (0,0,0) + if style.border_color != 0: c = style.border_color + w,h = s.get_width(),s.get_height() + + s.fill(c,(0,0,w,style.border_top)) + s.fill(c,(0,h-style.border_bottom,w,style.border_bottom)) + s.fill(c,(0,0,style.border_left,h)) + s.fill(c,(w-style.border_right,0,style.border_right,h)) + + + def getspacing(self,w): + # return the top, right, bottom, left spacing around the widget + if not hasattr(w,'_spacing'): #HACK: assume spacing doesn't change re pcls + s = w.style + xt = s.margin_top+s.border_top+s.padding_top + xr = s.padding_right+s.border_right+s.margin_right + xb = s.padding_bottom+s.border_bottom+s.margin_bottom + xl = s.margin_left+s.border_left+s.padding_left + w._spacing = xt,xr,xb,xl + return w._spacing + + + def resize(self,w,m): + # Returns the rectangle expanded in each direction + def expand_rect(rect, left, top, right, bottom): + return pygame.Rect(rect.x - left, + rect.y - top, + rect.w + left + right, + rect.h + top + bottom) + + def func(width=None,height=None): + s = w.style + + pt,pr,pb,pl = s.padding_top,s.padding_right,s.padding_bottom,s.padding_left + bt,br,bb,bl = s.border_top,s.border_right,s.border_bottom,s.border_left + mt,mr,mb,ml = s.margin_top,s.margin_right,s.margin_bottom,s.margin_left + # Calculate the total space on each side + top = pt+bt+mt + right = pr+br+mr + bottom = pb+bb+mb + left = pl+bl+ml + ttw = left+right + tth = top+bottom + + ww,hh = None,None + if width != None: ww = width-ttw + if height != None: hh = height-tth + ww,hh = m(ww,hh) + + if width == None: width = ww + if height == None: height = hh + + #if the widget hasn't respected the style.width, + #style height, we'll add in the space for it... + width = max(width-ttw, ww, w.style.width) + height = max(height-tth, hh, w.style.height) + + #width = max(ww,w.style.width-tw) + #height = max(hh,w.style.height-th) + + r = pygame.Rect(left,top,width,height) + + w._rect_padding = expand_rect(r, pl, pt, pr, pb) + w._rect_border = expand_rect(w._rect_padding, bl, bt, br, bb) + w._rect_margin = expand_rect(w._rect_border, ml, mt, mr, mb) + + #w._rect_padding = pygame.Rect(r.x-pl,r.y-pt,r.w+pl+pr,r.h+pt+pb) + #r = w._rect_padding + #w._rect_border = pygame.Rect(r.x-bl,r.y-bt,r.w+bl+br,r.h+bt+bb) + #r = w._rect_border + #w._rect_margin = pygame.Rect(r.x-ml,r.y-mt,r.w+ml+mr,r.h+mt+mb) + + # align it within it's zone of power. + rect = pygame.Rect(left, top, ww, hh) + dx = width-rect.w + dy = height-rect.h + rect.x += (w.style.align+1)*dx/2 + rect.y += (w.style.valign+1)*dy/2 + + w._rect_content = rect + + return (w._rect_margin.w, w._rect_margin.h) + return func + + + def paint(self,w,m): + def func(s): +# if w.disabled: +# if not hasattr(w,'_disabled_bkgr'): +# w._disabled_bkgr = s.convert() +# orig = s +# s = w._disabled_bkgr.convert() + +# if not hasattr(w,'_theme_paint_bkgr'): +# w._theme_paint_bkgr = s.convert() +# else: +# s.blit(w._theme_paint_bkgr,(0,0)) +# +# if w.disabled: +# orig = s +# s = w._theme_paint_bkgr.convert() + + if w.disabled: + if (not (hasattr(w,'_theme_bkgr') and + w._theme_bkgr.get_width() == s.get_width() and + w._theme_bkgr.get_height() == s.get_height())): + w._theme_bkgr = s.copy() + orig = s + s = w._theme_bkgr + s.fill((0,0,0,0)) + s.blit(orig,(0,0)) + + if hasattr(w,'background'): + w.background.paint(surface.subsurface(s,w._rect_border)) + self.box(w,surface.subsurface(s,w._rect_border)) + r = m(surface.subsurface(s,w._rect_content)) + + if w.disabled: + s.set_alpha(128) + orig.blit(s,(0,0)) + +# if w.disabled: +# orig.blit(w._disabled_bkgr,(0,0)) +# s.set_alpha(128) +# orig.blit(s,(0,0)) + + w._painted = True + return r + return func + + def event(self,w,m): + def func(e): + rect = w._rect_content + if e.type == MOUSEBUTTONUP or e.type == MOUSEBUTTONDOWN: + sub = pygame.event.Event(e.type,{ + 'button':e.button, + 'pos':(e.pos[0]-rect.x,e.pos[1]-rect.y)}) + elif e.type == CLICK: + sub = pygame.event.Event(e.type,{ + 'button':e.button, + 'pos':(e.pos[0]-rect.x,e.pos[1]-rect.y)}) + elif e.type == MOUSEMOTION: + sub = pygame.event.Event(e.type,{ + 'buttons':e.buttons, + 'pos':(e.pos[0]-rect.x,e.pos[1]-rect.y), + 'rel':e.rel}) + else: + sub = e + r = m(sub) + return r + return func + + def update(self,w,m): + def func(s): + if w.disabled: return [] + r = m(surface.subsurface(s,w._rect_content)) + if type(r) == list: + dx,dy = w._rect_content.topleft + for rr in r: + rr.x,rr.y = rr.x+dx,rr.y+dy + return r + return func + + def open(self,w,m): + def func(widget=None,x=None,y=None): + if not hasattr(w,'_rect_content'): w.rect.w,w.rect.h = w.resize() #HACK: so that container.open won't resize again! + rect = w._rect_content + ##print w.__class__.__name__, rect + if x != None: x += rect.x + if y != None: y += rect.y + return m(widget,x,y) + return func + + #def open(self,w,m): + # def func(widget=None): + # return m(widget) + # return func + + def decorate(self,widget,level): + """Interface method -- decorate a widget. + +

The theme system is given the opportunity to decorate a widget methods at the + end of the Widget initializer.

+ +
Theme.decorate(widget,level)
+ +
+
widget
the widget to be decorated +
level
the amount of decoration to do, False for none, True for normal amount, 'app' for special treatment of App objects. +
+ """ + + w = widget + if level == False: return + + if type(w.style.background) != int: + w.background = Background(w,self) + + if level == 'app': return + + for k,v in w.style.__dict__.items(): + if k in ('border','margin','padding'): + for kk in ('top','bottom','left','right'): + setattr(w.style,'%s_%s'%(k,kk),v) + + w.paint = self.paint(w,w.paint) + w.event = self.event(w,w.event) + w.update = self.update(w,w.update) + w.resize = self.resize(w,w.resize) + w.open = self.open(w,w.open) + + def render(self,s,box,r): + """Interface method - render a special widget feature. + +
Theme.render(s,box,r)
+ +
+
s
pygame.Surface +
box
box data, a value returned from Theme.get, typically a pygame.Surface +
r
pygame.Rect with the size that the box data should be rendered +
+ + """ + + if box == 0: return + + if is_color(box): + s.fill(box,r) + return + + x,y,w,h=r.x,r.y,r.w,r.h + ww,hh=box.get_width()/3,box.get_height()/3 + xx,yy=x+w,y+h + src = pygame.rect.Rect(0,0,ww,hh) + dest = pygame.rect.Rect(0,0,ww,hh) + + s.set_clip(pygame.Rect(x+ww,y+hh,w-ww*2,h-hh*2)) + src.x,src.y = ww,hh + for dest.y in xrange(y+hh,yy-hh,hh): + for dest.x in xrange(x+ww,xx-ww,ww): s.blit(box,dest,src) + + s.set_clip(pygame.Rect(x+ww,y,w-ww*3,hh)) + src.x,src.y,dest.y = ww,0,y + for dest.x in xrange(x+ww,xx-ww*2,ww): s.blit(box,dest,src) + dest.x = xx-ww*2 + s.set_clip(pygame.Rect(x+ww,y,w-ww*2,hh)) + s.blit(box,dest,src) + + s.set_clip(pygame.Rect(x+ww,yy-hh,w-ww*3,hh)) + src.x,src.y,dest.y = ww,hh*2,yy-hh + for dest.x in xrange(x+ww,xx-ww*2,ww): s.blit(box,dest,src) + dest.x = xx-ww*2 + s.set_clip(pygame.Rect(x+ww,yy-hh,w-ww*2,hh)) + s.blit(box,dest,src) + + s.set_clip(pygame.Rect(x,y+hh,xx,h-hh*3)) + src.y,src.x,dest.x = hh,0,x + for dest.y in xrange(y+hh,yy-hh*2,hh): s.blit(box,dest,src) + dest.y = yy-hh*2 + s.set_clip(pygame.Rect(x,y+hh,xx,h-hh*2)) + s.blit(box,dest,src) + + s.set_clip(pygame.Rect(xx-ww,y+hh,xx,h-hh*3)) + src.y,src.x,dest.x=hh,ww*2,xx-ww + for dest.y in xrange(y+hh,yy-hh*2,hh): s.blit(box,dest,src) + dest.y = yy-hh*2 + s.set_clip(pygame.Rect(xx-ww,y+hh,xx,h-hh*2)) + s.blit(box,dest,src) + + s.set_clip() + src.x,src.y,dest.x,dest.y = 0,0,x,y + s.blit(box,dest,src) + + src.x,src.y,dest.x,dest.y = ww*2,0,xx-ww,y + s.blit(box,dest,src) + + src.x,src.y,dest.x,dest.y = 0,hh*2,x,yy-hh + s.blit(box,dest,src) + + src.x,src.y,dest.x,dest.y = ww*2,hh*2,xx-ww,yy-hh + s.blit(box,dest,src) + + +class Background(widget.Widget): + def __init__(self,value,theme,**params): + params['decorate'] = False + widget.Widget.__init__(self,**params) + self.value = value + self.theme = theme + + def paint(self,s): + r = pygame.Rect(0,0,s.get_width(),s.get_height()) + v = self.value.style.background + if is_color(v): + s.fill(v) + else: + self.theme.render(s,v,r) diff --git a/src/pgu/gui/widget.py b/src/pgu/gui/widget.py new file mode 100644 index 0000000..f0f4b13 --- /dev/null +++ b/src/pgu/gui/widget.py @@ -0,0 +1,377 @@ +""" +""" +import pygame + +import pguglobals +import style + +class SignalCallback: + # The function to call + func = None + # The parameters to pass to the function (as a list) + params = None + +class Widget: + """Template object - base for all widgets. + +
Widget(**params)
+ +

A number of optional params may be passed to the Widget initializer.

+ +
+
decorate
defaults to True. If true, will call theme.decorate(self) to allow the theme a chance to decorate the widget. +
style
a dict of style parameters. +
x, y, width, height
position and size parameters, passed along to style +
align, valign
alignment parameters, passed along to style +
font, color, background
other common parameters that are passed along to style +
cls
class name as used by Theme +
name
name of widget as used by Form. If set, will call form.add(self,name) to add the widget to the most recently created Form. +
focusable
True if this widget can receive focus via Tab, etc. Defaults to True. +
disabled
True of this widget is disabled. Defaults to False. +
value
initial value +
+ + Example - Creating your own Widget +

This example shows which methods are template methods.

+ + class Draw(gui.Widget): + def paint(self,s): + #paint the pygame.Surface + return + + def update(self,s): + #update the pygame.Surface and return the update rects + return [pygame.Rect(0,0,self.rect.w,self.rect.h)] + + def event(self,e): + #handle the pygame.Event + return + + def resize(self,width=None,height=None): + #return the width and height of this widget + return 256,256 + + """ + + # The name of the widget (or None if not defined) + name = None + + def __init__(self,**params): + #object.Object.__init__(self) + self.connects = {} + params.setdefault('decorate',True) + params.setdefault('style',{}) + params.setdefault('focusable',True) + params.setdefault('disabled',False) + + self.focusable = params['focusable'] + self.disabled = params['disabled'] + + self.rect = pygame.Rect(params.get('x',0),params.get('y',0),params.get('width',0),params.get('height',0)) + + s = params['style'] + #some of this is a bit "theme-ish" but it is very handy, so these + #things don't have to be put directly into the style. + for att in ('align','valign','x','y','width','height','color','font','background'): + if att in params: s[att] = params[att] + self.style = style.Style(self,s) + + self.cls = 'default' + if 'cls' in params: self.cls = params['cls'] + if 'name' in params: + import form + self.name = params['name'] + if hasattr(form.Form,'form') and form.Form.form != None: + form.Form.form.add(self) + self.form = form.Form.form + if 'value' in params: self.value = params['value'] + self.pcls = "" + + if params['decorate'] != False: + if (not pguglobals.app): + # TODO - fix this somehow + import app + print 'gui.widget: creating an App' + app.App() + pguglobals.app.theme.decorate(self,params['decorate']) + + def focus(self): + """Focus this Widget. + +
Widget.focus()
+ """ + if getattr(self,'container',None) != None: + if self.container.myfocus != self: ## by Gal Koren + self.container.focus(self) + + def blur(self): + """Blur this Widget. + +
Widget.blur()
+ """ + if getattr(self,'container',None) != None: self.container.blur(self) + + def open(self): + """Open this Widget as a modal dialog. + +
Widget.open()
+ """ + #if getattr(self,'container',None) != None: self.container.open(self) + pguglobals.app.open(self) + + def close(self, w=None): + """Close this Widget (if it is a modal dialog.) + +
Widget.close()
+ """ + #if getattr(self,'container',None) != None: self.container.close(self) + if (not w): + w = self + pguglobals.app.close(w) + + def resize(self,width=None,height=None): + """Template method - return the size and width of this widget. + +

Responsible for also resizing all sub-widgets.

+ +
Widget.resize(width,height): return width,height
+ +
+
width
suggested width +
height
suggested height +
+ +

If not overridden, will return self.style.width, self.style.height

+ """ + return self.style.width, self.style.height + + def chsize(self): + """Change the size of this widget. + +

Calling this method will cause a resize on all the widgets, + including this one.

+ +
Widget.chsize()
+ """ + + if not hasattr(self,'_painted'): return + + if not hasattr(self,'container'): return + + if pguglobals.app: + if pguglobals.app._chsize: + return + pguglobals.app.chsize() + return + + #if hasattr(app.App,'app'): + # w,h = self.rect.w,self.rect.h + # w2,h2 = self.resize() + # if w2 != w or h2 != h: + # app.App.app.chsize() + # else: + # self.repaint() + + + def update(self,s): + """Template method - update the surface + +
Widget.update(s): return list of pygame.Rect(s)
+ +
+
s
pygame.Surface to update +
+ +

return - a list of the updated areas as pygame.Rect(s).

+ """ + return + + def paint(self,s): + """Template method - paint the surface + +
Widget.paint(s)
+ +
+
s
pygame.Surface to paint +
+ """ + return + + def repaint(self): + """Request a repaint of this Widget. + +
Widget.repaint()
+ """ + if getattr(self,'container',None) != None: self.container.repaint(self) + def repaintall(self): + """Request a repaint of all Widgets. + +
Widget.repaintall()
+ """ + if getattr(self,'container',None) != None: self.container.repaintall() + def reupdate(self): + """Request a reupdate of this Widget + +
Widget.reupdate()
+ """ + if getattr(self,'container',None) != None: self.container.reupdate(self) + def next(self): + """Pass focus to next Widget. + +

Widget order determined by the order they were added to their container.

+ +
Widget.next()
+ """ + if getattr(self,'container',None) != None: self.container.next(self) + def previous(self): + """Pass focus to previous Widget. + +

Widget order determined by the order they were added to their container.

+ +
Widget.previous()
+ """ + + if getattr(self,'container',None) != None: self.container.previous(self) + + def get_abs_rect(self): + """Get the absolute rect of this widget on the App screen + +
Widget.get_abs_rect(): return pygame.Rect
+ """ + x, y = self.rect.x, self.rect.y + x += self._rect_content.x + y += self._rect_content.y + c = getattr(self,'container',None) + while c: + x += c.rect.x + y += c.rect.y + if hasattr(c,'_rect_content'): + x += c._rect_content.x + y += c._rect_content.y + c = getattr(c,'container',None) + return pygame.Rect(x, y, self.rect.w, self.rect.h) + + def connect(self,code,func,*params): + """Connect a event code to a callback function. + +

There may be multiple callbacks per event code.

+ +
Object.connect(code,fnc,value)
+ +
+
code
event type [[gui-const]] +
fnc
callback function +
*values
values to pass to callback. Please note that callbacks may also have "magicaly" parameters. Such as: +
+
_event
receive the event +
_code
receive the event code +
_widget
receive the sending widget +
+
+ + Example + + def onclick(value): + print 'click',value + + w = Button("PGU!") + w.connect(gui.CLICK,onclick,'PGU Button Clicked') + + """ + if (not code in self.connects): + self.connects[code] = [] + for cb in self.connects[code]: + if (cb.func == func): + # Already connected to this callback function + return + # Wrap the callback function and add it to the list + cb = SignalCallback() + cb.func = func + cb.params = params + self.connects[code].append(cb) + + # Remove signal handlers from the given event code. If func is specified, + # only those handlers will be removed. If func is None, all handlers + # will be removed. + def disconnect(self, code, func=None): + if (not code in self.connects): + return + if (not func): + # Remove all signal handlers + del self.connects[code] + else: + # Remove handlers that call 'func' + n = 0 + callbacks = self.connects[code] + while (n < len(callbacks)): + if (callbacks[n].func == func): + # Remove this callback + del callbacks[n] + else: + n += 1 + + def send(self,code,event=None): + """Send a code, event callback trigger. + +
Object.send(code,event=None)
+ +
+
code
event code +
event
event +
+ """ + if (not code in self.connects): + return + # Trigger all connected signal handlers + for cb in self.connects[code]: + func = cb.func + values = list(cb.params) + + nargs = func.func_code.co_argcount + names = list(func.func_code.co_varnames)[:nargs] + if hasattr(func,'im_class'): names.pop(0) + + args = [] + magic = {'_event':event,'_code':code,'_widget':self} + for name in names: + if name in magic.keys(): + args.append(magic[name]) + elif len(values): + args.append(values.pop(0)) + else: + break + args.extend(values) + func(*args) + + def _event(self,e): + if self.disabled: return + self.send(e.type,e) + return self.event(e) +# return +# import app +# if hasattr(app.App,'app'): +# app.App.app.events.append((self,e)) + + def event(self,e): + """Template method - called when an event is passed to this object. + +

Please note that if you use an event, returning the value True + will stop parent containers from also using the event. (For example, if + your widget handles TABs or arrow keys, and you don't want those to + also alter the focus.)

+ +
+
e
event +
+ """ + + return + + # Returns the top-level widget (usually the Desktop) by following the + # chain of 'container' references. + def get_toplevel(self): + top = self + while (getattr(top, "container", None)): + top = top.container + return top + diff --git a/src/pgu/hexvid.py b/src/pgu/hexvid.py new file mode 100644 index 0000000..2d4156d --- /dev/null +++ b/src/pgu/hexvid.py @@ -0,0 +1,127 @@ +"""Hexagonal tile engine. + +

Note -- this engine is not finished. Sprites are not supported. It +can still be useful for using the level editor, and for rendering hex +terrains, however. If you are able to update it and use it in a real game, +help would be greatly appreciated!

+ +

please note that this file is alpha, and is subject to modification in +future versions of pgu!

+ +""" +print 'pgu.hexvid','This module is alpha, and is subject to change.' + +from pgu.vid import * +import pygame + + +class Hexvid(Vid): + """Create an hex vid engine. See [[vid]]""" + def update(self,screen): + return self.paint(screen) + + def paint(self,screen): + sw,sh = screen.get_width(),screen.get_height() + self.view.w,self.view.h = sw,sh + + tlayer = self.tlayer + blayer = self.blayer + #zlayer = self.zlayer + w,h = len(tlayer[0]),len(tlayer) + + #iso_w,iso_h,iso_z,tile_w,tile_h,base_w,base_h = self.iso_w,self.iso_h,self.iso_z,self.tile_w,self.tile_h,self.base_w,self.base_h + + tile_w,tile_h = self.tile_w,self.tile_h + tile_w2,tile_h2 = tile_w/2,tile_h/2 + + view = self.view + adj = self.adj = pygame.Rect(-self.view.x,-self.view.y,0,0) + + w,h = len(tlayer[0]),len(tlayer) + tiles = self.tiles + + #"" + if self.bounds == None: + tmp,y1 = self.tile_to_view((0,0)) + x1,tmp = self.tile_to_view((0,h+1)) + tmp,y2 = self.tile_to_view((w+1,h+1)) + x2,tmp = self.tile_to_view((w+1,0)) + self.bounds = pygame.Rect(x1,y1,x2-x1,y2-y1) + print self.bounds + #"" + + if self.bounds != None: self.view.clamp_ip(self.bounds) + + ox,oy = self.screen_to_tile((0,0)) + sx,sy = self.tile_to_view((ox,oy)) + dx,dy = sx - self.view.x,sy - self.view.y + + bot = 1 + + tile_wi = tile_w + tile_w/2 + tile_wi2 = tile_wi/2 + + #dx += tile_w/2 + + for i2 in xrange(-bot,self.view.h/tile_h2+bot*3): #NOTE: 3 seems a bit much, but it works. + tx,ty = ox + i2/2 + i2%2,oy + i2/2 + x,y = (i2%2)*tile_wi2 + dx,i2*tile_h2 + dy + + #to adjust for the -1 in i1 + x,tx,ty = x-tile_wi,tx-1,ty+1 + + x -= tile_w/2 + for i1 in xrange(-1,self.view.w/tile_wi+1): + if ty >= 0 and ty < h and tx >= 0 and tx < w: + if blayer != None: + n = blayer[ty][tx] + if n != 0: + t = tiles[n] + if t != None and t.image != None: + screen.blit(t.image,(x,y)) + n = tlayer[ty][tx] + if n != 0: + t = tiles[n] + if t != None and t.image != None: + screen.blit(t.image,(x,y)) + + + tx += 1 + ty -= 1 + x += tile_wi + + return [pygame.Rect(0,0,screen.get_width(),screen.get_height())] + + def view_to_tile(self,pos): + x,y = pos + #x = x + (self.tile_w*1/2) + + x,y = int(x*4/(self.tile_w*3)), y*2/self.tile_h + nx = (x + y) / 2 + ny = (y - x) / 2 + return nx,ny + + def tile_to_view(self,pos): + x,y = pos + nx = x - y + ny = x + y + nx,ny = int(nx*(self.tile_w*3)/4), ny*self.tile_h/2 + + #nx = nx - (self.tile_w*1/2) + return nx,ny + + def screen_to_tile(self,pos): #NOTE HACK : not sure if the 3/8 is right or not, but it is pretty close... + pos = pos[0]+self.view.x + self.tile_w*3/8,pos[1]+self.view.y + pos = self.view_to_tile(pos) + return pos + + def tile_to_screen(self,pos): + pos = self.tile_to_view(pos) + pos = pos[0]-self.view.x,pos[1]-self.view.y + return pos + + + def tga_load_tiles(self,fname,size,tdata={}): + Vid.tga_load_tiles(self,fname,size,tdata) + + self.tile_w,self.tile_h = size \ No newline at end of file diff --git a/src/pgu/high.py b/src/pgu/high.py new file mode 100644 index 0000000..e05d22a --- /dev/null +++ b/src/pgu/high.py @@ -0,0 +1,154 @@ +"""Classes for handling high score tables. +""" + +import os + +def High(fname,limit=10): + """Create a Highs object and returns the default high score table. + +
High(fname,limit=10)
+ +
+
fname
filename to store high scores in +
limit
limit of scores to be recorded, defaults to 10 +
+ """ + return Highs(fname,limit)['default'] + +class _Score: + def __init__(self,score,name,data=None): + self.score,self.name,self.data=score,name,data + +class _High: + """A high score table. These objects are passed to the user, but should not be created directly. + +

You can iterate them:

+ + for e in myhigh: + print e.score,e.name,e.data + + +

You can modify them:

+ + myhigh[0].name = 'Cuzco' + + +

You can find out their length:

+ + print len(myhigh) + + """ + + def __init__(self,highs,limit=10): + self.highs = highs + self._list = [] + self.limit = limit + + def save(self): + """Save the high scores. + +
_High.save()
+ """ + self.highs.save() + + def submit(self,score,name,data=None): + """Submit a high score to this table. + +
_High.submit(score,name,data=None)
+ +

return -- the position in the table that the score attained. None if the score did not attain a position in the table.

+ """ + n = 0 + for e in self._list: + if score > e.score: + self._list.insert(n,_Score(score,name,data)) + self._list = self._list[0:self.limit] + return n + n += 1 + if len(self._list) < self.limit: + self._list.append(_Score(score,name,data)) + return len(self._list)-1 + + def check(self,score): + """Check if a score will attain a position in the table. + +
_High.check(score)
+ +

return -- the position the score will attain, else None

+ """ + n = 0 + for e in self._list: + if score > e.score: + return n + n += 1 + if len(self._list) < self.limit: + return len(self._list) + + + def __iter__(self): + return self._list.__iter__() + + def __getitem__(self,key): + return self._list[key] + + def __len__(self): + return self._list.__len__() + + +class Highs: + """The high score object. + +
Highs(fname,limit=10)
+
    +
    fname
    filename to store high scores in +
    limit
    limit of scores to be recorded, defaults to 10 +
+ +

You may access _High objects through this object:

+ + + my_easy_hs = highs['easy'] + my_hard_hs = highs['hard'] + + + """ + def __init__(self,fname,limit=10): + self.fname = fname + self.limit = limit + self.load() + + def load(self): + """Re-load the high scores. + +
Highs.load()
+ """ + + self._dict = {} + try: + f = open(self.fname) + for line in f.readlines(): + key,score,name,data = line.strip().split("\t") + if key not in self._dict: + self._dict[key] = _High(self,self.limit) + high = self._dict[key] + high.submit(int(score),name,data) + f.close() + except: + pass + + def save(self): + """Save the high scores. + +
Highs.save()
+ """ + + f = open(self.fname,"w") + for key,high in self._dict.items(): + for e in high: + f.write("%s\t%d\t%s\t%s\n"%(key,e.score,e.name,str(e.data))) + f.close() + + def __getitem__(self,key): + if key not in self._dict: + self._dict[key] = _High(self,self.limit) + return self._dict[key] diff --git a/src/pgu/html.py b/src/pgu/html.py new file mode 100644 index 0000000..817c000 --- /dev/null +++ b/src/pgu/html.py @@ -0,0 +1,571 @@ +"""a html renderer +""" + +import sys +import htmllib +import re +import pygame +from pygame.locals import * + +from pgu import gui + +_amap = {'left':-1,'right':1,'center':0,None:None,'':None,} +_vamap = {'top':-1,'bottom':1,'center':0,'middle':0,None:None,'':None,} + +# Used by the HTML parser to load external resources (like images). This +# class loads content from the local file system. But you can pass your own +# resource loader to the HTML parser to find images by other means. +class ResourceLoader(object): + # Loads an image and returns it as a pygame image + def load_image(this, path): + return pygame.image.load(path) + +class _dummy: + pass + +class _flush: + def __init__(self): + self.style = _dummy() + self.style.font = None + self.style.color = None + self.cls = None + def add(self,w): pass + def space(self,v): pass + +class _hr(gui.Color): + def __init__(self,**params): + gui.Color.__init__(self,(0,0,0),**params) + def resize(self,width=None,height=None): + w,h = self.style.width,self.style.height + #if width != None: self.rect.w = width + #else: self.rect.w = 1 + + #xt,xr,xb,xl = self.getspacing() + + if width != None: w = max(w,width) + if height != None: h = max(h,height) + w = max(w,1) + h = max(h,1) + + return w,h #self.container.rect.w,h + + #self.rect.w = max(1,width,self.container.rect.w-(xl+xr)) + + #print self.rect + #self.rect.w = 1 + +class _html(htmllib.HTMLParser): + def init(self,doc,font,color,_globals,_locals,loader=None): + self.mystack = [] + self.document = doc + if (loader): + self.loader = loader + else: + # Use the default resource loader + self.loader = ResourceLoader() + self.myopen('document',self.document) + + self.myfont = self.font = font + self.mycolor = self.color = color + + self.form = None + + self._globals = _globals + self._locals = _locals + + def myopen(self,type_,w): + + self.mystack.append((type_,w)) + self.type,self.item = type_,w + + self.font = self.item.style.font + self.color = self.item.style.color + + if not self.font: self.font = self.myfont + if not self.color: self.color = self.mycolor + + def myclose(self,type_): + t = None + self.mydone() + while t != type_: + #if len(self.mystack)==0: return + t,w = self.mystack.pop() + t,w = self.mystack.pop() + self.myopen(t,w) + + def myback(self,type_): + if type(type_) == str: type_ = [type_,] + self.mydone() + #print 'myback',type_ + t = None + while t not in type_: + #if len(self.mystack)==0: return + t,w = self.mystack.pop() + self.myopen(t,w) + + def mydone(self): + #clearing out the last

+ if not hasattr(self.item,'layout'): return + if len(self.item.layout._widgets) == 0: return + w = self.item.layout._widgets[-1] + if type(w) == tuple: + del self.item.layout._widgets[-1] + + + def start_b(self,attrs): self.font.set_bold(1) + def end_b(self): self.font.set_bold(0) + def start_i(self,attrs): self.font.set_italic(1) + def end_i(self): self.font.set_italic(0) + def start_u(self,attrs): self.font.set_underline(1) + def end_u(self): self.font.set_underline(0) + def start_br(self,attrs): self.do_br(attrs) + def do_br(self,attrs): self.item.br(self.font.size(" ")[1]) + def attrs_to_map(self,attrs): + k = None + r = {} + for k,v in attrs: r[k] = v + return r + + def map_to_params(self,r): + anum = re.compile("\D") + + params = {'style':{}} + style = params['style'] + + if 'bgcolor' in r: + style['background'] = gui.parse_color(r['bgcolor']) + if 'background' in r: + style['background'] = self.loader.load_image(r['background']) + if 'border' in r: style['border'] = int(r['border']) + + for k in ['width','height','colspan','rowspan','size','min','max']: + if k in r: params[k] = int(anum.sub("",r[k])) + + for k in ['name','value']: + if k in r: params[k] = r[k] + + if 'class' in r: params['cls'] = r['class'] + + if 'align' in r: + params['align'] = _amap[r['align']] + if 'valign' in r: + params['valign'] = _vamap[r['valign']] + + if 'style' in r: + for st in r['style'].split(";"): + #print st + if ":" in st: + #print st.split(":") + k,v = st.split(":") + k = k.replace("-","_") + k = k.replace(" ","") + v = v.replace(" ","") + if k == 'color' or k == 'border_color' or k == 'background': + v = gui.parse_color(v) + else: + v = int(anum.sub("",v)) + style[k] = v + return params + + def map_to_connects(self,e,r): + for k,evt in [('onclick',gui.CLICK),('onchange',gui.CHANGE)]: #blah blah blah + + if k in r: + #print k,r[k] + e.connect(evt,self.myexec,(e,r[k])) + + def start_p(self,attrs): + r = self.attrs_to_map(attrs) + align = r.get("align","left") + + self.check_p() + self.item.block(_amap[align]) + + def check_p(self): + if len(self.item.layout._widgets) == 0: return + if type(self.item.layout._widgets[-1]) == tuple: + w,h = self.item.layout._widgets[-1] + if w == 0: return + self.do_br(None) + + def end_p(self): + #print 'end p' + self.check_p() + + + def start_block(self,t,attrs,align=-1): + r = self.attrs_to_map(attrs) + params = self.map_to_params(r) + if 'cls' in params: params['cls'] = t+"."+params['cls'] + else: params['cls'] = t + b = gui.Document(**params) + b.style.font = self.item.style.font + if 'align' in params: + align = params['align'] + self.item.block(align) + self.item.add(b) + self.myopen(t,b) + + + + def end_block(self,t): + self.myclose(t) + self.item.block(-1) + + def start_div(self,attrs): self.start_block('div',attrs) + def end_div(self): self.end_block('div') + def start_center(self,attrs): self.start_block('div',attrs,0) + def end_center(self): self.end_block('div') + + def start_h1(self,attrs): self.start_block('h1',attrs) + def end_h1(self): self.end_block('h1') + def start_h2(self,attrs): self.start_block('h2',attrs) + def end_h2(self): self.end_block('h2') + def start_h3(self,attrs): self.start_block('h3',attrs) + def end_h3(self): self.end_block('h3') + def start_h4(self,attrs): self.start_block('h4',attrs) + def end_h4(self): self.end_block('h4') + def start_h5(self,attrs): self.start_block('h5',attrs) + def end_h5(self): self.end_block('h5') + def start_h6(self,attrs): self.start_block('h6',attrs) + def end_h6(self): self.end_block('h6') + + def start_ul(self,attrs): self.start_block('ul',attrs) + def end_ul(self): self.end_block('ul') + def start_ol(self,attrs): + self.start_block('ol',attrs) + self.item.counter = 0 + def end_ol(self): self.end_block('ol') + def start_li(self,attrs): + self.myback(['ul','ol']) + cur = self.item + self.start_block('li',attrs) + if hasattr(cur,'counter'): + cur.counter += 1 + self.handle_data("%d. "%cur.counter) + else: + self.handle_data("- ") + #def end_li(self): self.end_block('li') #this isn't needed because of how the parser works + + def start_pre(self,attrs): self.start_block('pre',attrs) + def end_pre(self): self.end_block('pre') + def start_code(self,attrs): self.start_block('code',attrs) + def end_code(self): self.end_block('code') + + def start_table(self,attrs): + r = self.attrs_to_map(attrs) + params = self.map_to_params(r) + + align = r.get("align","left") + self.item.block(_amap[align]) + + t = gui.Table(**params) + self.item.add(t) + + self.myopen('table',t) + + def start_tr(self,attrs): + self.myback('table') + self.item.tr() + + def _start_td(self,t,attrs): + r = self.attrs_to_map(attrs) + params = self.map_to_params(r) + if 'cls' in params: params['cls'] = t+"."+params['cls'] + else: params['cls'] = t + b = gui.Document(cls=t) + + self.myback('table') + self.item.td(b,**params) + self.myopen(t,b) + + self.font = self.item.style.font + self.color = self.item.style.color + + def start_td(self,attrs): + self._start_td('td',attrs) + + def start_th(self,attrs): + self._start_td('th',attrs) + + def end_table(self): + self.myclose('table') + self.item.block(-1) + + def start_form(self,attrs): + r = self.attrs_to_map(attrs) + e = self.form = gui.Form() + e.groups = {} + + self._locals[r.get('id',None)] = e + + def start_input(self,attrs): + r = self.attrs_to_map(attrs) + params = self.map_to_params(r) #why bother + #params = {} + + type_,name,value = r.get('type','text'),r.get('name',None),r.get('value',None) + f = self.form + if type_ == 'text': + e = gui.Input(**params) + self.map_to_connects(e,r) + self.item.add(e) + elif type_ == 'radio': + if name not in f.groups: + f.groups[name] = gui.Group(name=name) + g = f.groups[name] + del params['name'] + e = gui.Radio(group=g,**params) + self.map_to_connects(e,r) + self.item.add(e) + if 'checked' in r: g.value = value + elif type_ == 'checkbox': + if name not in f.groups: + f.groups[name] = gui.Group(name=name) + g = f.groups[name] + del params['name'] + e = gui.Checkbox(group=g,**params) + self.map_to_connects(e,r) + self.item.add(e) + if 'checked' in r: g.value = value + + elif type_ == 'button': + e = gui.Button(**params) + self.map_to_connects(e,r) + self.item.add(e) + elif type_ == 'submit': + e = gui.Button(**params) + self.map_to_connects(e,r) + self.item.add(e) + elif type_ == 'file': + e = gui.Input(**params) + self.map_to_connects(e,r) + self.item.add(e) + b = gui.Button(value='Browse...') + self.item.add(b) + def _browse(value): + d = gui.FileDialog(); + d.connect(gui.CHANGE,gui.action_setvalue,(d,e)) + d.open(); + b.connect(gui.CLICK,_browse,None) + + self._locals[r.get('id',None)] = e + + def start_object(self,attrs): + r = self.attrs_to_map(attrs) + params = self.map_to_params(r) + code = "e = %s(**params)"%r['type'] + #print code + #print params + exec(code) + #print e + #print e.style.width,e.style.height + self.map_to_connects(e,r) + self.item.add(e) + + self._locals[r.get('id',None)] = e + + def start_select(self,attrs): + r = self.attrs_to_map(attrs) + params = {} + + name,value = r.get('name',None),r.get('value',None) + e = gui.Select(name=name,value=value,**params) + self.map_to_connects(e,r) + self.item.add(e) + self.myopen('select',e) + + def start_option(self,attrs): + r = self.attrs_to_map(attrs) + params = {} #style = self.map_to_style(r) + + self.myback('select') + e = gui.Document(**params) + self.item.add(e,value=r.get('value',None)) + self.myopen('option',e) + + + def end_select(self): + self.myclose('select') + + def start_hr(self,attrs): + self.do_hr(attrs) + def do_hr(self,attrs): + h = self.font.size(" ")[1]/2 + + r = self.attrs_to_map(attrs) + params = self.map_to_params(r) + params['style']['padding'] = h + print params + + self.item.block(0) + self.item.add(_hr(**params)) + self.item.block(-1) + + def anchor_begin(self,href,name,type_): + pass + + def anchor_end(self): + pass + + def start_title(self,attrs): self.myopen('title',_flush()) + def end_title(self): self.myclose('title') + + def myexec(self,value): + w,code = value + g = self._globals + l = self._locals + l['self'] = w + exec(code,g,l) + + def handle_image(self,src,alt,ismap,align,width,height): + try: + w = gui.Image(self.loader.load_image(src)) + if align != '': + self.item.add(w,_amap[align]) + else: + self.item.add(w) + except: + print 'handle_image: missing %s'%src + + def handle_data(self,txt): + if self.type == 'table': return + elif self.type in ('pre','code'): + txt = txt.replace("\t"," ") + ss = txt.split("\n") + if ss[-1] == "": del ss[-1] + for sentence in ss: + img = self.font.render(sentence,1,self.color) + w = gui.Image(img) + self.item.add(w) + self.item.block(-1) + return + + txt = re.compile("^[\t\r\n]+").sub("",txt) + txt = re.compile("[\t\r\n]+$").sub("",txt) + + tst = re.compile("[\t\r\n]+").sub("",txt) + if tst == "": return + + txt = re.compile("\s+").sub(" ",txt) + if txt == "": return + + if txt == " ": + self.item.space(self.font.size(" ")) + return + + for word in txt.split(" "): + word = word.replace(chr(160)," ") #  + #print self.item.cls + w = gui.Image(self.font.render(word,1,self.color)) + self.item.add(w) + self.item.space(self.font.size(" ")) + + +class HTML(gui.Document): + """a gui HTML object + +
HTML(data,globals=None,locals=None)
+ +
+
data
html data +
globals
global variables (for scripting) +
locals
local variables (for scripting) +
loader
the resource loader +
+ +

you may access html elements that have an id via widget[id]

+ """ + def __init__(self,data,globals=None,locals=None,loader=None,**params): + gui.Document.__init__(self,**params) + # This ensures that the whole HTML document is left-aligned within + # the rendered surface. + self.style.align = -1 + + _globals,_locals = globals,locals + + if _globals == None: _globals = {} + if _locals == None: _locals = {} + self._globals = _globals + self._locals = _locals + + #font = gui.theme.get("label","","font") + p = _html(htmllib.AS_IS,0) + p.init(self,self.style.font,self.style.color,_globals,_locals, + loader=loader) + p.feed(data) + p.close() + p.mydone() + + + def __getitem__(self,k): + return self._locals[k] + + # Returns a box (pygame rectangle) surrounding all widgets in this document + def get_bounding_box(this): + minx = miny = sys.maxint + maxx = maxy = -sys.maxint + for e in this.layout.widgets: + minx = min(minx, e.rect.left) + miny = min(miny, e.rect.top) + maxx = max(maxx, e.rect.right+1) + maxy = max(maxy, e.rect.bottom+1) + return pygame.Rect(minx, miny, maxx-minx, maxy-miny) + + +def render_ext(font, rect, text, aa, color, bgcolor=(0,0,0,0), **params): + """Renders some html and returns the rendered surface, plus the + HTML instance that produced it. + """ + + htm = HTML(text, font=font, color=color, **params) + + if (rect == -1): + # Make the surface large enough to fit the rendered text + htm.resize(width=sys.maxint) + (width, height) = htm.get_bounding_box().size + # Now set the proper document width (computed from the bounding box) + htm.resize(width=width) + elif (type(rect) == int): + # Fix the width of the document, while the height is variable + width = rect + height = htm.resize(width=width)[1] + else: + # Otherwise the width and height of the document is fixed + (width, height) = rect.size + htm.resize(width=width) + + # Now construct a surface and paint to it + surf = pygame.Surface((width, height)).convert_alpha() + surf.fill(bgcolor) + htm.paint(surf) + return (surf, htm) + +def render(font, rect, text, aa, color, bgcolor=(0,0,0,0), **params): + """Renders some html + +
render(font,rect,text,aa,color,bgcolor=(0,0,0,0))
+ """ + return render_ext(font, rect, text, aa, color, bgcolor, **params)[0] + +def rendertrim(font,rect,text,aa,color,bgcolor=(0,0,0,0),**params): + """render html, and make sure to trim the size + + rendertrim(font,rect,text,aa,color,bgcolor=(0,0,0,0)) + """ + # Render the HTML + (surf, htm) = render_ext(font, rect, text, aa, color, bgcolor, **params) + return surf.subsurface(htm.get_bounding_box()) + + +def write(s,font,rect,text,aa=0,color=(0,0,0), **params): + """write html to a surface + + write(s,font,rect,text,aa=0,color=(0,0,0)) + """ + htm = HTML(text, font=font, color=color, **params) + htm.resize(width=rect.w) + s = s.subsurface(rect) + htm.paint(s) + +# vim: set filetype=python sts=4 sw=4 noet si : diff --git a/src/pgu/isovid.py b/src/pgu/isovid.py new file mode 100644 index 0000000..d5048ec --- /dev/null +++ b/src/pgu/isovid.py @@ -0,0 +1,182 @@ +"""Isometric tile engine. + +

Note -- this engine is not finished, any may not work for your +particular needs. If you are able to update it, help would be +greatly appreciated!

+ +

please note that this file is alpha, and is subject to modification in +future versions of pgu!

+ +""" +print 'pgu.isovid','This module is alpha, and is subject to change.' + +from pgu.vid import * +import pygame + +class Isovid(Vid): + """Create an iso vid engine. See [[vid]]""" + def update(self,screen): + return self.paint(screen) + + def paint(self,screen): + sw,sh = screen.get_width(),screen.get_height() + + tlayer = self.tlayer + blayer = self.blayer + zlayer = self.zlayer + w,h = len(tlayer[0]),len(tlayer) + + iso_w,iso_h,iso_z,tile_w,tile_h,base_w,base_h = self.iso_w,self.iso_h,self.iso_z,self.tile_w,self.tile_h,self.base_w,self.base_h + + base_h2 = base_h/2 + base_w2 = base_w/2 + + bot = tile_h/base_h2 + todo_max = sh/base_h2+bot + todo = [[] for y in xrange(0,todo_max)] + + self.view.w,self.view.h = sw,sh + view = self.view + adj = self.adj = pygame.Rect(-self.view.x,-self.view.y,0,0) + + for s in self.sprites: + self.sprite_calc_irect(s) + x,y = self.iso_to_view((s.rect.centerx,s.rect.centery)) + v = (y+adj.y)/base_h2 - 1 + if v >= 0 and v < todo_max: + todo[v].append((s.image,s.irect)) + #else: print 'doesnt fit',v + + w,h = len(tlayer[0]),len(tlayer) + tiles = self.tiles + + #"" + if self.bounds == None: + tmp,y1 = self.tile_to_view((0,0)) + x1,tmp = self.tile_to_view((0,h+1)) + tmp,y2 = self.tile_to_view((w+1,h+1)) + x2,tmp = self.tile_to_view((w+1,0)) + self.bounds = pygame.Rect(x1,y1,x2-x1,y2-y1) + #"" + + if self.bounds != None: self.view.clamp_ip(self.bounds) + + ox,oy = self.screen_to_tile((0,0)) + sx,sy = self.iso_to_view((ox*iso_w,oy*iso_h)) + dx,dy = sx - self.view.x,sy - self.view.y + + for i2 in xrange(-bot,self.view.h/base_h2+bot): + tx,ty = ox + i2/2 + i2%2,oy + i2/2 + x,y = (i2%2)*base_w2 + dx,i2*base_h2 + dy + + #to adjust for the -1 in i1 + x,tx,ty = x-base_w,tx-1,ty+1 + for i1 in xrange(-1,self.view.w/base_w+2): #NOTE: not sure why +2 + if ty >= 0 and ty < h and tx >= 0 and tx < w: + z = zlayer[ty][tx]*iso_z + if blayer != None: + n = blayer[ty][tx] + if n != 0: + t = tiles[n] + if t != None and t.image != None: + screen.blit(t.image,(x-base_w2,y+z)) + n = tlayer[ty][tx] + if n != 0: + t = tiles[n] + if t != None and t.image != None: + screen.blit(t.image,(x-base_w2,y-(t.image_h-base_h)+z)) + + tx += 1 + ty -= 1 + x += base_w + for img,irect in todo[y/base_h2]: + screen.blit(img,(irect.x+adj.x,irect.y+adj.y)) + + return [pygame.Rect(0,0,screen.get_width(),screen.get_height())] + + def iso_to_view(self,pos): + tlayer = self.tlayer + w,h = len(tlayer[0]),len(tlayer) + + x,y = pos + + #nx,ny = (h*self.iso_w + x - y)/2, (0 + x + y)/2 + nx,ny = (x - y)/2, (0 + x + y)/2 + + return (nx * self.base_w / self.iso_w), (ny * self.base_h / self.iso_h) + + def view_to_iso(self,pos): + tlayer = self.tlayer + w,h = len(tlayer[0]),len(tlayer) + + x,y = pos + + x,y = x*self.iso_w/self.base_w, y*self.iso_h/self.base_h + + #x -= (self.iso_w/2) * h + #x -= (self.iso_w/2) * h + + nx = (x+y) + ny = y*2-nx + + return nx,ny + + def tile_to_view(self,pos): + return self.iso_to_view((pos[0]*self.iso_w,pos[1]*self.iso_h)) + + def screen_to_tile(self,pos): + x,y = pos + x += self.view.x + y += self.view.y + x,y = self.view_to_iso((x,y)) + return x/self.iso_w,y/self.iso_h + + def tile_to_screen(self,pos): + x,y = self.iso_to_view((pos[0]*self.iso_w,pos[1]*self.iso_h)) + return x-self.view.x,y-self.view.y + + def tga_load_tiles(self,fname,size,tdata={}): + Vid.tga_load_tiles(self,fname,size,tdata) + + self.tile_w,self.tile_h = size + self.iso_w,self.iso_h,self.iso_z = self.tile_w,self.tile_w,1 + self.base_w,self.base_h = self.tile_w,self.tile_w/2 + + + + def resize(self,size,bg=0): + Vid.resize(self,size,bg) + + tlayer = self.tlayer + w,h = len(tlayer[0]),len(tlayer) + + self.zlayer = [[0 for x in xrange(0,w)] for y in xrange(0,h)] + + + + + def sprite_calc_irect(self,s): + tlayer = self.tlayer + w,h = len(tlayer[0]),len(tlayer) + zlayer = self.zlayer + + x,y = self.iso_to_view((s.rect.centerx,s.rect.centery)) + tx,ty = s.rect.centerx/self.iso_w,s.rect.centery/self.iso_h + z = 0 + if ty >= 0 and ty < h and tx >= 0 and tx < w: + z = zlayer[ty][tx]*self.iso_z + + nx,ny = x - s.shape.centerx, y - s.shape.centery + z + + s.irect.x,s.irect.y = nx,ny + + def run_codes(self,cdata,rect): + #HACK to make run_codes work + w,h = self.iso_w,self.iso_h + + img = self.tiles[0].image + + self.tiles[0].image = pygame.Surface((w,h)) + r = Vid.run_codes(self,cdata,rect) + self.tiles[0].image = img + return r diff --git a/src/pgu/layout.py b/src/pgu/layout.py new file mode 100644 index 0000000..75b6c9a --- /dev/null +++ b/src/pgu/layout.py @@ -0,0 +1,4 @@ +print 'pgu.layout','Scheduled to be deprecated.' + +from pgu.gui.layout import * + diff --git a/src/pgu/text.py b/src/pgu/text.py new file mode 100644 index 0000000..1010a87 --- /dev/null +++ b/src/pgu/text.py @@ -0,0 +1,61 @@ +"""a collection of text rendering functions +""" +def write(s,font,pos,color,text,border=1): + """write text to a surface with a black border + +
write(s,font,pos,color,text,border=1)
+ """ + i = font.render(text,1,(0,0,0)) + si = border + dirs = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)] + for dx,dy in dirs: s.blit(i,(pos[0]+dx*si,pos[1]+dy*si)) + i = font.render(text,1,color) + s.blit(i,pos) + +def writec(s,font,color,text,border=1): + """write centered text to a surface with a black border + +
writec(s,font,color,text,border=1)
+ """ + w,h = font.size(text) + x = (s.get_width()-w)/2 + y = (s.get_height()-h)/2 + write(s,font,(x,y),color,text,border) + +def writepre(s,font,rect,color,text): + """write preformatted text + +
writepre(s,font,rect,color,text)
+ """ + r,c,txt = rect,color,text + txt = txt.replace("\t"," ") + i = font.render(" ",1,c) + sw,sh = i.get_width(),i.get_height() + y = r.top + for sentence in txt.split("\n"): + x = r.left + i = font.render(sentence,1,c) + s.blit(i,(x,y)) + y += sh + +def writewrap(s,font,rect,color,text): + """write wrapped text + +
writewrap(s,font,rect,color,text)
+ """ + r,c,txt = rect,color,text + txt = txt.replace("\t"," ") + i = font.render(" ",1,c) + sw,sh = i.get_width(),i.get_height() + y = r.top + for sentence in txt.split("\n"): + x = r.left + for word in sentence.split(" "): + i = font.render(word,1,c) + iw,ih = i.get_width(),i.get_height() + if x+iw > r.right: x,y = r.left,y+sh + s.blit(i,(x,y)) + x += iw+sw + y += sh + +# vim: set filetype=python sts=4 sw=4 noet si : diff --git a/src/pgu/tilevid.py b/src/pgu/tilevid.py new file mode 100644 index 0000000..00f730d --- /dev/null +++ b/src/pgu/tilevid.py @@ -0,0 +1,195 @@ +"""Square tile based engine.""" + +from pgu.vid import * +import pygame + +class Tilevid(Vid): + """Based on [[vid]] -- see for reference.""" + def paint(self,s): + sw,sh = s.get_width(),s.get_height() + self.view.w,self.view.h = sw,sh + + tiles = self.tiles + tw,th = tiles[0].image.get_width(),tiles[0].image.get_height() + w,h = self.size + + if self.bounds != None: self.view.clamp_ip(self.bounds) + + ox,oy = self.view.x,self.view.y + tlayer = self.tlayer + blayer = self.blayer + alayer = self.alayer + sprites = self.sprites + + blit = s.blit + yy = - (self.view.y%th) + my = (oy+sh)/th + if (oy+sh)%th: my += 1 + + if blayer != None: + for y in xrange(oy/th,my): + if y >=0 and y < h: + trow = tlayer[y] + brow = blayer[y] + arow = alayer[y] + xx= - (self.view.x%tw) + mx = (ox+sw)/tw + #if (ox+sh)%tw: mx += 1 + for x in xrange(ox/tw,mx+1): + if x >=0and x=0 and y=0 and xTimer(fps) + """ + + def __init__(self,fps): + if fps == 0: + self.tick = self._blank + return + self.wait = 1000/fps + self.nt = pygame.time.get_ticks() + pygame.time.wait(0) + + def _blank(self): + pass + + def tick(self): + """Wait correct amount of time each frame. Call this once per frame. + +
Timer.tick()
+ """ + self.ct = pygame.time.get_ticks() + if self.ct < self.nt: + pygame.time.wait(self.nt-self.ct) + self.nt+=self.wait + else: + self.nt = pygame.time.get_ticks()+self.wait + + +class Speedometer: + """A timer replacement that returns out FPS once a second. +
Speedometer()
+ + Attributes +
+
fps
always set to the current FPS +
+ """ + def __init__(self): + self.frames = 0 + self.st = pygame.time.get_ticks() + self.fps = 0 + + def tick(self): + """ Call this once per frame. + +
Speedometer.tick()
+ """ + r = None + self.frames += 1 + self.ct = pygame.time.get_ticks() + if (self.ct - self.st) >= 1000: + r = self.fps = self.frames + #print "%s: %d fps"%(self.__class__.__name__,self.fps) + self.frames = 0 + self.st += 1000 + pygame.time.wait(0) #NOTE: not sure why, but you gotta call this now and again + return r + + + +# vim: set filetype=python sts=4 sw=4 noet si : diff --git a/src/pgu/vid.py b/src/pgu/vid.py new file mode 100644 index 0000000..6890e5d --- /dev/null +++ b/src/pgu/vid.py @@ -0,0 +1,560 @@ +"""Sprite and tile engine. + +

[[tilevid]], [[isovid]], [[hexvid]] are all subclasses of +this interface.

+ +

Includes support for:

+ +
    +
  • Foreground Tiles +
  • Background Tiles +
  • Sprites +
  • Sprite-Sprite Collision handling +
  • Sprite-Tile Collision handling +
  • Scrolling +
  • Loading from PGU tile and sprite formats (optional) +
  • Set rate FPS (optional) +
+ +

This code was previously known as the King James Version (named after the +Bible of the same name for historical reasons.)

+""" + +import pygame +from pygame.rect import Rect +from pygame.locals import * +import math + +class Sprite: + """The object used for Sprites. + +
Sprite(ishape,pos)
+ +
+
ishape
an image, or an image, rectstyle. The rectstyle will + describe the shape of the image, used for collision + detection. +
pos
initial (x,y) position of the Sprite. +
+ + Attributes +
+
rect
the current position of the Sprite +
_rect
the previous position of the Sprite +
groups
the groups the Sprite is in +
agroups
the groups the Sprite can hit in a collision +
hit
the handler for hits -- hit(g,s,a) +
loop
the loop handler, called once a frame +
+ """ + def __init__(self,ishape,pos): + if not isinstance(ishape, tuple): + ishape = ishape,None + image,shape = ishape + if shape == None: + shape = pygame.Rect(0,0,image.get_width(),image.get_height()) + if isinstance(shape, tuple): shape = pygame.Rect(shape) + self.image = image + self._image = self.image + self.shape = shape + self.rect = pygame.Rect(pos[0],pos[1],shape.w,shape.h) + self._rect = pygame.Rect(self.rect) + self.irect = pygame.Rect(pos[0]-self.shape.x,pos[1]-self.shape.y, + image.get_width(),image.get_height()) + self._irect = pygame.Rect(self.irect) + self.groups = 0 + self.agroups = 0 + self.updated = 1 + + def setimage(self,ishape): + """Set the image of the Sprite. + +
Sprite.setimage(ishape)
+ +
+
ishape
an image, or an image, rectstyle. The rectstyle will + describe the shape of the image, used for collision detection. +
+ """ + if not isinstance(ishape, tuple): + ishape = ishape,None + image,shape = ishape + if shape == None: + shape = pygame.Rect(0,0,image.get_width(),image.get_height()) + if isinstance(shape, tuple): + shape = pygame.Rect(shape) + self.image = image + self.shape = shape + self.rect.w,self.rect.h = shape.w,shape.h + self.irect.w,self.irect.h = image.get_width(),image.get_height() + self.updated = 1 + + +class Tile: + """Tile Object used by TileCollide. + +
Tile(image=None)
+
+
image
an image for the Tile. +
+ + Attributes +
+
agroups
the groups the Tile can hit in a collision +
hit
the handler for hits -- hit(g,t,a) +
+ """ + def __init__(self,image=None): + self.image = image + self.agroups = 0 + + def __setattr__(self,k,v): + if k == 'image' and v != None: + self.image_h = v.get_height() + self.image_w = v.get_width() + self.__dict__[k] = v + +class _Sprites(list): + def __init__(self): + list.__init__(self) + self.removed = [] + + def append(self,v): + list.append(self,v) + v.updated = 1 + + def remove(self,v): + list.remove(self,v) + v.updated = 1 + self.removed.append(v) + +class Vid: + """An engine for rendering Sprites and Tiles. + +
Vid()
+ + Attributes +
+
sprites
a list of the Sprites to be displayed. You may append and + remove Sprites from it. +
images
a dict for images to be put in. +
size
the width, height in Tiles of the layers. Do not modify. +
view
a pygame.Rect of the viewed area. You may change .x, .y, + etc to move the viewed area around. +
bounds
a pygame.Rect (set to None by default) that sets the bounds + of the viewable area. Useful for setting certain borders + as not viewable. +
tlayer
the foreground tiles layer +
clayer
the code layer (optional) +
blayer
the background tiles layer (optional) +
groups
a hash of group names to group values (32 groups max, as a tile/sprites + membership in a group is determined by the bits in an integer) +
+ """ + + def __init__(self): + self.tiles = [None for x in xrange(0,256)] + self.sprites = _Sprites() + self.images = {} #just a store for images. + self.layers = None + self.size = None + self.view = pygame.Rect(0,0,0,0) + self._view = pygame.Rect(self.view) + self.bounds = None + self.updates = [] + self.groups = {} + + + def resize(self,size,bg=0): + """Resize the layers. + +
Vid.resize(size,bg=0)
+ +
+
size
w,h in Tiles of the layers +
bg
set to 1 if you wish to use both a foreground layer and a + background layer +
+ """ + self.size = size + w,h = size + self.layers = [[[0 for x in xrange(0,w)] for y in xrange(0,h)] + for z in xrange(0,4)] + self.tlayer = self.layers[0] + self.blayer = self.layers[1] + if not bg: self.blayer = None + self.clayer = self.layers[2] + self.alayer = self.layers[3] + + self.view.x, self.view.y = 0,0 + self._view.x, self.view.y = 0,0 + self.bounds = None + + self.updates = [] + + def set(self,pos,v): + """Set a tile in the foreground to a value. + +

Use this method to set tiles in the foreground, as it will make + sure the screen is updated with the change. Directly changing + the tlayer will not guarantee updates unless you are using .paint() +

+ +
Vid.set(pos,v)
+ +
+
pos
(x,y) of tile +
v
value +
+ """ + if self.tlayer[pos[1]][pos[0]] == v: return + self.tlayer[pos[1]][pos[0]] = v + self.alayer[pos[1]][pos[0]] = 1 + self.updates.append(pos) + + def get(self,pos): + """Get the tlayer at pos. + +
Vid.get(pos): return value
+ +
+
pos
(x,y) of tile +
+ """ + return self.tlayer[pos[1]][pos[0]] + + def paint(self,s): + """Paint the screen. + +
Vid.paint(screen): return [updates]
+ +
+
screen
a pygame.Surface to paint to +
+ +

returns the updated portion of the screen (all of it)

+ """ + return [] + + def update(self,s): + """Update the screen. + +
Vid.update(screen): return [updates]
+ +
+
screen
a pygame.Rect to update +
+ +

returns a list of updated rectangles.

+ """ + self.updates = [] + return [] + + def tga_load_level(self,fname,bg=0): + """Load a TGA level. + +
Vid.tga_load_level(fname,bg=0)
+ +
+
g
a Tilevid instance +
fname
tga image to load +
bg
set to 1 if you wish to load the background layer +
+ """ + if type(fname) == str: img = pygame.image.load(fname) + else: img = fname + w,h = img.get_width(),img.get_height() + self.resize((w,h),bg) + for y in range(0,h): + for x in range(0,w): + t,b,c,_a = img.get_at((x,y)) + self.tlayer[y][x] = t + if bg: self.blayer[y][x] = b + self.clayer[y][x] = c + + def tga_save_level(self,fname): + """Save a TGA level. + +
Vid.tga_save_level(fname)
+ +
+
fname
tga image to save to +
+ """ + w,h = self.size + img = pygame.Surface((w,h),SWSURFACE,32) + img.fill((0,0,0,0)) + for y in range(0,h): + for x in range(0,w): + t = self.tlayer[y][x] + b = 0 + if self.blayer: + b = self.blayer[y][x] + c = self.clayer[y][x] + _a = 0 + img.set_at((x,y),(t,b,c,_a)) + pygame.image.save(img,fname) + + + + def tga_load_tiles(self,fname,size,tdata={}): + """Load a TGA tileset. + +
Vid.tga_load_tiles(fname,size,tdata={})
+ +
+
g
a Tilevid instance +
fname
tga image to load +
size
(w,h) size of tiles in pixels +
tdata
tile data, a dict of tile:(agroups, hit handler, config) +
+ """ + TW,TH = size + if type(fname) == str: img = pygame.image.load(fname).convert_alpha() + else: img = fname + w,h = img.get_width(),img.get_height() + + n = 0 + for y in range(0,h,TH): + for x in range(0,w,TW): + i = img.subsurface((x,y,TW,TH)) + tile = Tile(i) + self.tiles[n] = tile + if n in tdata: + agroups,hit,config = tdata[n] + tile.agroups = self.string2groups(agroups) + tile.hit = hit + tile.config = config + n += 1 + + + def load_images(self,idata): + """Load images. + +
Vid.load_images(idata)
+ +
+
idata
a list of (name, fname, shape) +
+ """ + for name,fname,shape in idata: + self.images[name] = pygame.image.load(fname).convert_alpha(),shape + + def run_codes(self,cdata,rect): + """Run codes. + +
Vid.run_codes(cdata,rect)
+ +
+
cdata
a dict of code:(handler function, value) +
rect
a tile rect of the parts of the layer that should have + their codes run +
+ """ + tw,th = self.tiles[0].image.get_width(),self.tiles[0].image.get_height() + + x1,y1,w,h = rect + clayer = self.clayer + t = Tile() + for y in range(y1,y1+h): + for x in range(x1,x1+w): + n = clayer[y][x] + if n in cdata: + fnc,value = cdata[n] + t.tx,t.ty = x,y + t.rect = pygame.Rect(x*tw,y*th,tw,th) + fnc(self,t,value) + + + def string2groups(self,str): + """Convert a string to groups. + +
Vid.string2groups(str): return groups
+ """ + if str == None: return 0 + return self.list2groups(str.split(",")) + + def list2groups(self,igroups): + """Convert a list to groups. +
Vid.list2groups(igroups): return groups
+ """ + for s in igroups: + if not s in self.groups: + self.groups[s] = 2**len(self.groups) + v = 0 + for s,n in self.groups.items(): + if s in igroups: v|=n + return v + + def groups2list(self,groups): + """Convert a groups to a list. +
Vid.groups2list(groups): return list
+ """ + v = [] + for s,n in self.groups.items(): + if (n&groups)!=0: v.append(s) + return v + + def hit(self,x,y,t,s): + tiles = self.tiles + tw,th = tiles[0].image.get_width(),tiles[0].image.get_height() + t.tx = x + t.ty = y + t.rect = Rect(x*tw,y*th,tw,th) + t._rect = t.rect + if hasattr(t,'hit'): + t.hit(self,t,s) + + def loop(self): + """Update and hit testing loop. Run this once per frame. +
Vid.loop()
+ """ + self.loop_sprites() #sprites may move + self.loop_tilehits() #sprites move + self.loop_spritehits() #no sprites should move + for s in self.sprites: + s._rect = pygame.Rect(s.rect) + + def loop_sprites(self): + as_ = self.sprites[:] + for s in as_: + if hasattr(s,'loop'): + s.loop(self,s) + + def loop_tilehits(self): + tiles = self.tiles + tw,th = tiles[0].image.get_width(),tiles[0].image.get_height() + + layer = self.layers[0] + + as_ = self.sprites[:] + for s in as_: + self._tilehits(s) + + def _tilehits(self,s): + tiles = self.tiles + tw,th = tiles[0].image.get_width(),tiles[0].image.get_height() + layer = self.layers[0] + + for _z in (0,): + if s.groups != 0: + + _rect = s._rect + rect = s.rect + + _rectx = _rect.x + _recty = _rect.y + _rectw = _rect.w + _recth = _rect.h + + rectx = rect.x + recty = rect.y + rectw = rect.w + recth = rect.h + + rect.y = _rect.y + rect.h = _rect.h + + hits = [] + ct,cb,cl,cr = rect.top,rect.bottom,rect.left,rect.right + #nasty ol loops + y = ct/th*th + while y < cb: + x = cl/tw*tw + yy = y/th + while x < cr: + xx = x/tw + t = tiles[layer[yy][xx]] + if (s.groups & t.agroups)!=0: + #self.hit(xx,yy,t,s) + d = math.hypot(rect.centerx-(xx*tw+tw/2), + rect.centery-(yy*th+th/2)) + hits.append((d,t,xx,yy)) + + x += tw + y += th + + hits.sort() + #if len(hits) > 0: print self.frame,hits + for d,t,xx,yy in hits: + self.hit(xx,yy,t,s) + + #switching directions... + _rect.x = rect.x + _rect.w = rect.w + rect.y = recty + rect.h = recth + + hits = [] + ct,cb,cl,cr = rect.top,rect.bottom,rect.left,rect.right + #nasty ol loops + y = ct/th*th + while y < cb: + x = cl/tw*tw + yy = y/th + while x < cr: + xx = x/tw + t = tiles[layer[yy][xx]] + if (s.groups & t.agroups)!=0: + d = math.hypot(rect.centerx-(xx*tw+tw/2), + rect.centery-(yy*th+th/2)) + hits.append((d,t,xx,yy)) + #self.hit(xx,yy,t,s) + x += tw + y += th + + hits.sort() + #if len(hits) > 0: print self.frame,hits + for d,t,xx,yy in hits: + self.hit(xx,yy,t,s) + + #done with loops + _rect.x = _rectx + _rect.y = _recty + + + def loop_spritehits(self): + as_ = self.sprites[:] + + groups = {} + for n in range(0,31): + groups[1<>= 1 + n <<= 1 + + for s in as_: + if s.agroups!=0: + rect1,rect2 = s.rect,Rect(s.rect) + #if rect1.centerx < 320: rect2.x += 640 + #else: rect2.x -= 640 + g = s.agroups + n = 1 + while g: + if (g&1)!=0: + for b in groups[n]: + if (s != b and (s.agroups & b.groups)!=0 + and s.rect.colliderect(b.rect)): + s.hit(self,s,b) + + g >>= 1 + n <<= 1 + + + def screen_to_tile(self,pos): + """Convert a screen position to a tile position. +
Vid.screen_to_tile(pos): return pos
+ """ + return pos + + def tile_to_screen(self,pos): + """Convert a tile position to a screen position. +
Vid.tile_to_screen(pos): return pos
+ """ + return pos + +# vim: set filetype=python sts=4 sw=4 noet si : diff --git a/src/songs/MidiToSong.py b/src/songs/MidiToSong.py new file mode 100644 index 0000000..f85b06c --- /dev/null +++ b/src/songs/MidiToSong.py @@ -0,0 +1,60 @@ +''' +Created on 8 dec. 2009 + +@author: Samuel Benveniste +''' + +from mxmMidi.MidiOutStream import MidiOutStream + +class MidiToSong(MidiOutStream): + ''' + Creates songs from midi files using mxmMidi package + ''' + def __init__(self): + self.midiNoteNumbers = [] + self.noteLengths = [] + self.quarterNoteLength = 500 + self.firstNoteOn = True + self._lastNoteOnTime = 0 + + def header(self, format=0, nTracks=1, division=96): + print 'format: %s, nTracks: %s, division: %s' % (format, nTracks, division) + print '----------------------------------' + print '' + self.division = division + + def tempo(self,value): + self.quarterNoteLength = value/1000 + print "quarterNoteLength in ms :" + str(self.quarterNoteLength) + + def note_on(self, channel=0, note=0x40, velocity=0x40): + self.midiNoteNumbers.append(note) + # if it's the first note_on take note of time (the song begins here) + # from the second note_on and after, mark the length of the preceding note + if self.firstNoteOn : + self.firstNoteOn = False + self._lastNoteOnTime = self.abs_time() + else : + self.noteLengths.append(float(self.abs_time()-self._lastNoteOnTime)/float(self.division)) + self._lastNoteOnTime = self.abs_time() + + def eof(self): + self.noteLengths.append(4) + for i in range(len(self.midiNoteNumbers)): + print "note number :" + str(self.midiNoteNumbers[i]) + ", length in quarter Notes :" + str(self.noteLengths[i]) + print"--------------" + print "end of file" + +if __name__ == '__main__': + + # get data + test_file = '../songs/midis/test.mid' + f = open(test_file, 'rb') + + # do parsing + from mxmMidi.MidiInFile import MidiInFile + mts = MidiToSong() + midiIn = MidiInFile(mts, f) + midiIn.read() + f.close() + \ No newline at end of file diff --git a/src/songs/Song.py b/src/songs/Song.py new file mode 100755 index 0000000..c018eae --- /dev/null +++ b/src/songs/Song.py @@ -0,0 +1,137 @@ +''' +Created on 2 oct. 2009 + +@author: samsam +''' +import pickle +import os.path +from MidiToSong import MidiToSong +from mxmMidi.MidiInFile import MidiInFile + +class Song: + ''' + classdocs + ''' + + + def __init__(self,scale,notesInExtendedScale=[], requiresExtendedScale = False,midiNoteNumbers = None, alterationIndexes = None, alterations = None, modulationIndexes = None, modulationScales = None, lyrics =None, noteLengths = None, quarterNoteLength = 750, name = "unknownSong"): + ''' + Constructor + ''' + self.name = name + self.scale = scale + self.notes = notesInExtendedScale + self.lyrics = lyrics + self.noteLengths = noteLengths + self.quarterNoteLength = quarterNoteLength + if midiNoteNumbers == None : + self.midiNoteNumbers = [self.scale[note] for note in self.notes] + else: + self.midiNoteNumbers = midiNoteNumbers + if self.notes == [] : + self.assignNotesFromMidiNoteNumbers() + self.requiresExtendedScale = requiresExtendedScale + if alterationIndexes != None and alterations != None : + self.alterNotes(alterationIndexes, alterations) + if modulationIndexes != None and modulationScales != None : + self.modulate(modulationIndexes, modulationScales) + + def getSongIterator(self): + while True: + for i in range(len(self.notes)): + if self.lyrics : + lyrics = self.lyrics[i] + else : + lyrics = None + + if self.noteLengths : + noteLength = self.noteLengths[i] + else : + noteLength = 1 + + yield [self.notes[i],self.midiNoteNumbers[i],lyrics,noteLength] + + def alterNotes(self,noteIndexes,alterations): + for i in range(len(noteIndexes)) : + self.midiNoteNumbers[noteIndexes[i]] = self.midiNoteNumbers[noteIndexes[i]] + alterations[i] + + def modulate(self,modulationIndexes,scales): + for i in range(len(scales)): + if i < len(scales)-1 : + bound = modulationIndexes[i+1] + else : + bound = len(self.notes) + for j in range(modulationIndexes[i],bound): + self.midiNoteNumbers[j]=scales[i][self.notes[j]] + + def assignNotesFromMidiNoteNumbers(self): + for i in range(len(self.midiNoteNumbers)): + noteInExtendedScale = 0 + while self.midiNoteNumbers[i] > self.scale[noteInExtendedScale] and noteInExtendedScale < len(self.scale)-1: + noteInExtendedScale += 1 + if self.midiNoteNumbers[i]9ajq_SB;H^eQ7E^R19Dc74>Z`Q^%Xf-_W(ifH3)TR$K@u7c` zVTZD5c<97_AwN*R1D&>yGdVfuH)neNcUP8WWvrC7kiPHrM>jH+t$BLsVmP`Uj)vBJ z@F0^eE?e`nbhdhL&7WHTRjJ>!!qA&MWYf(f_|s2lN^1=JlVt>Ffz4r3V5oU$Y&t^- zp0QH1m%LZ^P}#{5?rl(wm8N44B^;!9A*e%dHD(8rGYnnk_81J$!#uuoaafjjb z*CoPY{F*`2DMGo(x<=;=^|z=O<3of>lS7^4Ff0pPm$IT6Z?n;}0-CbWwUQHrf+U+) zbS|qrM*)3gQ?Fu_CxNYc9JZ&I48DtDZek-;E3BJ$*QoO}VBMw;YCF#d9s0`JbMPP+ zOL+N~L-YMThR*mAhdym%xG7x0Y!$)v*feH24pj<`OCK0s*ciGbxLZ$HE3t)+FRs&X z2s;^80o_WF^yL1uP%p(1Lv!*Np|s1!PWAfwEHbzeT1&x2gx{+k1vtucpN&@1s>fAk-U;O>~ EAD(rn<^TWy literal 0 HcmV?d00001 diff --git a/src/songs/midis/boheme.mid b/src/songs/midis/boheme.mid new file mode 100644 index 0000000000000000000000000000000000000000..f7f2800cc4a13b194909f98ab6fbd8f2321aac1c GIT binary patch literal 1055 zcmXYw?^2sZ6vkgjNl1ukN`xdN1QH0Q{A=qpq5kJ4v!DL%e^bnNN&)(+=>jH{Ow)d@ZKdw{{8s~e$mX6AGcHR$J`!7EkS;t zOOr@1z%RHjAc|4)W9~kQNEX3Oo2MXQb`dO?=M*H(0fHGfO+ji2VZ~jeF!2eWxqXBM zcZ|Mv>wT{`3P#sJ|dObfGjwlWTF8z;j$drg`U4y zBt2jf5P6KU2B)E$wnMtF0yXXyII9UcV^8_s*U(FLige5zLlw+1sf2lgK>eDeAani# zy6TomXU3pvu0g7jgDksmSj`ahjAI?s|wfuQB86l9z5%Qi-S!mPl5-}S&ghN!S+k-W*^-6r`1 z9s_n${L(6d>-KsN?lJ>>huKGvJ4+%QU#1{tPbf^~5R_dPVRg6{c}`*aA>_Q-<08y6 z$XWB{|ErSA@oEif){T%#Z9-1ES(33?sH%C|t8fsyWhLpj=|V63wof`Gps(3}(!=Hv zbj3VlSmsmc0{4TCuV8(R-&#+uqEoje>SW9>J+x2>vpi0ehgh^xH>+~AK4?e z=lfpzDRoNg&^0^VdwmN!@1BxQ_e0ffgjC*0s1lp6Dz~``TVXfN8roIYrMBmx-HB2= zLtjiS+U z_i$&iPK~77h1lq)J9B>xkSLrTLaJAzXm5YWX(?1nTZB+<>8(Hu{Yd=)ldhZH+!8f`Mq|^oral-YmiPvZHI31k z-4u)_W)lC9{|slNZ?k7+_nb3ldncFgJO3Rz>d;g|lzrRarS8SHVK?~YRJO+`%h{T$SgYa>SM2J@o>yxOD*Fnr< zlQH`O#LPL#swsk;$ADzf?0`(-0?ELX9Ck{wG`;|tDw8PM8xYxbQi0h7mBucqf@y+U z#3fRz<`mQ_#<`lrK!q(54f~1TpCi3%9)MoNJ<@rz4LXHA(jk5UeHY)5uHJqCJ&!}K z>?*0pd7d>H_v}+gRR@*A9nuxs@cM{ARUa)os2Z;HT()X=VSyn#WECi$|izN5^qQsu#5C(kDG?7nXp7_y+9+CP)NW1d+ol5@jP@hG~~;2qJ;c+3+Oks(YL~ zK5^X<$%^qoCh*WzM<8dgMskINVl2Zba&lDS#^B uTZ%5mHHdQfj9p^H-b_Gh$3A4g8Io%@1ex9EKZPR@ZWrS4R|SOUzUE)jLEIt$ literal 0 HcmV?d00001 diff --git a/src/songs/midis/feuillesmortes.mid b/src/songs/midis/feuillesmortes.mid new file mode 100644 index 0000000000000000000000000000000000000000..2c16ae6b994747f73f75507fbd9bd4adbd3803aa GIT binary patch literal 717 zcmXAnT~8B16oz-ZwP7n1LR;E}LiyT=C?#q`z_z=?4CAhaN>E}dkPw3qPz({&G)l~w z?O>yDaW1*^0>zI&_zC{AI*pfe@}6^^JZCD)+b=Xti)gwQGX7SU_g|@(tu>9<*54s0Iy5f=nb8%fTv3Xi@kCO9ZOW9 zs0RroeN}J_Swmh50kO`vfg7KbSV+qaEZvbS=uYIJpie3kaoEXG_Ih=0~fsZz(ueB zd{p6yA{IMk1)Y>gw(t&-SkGH{4}iowk!ODB!1YEAY4)fedA3bCIT{8&U?Ll-uLJ87 z29o^o4v<^lW|52u4x~F!dWM2WK)SA>yC5Urn)9v72#{fsL;CFZ9?<9_(&Wi?wQxqU z1zX4pgUZJ*9ayYBi0tl{D$=Piu;Jh%vME#f4Q7!)o(2{_s{xPopp$FNV7c4@PPB0k z%9ertTw@fyxfuA?#h5xo4*B9q0=?`*Wm)a_tWor*gEjEu!5I2O!3OvPF%=STfTx0a zF2x5X2rm16^FUk~~@)#%5Ci5{yL!LvmKy_*;Il~*#aJR;WA)EJUdV-)xn88Wx328$I{N?>6;aF9H;pkQ7WfK0T0&dvH+wr7a9Nn literal 0 HcmV?d00001 diff --git a/src/songs/midis/test.mid b/src/songs/midis/test.mid new file mode 100644 index 0000000000000000000000000000000000000000..7df48243e2b5ab13e23e3f8a14357e2a95929f6f GIT binary patch literal 275 zcmXYsy-vbl6ox-(3xojH!GI}};sA}YanJ~D`RNZ(%FjT;Ad`z46BnZ-ni#`5;p`qS z!NHwN@H)JiS`)|j$@2{FY;kujgh-1Wk&?b=i^uz9X(E>7)y>mN#Fw(1DrZGJmolHa zh)>18^7E0|PG1V!>H0n7<~~NyRH(tN8Wy0Xkk3{XJ+MlYW4n$f*eaRq9O4-`B@*1O zqYZ716z*79gO0j+;BEzV=oZQ5p7{p799^(`glTZ|n^*SqB=9uaW52ovzeoWGI#wVk z(gF7ySI{p}$O8k*Fi;XSJi%QUDr9izU<1Mm={#DZ0VDIv79&pr3ed-@*m7kD*My}Pzojv!=x#yhO-ut0vS=N{pvo6^mw)YO7^H;^X zuoK76`iDOr^{tD?pN!ds%httxdwl7pb#cr3A7%gZZw6|87>Bp4ZBmowCFDYaykc}0 zqTL}mImnWzOu%gfyX3~JP#fkuQt^FwwewZTLXEu1@CrmDMlv7$LZVcLyBs|uH*o@| zr2FJlO%C3QIV3OJf}A~nPSQSxs0T5oX0#i9#nfwXD&YY+F>?>js&0+u1iZDtWjS%k z)?ZIaCMyur!xD+>rVYP^Ce-{g`T4LwD&2-RJ2-~yqmzD3P1e zNvPEz%g9x>6}#lkOmM7Wg5-Fg(Stn}pN6~gCJCo;hf{mX