From a512d1462833d8c592a44fda864e54b0144bcce7 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 26 Feb 2015 21:10:46 +1100 Subject: [PATCH] Update to v094r09 release. byuu says: This will easily be the biggest diff in the history of higan. And not in a good way. * target-higan and target-loki have been blown away completely * nall and ruby massively updated * phoenix replaced with hiro (pretty near a total rewrite) * target-higan restarted using hiro (just a window for now) * all emulation cores updated to compile again * installation changed to not require root privileges (installs locally) For the foreseeable future (maybe even permanently?), the new higan UI will only build under Linux/BSD with GTK+ 2.20+. Probably the most likely route for Windows/OS X will be to try and figure out how to build hiro/GTK on those platforms, as awful as that would be. The other alternative would be to produce new UIs for those platforms ... which would actually be a good opportunity to make something much more user friendly. Being that I just started on this a few hours ago, that means that for at least a few weeks, don't expect to be able to actually play any games. Right now, you can pretty much just compile the binary and that's it. It's quite possible that some nall changes didn't produce compilation errors, but will produce runtime errors. So until the UI can actually load games, we won't know if anything is broken. But we should mostly be okay. It was mostly just trim<1> -> trim changes, moving to Hash::SHA256 (much cleaner), and patching some reckless memory copy functions enough to compile. Progress isn't going to be like it was before: I'm now dividing my time much thinner between studying and other hobbies. My aim this time is not to produce a binary for everyone to play games on. Rather, it's to keep the emulator alive. I want to be able to apply critical patches again. And I would also like the base of the emulator to live on, for use in other emulator frontends that utilize higan. --- Makefile => GNUmakefile | 31 +- data/higan.desktop | 2 +- emulator/emulator.hpp | 5 +- fc/{Makefile => GNUmakefile} | 0 fc/cartridge/cartridge.cpp | 14 +- gb/{Makefile => GNUmakefile} | 0 gb/cartridge/cartridge.cpp | 4 +- gba/{Makefile => GNUmakefile} | 0 gba/cartridge/cartridge.cpp | 2 +- gba/player/player.cpp | 2 +- hiro/GNUmakefile | 24 + {phoenix => hiro}/cocoa/action/action.cpp | 0 {phoenix => hiro}/cocoa/action/action.hpp | 0 {phoenix => hiro}/cocoa/action/check-item.cpp | 0 {phoenix => hiro}/cocoa/action/check-item.hpp | 0 {phoenix => hiro}/cocoa/action/item.cpp | 0 {phoenix => hiro}/cocoa/action/item.hpp | 0 {phoenix => hiro}/cocoa/action/menu.cpp | 0 {phoenix => hiro}/cocoa/action/menu.hpp | 0 {phoenix => hiro}/cocoa/action/radio-item.cpp | 0 {phoenix => hiro}/cocoa/action/radio-item.hpp | 0 {phoenix => hiro}/cocoa/action/separator.cpp | 0 {phoenix => hiro}/cocoa/action/separator.hpp | 0 {phoenix => hiro}/cocoa/application.cpp | 0 {phoenix => hiro}/cocoa/application.hpp | 0 {phoenix => hiro}/cocoa/browser-window.cpp | 4 +- {phoenix => hiro}/cocoa/browser-window.hpp | 0 {phoenix => hiro}/cocoa/desktop.cpp | 0 {phoenix => hiro}/cocoa/desktop.hpp | 0 {phoenix => hiro}/cocoa/font.cpp | 0 {phoenix => hiro}/cocoa/font.hpp | 0 {phoenix => hiro}/cocoa/header.hpp | 0 {phoenix => hiro}/cocoa/keyboard.cpp | 0 {phoenix => hiro}/cocoa/keyboard.hpp | 0 {phoenix => hiro}/cocoa/message-window.cpp | 0 {phoenix => hiro}/cocoa/message-window.hpp | 0 {phoenix => hiro}/cocoa/monitor.cpp | 0 {phoenix => hiro}/cocoa/monitor.hpp | 0 {phoenix => hiro}/cocoa/mouse.cpp | 0 {phoenix => hiro}/cocoa/mouse.hpp | 0 {phoenix => hiro}/cocoa/object.cpp | 0 {phoenix => hiro}/cocoa/object.hpp | 0 {phoenix => hiro}/cocoa/platform.cpp | 0 {phoenix => hiro}/cocoa/platform.hpp | 0 {phoenix => hiro}/cocoa/timer.cpp | 0 {phoenix => hiro}/cocoa/timer.hpp | 0 {phoenix => hiro}/cocoa/utility.cpp | 0 {phoenix => hiro}/cocoa/widget/button.cpp | 5 +- {phoenix => hiro}/cocoa/widget/button.hpp | 1 + {phoenix => hiro}/cocoa/widget/canvas.cpp | 0 {phoenix => hiro}/cocoa/widget/canvas.hpp | 0 .../cocoa/widget/check-button.cpp | 0 .../cocoa/widget/check-button.hpp | 0 .../cocoa/widget/check-label.cpp | 0 .../cocoa/widget/check-label.hpp | 0 .../cocoa/widget/combo-button.cpp | 0 .../cocoa/widget/combo-button.hpp | 0 {phoenix => hiro}/cocoa/widget/console.cpp | 0 {phoenix => hiro}/cocoa/widget/console.hpp | 0 {phoenix => hiro}/cocoa/widget/frame.cpp | 0 {phoenix => hiro}/cocoa/widget/frame.hpp | 0 {phoenix => hiro}/cocoa/widget/hex-edit.cpp | 0 {phoenix => hiro}/cocoa/widget/hex-edit.hpp | 0 .../cocoa/widget/horizontal-scroller.cpp | 0 .../cocoa/widget/horizontal-scroller.hpp | 0 .../cocoa/widget/horizontal-slider.cpp | 0 .../cocoa/widget/horizontal-slider.hpp | 0 {phoenix => hiro}/cocoa/widget/label.cpp | 0 {phoenix => hiro}/cocoa/widget/label.hpp | 0 {phoenix => hiro}/cocoa/widget/layout.hpp | 0 {phoenix => hiro}/cocoa/widget/line-edit.cpp | 0 {phoenix => hiro}/cocoa/widget/line-edit.hpp | 0 {phoenix => hiro}/cocoa/widget/list-view.cpp | 0 {phoenix => hiro}/cocoa/widget/list-view.hpp | 0 .../cocoa/widget/progress-bar.cpp | 0 .../cocoa/widget/progress-bar.hpp | 0 .../cocoa/widget/radio-button.cpp | 0 .../cocoa/widget/radio-button.hpp | 0 .../cocoa/widget/radio-label.cpp | 0 .../cocoa/widget/radio-label.hpp | 0 {phoenix => hiro}/cocoa/widget/sizable.hpp | 0 {phoenix => hiro}/cocoa/widget/tab-frame.cpp | 0 {phoenix => hiro}/cocoa/widget/tab-frame.hpp | 0 {phoenix => hiro}/cocoa/widget/text-edit.cpp | 0 {phoenix => hiro}/cocoa/widget/text-edit.hpp | 0 .../cocoa/widget/vertical-scroller.cpp | 0 .../cocoa/widget/vertical-scroller.hpp | 0 .../cocoa/widget/vertical-slider.cpp | 0 .../cocoa/widget/vertical-slider.hpp | 0 {phoenix => hiro}/cocoa/widget/viewport.cpp | 0 {phoenix => hiro}/cocoa/widget/viewport.hpp | 0 {phoenix => hiro}/cocoa/widget/widget.cpp | 0 {phoenix => hiro}/cocoa/widget/widget.hpp | 0 {phoenix => hiro}/cocoa/window.cpp | 0 {phoenix => hiro}/cocoa/window.hpp | 0 hiro/core/action/action.cpp | 12 + hiro/core/action/menu-check-item.cpp | 33 + hiro/core/action/menu-item.cpp | 34 + hiro/core/action/menu-radio-item.cpp | 51 + hiro/core/action/menu-separator.cpp | 3 + hiro/core/action/menu.cpp | 60 + hiro/core/application.cpp | 97 + hiro/core/browser-window.cpp | 31 + hiro/core/color.cpp | 83 + hiro/core/core.cpp | 100 + hiro/core/core.hpp | 1571 +++++++ hiro/core/desktop.cpp | 7 + hiro/core/font.cpp | 15 + hiro/core/geometry.cpp | 112 + hiro/core/hotkey.cpp | 53 + hiro/core/keyboard.cpp | 74 + hiro/core/layout.cpp | 58 + hiro/core/menu-bar.cpp | 47 + hiro/core/message-window.cpp | 38 + hiro/core/monitor.cpp | 11 + hiro/core/mouse.cpp | 11 + hiro/core/object.cpp | 233 + hiro/core/popup-menu.cpp | 47 + hiro/core/position.cpp | 43 + hiro/core/sizable.cpp | 17 + hiro/core/size.cpp | 43 + hiro/core/status-bar.cpp | 20 + hiro/core/timer.cpp | 24 + hiro/core/widget/button.cpp | 54 + hiro/core/widget/canvas.cpp | 125 + hiro/core/widget/check-button.cpp | 64 + hiro/core/widget/check-label.cpp | 34 + hiro/core/widget/combo-button-item.cpp | 43 + hiro/core/widget/combo-button.cpp | 61 + hiro/core/widget/console.cpp | 54 + hiro/core/widget/frame.cpp | 42 + hiro/core/widget/hex-edit.cpp | 89 + hiro/core/widget/horizontal-scroller.cpp | 34 + hiro/core/widget/horizontal-slider.cpp | 34 + hiro/core/widget/icon-view-item.cpp | 40 + hiro/core/widget/icon-view.cpp | 148 + hiro/core/widget/label.cpp | 37 + hiro/core/widget/line-edit.cpp | 63 + hiro/core/widget/list-view-column.cpp | 135 + hiro/core/widget/list-view-item.cpp | 65 + hiro/core/widget/list-view.cpp | 228 + hiro/core/widget/progress-bar.cpp | 15 + hiro/core/widget/radio-button.cpp | 81 + hiro/core/widget/radio-label.cpp | 51 + hiro/core/widget/source-edit.cpp | 52 + hiro/core/widget/tab-frame-item.cpp | 95 + hiro/core/widget/tab-frame.cpp | 90 + hiro/core/widget/text-edit.cpp | 83 + hiro/core/widget/tree-view-item.cpp | 98 + hiro/core/widget/tree-view.cpp | 128 + hiro/core/widget/vertical-scroller.cpp | 34 + hiro/core/widget/vertical-slider.cpp | 34 + hiro/core/widget/viewport.cpp | 64 + hiro/core/widget/widget.cpp | 20 + hiro/core/window.cpp | 271 ++ hiro/extension/browser-dialog.cpp | 231 + hiro/extension/browser-dialog.hpp | 29 + hiro/extension/extension.cpp | 11 + hiro/extension/extension.hpp | 9 + hiro/extension/fixed-layout.cpp | 51 + hiro/extension/fixed-layout.hpp | 18 + hiro/extension/horizontal-layout.cpp | 125 + hiro/extension/horizontal-layout.hpp | 30 + hiro/extension/message-dialog.cpp | 77 + hiro/extension/message-dialog.hpp | 24 + hiro/extension/shared.hpp | 768 ++++ hiro/extension/vertical-layout.cpp | 127 + hiro/extension/vertical-layout.hpp | 30 + {phoenix => hiro}/gtk/action/action.cpp | 28 +- hiro/gtk/action/action.hpp | 15 + hiro/gtk/action/menu-check-item.cpp | 34 + hiro/gtk/action/menu-check-item.hpp | 11 + hiro/gtk/action/menu-item.cpp | 30 + hiro/gtk/action/menu-item.hpp | 10 + hiro/gtk/action/menu-radio-item.cpp | 75 + hiro/gtk/action/menu-radio-item.hpp | 14 + hiro/gtk/action/menu-separator.cpp | 11 + hiro/gtk/action/menu-separator.hpp | 7 + hiro/gtk/action/menu.cpp | 48 + hiro/gtk/action/menu.hpp | 15 + hiro/gtk/application.cpp | 84 + hiro/gtk/application.hpp | 14 + {phoenix => hiro}/gtk/browser-window.cpp | 18 +- hiro/gtk/browser-window.hpp | 9 + {phoenix => hiro}/gtk/desktop.cpp | 4 +- hiro/gtk/desktop.hpp | 8 + {phoenix => hiro}/gtk/font.cpp | 6 +- hiro/gtk/font.hpp | 16 + {phoenix => hiro}/gtk/header.hpp | 5 +- hiro/gtk/hotkey.cpp | 9 + hiro/gtk/hotkey.hpp | 7 + hiro/gtk/keyboard.cpp | 344 ++ hiro/gtk/keyboard.hpp | 13 + hiro/gtk/layout.cpp | 29 + hiro/gtk/layout.hpp | 11 + hiro/gtk/menu-bar.cpp | 45 + hiro/gtk/menu-bar.hpp | 15 + {phoenix => hiro}/gtk/message-window.cpp | 16 +- hiro/gtk/message-window.hpp | 10 + {phoenix => hiro}/gtk/monitor.cpp | 2 +- hiro/gtk/monitor.hpp | 9 + {phoenix => hiro}/gtk/mouse.cpp | 6 +- hiro/gtk/mouse.hpp | 8 + hiro/gtk/object.cpp | 31 + hiro/gtk/object.hpp | 27 + {phoenix => hiro}/gtk/platform.cpp | 30 +- hiro/gtk/platform.hpp | 75 + hiro/gtk/popup-menu.cpp | 32 + hiro/gtk/popup-menu.hpp | 14 + {phoenix => hiro}/gtk/settings.cpp | 4 +- hiro/gtk/settings.hpp | 26 + hiro/gtk/sizable.cpp | 16 + hiro/gtk/sizable.hpp | 10 + hiro/gtk/status-bar.cpp | 38 + hiro/gtk/status-bar.hpp | 14 + hiro/gtk/timer.cpp | 31 + hiro/gtk/timer.hpp | 10 + hiro/gtk/utility.cpp | 49 + hiro/gtk/widget/button.cpp | 68 + hiro/gtk/widget/button.hpp | 17 + hiro/gtk/widget/canvas.cpp | 212 + hiro/gtk/widget/canvas.hpp | 28 + hiro/gtk/widget/check-button.cpp | 73 + hiro/gtk/widget/check-button.hpp | 14 + hiro/gtk/widget/check-label.cpp | 39 + hiro/gtk/widget/check-label.hpp | 11 + hiro/gtk/widget/combo-button-item.cpp | 42 + hiro/gtk/widget/combo-button-item.hpp | 15 + hiro/gtk/widget/combo-button.cpp | 91 + hiro/gtk/widget/combo-button.hpp | 21 + {phoenix => hiro}/gtk/widget/console.cpp | 119 +- hiro/gtk/widget/console.hpp | 23 + hiro/gtk/widget/frame.cpp | 66 + hiro/gtk/widget/frame.hpp | 20 + {phoenix => hiro}/gtk/widget/hex-edit.cpp | 263 +- hiro/gtk/widget/hex-edit.hpp | 31 + hiro/gtk/widget/horizontal-scroller.cpp | 41 + hiro/gtk/widget/horizontal-scroller.hpp | 11 + hiro/gtk/widget/horizontal-slider.cpp | 40 + hiro/gtk/widget/horizontal-slider.hpp | 11 + hiro/gtk/widget/icon-view-item.cpp | 32 + hiro/gtk/widget/icon-view-item.hpp | 13 + hiro/gtk/widget/icon-view.cpp | 224 + hiro/gtk/widget/icon-view.hpp | 29 + hiro/gtk/widget/label.cpp | 41 + hiro/gtk/widget/label.hpp | 14 + hiro/gtk/widget/line-edit.cpp | 55 + hiro/gtk/widget/line-edit.hpp | 13 + hiro/gtk/widget/list-view-column.cpp | 133 + hiro/gtk/widget/list-view-column.hpp | 32 + hiro/gtk/widget/list-view-item.cpp | 59 + hiro/gtk/widget/list-view-item.hpp | 17 + hiro/gtk/widget/list-view.cpp | 369 ++ hiro/gtk/widget/list-view.hpp | 45 + hiro/gtk/widget/progress-bar.cpp | 24 + hiro/gtk/widget/progress-bar.hpp | 10 + hiro/gtk/widget/radio-button.cpp | 101 + hiro/gtk/widget/radio-button.hpp | 17 + hiro/gtk/widget/radio-label.cpp | 71 + hiro/gtk/widget/radio-label.hpp | 14 + hiro/gtk/widget/source-edit.cpp | 126 + hiro/gtk/widget/source-edit.hpp | 25 + hiro/gtk/widget/tab-frame-item.cpp | 46 + hiro/gtk/widget/tab-frame-item.hpp | 15 + hiro/gtk/widget/tab-frame.cpp | 265 ++ hiro/gtk/widget/tab-frame.hpp | 39 + hiro/gtk/widget/text-edit.cpp | 100 + hiro/gtk/widget/text-edit.hpp | 19 + hiro/gtk/widget/tree-view-item.cpp | 82 + hiro/gtk/widget/tree-view-item.hpp | 20 + hiro/gtk/widget/tree-view.cpp | 162 + hiro/gtk/widget/tree-view.hpp | 32 + hiro/gtk/widget/vertical-scroller.cpp | 41 + hiro/gtk/widget/vertical-scroller.hpp | 11 + hiro/gtk/widget/vertical-slider.cpp | 40 + hiro/gtk/widget/vertical-slider.hpp | 11 + hiro/gtk/widget/viewport.cpp | 78 + hiro/gtk/widget/viewport.hpp | 10 + hiro/gtk/widget/widget.cpp | 51 + hiro/gtk/widget/widget.hpp | 18 + hiro/gtk/window.cpp | 400 ++ hiro/gtk/window.hpp | 46 + hiro/hiro.cpp | 7 + hiro/hiro.hpp | 16 + {phoenix => hiro}/qt/action/action.cpp | 0 {phoenix => hiro}/qt/action/check-item.cpp | 0 {phoenix => hiro}/qt/action/item.cpp | 0 {phoenix => hiro}/qt/action/menu.cpp | 2 +- {phoenix => hiro}/qt/action/radio-item.cpp | 6 +- {phoenix => hiro}/qt/action/separator.cpp | 0 {phoenix => hiro}/qt/application.cpp | 0 {phoenix => hiro}/qt/browser-window.cpp | 0 {phoenix => hiro}/qt/desktop.cpp | 0 {phoenix => hiro}/qt/font.cpp | 4 +- {phoenix => hiro}/qt/header.hpp | 0 {phoenix/gtk => hiro/qt}/keyboard.cpp | 0 {phoenix => hiro}/qt/message-window.cpp | 0 {phoenix => hiro}/qt/monitor.cpp | 0 {phoenix => hiro}/qt/mouse.cpp | 0 {phoenix => hiro}/qt/platform.cpp | 2 + {phoenix => hiro}/qt/platform.moc | 199 +- {phoenix => hiro}/qt/platform.moc.hpp | 124 +- hiro/qt/popup-menu.cpp | 46 + {phoenix => hiro}/qt/settings.cpp | 0 {phoenix => hiro}/qt/timer.cpp | 0 {phoenix => hiro}/qt/utility.cpp | 1 + {phoenix => hiro}/qt/widget/button.cpp | 8 +- {phoenix => hiro}/qt/widget/canvas.cpp | 0 {phoenix => hiro}/qt/widget/check-button.cpp | 6 +- {phoenix => hiro}/qt/widget/check-label.cpp | 6 +- {phoenix => hiro}/qt/widget/combo-button.cpp | 36 +- {phoenix => hiro}/qt/widget/console.cpp | 7 + {phoenix => hiro}/qt/widget/frame.cpp | 0 {phoenix => hiro}/qt/widget/hex-edit.cpp | 13 +- .../qt/widget/horizontal-scroller.cpp | 0 .../qt/widget/horizontal-slider.cpp | 0 hiro/qt/widget/icon-view.cpp | 148 + {phoenix => hiro}/qt/widget/label.cpp | 0 {phoenix => hiro}/qt/widget/line-edit.cpp | 7 + hiro/qt/widget/list-view.cpp | 395 ++ {phoenix => hiro}/qt/widget/progress-bar.cpp | 0 {phoenix => hiro}/qt/widget/radio-button.cpp | 10 +- {phoenix => hiro}/qt/widget/radio-label.cpp | 10 +- {phoenix => hiro}/qt/widget/tab-frame.cpp | 16 +- {phoenix => hiro}/qt/widget/text-edit.cpp | 7 + .../qt/widget/vertical-scroller.cpp | 0 .../qt/widget/vertical-slider.cpp | 0 {phoenix => hiro}/qt/widget/viewport.cpp | 0 {phoenix => hiro}/qt/widget/widget.cpp | 0 {phoenix => hiro}/qt/window.cpp | 41 +- {phoenix => hiro}/reference/action/action.cpp | 0 {phoenix => hiro}/reference/action/action.hpp | 0 .../reference/action/check-item.cpp | 0 .../reference/action/check-item.hpp | 0 {phoenix => hiro}/reference/action/item.cpp | 0 {phoenix => hiro}/reference/action/item.hpp | 0 {phoenix => hiro}/reference/action/menu.cpp | 0 {phoenix => hiro}/reference/action/menu.hpp | 0 .../reference/action/radio-item.cpp | 0 .../reference/action/radio-item.hpp | 0 .../reference/action/separator.cpp | 0 .../reference/action/separator.hpp | 0 {phoenix => hiro}/reference/application.cpp | 0 {phoenix => hiro}/reference/application.hpp | 0 .../reference/browser-window.cpp | 0 .../reference/browser-window.hpp | 0 {phoenix => hiro}/reference/desktop.cpp | 0 {phoenix => hiro}/reference/desktop.hpp | 0 {phoenix => hiro}/reference/font.cpp | 0 {phoenix => hiro}/reference/font.hpp | 0 {phoenix => hiro}/reference/header.hpp | 0 {phoenix => hiro}/reference/keyboard.cpp | 0 {phoenix => hiro}/reference/keyboard.hpp | 0 .../reference/message-window.cpp | 0 .../reference/message-window.hpp | 0 {phoenix => hiro}/reference/monitor.cpp | 0 {phoenix => hiro}/reference/monitor.hpp | 0 {phoenix => hiro}/reference/mouse.cpp | 0 {phoenix => hiro}/reference/mouse.hpp | 0 {phoenix => hiro}/reference/object.cpp | 0 {phoenix => hiro}/reference/object.hpp | 0 {phoenix => hiro}/reference/platform.cpp | 1 + {phoenix => hiro}/reference/platform.hpp | 1 + hiro/reference/popup-menu.cpp | 18 + hiro/reference/popup-menu.hpp | 15 + {phoenix => hiro}/reference/timer.cpp | 0 {phoenix => hiro}/reference/timer.hpp | 0 {phoenix => hiro}/reference/widget/button.cpp | 3 + {phoenix => hiro}/reference/widget/button.hpp | 1 + {phoenix => hiro}/reference/widget/canvas.cpp | 0 {phoenix => hiro}/reference/widget/canvas.hpp | 0 .../reference/widget/check-button.cpp | 0 .../reference/widget/check-button.hpp | 0 .../reference/widget/check-label.cpp | 0 .../reference/widget/check-label.hpp | 0 .../reference/widget/combo-button.cpp | 4 +- .../reference/widget/combo-button.hpp | 4 +- .../reference/widget/console.cpp | 0 .../reference/widget/console.hpp | 0 {phoenix => hiro}/reference/widget/frame.cpp | 0 {phoenix => hiro}/reference/widget/frame.hpp | 0 .../reference/widget/hex-edit.cpp | 0 .../reference/widget/hex-edit.hpp | 0 .../reference/widget/horizontal-scroller.cpp | 0 .../reference/widget/horizontal-scroller.hpp | 0 .../reference/widget/horizontal-slider.cpp | 0 .../reference/widget/horizontal-slider.hpp | 0 {phoenix => hiro}/reference/widget/label.cpp | 0 {phoenix => hiro}/reference/widget/label.hpp | 0 {phoenix => hiro}/reference/widget/layout.hpp | 0 .../reference/widget/line-edit.cpp | 0 .../reference/widget/line-edit.hpp | 0 .../reference/widget/list-view.cpp | 24 +- .../reference/widget/list-view.hpp | 12 +- .../reference/widget/progress-bar.cpp | 0 .../reference/widget/progress-bar.hpp | 0 .../reference/widget/radio-button.cpp | 0 .../reference/widget/radio-button.hpp | 0 .../reference/widget/radio-label.cpp | 0 .../reference/widget/radio-label.hpp | 0 .../reference/widget/sizable.hpp | 0 .../reference/widget/tab-frame.cpp | 4 +- .../reference/widget/tab-frame.hpp | 4 +- .../reference/widget/text-edit.cpp | 0 .../reference/widget/text-edit.hpp | 0 .../reference/widget/vertical-scroller.cpp | 0 .../reference/widget/vertical-scroller.hpp | 0 .../reference/widget/vertical-slider.cpp | 0 .../reference/widget/vertical-slider.hpp | 0 .../reference/widget/viewport.cpp | 0 .../reference/widget/viewport.hpp | 0 {phoenix => hiro}/reference/widget/widget.cpp | 0 {phoenix => hiro}/reference/widget/widget.hpp | 0 {phoenix => hiro}/reference/window.cpp | 4 - {phoenix => hiro}/reference/window.hpp | 1 - hiro/resource/GNUmakefile | 13 + hiro/resource/icon/action/add.png | Bin 0 -> 323 bytes hiro/resource/icon/action/attach.png | Bin 0 -> 649 bytes hiro/resource/icon/action/bookmark.png | Bin 0 -> 686 bytes hiro/resource/icon/action/full-screen.png | Bin 0 -> 650 bytes hiro/resource/icon/action/mute.png | Bin 0 -> 632 bytes hiro/resource/icon/action/new.png | Bin 0 -> 477 bytes hiro/resource/icon/action/open.png | Bin 0 -> 672 bytes hiro/resource/icon/action/properties.png | Bin 0 -> 464 bytes hiro/resource/icon/action/quit.png | Bin 0 -> 799 bytes hiro/resource/icon/action/refresh.png | Bin 0 -> 912 bytes hiro/resource/icon/action/remove.png | Bin 0 -> 247 bytes hiro/resource/icon/action/save.png | Bin 0 -> 911 bytes hiro/resource/icon/action/search.png | Bin 0 -> 935 bytes .../resource/icon/action/settings.png | Bin hiro/resource/icon/action/stop.png | Bin 0 -> 820 bytes hiro/resource/icon/application/browser.png | Bin 0 -> 928 bytes hiro/resource/icon/application/calculator.png | Bin 0 -> 686 bytes hiro/resource/icon/application/calendar.png | Bin 0 -> 603 bytes hiro/resource/icon/application/chat.png | Bin 0 -> 422 bytes .../icon/application/file-manager.png | Bin hiro/resource/icon/application/mail.png | Bin 0 -> 550 bytes hiro/resource/icon/application/monitor.png | Bin 0 -> 611 bytes hiro/resource/icon/application/terminal.png | Bin 0 -> 668 bytes .../resource/icon/application/text-editor.png | Bin 0 -> 574 bytes .../resource/icon/device/clock.png | Bin .../resource/icon/device/display.png | Bin .../resource/icon/device/joypad.png | Bin .../resource/icon/device/keyboard.png | Bin hiro/resource/icon/device/microphone.png | Bin 0 -> 703 bytes hiro/resource/icon/device/mouse.png | Bin 0 -> 720 bytes .../resource/icon/device/network.png | Bin hiro/resource/icon/device/optical.png | Bin 0 -> 720 bytes hiro/resource/icon/device/printer.png | Bin 0 -> 481 bytes .../resource/icon/device/speaker.png | Bin hiro/resource/icon/device/storage.png | Bin 0 -> 603 bytes hiro/resource/icon/edit/clear.png | Bin 0 -> 773 bytes hiro/resource/icon/edit/copy.png | Bin 0 -> 498 bytes hiro/resource/icon/edit/cut.png | Bin 0 -> 807 bytes hiro/resource/icon/edit/delete.png | Bin 0 -> 680 bytes hiro/resource/icon/edit/find.png | Bin 0 -> 617 bytes hiro/resource/icon/edit/paste.png | Bin 0 -> 561 bytes hiro/resource/icon/edit/redo.png | Bin 0 -> 591 bytes hiro/resource/icon/edit/replace.png | Bin 0 -> 776 bytes hiro/resource/icon/edit/undo.png | Bin 0 -> 650 bytes hiro/resource/icon/emblem/archive.png | Bin 0 -> 540 bytes hiro/resource/icon/emblem/audio.png | Bin 0 -> 688 bytes hiro/resource/icon/emblem/binary.png | Bin 0 -> 560 bytes hiro/resource/icon/emblem/file.png | Bin 0 -> 741 bytes hiro/resource/icon/emblem/folder.png | Bin 0 -> 581 bytes hiro/resource/icon/emblem/font.png | Bin 0 -> 627 bytes hiro/resource/icon/emblem/image.png | Bin 0 -> 558 bytes hiro/resource/icon/emblem/markup.png | Bin 0 -> 709 bytes hiro/resource/icon/emblem/program.png | Bin 0 -> 609 bytes hiro/resource/icon/emblem/script.png | Bin 0 -> 516 bytes hiro/resource/icon/emblem/text.png | Bin 0 -> 333 bytes hiro/resource/icon/emblem/video.png | Bin 0 -> 592 bytes hiro/resource/icon/go/down.png | Bin 0 -> 683 bytes .../resource/icon/go}/home.png | Bin hiro/resource/icon/go/left.png | Bin 0 -> 655 bytes hiro/resource/icon/go/right.png | Bin 0 -> 676 bytes .../resource => hiro/resource/icon/go}/up.png | Bin hiro/resource/icon/media/back.png | Bin 0 -> 770 bytes hiro/resource/icon/media/eject.png | Bin 0 -> 628 bytes hiro/resource/icon/media/flash.png | Bin 0 -> 607 bytes hiro/resource/icon/media/floppy.png | Bin 0 -> 561 bytes hiro/resource/icon/media/next.png | Bin 0 -> 771 bytes hiro/resource/icon/media/optical.png | Bin 0 -> 931 bytes hiro/resource/icon/media/pause.png | Bin 0 -> 464 bytes hiro/resource/icon/media/play.png | Bin 0 -> 660 bytes hiro/resource/icon/media/record.png | Bin 0 -> 653 bytes hiro/resource/icon/media/rewind.png | Bin 0 -> 764 bytes hiro/resource/icon/media/skip.png | Bin 0 -> 782 bytes hiro/resource/icon/media/stop.png | Bin 0 -> 429 bytes hiro/resource/icon/place/bookmarks.png | Bin 0 -> 753 bytes hiro/resource/icon/place/desktop.png | Bin 0 -> 722 bytes hiro/resource/icon/place/home.png | Bin 0 -> 679 bytes hiro/resource/icon/place/server.png | Bin 0 -> 642 bytes hiro/resource/icon/place/share.png | Bin 0 -> 697 bytes hiro/resource/icon/prompt/error.png | Bin 0 -> 653 bytes hiro/resource/icon/prompt/information.png | Bin 0 -> 863 bytes hiro/resource/icon/prompt/question.png | Bin 0 -> 932 bytes hiro/resource/icon/prompt/warning.png | Bin 0 -> 603 bytes hiro/resource/resource.bml | 92 + hiro/resource/resource.cpp | 1891 ++++++++ hiro/resource/resource.hpp | 102 + {phoenix => hiro}/windows/action/action.cpp | 0 .../windows/action/check-item.cpp | 0 {phoenix => hiro}/windows/action/item.cpp | 0 {phoenix => hiro}/windows/action/menu.cpp | 0 .../windows/action/radio-item.cpp | 0 .../windows/action/separator.cpp | 0 {phoenix => hiro}/windows/application.cpp | 0 {phoenix => hiro}/windows/browser-window.cpp | 2 +- {phoenix => hiro}/windows/desktop.cpp | 0 {phoenix => hiro}/windows/font.cpp | 4 +- {phoenix => hiro}/windows/header.hpp | 0 {phoenix => hiro}/windows/keyboard.cpp | 0 {phoenix => hiro}/windows/message-window.cpp | 0 {phoenix => hiro}/windows/monitor.cpp | 0 {phoenix => hiro}/windows/mouse.cpp | 0 {phoenix => hiro}/windows/object.cpp | 0 {phoenix => hiro}/windows/phoenix.Manifest | 0 {phoenix => hiro}/windows/phoenix.rc | 0 {phoenix => hiro}/windows/platform.cpp | 0 {phoenix => hiro}/windows/platform.hpp | 5 + {phoenix => hiro}/windows/settings.cpp | 0 {phoenix => hiro}/windows/timer.cpp | 0 {phoenix => hiro}/windows/utility.cpp | 36 +- {phoenix => hiro}/windows/widget/button.cpp | 6 +- {phoenix => hiro}/windows/widget/canvas.cpp | 0 .../windows/widget/check-button.cpp | 0 .../windows/widget/check-label.cpp | 0 .../windows/widget/combo-button.cpp | 0 {phoenix => hiro}/windows/widget/console.cpp | 3 + {phoenix => hiro}/windows/widget/frame.cpp | 0 {phoenix => hiro}/windows/widget/hex-edit.cpp | 3 + .../windows/widget/horizontal-scroller.cpp | 0 .../windows/widget/horizontal-slider.cpp | 0 {phoenix => hiro}/windows/widget/label.cpp | 0 .../windows/widget/line-edit.cpp | 3 + .../windows/widget/list-view.cpp | 25 +- .../windows/widget/progress-bar.cpp | 0 .../windows/widget/radio-button.cpp | 0 .../windows/widget/radio-label.cpp | 0 .../windows/widget/tab-frame.cpp | 0 .../windows/widget/text-edit.cpp | 3 + .../windows/widget/vertical-scroller.cpp | 0 .../windows/widget/vertical-slider.cpp | 0 {phoenix => hiro}/windows/widget/viewport.cpp | 0 {phoenix => hiro}/windows/widget/widget.cpp | 0 {phoenix => hiro}/windows/window.cpp | 6 +- nall/{Makefile => GNUmakefile} | 26 +- nall/algorithm.hpp | 16 +- nall/any.hpp | 8 +- nall/beat/archive.hpp | 22 +- nall/beat/base.hpp | 20 +- nall/beat/delta.hpp | 14 +- nall/beat/linear.hpp | 11 +- nall/beat/metadata.hpp | 7 +- nall/beat/multi.hpp | 34 +- nall/beat/patch.hpp | 14 +- nall/config.hpp | 2 +- nall/crc16.hpp | 27 - nall/decode/bmp.hpp | 8 + nall/{ => decode}/gzip.hpp | 24 +- nall/{ => decode}/inflate.hpp | 8 +- nall/{ => decode}/png.hpp | 39 +- nall/{unzip.hpp => decode/zip.hpp} | 14 +- nall/directory.hpp | 45 +- nall/dl.hpp | 18 +- nall/file.hpp | 106 +- nall/function.hpp | 21 +- nall/hash/crc16.hpp | 43 + nall/{ => hash}/crc32.hpp | 47 +- nall/hash/sha256.hpp | 111 + nall/http.hpp | 176 - nall/http/client.hpp | 59 + nall/http/message.hpp | 77 + nall/http/request.hpp | 146 + nall/http/response.hpp | 253 ++ nall/http/role.hpp | 161 + nall/http/server.hpp | 136 + nall/image.hpp | 3 +- nall/image/base.hpp | 2 + nall/image/core.hpp | 8 + nall/image/load.hpp | 2 +- nall/intrinsics.hpp | 18 + nall/invoke.hpp | 2 +- nall/main.hpp | 29 + nall/maybe.hpp | 95 +- nall/memory.hpp | 8 + nall/memory/memory.hpp | 131 + nall/memory/pool.hpp | 64 + nall/method.hpp | 59 + nall/mosaic/context.hpp | 21 +- nall/nall.hpp | 28 +- nall/platform.hpp | 51 +- nall/range.hpp | 48 + nall/service.hpp | 120 + nall/sha256.hpp | 147 - nall/shared-memory.hpp | 157 + nall/shared-pointer.hpp | 268 ++ nall/smtp.hpp | 2 +- nall/storage.hpp | 95 + nall/stream.hpp | 6 +- nall/stream/auto.hpp | 1 - nall/stream/gzip.hpp | 4 +- nall/stream/http.hpp | 49 - nall/stream/stream.hpp | 1 - nall/stream/zip.hpp | 4 +- nall/string.hpp | 23 +- nall/string/allocator/adaptive.hpp | 123 + nall/string/allocator/copy-on-write.hpp | 132 +- .../allocator/small-string-optimization.hpp | 126 +- nall/string/allocator/vector.hpp | 70 +- nall/string/base.hpp | 475 +- nall/string/cast.hpp | 216 +- nall/string/char.hpp | 13 - nall/string/char/base.hpp | 69 - nall/string/char/compare.hpp | 81 - nall/string/char/convert.hpp | 68 - nall/string/char/strm.hpp | 41 - nall/string/char/strpos.hpp | 33 - nall/string/char/trim.hpp | 62 - nall/string/char/utf8.hpp | 37 - nall/string/char/utility.hpp | 50 - nall/string/compare.hpp | 50 + nall/string/convert.hpp | 55 + nall/string/core.hpp | 95 +- nall/string/datetime.hpp | 25 +- nall/string/eval/evaluator.hpp | 2 +- nall/string/file.hpp | 31 - nall/string/filename.hpp | 84 - nall/string/find.hpp | 30 + nall/string/format.hpp | 151 +- nall/string/hash.hpp | 35 + nall/string/list.hpp | 87 +- nall/string/markup/bml.hpp | 4 +- nall/string/markup/node.hpp | 8 +- nall/string/markup/xml.hpp | 34 +- nall/string/{char => }/match.hpp | 37 +- nall/string/path.hpp | 73 + nall/string/platform.hpp | 16 +- nall/string/ref.hpp | 39 +- nall/string/replace.hpp | 109 +- nall/string/split.hpp | 58 +- nall/string/transform/cml.hpp | 93 + nall/string/transform/dml.hpp | 259 ++ nall/string/trim.hpp | 82 + nall/string/utility.hpp | 135 +- nall/string/variadic.hpp | 20 - nall/string/wrapper.hpp | 124 - nall/thread.hpp | 185 +- nall/traits.hpp | 53 +- nall/varint.hpp | 4 +- nall/vector.hpp | 9 +- nall/windows/detour.hpp | 2 +- nall/windows/registry.hpp | 2 +- nall/windows/utf8.hpp | 6 +- nall/zip.hpp | 4 +- out/.gitignore | 1 - phoenix/Makefile | 24 - phoenix/core/core.cpp | 2046 --------- phoenix/core/core.hpp | 826 ---- phoenix/core/keyboard.hpp | 45 - phoenix/core/layout/fixed-layout.cpp | 68 - phoenix/core/layout/fixed-layout.hpp | 19 - phoenix/core/layout/horizontal-layout.cpp | 127 - phoenix/core/layout/horizontal-layout.hpp | 26 - phoenix/core/layout/vertical-layout.cpp | 127 - phoenix/core/layout/vertical-layout.hpp | 26 - phoenix/core/state.hpp | 227 - phoenix/gtk/action/check-item.cpp | 34 - phoenix/gtk/action/item.cpp | 35 - phoenix/gtk/action/menu.cpp | 55 - phoenix/gtk/action/radio-item.cpp | 62 - phoenix/gtk/action/separator.cpp | 16 - phoenix/gtk/application.cpp | 60 - phoenix/gtk/platform.hpp | 640 --- phoenix/gtk/timer.cpp | 28 - phoenix/gtk/utility.cpp | 259 -- phoenix/gtk/widget/button.cpp | 57 - phoenix/gtk/widget/canvas.cpp | 177 - phoenix/gtk/widget/check-button.cpp | 70 - phoenix/gtk/widget/check-label.cpp | 40 - phoenix/gtk/widget/combo-button.cpp | 74 - phoenix/gtk/widget/frame.cpp | 48 - phoenix/gtk/widget/horizontal-scroller.cpp | 43 - phoenix/gtk/widget/horizontal-slider.cpp | 42 - phoenix/gtk/widget/label.cpp | 28 - phoenix/gtk/widget/line-edit.cpp | 59 - phoenix/gtk/widget/list-view.cpp | 216 - phoenix/gtk/widget/progress-bar.cpp | 27 - phoenix/gtk/widget/radio-button.cpp | 89 - phoenix/gtk/widget/radio-label.cpp | 69 - phoenix/gtk/widget/tab-frame.cpp | 126 - phoenix/gtk/widget/text-edit.cpp | 88 - phoenix/gtk/widget/vertical-scroller.cpp | 43 - phoenix/gtk/widget/vertical-slider.cpp | 42 - phoenix/gtk/widget/viewport.cpp | 76 - phoenix/gtk/widget/widget.cpp | 62 - phoenix/gtk/window.cpp | 402 -- phoenix/phoenix.cpp | 6 - phoenix/phoenix.hpp | 6 - phoenix/qt/keyboard.cpp | 149 - phoenix/qt/widget/list-view.cpp | 156 - processor/{Makefile => GNUmakefile} | 0 processor/arm/disassembler.cpp | 6 +- processor/lr35902/disassembler.cpp | 6 +- processor/r6502/disassembler.cpp | 2 +- ruby/{Makefile => GNUmakefile} | 0 ruby/ruby.cpp | 1 + ruby/ruby.hpp | 13 +- ruby/video/opengl/main.hpp | 4 +- ruby/video/opengl/program.hpp | 6 +- ruby/video/sdl.cpp | 1 + ruby/video/xshm.cpp | 120 +- sfc/{Makefile => GNUmakefile} | 0 sfc/cartridge/cartridge.cpp | 52 +- sfc/chip/event/event.cpp | 6 +- sfc/chip/hsu1/hsu1.cpp | 6 +- sfc/system/serialization.cpp | 2 +- target-higan/GNUmakefile | 53 + target-higan/Makefile | 117 - target-higan/bootstrap.cpp | 15 - target-higan/configuration/configuration.cpp | 60 - target-higan/configuration/configuration.hpp | 60 - target-higan/general/dip-switches.cpp | 66 - target-higan/general/dip-switches.hpp | 22 - target-higan/general/general.cpp | 4 - target-higan/general/general.hpp | 3 - target-higan/general/library.cpp | 298 -- target-higan/general/library.hpp | 55 - target-higan/general/presentation.cpp | 257 -- target-higan/general/presentation.hpp | 63 - target-higan/higan.cpp | 173 +- target-higan/higan.hpp | 59 +- target-higan/input/hotkeys.cpp | 146 - target-higan/input/input.cpp | 294 -- target-higan/input/input.hpp | 71 - target-higan/interface/interface.cpp | 139 - target-higan/interface/interface.hpp | 16 - target-higan/resource.rc | 2 - target-higan/resource/cheat-editor.png | Bin 937 -> 0 bytes target-higan/resource/folder.png | Bin 1176 -> 0 bytes target-higan/resource/game.png | Bin 1490 -> 0 bytes target-higan/resource/resource.bml | 15 - target-higan/resource/resource.cpp | 411 -- target-higan/resource/resource.hpp | 16 - target-higan/resource/unverified.png | Bin 1675 -> 0 bytes target-higan/settings/advanced.cpp | 81 - target-higan/settings/advanced.hpp | 26 - target-higan/settings/audio.cpp | 79 - target-higan/settings/audio.hpp | 23 - target-higan/settings/hotkey.cpp | 58 - target-higan/settings/hotkey.hpp | 18 - target-higan/settings/input.cpp | 187 - target-higan/settings/input.hpp | 38 - target-higan/settings/server.cpp | 29 - target-higan/settings/server.hpp | 14 - target-higan/settings/settings.cpp | 46 - target-higan/settings/settings.hpp | 20 - target-higan/settings/timing.cpp | 126 - target-higan/settings/timing.hpp | 34 - target-higan/settings/video.cpp | 64 - target-higan/settings/video.hpp | 23 - target-higan/tools/cheat-database.cpp | 68 - target-higan/tools/cheat-database.hpp | 22 - target-higan/tools/cheat-editor.cpp | 178 - target-higan/tools/cheat-editor.hpp | 38 - target-higan/tools/state-manager.cpp | 153 - target-higan/tools/state-manager.hpp | 36 - target-higan/tools/tools.cpp | 25 - target-higan/tools/tools.hpp | 16 - target-higan/utility/utility.cpp | 314 -- target-higan/utility/utility.hpp | 42 - target-higan/window/window.cpp | 39 - target-higan/window/window.hpp | 18 - target-loki/Makefile | 96 - target-loki/debugger/debugger.cpp | 479 --- target-loki/debugger/debugger.hpp | 92 - target-loki/input/input.cpp | 82 - target-loki/input/input.hpp | 25 - target-loki/interface/interface.cpp | 117 - target-loki/interface/interface.hpp | 25 - target-loki/loki.cpp | 97 - target-loki/loki.hpp | 47 - target-loki/presentation/presentation.cpp | 39 - target-loki/presentation/presentation.hpp | 11 - target-loki/resource/loki.png | Bin 121905 -> 0 bytes target-loki/resource/resource.bml | 2 - target-loki/resource/resource.cpp | 3816 ----------------- target-loki/resource/resource.hpp | 3 - target-loki/settings/settings.cpp | 57 - target-loki/settings/settings.hpp | 34 - target-loki/terminal/terminal.cpp | 384 -- target-loki/terminal/terminal.hpp | 31 - 793 files changed, 20182 insertions(+), 19416 deletions(-) rename Makefile => GNUmakefile (75%) rename fc/{Makefile => GNUmakefile} (100%) rename gb/{Makefile => GNUmakefile} (100%) rename gba/{Makefile => GNUmakefile} (100%) create mode 100644 hiro/GNUmakefile rename {phoenix => hiro}/cocoa/action/action.cpp (100%) rename {phoenix => hiro}/cocoa/action/action.hpp (100%) rename {phoenix => hiro}/cocoa/action/check-item.cpp (100%) rename {phoenix => hiro}/cocoa/action/check-item.hpp (100%) rename {phoenix => hiro}/cocoa/action/item.cpp (100%) rename {phoenix => hiro}/cocoa/action/item.hpp (100%) rename {phoenix => hiro}/cocoa/action/menu.cpp (100%) rename {phoenix => hiro}/cocoa/action/menu.hpp (100%) rename {phoenix => hiro}/cocoa/action/radio-item.cpp (100%) rename {phoenix => hiro}/cocoa/action/radio-item.hpp (100%) rename {phoenix => hiro}/cocoa/action/separator.cpp (100%) rename {phoenix => hiro}/cocoa/action/separator.hpp (100%) rename {phoenix => hiro}/cocoa/application.cpp (100%) rename {phoenix => hiro}/cocoa/application.hpp (100%) rename {phoenix => hiro}/cocoa/browser-window.cpp (94%) rename {phoenix => hiro}/cocoa/browser-window.hpp (100%) rename {phoenix => hiro}/cocoa/desktop.cpp (100%) rename {phoenix => hiro}/cocoa/desktop.hpp (100%) rename {phoenix => hiro}/cocoa/font.cpp (100%) rename {phoenix => hiro}/cocoa/font.hpp (100%) rename {phoenix => hiro}/cocoa/header.hpp (100%) rename {phoenix => hiro}/cocoa/keyboard.cpp (100%) rename {phoenix => hiro}/cocoa/keyboard.hpp (100%) rename {phoenix => hiro}/cocoa/message-window.cpp (100%) rename {phoenix => hiro}/cocoa/message-window.hpp (100%) rename {phoenix => hiro}/cocoa/monitor.cpp (100%) rename {phoenix => hiro}/cocoa/monitor.hpp (100%) rename {phoenix => hiro}/cocoa/mouse.cpp (100%) rename {phoenix => hiro}/cocoa/mouse.hpp (100%) rename {phoenix => hiro}/cocoa/object.cpp (100%) rename {phoenix => hiro}/cocoa/object.hpp (100%) rename {phoenix => hiro}/cocoa/platform.cpp (100%) rename {phoenix => hiro}/cocoa/platform.hpp (100%) rename {phoenix => hiro}/cocoa/timer.cpp (100%) rename {phoenix => hiro}/cocoa/timer.hpp (100%) rename {phoenix => hiro}/cocoa/utility.cpp (100%) rename {phoenix => hiro}/cocoa/widget/button.cpp (94%) rename {phoenix => hiro}/cocoa/widget/button.hpp (93%) rename {phoenix => hiro}/cocoa/widget/canvas.cpp (100%) rename {phoenix => hiro}/cocoa/widget/canvas.hpp (100%) rename {phoenix => hiro}/cocoa/widget/check-button.cpp (100%) rename {phoenix => hiro}/cocoa/widget/check-button.hpp (100%) rename {phoenix => hiro}/cocoa/widget/check-label.cpp (100%) rename {phoenix => hiro}/cocoa/widget/check-label.hpp (100%) rename {phoenix => hiro}/cocoa/widget/combo-button.cpp (100%) rename {phoenix => hiro}/cocoa/widget/combo-button.hpp (100%) rename {phoenix => hiro}/cocoa/widget/console.cpp (100%) rename {phoenix => hiro}/cocoa/widget/console.hpp (100%) rename {phoenix => hiro}/cocoa/widget/frame.cpp (100%) rename {phoenix => hiro}/cocoa/widget/frame.hpp (100%) rename {phoenix => hiro}/cocoa/widget/hex-edit.cpp (100%) rename {phoenix => hiro}/cocoa/widget/hex-edit.hpp (100%) rename {phoenix => hiro}/cocoa/widget/horizontal-scroller.cpp (100%) rename {phoenix => hiro}/cocoa/widget/horizontal-scroller.hpp (100%) rename {phoenix => hiro}/cocoa/widget/horizontal-slider.cpp (100%) rename {phoenix => hiro}/cocoa/widget/horizontal-slider.hpp (100%) rename {phoenix => hiro}/cocoa/widget/label.cpp (100%) rename {phoenix => hiro}/cocoa/widget/label.hpp (100%) rename {phoenix => hiro}/cocoa/widget/layout.hpp (100%) rename {phoenix => hiro}/cocoa/widget/line-edit.cpp (100%) rename {phoenix => hiro}/cocoa/widget/line-edit.hpp (100%) rename {phoenix => hiro}/cocoa/widget/list-view.cpp (100%) rename {phoenix => hiro}/cocoa/widget/list-view.hpp (100%) rename {phoenix => hiro}/cocoa/widget/progress-bar.cpp (100%) rename {phoenix => hiro}/cocoa/widget/progress-bar.hpp (100%) rename {phoenix => hiro}/cocoa/widget/radio-button.cpp (100%) rename {phoenix => hiro}/cocoa/widget/radio-button.hpp (100%) rename {phoenix => hiro}/cocoa/widget/radio-label.cpp (100%) rename {phoenix => hiro}/cocoa/widget/radio-label.hpp (100%) rename {phoenix => hiro}/cocoa/widget/sizable.hpp (100%) rename {phoenix => hiro}/cocoa/widget/tab-frame.cpp (100%) rename {phoenix => hiro}/cocoa/widget/tab-frame.hpp (100%) rename {phoenix => hiro}/cocoa/widget/text-edit.cpp (100%) rename {phoenix => hiro}/cocoa/widget/text-edit.hpp (100%) rename {phoenix => hiro}/cocoa/widget/vertical-scroller.cpp (100%) rename {phoenix => hiro}/cocoa/widget/vertical-scroller.hpp (100%) rename {phoenix => hiro}/cocoa/widget/vertical-slider.cpp (100%) rename {phoenix => hiro}/cocoa/widget/vertical-slider.hpp (100%) rename {phoenix => hiro}/cocoa/widget/viewport.cpp (100%) rename {phoenix => hiro}/cocoa/widget/viewport.hpp (100%) rename {phoenix => hiro}/cocoa/widget/widget.cpp (100%) rename {phoenix => hiro}/cocoa/widget/widget.hpp (100%) rename {phoenix => hiro}/cocoa/window.cpp (100%) rename {phoenix => hiro}/cocoa/window.hpp (100%) create mode 100644 hiro/core/action/action.cpp create mode 100644 hiro/core/action/menu-check-item.cpp create mode 100644 hiro/core/action/menu-item.cpp create mode 100644 hiro/core/action/menu-radio-item.cpp create mode 100644 hiro/core/action/menu-separator.cpp create mode 100644 hiro/core/action/menu.cpp create mode 100644 hiro/core/application.cpp create mode 100644 hiro/core/browser-window.cpp create mode 100644 hiro/core/color.cpp create mode 100644 hiro/core/core.cpp create mode 100644 hiro/core/core.hpp create mode 100644 hiro/core/desktop.cpp create mode 100644 hiro/core/font.cpp create mode 100644 hiro/core/geometry.cpp create mode 100644 hiro/core/hotkey.cpp create mode 100644 hiro/core/keyboard.cpp create mode 100644 hiro/core/layout.cpp create mode 100644 hiro/core/menu-bar.cpp create mode 100644 hiro/core/message-window.cpp create mode 100644 hiro/core/monitor.cpp create mode 100644 hiro/core/mouse.cpp create mode 100644 hiro/core/object.cpp create mode 100644 hiro/core/popup-menu.cpp create mode 100644 hiro/core/position.cpp create mode 100644 hiro/core/sizable.cpp create mode 100644 hiro/core/size.cpp create mode 100644 hiro/core/status-bar.cpp create mode 100644 hiro/core/timer.cpp create mode 100644 hiro/core/widget/button.cpp create mode 100644 hiro/core/widget/canvas.cpp create mode 100644 hiro/core/widget/check-button.cpp create mode 100644 hiro/core/widget/check-label.cpp create mode 100644 hiro/core/widget/combo-button-item.cpp create mode 100644 hiro/core/widget/combo-button.cpp create mode 100644 hiro/core/widget/console.cpp create mode 100644 hiro/core/widget/frame.cpp create mode 100644 hiro/core/widget/hex-edit.cpp create mode 100644 hiro/core/widget/horizontal-scroller.cpp create mode 100644 hiro/core/widget/horizontal-slider.cpp create mode 100644 hiro/core/widget/icon-view-item.cpp create mode 100644 hiro/core/widget/icon-view.cpp create mode 100644 hiro/core/widget/label.cpp create mode 100644 hiro/core/widget/line-edit.cpp create mode 100644 hiro/core/widget/list-view-column.cpp create mode 100644 hiro/core/widget/list-view-item.cpp create mode 100644 hiro/core/widget/list-view.cpp create mode 100644 hiro/core/widget/progress-bar.cpp create mode 100644 hiro/core/widget/radio-button.cpp create mode 100644 hiro/core/widget/radio-label.cpp create mode 100644 hiro/core/widget/source-edit.cpp create mode 100644 hiro/core/widget/tab-frame-item.cpp create mode 100644 hiro/core/widget/tab-frame.cpp create mode 100644 hiro/core/widget/text-edit.cpp create mode 100644 hiro/core/widget/tree-view-item.cpp create mode 100644 hiro/core/widget/tree-view.cpp create mode 100644 hiro/core/widget/vertical-scroller.cpp create mode 100644 hiro/core/widget/vertical-slider.cpp create mode 100644 hiro/core/widget/viewport.cpp create mode 100644 hiro/core/widget/widget.cpp create mode 100644 hiro/core/window.cpp create mode 100644 hiro/extension/browser-dialog.cpp create mode 100644 hiro/extension/browser-dialog.hpp create mode 100644 hiro/extension/extension.cpp create mode 100644 hiro/extension/extension.hpp create mode 100644 hiro/extension/fixed-layout.cpp create mode 100644 hiro/extension/fixed-layout.hpp create mode 100644 hiro/extension/horizontal-layout.cpp create mode 100644 hiro/extension/horizontal-layout.hpp create mode 100644 hiro/extension/message-dialog.cpp create mode 100644 hiro/extension/message-dialog.hpp create mode 100644 hiro/extension/shared.hpp create mode 100644 hiro/extension/vertical-layout.cpp create mode 100644 hiro/extension/vertical-layout.hpp rename {phoenix => hiro}/gtk/action/action.cpp (56%) create mode 100644 hiro/gtk/action/action.hpp create mode 100644 hiro/gtk/action/menu-check-item.cpp create mode 100644 hiro/gtk/action/menu-check-item.hpp create mode 100644 hiro/gtk/action/menu-item.cpp create mode 100644 hiro/gtk/action/menu-item.hpp create mode 100644 hiro/gtk/action/menu-radio-item.cpp create mode 100644 hiro/gtk/action/menu-radio-item.hpp create mode 100644 hiro/gtk/action/menu-separator.cpp create mode 100644 hiro/gtk/action/menu-separator.hpp create mode 100644 hiro/gtk/action/menu.cpp create mode 100644 hiro/gtk/action/menu.hpp create mode 100644 hiro/gtk/application.cpp create mode 100644 hiro/gtk/application.hpp rename {phoenix => hiro}/gtk/browser-window.cpp (78%) create mode 100644 hiro/gtk/browser-window.hpp rename {phoenix => hiro}/gtk/desktop.cpp (88%) create mode 100644 hiro/gtk/desktop.hpp rename {phoenix => hiro}/gtk/font.cpp (95%) create mode 100644 hiro/gtk/font.hpp rename {phoenix => hiro}/gtk/header.hpp (56%) create mode 100644 hiro/gtk/hotkey.cpp create mode 100644 hiro/gtk/hotkey.hpp create mode 100644 hiro/gtk/keyboard.cpp create mode 100644 hiro/gtk/keyboard.hpp create mode 100644 hiro/gtk/layout.cpp create mode 100644 hiro/gtk/layout.hpp create mode 100644 hiro/gtk/menu-bar.cpp create mode 100644 hiro/gtk/menu-bar.hpp rename {phoenix => hiro}/gtk/message-window.cpp (73%) create mode 100644 hiro/gtk/message-window.hpp rename {phoenix => hiro}/gtk/monitor.cpp (95%) create mode 100644 hiro/gtk/monitor.hpp rename {phoenix => hiro}/gtk/mouse.cpp (86%) create mode 100644 hiro/gtk/mouse.hpp create mode 100644 hiro/gtk/object.cpp create mode 100644 hiro/gtk/object.hpp rename {phoenix => hiro}/gtk/platform.cpp (63%) create mode 100644 hiro/gtk/platform.hpp create mode 100644 hiro/gtk/popup-menu.cpp create mode 100644 hiro/gtk/popup-menu.hpp rename {phoenix => hiro}/gtk/settings.cpp (93%) create mode 100644 hiro/gtk/settings.hpp create mode 100644 hiro/gtk/sizable.cpp create mode 100644 hiro/gtk/sizable.hpp create mode 100644 hiro/gtk/status-bar.cpp create mode 100644 hiro/gtk/status-bar.hpp create mode 100644 hiro/gtk/timer.cpp create mode 100644 hiro/gtk/timer.hpp create mode 100644 hiro/gtk/utility.cpp create mode 100644 hiro/gtk/widget/button.cpp create mode 100644 hiro/gtk/widget/button.hpp create mode 100644 hiro/gtk/widget/canvas.cpp create mode 100644 hiro/gtk/widget/canvas.hpp create mode 100644 hiro/gtk/widget/check-button.cpp create mode 100644 hiro/gtk/widget/check-button.hpp create mode 100644 hiro/gtk/widget/check-label.cpp create mode 100644 hiro/gtk/widget/check-label.hpp create mode 100644 hiro/gtk/widget/combo-button-item.cpp create mode 100644 hiro/gtk/widget/combo-button-item.hpp create mode 100644 hiro/gtk/widget/combo-button.cpp create mode 100644 hiro/gtk/widget/combo-button.hpp rename {phoenix => hiro}/gtk/widget/console.cpp (76%) create mode 100644 hiro/gtk/widget/console.hpp create mode 100644 hiro/gtk/widget/frame.cpp create mode 100644 hiro/gtk/widget/frame.hpp rename {phoenix => hiro}/gtk/widget/hex-edit.cpp (57%) create mode 100644 hiro/gtk/widget/hex-edit.hpp create mode 100644 hiro/gtk/widget/horizontal-scroller.cpp create mode 100644 hiro/gtk/widget/horizontal-scroller.hpp create mode 100644 hiro/gtk/widget/horizontal-slider.cpp create mode 100644 hiro/gtk/widget/horizontal-slider.hpp create mode 100644 hiro/gtk/widget/icon-view-item.cpp create mode 100644 hiro/gtk/widget/icon-view-item.hpp create mode 100644 hiro/gtk/widget/icon-view.cpp create mode 100644 hiro/gtk/widget/icon-view.hpp create mode 100644 hiro/gtk/widget/label.cpp create mode 100644 hiro/gtk/widget/label.hpp create mode 100644 hiro/gtk/widget/line-edit.cpp create mode 100644 hiro/gtk/widget/line-edit.hpp create mode 100644 hiro/gtk/widget/list-view-column.cpp create mode 100644 hiro/gtk/widget/list-view-column.hpp create mode 100644 hiro/gtk/widget/list-view-item.cpp create mode 100644 hiro/gtk/widget/list-view-item.hpp create mode 100644 hiro/gtk/widget/list-view.cpp create mode 100644 hiro/gtk/widget/list-view.hpp create mode 100644 hiro/gtk/widget/progress-bar.cpp create mode 100644 hiro/gtk/widget/progress-bar.hpp create mode 100644 hiro/gtk/widget/radio-button.cpp create mode 100644 hiro/gtk/widget/radio-button.hpp create mode 100644 hiro/gtk/widget/radio-label.cpp create mode 100644 hiro/gtk/widget/radio-label.hpp create mode 100644 hiro/gtk/widget/source-edit.cpp create mode 100644 hiro/gtk/widget/source-edit.hpp create mode 100644 hiro/gtk/widget/tab-frame-item.cpp create mode 100644 hiro/gtk/widget/tab-frame-item.hpp create mode 100644 hiro/gtk/widget/tab-frame.cpp create mode 100644 hiro/gtk/widget/tab-frame.hpp create mode 100644 hiro/gtk/widget/text-edit.cpp create mode 100644 hiro/gtk/widget/text-edit.hpp create mode 100644 hiro/gtk/widget/tree-view-item.cpp create mode 100644 hiro/gtk/widget/tree-view-item.hpp create mode 100644 hiro/gtk/widget/tree-view.cpp create mode 100644 hiro/gtk/widget/tree-view.hpp create mode 100644 hiro/gtk/widget/vertical-scroller.cpp create mode 100644 hiro/gtk/widget/vertical-scroller.hpp create mode 100644 hiro/gtk/widget/vertical-slider.cpp create mode 100644 hiro/gtk/widget/vertical-slider.hpp create mode 100644 hiro/gtk/widget/viewport.cpp create mode 100644 hiro/gtk/widget/viewport.hpp create mode 100644 hiro/gtk/widget/widget.cpp create mode 100644 hiro/gtk/widget/widget.hpp create mode 100644 hiro/gtk/window.cpp create mode 100644 hiro/gtk/window.hpp create mode 100644 hiro/hiro.cpp create mode 100644 hiro/hiro.hpp rename {phoenix => hiro}/qt/action/action.cpp (100%) rename {phoenix => hiro}/qt/action/check-item.cpp (100%) rename {phoenix => hiro}/qt/action/item.cpp (100%) rename {phoenix => hiro}/qt/action/menu.cpp (96%) rename {phoenix => hiro}/qt/action/radio-item.cpp (89%) rename {phoenix => hiro}/qt/action/separator.cpp (100%) rename {phoenix => hiro}/qt/application.cpp (100%) rename {phoenix => hiro}/qt/browser-window.cpp (100%) rename {phoenix => hiro}/qt/desktop.cpp (100%) rename {phoenix => hiro}/qt/font.cpp (93%) rename {phoenix => hiro}/qt/header.hpp (100%) rename {phoenix/gtk => hiro/qt}/keyboard.cpp (100%) rename {phoenix => hiro}/qt/message-window.cpp (100%) rename {phoenix => hiro}/qt/monitor.cpp (100%) rename {phoenix => hiro}/qt/mouse.cpp (100%) rename {phoenix => hiro}/qt/platform.cpp (95%) rename {phoenix => hiro}/qt/platform.moc (90%) rename {phoenix => hiro}/qt/platform.moc.hpp (83%) create mode 100644 hiro/qt/popup-menu.cpp rename {phoenix => hiro}/qt/settings.cpp (100%) rename {phoenix => hiro}/qt/timer.cpp (100%) rename {phoenix => hiro}/qt/utility.cpp (99%) rename {phoenix => hiro}/qt/widget/button.cpp (84%) rename {phoenix => hiro}/qt/widget/canvas.cpp (100%) rename {phoenix => hiro}/qt/widget/check-button.cpp (94%) rename {phoenix => hiro}/qt/widget/check-label.cpp (90%) rename {phoenix => hiro}/qt/widget/combo-button.cpp (67%) rename {phoenix => hiro}/qt/widget/console.cpp (67%) rename {phoenix => hiro}/qt/widget/frame.cpp (100%) rename {phoenix => hiro}/qt/widget/hex-edit.cpp (95%) rename {phoenix => hiro}/qt/widget/horizontal-scroller.cpp (100%) rename {phoenix => hiro}/qt/widget/horizontal-slider.cpp (100%) create mode 100644 hiro/qt/widget/icon-view.cpp rename {phoenix => hiro}/qt/widget/label.cpp (100%) rename {phoenix => hiro}/qt/widget/line-edit.cpp (76%) create mode 100644 hiro/qt/widget/list-view.cpp rename {phoenix => hiro}/qt/widget/progress-bar.cpp (100%) rename {phoenix => hiro}/qt/widget/radio-button.cpp (94%) rename {phoenix => hiro}/qt/widget/radio-label.cpp (91%) rename {phoenix => hiro}/qt/widget/tab-frame.cpp (83%) rename {phoenix => hiro}/qt/widget/text-edit.cpp (81%) rename {phoenix => hiro}/qt/widget/vertical-scroller.cpp (100%) rename {phoenix => hiro}/qt/widget/vertical-slider.cpp (100%) rename {phoenix => hiro}/qt/widget/viewport.cpp (100%) rename {phoenix => hiro}/qt/widget/widget.cpp (100%) rename {phoenix => hiro}/qt/window.cpp (89%) rename {phoenix => hiro}/reference/action/action.cpp (100%) rename {phoenix => hiro}/reference/action/action.hpp (100%) rename {phoenix => hiro}/reference/action/check-item.cpp (100%) rename {phoenix => hiro}/reference/action/check-item.hpp (100%) rename {phoenix => hiro}/reference/action/item.cpp (100%) rename {phoenix => hiro}/reference/action/item.hpp (100%) rename {phoenix => hiro}/reference/action/menu.cpp (100%) rename {phoenix => hiro}/reference/action/menu.hpp (100%) rename {phoenix => hiro}/reference/action/radio-item.cpp (100%) rename {phoenix => hiro}/reference/action/radio-item.hpp (100%) rename {phoenix => hiro}/reference/action/separator.cpp (100%) rename {phoenix => hiro}/reference/action/separator.hpp (100%) rename {phoenix => hiro}/reference/application.cpp (100%) rename {phoenix => hiro}/reference/application.hpp (100%) rename {phoenix => hiro}/reference/browser-window.cpp (100%) rename {phoenix => hiro}/reference/browser-window.hpp (100%) rename {phoenix => hiro}/reference/desktop.cpp (100%) rename {phoenix => hiro}/reference/desktop.hpp (100%) rename {phoenix => hiro}/reference/font.cpp (100%) rename {phoenix => hiro}/reference/font.hpp (100%) rename {phoenix => hiro}/reference/header.hpp (100%) rename {phoenix => hiro}/reference/keyboard.cpp (100%) rename {phoenix => hiro}/reference/keyboard.hpp (100%) rename {phoenix => hiro}/reference/message-window.cpp (100%) rename {phoenix => hiro}/reference/message-window.hpp (100%) rename {phoenix => hiro}/reference/monitor.cpp (100%) rename {phoenix => hiro}/reference/monitor.hpp (100%) rename {phoenix => hiro}/reference/mouse.cpp (100%) rename {phoenix => hiro}/reference/mouse.hpp (100%) rename {phoenix => hiro}/reference/object.cpp (100%) rename {phoenix => hiro}/reference/object.hpp (100%) rename {phoenix => hiro}/reference/platform.cpp (97%) rename {phoenix => hiro}/reference/platform.hpp (98%) create mode 100644 hiro/reference/popup-menu.cpp create mode 100644 hiro/reference/popup-menu.hpp rename {phoenix => hiro}/reference/timer.cpp (100%) rename {phoenix => hiro}/reference/timer.hpp (100%) rename {phoenix => hiro}/reference/widget/button.cpp (81%) rename {phoenix => hiro}/reference/widget/button.hpp (88%) rename {phoenix => hiro}/reference/widget/canvas.cpp (100%) rename {phoenix => hiro}/reference/widget/canvas.hpp (100%) rename {phoenix => hiro}/reference/widget/check-button.cpp (100%) rename {phoenix => hiro}/reference/widget/check-button.hpp (100%) rename {phoenix => hiro}/reference/widget/check-label.cpp (100%) rename {phoenix => hiro}/reference/widget/check-label.hpp (100%) rename {phoenix => hiro}/reference/widget/combo-button.cpp (72%) rename {phoenix => hiro}/reference/widget/combo-button.hpp (82%) rename {phoenix => hiro}/reference/widget/console.cpp (100%) rename {phoenix => hiro}/reference/widget/console.hpp (100%) rename {phoenix => hiro}/reference/widget/frame.cpp (100%) rename {phoenix => hiro}/reference/widget/frame.hpp (100%) rename {phoenix => hiro}/reference/widget/hex-edit.cpp (100%) rename {phoenix => hiro}/reference/widget/hex-edit.hpp (100%) rename {phoenix => hiro}/reference/widget/horizontal-scroller.cpp (100%) rename {phoenix => hiro}/reference/widget/horizontal-scroller.hpp (100%) rename {phoenix => hiro}/reference/widget/horizontal-slider.cpp (100%) rename {phoenix => hiro}/reference/widget/horizontal-slider.hpp (100%) rename {phoenix => hiro}/reference/widget/label.cpp (100%) rename {phoenix => hiro}/reference/widget/label.hpp (100%) rename {phoenix => hiro}/reference/widget/layout.hpp (100%) rename {phoenix => hiro}/reference/widget/line-edit.cpp (100%) rename {phoenix => hiro}/reference/widget/line-edit.hpp (100%) rename {phoenix => hiro}/reference/widget/list-view.cpp (61%) rename {phoenix => hiro}/reference/widget/list-view.hpp (67%) rename {phoenix => hiro}/reference/widget/progress-bar.cpp (100%) rename {phoenix => hiro}/reference/widget/progress-bar.hpp (100%) rename {phoenix => hiro}/reference/widget/radio-button.cpp (100%) rename {phoenix => hiro}/reference/widget/radio-button.hpp (100%) rename {phoenix => hiro}/reference/widget/radio-label.cpp (100%) rename {phoenix => hiro}/reference/widget/radio-label.hpp (100%) rename {phoenix => hiro}/reference/widget/sizable.hpp (100%) rename {phoenix => hiro}/reference/widget/tab-frame.cpp (71%) rename {phoenix => hiro}/reference/widget/tab-frame.hpp (79%) rename {phoenix => hiro}/reference/widget/text-edit.cpp (100%) rename {phoenix => hiro}/reference/widget/text-edit.hpp (100%) rename {phoenix => hiro}/reference/widget/vertical-scroller.cpp (100%) rename {phoenix => hiro}/reference/widget/vertical-scroller.hpp (100%) rename {phoenix => hiro}/reference/widget/vertical-slider.cpp (100%) rename {phoenix => hiro}/reference/widget/vertical-slider.hpp (100%) rename {phoenix => hiro}/reference/widget/viewport.cpp (100%) rename {phoenix => hiro}/reference/widget/viewport.hpp (100%) rename {phoenix => hiro}/reference/widget/widget.cpp (100%) rename {phoenix => hiro}/reference/widget/widget.hpp (100%) rename {phoenix => hiro}/reference/window.cpp (95%) rename {phoenix => hiro}/reference/window.hpp (97%) create mode 100644 hiro/resource/GNUmakefile create mode 100644 hiro/resource/icon/action/add.png create mode 100644 hiro/resource/icon/action/attach.png create mode 100644 hiro/resource/icon/action/bookmark.png create mode 100644 hiro/resource/icon/action/full-screen.png create mode 100644 hiro/resource/icon/action/mute.png create mode 100644 hiro/resource/icon/action/new.png create mode 100644 hiro/resource/icon/action/open.png create mode 100644 hiro/resource/icon/action/properties.png create mode 100644 hiro/resource/icon/action/quit.png create mode 100644 hiro/resource/icon/action/refresh.png create mode 100644 hiro/resource/icon/action/remove.png create mode 100644 hiro/resource/icon/action/save.png create mode 100644 hiro/resource/icon/action/search.png rename target-higan/resource/advanced.png => hiro/resource/icon/action/settings.png (100%) create mode 100644 hiro/resource/icon/action/stop.png create mode 100644 hiro/resource/icon/application/browser.png create mode 100644 hiro/resource/icon/application/calculator.png create mode 100644 hiro/resource/icon/application/calendar.png create mode 100644 hiro/resource/icon/application/chat.png rename target-higan/resource/state-manager.png => hiro/resource/icon/application/file-manager.png (100%) create mode 100644 hiro/resource/icon/application/mail.png create mode 100644 hiro/resource/icon/application/monitor.png create mode 100644 hiro/resource/icon/application/terminal.png create mode 100644 hiro/resource/icon/application/text-editor.png rename target-higan/resource/timing.png => hiro/resource/icon/device/clock.png (100%) rename target-higan/resource/video.png => hiro/resource/icon/device/display.png (100%) rename target-higan/resource/input.png => hiro/resource/icon/device/joypad.png (100%) rename target-higan/resource/hotkeys.png => hiro/resource/icon/device/keyboard.png (100%) create mode 100644 hiro/resource/icon/device/microphone.png create mode 100644 hiro/resource/icon/device/mouse.png rename target-higan/resource/server.png => hiro/resource/icon/device/network.png (100%) create mode 100644 hiro/resource/icon/device/optical.png create mode 100644 hiro/resource/icon/device/printer.png rename target-higan/resource/audio.png => hiro/resource/icon/device/speaker.png (100%) create mode 100644 hiro/resource/icon/device/storage.png create mode 100644 hiro/resource/icon/edit/clear.png create mode 100644 hiro/resource/icon/edit/copy.png create mode 100644 hiro/resource/icon/edit/cut.png create mode 100644 hiro/resource/icon/edit/delete.png create mode 100644 hiro/resource/icon/edit/find.png create mode 100644 hiro/resource/icon/edit/paste.png create mode 100644 hiro/resource/icon/edit/redo.png create mode 100644 hiro/resource/icon/edit/replace.png create mode 100644 hiro/resource/icon/edit/undo.png create mode 100644 hiro/resource/icon/emblem/archive.png create mode 100644 hiro/resource/icon/emblem/audio.png create mode 100644 hiro/resource/icon/emblem/binary.png create mode 100644 hiro/resource/icon/emblem/file.png create mode 100644 hiro/resource/icon/emblem/folder.png create mode 100644 hiro/resource/icon/emblem/font.png create mode 100644 hiro/resource/icon/emblem/image.png create mode 100644 hiro/resource/icon/emblem/markup.png create mode 100644 hiro/resource/icon/emblem/program.png create mode 100644 hiro/resource/icon/emblem/script.png create mode 100644 hiro/resource/icon/emblem/text.png create mode 100644 hiro/resource/icon/emblem/video.png create mode 100644 hiro/resource/icon/go/down.png rename {target-higan/resource => hiro/resource/icon/go}/home.png (100%) create mode 100644 hiro/resource/icon/go/left.png create mode 100644 hiro/resource/icon/go/right.png rename {target-higan/resource => hiro/resource/icon/go}/up.png (100%) create mode 100644 hiro/resource/icon/media/back.png create mode 100644 hiro/resource/icon/media/eject.png create mode 100644 hiro/resource/icon/media/flash.png create mode 100644 hiro/resource/icon/media/floppy.png create mode 100644 hiro/resource/icon/media/next.png create mode 100644 hiro/resource/icon/media/optical.png create mode 100644 hiro/resource/icon/media/pause.png create mode 100644 hiro/resource/icon/media/play.png create mode 100644 hiro/resource/icon/media/record.png create mode 100644 hiro/resource/icon/media/rewind.png create mode 100644 hiro/resource/icon/media/skip.png create mode 100644 hiro/resource/icon/media/stop.png create mode 100644 hiro/resource/icon/place/bookmarks.png create mode 100644 hiro/resource/icon/place/desktop.png create mode 100644 hiro/resource/icon/place/home.png create mode 100644 hiro/resource/icon/place/server.png create mode 100644 hiro/resource/icon/place/share.png create mode 100644 hiro/resource/icon/prompt/error.png create mode 100644 hiro/resource/icon/prompt/information.png create mode 100644 hiro/resource/icon/prompt/question.png create mode 100644 hiro/resource/icon/prompt/warning.png create mode 100644 hiro/resource/resource.bml create mode 100644 hiro/resource/resource.cpp create mode 100644 hiro/resource/resource.hpp rename {phoenix => hiro}/windows/action/action.cpp (100%) rename {phoenix => hiro}/windows/action/check-item.cpp (100%) rename {phoenix => hiro}/windows/action/item.cpp (100%) rename {phoenix => hiro}/windows/action/menu.cpp (100%) rename {phoenix => hiro}/windows/action/radio-item.cpp (100%) rename {phoenix => hiro}/windows/action/separator.cpp (100%) rename {phoenix => hiro}/windows/application.cpp (100%) rename {phoenix => hiro}/windows/browser-window.cpp (96%) rename {phoenix => hiro}/windows/desktop.cpp (100%) rename {phoenix => hiro}/windows/font.cpp (94%) rename {phoenix => hiro}/windows/header.hpp (100%) rename {phoenix => hiro}/windows/keyboard.cpp (100%) rename {phoenix => hiro}/windows/message-window.cpp (100%) rename {phoenix => hiro}/windows/monitor.cpp (100%) rename {phoenix => hiro}/windows/mouse.cpp (100%) rename {phoenix => hiro}/windows/object.cpp (100%) rename {phoenix => hiro}/windows/phoenix.Manifest (100%) rename {phoenix => hiro}/windows/phoenix.rc (100%) rename {phoenix => hiro}/windows/platform.cpp (100%) rename {phoenix => hiro}/windows/platform.hpp (98%) rename {phoenix => hiro}/windows/settings.cpp (100%) rename {phoenix => hiro}/windows/timer.cpp (100%) rename {phoenix => hiro}/windows/utility.cpp (86%) rename {phoenix => hiro}/windows/widget/button.cpp (95%) rename {phoenix => hiro}/windows/widget/canvas.cpp (100%) rename {phoenix => hiro}/windows/widget/check-button.cpp (100%) rename {phoenix => hiro}/windows/widget/check-label.cpp (100%) rename {phoenix => hiro}/windows/widget/combo-button.cpp (100%) rename {phoenix => hiro}/windows/widget/console.cpp (86%) rename {phoenix => hiro}/windows/widget/frame.cpp (100%) rename {phoenix => hiro}/windows/widget/hex-edit.cpp (97%) rename {phoenix => hiro}/windows/widget/horizontal-scroller.cpp (100%) rename {phoenix => hiro}/windows/widget/horizontal-slider.cpp (100%) rename {phoenix => hiro}/windows/widget/label.cpp (100%) rename {phoenix => hiro}/windows/widget/line-edit.cpp (87%) rename {phoenix => hiro}/windows/widget/list-view.cpp (91%) rename {phoenix => hiro}/windows/widget/progress-bar.cpp (100%) rename {phoenix => hiro}/windows/widget/radio-button.cpp (100%) rename {phoenix => hiro}/windows/widget/radio-label.cpp (100%) rename {phoenix => hiro}/windows/widget/tab-frame.cpp (100%) rename {phoenix => hiro}/windows/widget/text-edit.cpp (91%) rename {phoenix => hiro}/windows/widget/vertical-scroller.cpp (100%) rename {phoenix => hiro}/windows/widget/vertical-slider.cpp (100%) rename {phoenix => hiro}/windows/widget/viewport.cpp (100%) rename {phoenix => hiro}/windows/widget/widget.cpp (100%) rename {phoenix => hiro}/windows/window.cpp (98%) rename nall/{Makefile => GNUmakefile} (90%) delete mode 100644 nall/crc16.hpp create mode 100644 nall/decode/bmp.hpp rename nall/{ => decode}/gzip.hpp (81%) rename nall/{ => decode}/inflate.hpp (98%) rename nall/{ => decode}/png.hpp (93%) rename nall/{unzip.hpp => decode/zip.hpp} (94%) create mode 100644 nall/hash/crc16.hpp rename nall/{ => hash}/crc32.hpp (80%) create mode 100644 nall/hash/sha256.hpp delete mode 100644 nall/http.hpp create mode 100644 nall/http/client.hpp create mode 100644 nall/http/message.hpp create mode 100644 nall/http/request.hpp create mode 100644 nall/http/response.hpp create mode 100644 nall/http/role.hpp create mode 100644 nall/http/server.hpp create mode 100644 nall/main.hpp create mode 100644 nall/memory.hpp create mode 100644 nall/memory/memory.hpp create mode 100644 nall/memory/pool.hpp create mode 100644 nall/method.hpp create mode 100644 nall/range.hpp create mode 100644 nall/service.hpp delete mode 100644 nall/sha256.hpp create mode 100644 nall/shared-memory.hpp create mode 100644 nall/shared-pointer.hpp create mode 100644 nall/storage.hpp delete mode 100644 nall/stream/http.hpp create mode 100644 nall/string/allocator/adaptive.hpp delete mode 100644 nall/string/char.hpp delete mode 100644 nall/string/char/base.hpp delete mode 100644 nall/string/char/compare.hpp delete mode 100644 nall/string/char/convert.hpp delete mode 100644 nall/string/char/strm.hpp delete mode 100644 nall/string/char/strpos.hpp delete mode 100644 nall/string/char/trim.hpp delete mode 100644 nall/string/char/utf8.hpp delete mode 100644 nall/string/char/utility.hpp create mode 100644 nall/string/compare.hpp create mode 100644 nall/string/convert.hpp delete mode 100644 nall/string/file.hpp delete mode 100644 nall/string/filename.hpp create mode 100644 nall/string/find.hpp create mode 100644 nall/string/hash.hpp rename nall/string/{char => }/match.hpp (55%) create mode 100644 nall/string/path.hpp create mode 100644 nall/string/transform/cml.hpp create mode 100644 nall/string/transform/dml.hpp create mode 100644 nall/string/trim.hpp delete mode 100644 nall/string/variadic.hpp delete mode 100644 nall/string/wrapper.hpp delete mode 100644 phoenix/Makefile delete mode 100644 phoenix/core/core.cpp delete mode 100644 phoenix/core/core.hpp delete mode 100644 phoenix/core/keyboard.hpp delete mode 100644 phoenix/core/layout/fixed-layout.cpp delete mode 100644 phoenix/core/layout/fixed-layout.hpp delete mode 100644 phoenix/core/layout/horizontal-layout.cpp delete mode 100644 phoenix/core/layout/horizontal-layout.hpp delete mode 100644 phoenix/core/layout/vertical-layout.cpp delete mode 100644 phoenix/core/layout/vertical-layout.hpp delete mode 100644 phoenix/core/state.hpp delete mode 100644 phoenix/gtk/action/check-item.cpp delete mode 100644 phoenix/gtk/action/item.cpp delete mode 100644 phoenix/gtk/action/menu.cpp delete mode 100644 phoenix/gtk/action/radio-item.cpp delete mode 100644 phoenix/gtk/action/separator.cpp delete mode 100644 phoenix/gtk/application.cpp delete mode 100644 phoenix/gtk/platform.hpp delete mode 100644 phoenix/gtk/timer.cpp delete mode 100644 phoenix/gtk/utility.cpp delete mode 100644 phoenix/gtk/widget/button.cpp delete mode 100644 phoenix/gtk/widget/canvas.cpp delete mode 100644 phoenix/gtk/widget/check-button.cpp delete mode 100644 phoenix/gtk/widget/check-label.cpp delete mode 100644 phoenix/gtk/widget/combo-button.cpp delete mode 100644 phoenix/gtk/widget/frame.cpp delete mode 100644 phoenix/gtk/widget/horizontal-scroller.cpp delete mode 100644 phoenix/gtk/widget/horizontal-slider.cpp delete mode 100644 phoenix/gtk/widget/label.cpp delete mode 100644 phoenix/gtk/widget/line-edit.cpp delete mode 100644 phoenix/gtk/widget/list-view.cpp delete mode 100644 phoenix/gtk/widget/progress-bar.cpp delete mode 100644 phoenix/gtk/widget/radio-button.cpp delete mode 100644 phoenix/gtk/widget/radio-label.cpp delete mode 100644 phoenix/gtk/widget/tab-frame.cpp delete mode 100644 phoenix/gtk/widget/text-edit.cpp delete mode 100644 phoenix/gtk/widget/vertical-scroller.cpp delete mode 100644 phoenix/gtk/widget/vertical-slider.cpp delete mode 100644 phoenix/gtk/widget/viewport.cpp delete mode 100644 phoenix/gtk/widget/widget.cpp delete mode 100644 phoenix/gtk/window.cpp delete mode 100644 phoenix/phoenix.cpp delete mode 100644 phoenix/phoenix.hpp delete mode 100644 phoenix/qt/keyboard.cpp delete mode 100644 phoenix/qt/widget/list-view.cpp rename processor/{Makefile => GNUmakefile} (100%) rename ruby/{Makefile => GNUmakefile} (100%) rename sfc/{Makefile => GNUmakefile} (100%) create mode 100644 target-higan/GNUmakefile delete mode 100644 target-higan/Makefile delete mode 100644 target-higan/bootstrap.cpp delete mode 100644 target-higan/configuration/configuration.cpp delete mode 100644 target-higan/configuration/configuration.hpp delete mode 100644 target-higan/general/dip-switches.cpp delete mode 100644 target-higan/general/dip-switches.hpp delete mode 100644 target-higan/general/general.cpp delete mode 100644 target-higan/general/general.hpp delete mode 100644 target-higan/general/library.cpp delete mode 100644 target-higan/general/library.hpp delete mode 100644 target-higan/general/presentation.cpp delete mode 100644 target-higan/general/presentation.hpp delete mode 100644 target-higan/input/hotkeys.cpp delete mode 100644 target-higan/input/input.cpp delete mode 100644 target-higan/input/input.hpp delete mode 100644 target-higan/interface/interface.cpp delete mode 100644 target-higan/interface/interface.hpp delete mode 100644 target-higan/resource.rc delete mode 100644 target-higan/resource/cheat-editor.png delete mode 100644 target-higan/resource/folder.png delete mode 100644 target-higan/resource/game.png delete mode 100644 target-higan/resource/resource.bml delete mode 100644 target-higan/resource/resource.cpp delete mode 100644 target-higan/resource/resource.hpp delete mode 100644 target-higan/resource/unverified.png delete mode 100644 target-higan/settings/advanced.cpp delete mode 100644 target-higan/settings/advanced.hpp delete mode 100644 target-higan/settings/audio.cpp delete mode 100644 target-higan/settings/audio.hpp delete mode 100644 target-higan/settings/hotkey.cpp delete mode 100644 target-higan/settings/hotkey.hpp delete mode 100644 target-higan/settings/input.cpp delete mode 100644 target-higan/settings/input.hpp delete mode 100644 target-higan/settings/server.cpp delete mode 100644 target-higan/settings/server.hpp delete mode 100644 target-higan/settings/settings.cpp delete mode 100644 target-higan/settings/settings.hpp delete mode 100644 target-higan/settings/timing.cpp delete mode 100644 target-higan/settings/timing.hpp delete mode 100644 target-higan/settings/video.cpp delete mode 100644 target-higan/settings/video.hpp delete mode 100644 target-higan/tools/cheat-database.cpp delete mode 100644 target-higan/tools/cheat-database.hpp delete mode 100644 target-higan/tools/cheat-editor.cpp delete mode 100644 target-higan/tools/cheat-editor.hpp delete mode 100644 target-higan/tools/state-manager.cpp delete mode 100644 target-higan/tools/state-manager.hpp delete mode 100644 target-higan/tools/tools.cpp delete mode 100644 target-higan/tools/tools.hpp delete mode 100644 target-higan/utility/utility.cpp delete mode 100644 target-higan/utility/utility.hpp delete mode 100644 target-higan/window/window.cpp delete mode 100644 target-higan/window/window.hpp delete mode 100644 target-loki/Makefile delete mode 100644 target-loki/debugger/debugger.cpp delete mode 100644 target-loki/debugger/debugger.hpp delete mode 100644 target-loki/input/input.cpp delete mode 100644 target-loki/input/input.hpp delete mode 100644 target-loki/interface/interface.cpp delete mode 100644 target-loki/interface/interface.hpp delete mode 100644 target-loki/loki.cpp delete mode 100644 target-loki/loki.hpp delete mode 100644 target-loki/presentation/presentation.cpp delete mode 100644 target-loki/presentation/presentation.hpp delete mode 100644 target-loki/resource/loki.png delete mode 100644 target-loki/resource/resource.bml delete mode 100644 target-loki/resource/resource.cpp delete mode 100644 target-loki/resource/resource.hpp delete mode 100644 target-loki/settings/settings.cpp delete mode 100644 target-loki/settings/settings.hpp delete mode 100644 target-loki/terminal/terminal.cpp delete mode 100644 target-loki/terminal/terminal.hpp diff --git a/Makefile b/GNUmakefile similarity index 75% rename from Makefile rename to GNUmakefile index c5241339..616430e8 100644 --- a/Makefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -include nall/Makefile +include nall/GNUmakefile fc := fc sfc := sfc @@ -7,17 +7,12 @@ gba := gba profile := accuracy target := higan -# target := loki - -ifeq ($(target),loki) - options += debugger -endif # arch := x86 # console := true # compiler -flags += -I. -O3 -fomit-frame-pointer +flags += -I. -O3 link += objects := libco @@ -43,16 +38,16 @@ ifeq ($(platform),windows) else link += -mwindows endif - link += -s -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 -lws2_32 + link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 -lws2_32 link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc else ifeq ($(platform),macosx) flags += -march=native else ifeq ($(platform),linux) flags += -march=native - link += -s -Wl,-export-dynamic -lX11 -lXext -ldl + link += -Wl,-export-dynamic -lX11 -lXext -ldl else ifeq ($(platform),bsd) flags += -march=native - link += -s -Wl,-export-dynamic -lX11 -lXext + link += -Wl,-export-dynamic -lX11 -lXext else $(error unsupported platform.) endif @@ -76,7 +71,7 @@ all: build; obj/libco.o: libco/libco.c libco/* -include $(ui)/Makefile +include $(ui)/GNUmakefile flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o) # targets @@ -87,8 +82,6 @@ clean: -@$(call delete,obj/*.so) -@$(call delete,obj/*.dylib) -@$(call delete,obj/*.dll) - -@$(call delete,*.res) - -@$(call delete,*.manifest) archive: if [ -f higan.tar.xz ]; then rm higan.tar.xz; fi @@ -99,16 +92,16 @@ ifeq ($(shell id -un),byuu) if [ -d ./libco ]; then rm -r ./libco; fi if [ -d ./nall ]; then rm -r ./nall; fi if [ -d ./ruby ]; then rm -r ./ruby; fi - if [ -d ./phoenix ]; then rm -r ./phoenix; fi + if [ -d ./hiro ]; then rm -r ./hiro; fi cp -r ../libco ./libco cp -r ../nall ./nall cp -r ../ruby ./ruby - cp -r ../phoenix ./phoenix + cp -r ../hiro ./hiro rm -r libco/doc - rm -r libco/.test - rm -r nall/.test - rm -r ruby/.test - rm -r phoenix/.test + rm -r libco/-test + rm -r nall/-test + rm -r ruby/-test + rm -r hiro/-test endif help:; diff --git a/data/higan.desktop b/data/higan.desktop index 70a2242e..4731230b 100644 --- a/data/higan.desktop +++ b/data/higan.desktop @@ -1,6 +1,6 @@ [Desktop Entry] Name=higan -Comment=SNES emulator +Comment=Nintendo emulator Exec=higan Icon=higan Terminal=false diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 8b59706b..efa5b2b4 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { static const char Name[] = "higan"; - static const char Version[] = "094.08"; + static const char Version[] = "094.09"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; static const char Website[] = "http://byuu.org/"; @@ -26,7 +26,6 @@ namespace Emulator { #include #include #include -#include #include #include #include @@ -34,12 +33,12 @@ namespace Emulator { #include #include #include -#include #include #include #include #include #include +#include #include #include using namespace nall; diff --git a/fc/Makefile b/fc/GNUmakefile similarity index 100% rename from fc/Makefile rename to fc/GNUmakefile diff --git a/fc/cartridge/cartridge.cpp b/fc/cartridge/cartridge.cpp index 57dc723b..844c3b0d 100644 --- a/fc/cartridge/cartridge.cpp +++ b/fc/cartridge/cartridge.cpp @@ -24,16 +24,10 @@ void Cartridge::load() { Board::load(information.markup); //this call will set Cartridge::board if successful if(board == nullptr) return; - sha256_ctx sha; - uint8 hash[32]; - sha256_init(&sha); - sha256_chunk(&sha, board->prgrom.data, board->prgrom.size); - sha256_chunk(&sha, board->chrrom.data, board->chrrom.size); - sha256_final(&sha); - sha256_hash(&sha, hash); - string result; - for(auto& byte : hash) result.append(hex<2>(byte)); - sha256 = result; + Hash::SHA256 sha; + sha.data(board->prgrom.data, board->prgrom.size); + sha.data(board->chrrom.data, board->chrrom.size); + sha256 = sha.digest(); system.load(); loaded = true; diff --git a/gb/Makefile b/gb/GNUmakefile similarity index 100% rename from gb/Makefile rename to gb/GNUmakefile diff --git a/gb/cartridge/cartridge.cpp b/gb/cartridge/cartridge.cpp index fa8b2706..0b85220c 100644 --- a/gb/cartridge/cartridge.cpp +++ b/gb/cartridge/cartridge.cpp @@ -25,7 +25,7 @@ void Cartridge::load_empty(System::Revision revision) { romdata = allocate(romsize, 0xff); ramsize = 0; mapper = &mbc0; - sha256 = nall::sha256(romdata, romsize); + sha256 = Hash::SHA256(romdata, romsize).digest(); loaded = true; system.load(revision); } @@ -94,7 +94,7 @@ void Cartridge::load(System::Revision revision) { case Mapper::HuC3: mapper = &huc3; break; } - sha256 = nall::sha256(romdata, romsize); + sha256 = Hash::SHA256(romdata, romsize).digest(); loaded = true; system.load(revision); } diff --git a/gba/Makefile b/gba/GNUmakefile similarity index 100% rename from gba/Makefile rename to gba/GNUmakefile diff --git a/gba/cartridge/cartridge.cpp b/gba/cartridge/cartridge.cpp index e2d787d3..24f6be0f 100644 --- a/gba/cartridge/cartridge.cpp +++ b/gba/cartridge/cartridge.cpp @@ -68,7 +68,7 @@ void Cartridge::load() { } } - sha256 = nall::sha256(rom.data, rom_size); + sha256 = Hash::SHA256(rom.data, rom_size).digest(); system.load(); loaded = true; diff --git a/gba/player/player.cpp b/gba/player/player.cpp index 4248b916..1b7b59bb 100644 --- a/gba/player/player.cpp +++ b/gba/player/player.cpp @@ -20,7 +20,7 @@ void Player::power() { } void Player::frame() { - uint32 hash = crc32_calculate((const uint8*)ppu.output, 240 * 160 * sizeof(uint32)); + uint32 hash = Hash::CRC32(ppu.output, 240 * 160 * sizeof(uint32)).value(); status.logoDetected = (hash == 0x7776eb55); if(status.logoDetected) { diff --git a/hiro/GNUmakefile b/hiro/GNUmakefile new file mode 100644 index 00000000..1be0edb0 --- /dev/null +++ b/hiro/GNUmakefile @@ -0,0 +1,24 @@ +ifeq ($(platform),) + hiroflags = $(cppflags) $(flags) -DHIRO_REFERENCE + hirolink = +else ifeq ($(platform),windows) + hiroflags = $(cppflags) $(flags) -DHIRO_WINDOWS + hirolink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi +else ifeq ($(platform),macosx) + hiroflags = $(objcppflags) $(flags) -DHIRO_COCOA + hirolink = -framework Cocoa -framework Carbon +else + ifeq ($(hiro),) + hiro := gtk + endif + + ifeq ($(hiro),gtk) + hiroflags = $(cppflags) $(flags) -DHIRO_GTK `pkg-config --cflags gtk+-2.0 gtksourceview-2.0` + hirolink = `pkg-config --libs gtk+-2.0 gtksourceview-2.0` -lX11 + endif + + ifeq ($(hiro),qt) + hiroflags = $(cppflags) $(flags) -DHIRO_QT `pkg-config --cflags QtCore QtGui` + hirolink = `pkg-config --libs QtCore QtGui` -lX11 + endif +endif diff --git a/phoenix/cocoa/action/action.cpp b/hiro/cocoa/action/action.cpp similarity index 100% rename from phoenix/cocoa/action/action.cpp rename to hiro/cocoa/action/action.cpp diff --git a/phoenix/cocoa/action/action.hpp b/hiro/cocoa/action/action.hpp similarity index 100% rename from phoenix/cocoa/action/action.hpp rename to hiro/cocoa/action/action.hpp diff --git a/phoenix/cocoa/action/check-item.cpp b/hiro/cocoa/action/check-item.cpp similarity index 100% rename from phoenix/cocoa/action/check-item.cpp rename to hiro/cocoa/action/check-item.cpp diff --git a/phoenix/cocoa/action/check-item.hpp b/hiro/cocoa/action/check-item.hpp similarity index 100% rename from phoenix/cocoa/action/check-item.hpp rename to hiro/cocoa/action/check-item.hpp diff --git a/phoenix/cocoa/action/item.cpp b/hiro/cocoa/action/item.cpp similarity index 100% rename from phoenix/cocoa/action/item.cpp rename to hiro/cocoa/action/item.cpp diff --git a/phoenix/cocoa/action/item.hpp b/hiro/cocoa/action/item.hpp similarity index 100% rename from phoenix/cocoa/action/item.hpp rename to hiro/cocoa/action/item.hpp diff --git a/phoenix/cocoa/action/menu.cpp b/hiro/cocoa/action/menu.cpp similarity index 100% rename from phoenix/cocoa/action/menu.cpp rename to hiro/cocoa/action/menu.cpp diff --git a/phoenix/cocoa/action/menu.hpp b/hiro/cocoa/action/menu.hpp similarity index 100% rename from phoenix/cocoa/action/menu.hpp rename to hiro/cocoa/action/menu.hpp diff --git a/phoenix/cocoa/action/radio-item.cpp b/hiro/cocoa/action/radio-item.cpp similarity index 100% rename from phoenix/cocoa/action/radio-item.cpp rename to hiro/cocoa/action/radio-item.cpp diff --git a/phoenix/cocoa/action/radio-item.hpp b/hiro/cocoa/action/radio-item.hpp similarity index 100% rename from phoenix/cocoa/action/radio-item.hpp rename to hiro/cocoa/action/radio-item.hpp diff --git a/phoenix/cocoa/action/separator.cpp b/hiro/cocoa/action/separator.cpp similarity index 100% rename from phoenix/cocoa/action/separator.cpp rename to hiro/cocoa/action/separator.cpp diff --git a/phoenix/cocoa/action/separator.hpp b/hiro/cocoa/action/separator.hpp similarity index 100% rename from phoenix/cocoa/action/separator.hpp rename to hiro/cocoa/action/separator.hpp diff --git a/phoenix/cocoa/application.cpp b/hiro/cocoa/application.cpp similarity index 100% rename from phoenix/cocoa/application.cpp rename to hiro/cocoa/application.cpp diff --git a/phoenix/cocoa/application.hpp b/hiro/cocoa/application.hpp similarity index 100% rename from phoenix/cocoa/application.hpp rename to hiro/cocoa/application.hpp diff --git a/phoenix/cocoa/browser-window.cpp b/hiro/cocoa/browser-window.cpp similarity index 94% rename from phoenix/cocoa/browser-window.cpp rename to hiro/cocoa/browser-window.cpp index 014cb6dd..9302061b 100644 --- a/phoenix/cocoa/browser-window.cpp +++ b/hiro/cocoa/browser-window.cpp @@ -24,7 +24,7 @@ string pBrowserWindow::open(BrowserWindow::State& state) { @autoreleasepool { NSMutableArray* filters = [[NSMutableArray alloc] init]; for(auto& rule : state.filters) { - string pattern = rule.split<1>("(")(1).rtrim<1>(")"); + string pattern = rule.split<1>("(")(1).rtrim(")"); if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]]; } NSOpenPanel* panel = [NSOpenPanel openPanel]; @@ -49,7 +49,7 @@ string pBrowserWindow::save(BrowserWindow::State& state) { @autoreleasepool { NSMutableArray* filters = [[NSMutableArray alloc] init]; for(auto& rule : state.filters) { - string pattern = rule.split<1>("(")(1).rtrim<1>(")"); + string pattern = rule.split<1>("(")(1).rtrim(")"); if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]]; } NSSavePanel* panel = [NSSavePanel savePanel]; diff --git a/phoenix/cocoa/browser-window.hpp b/hiro/cocoa/browser-window.hpp similarity index 100% rename from phoenix/cocoa/browser-window.hpp rename to hiro/cocoa/browser-window.hpp diff --git a/phoenix/cocoa/desktop.cpp b/hiro/cocoa/desktop.cpp similarity index 100% rename from phoenix/cocoa/desktop.cpp rename to hiro/cocoa/desktop.cpp diff --git a/phoenix/cocoa/desktop.hpp b/hiro/cocoa/desktop.hpp similarity index 100% rename from phoenix/cocoa/desktop.hpp rename to hiro/cocoa/desktop.hpp diff --git a/phoenix/cocoa/font.cpp b/hiro/cocoa/font.cpp similarity index 100% rename from phoenix/cocoa/font.cpp rename to hiro/cocoa/font.cpp diff --git a/phoenix/cocoa/font.hpp b/hiro/cocoa/font.hpp similarity index 100% rename from phoenix/cocoa/font.hpp rename to hiro/cocoa/font.hpp diff --git a/phoenix/cocoa/header.hpp b/hiro/cocoa/header.hpp similarity index 100% rename from phoenix/cocoa/header.hpp rename to hiro/cocoa/header.hpp diff --git a/phoenix/cocoa/keyboard.cpp b/hiro/cocoa/keyboard.cpp similarity index 100% rename from phoenix/cocoa/keyboard.cpp rename to hiro/cocoa/keyboard.cpp diff --git a/phoenix/cocoa/keyboard.hpp b/hiro/cocoa/keyboard.hpp similarity index 100% rename from phoenix/cocoa/keyboard.hpp rename to hiro/cocoa/keyboard.hpp diff --git a/phoenix/cocoa/message-window.cpp b/hiro/cocoa/message-window.cpp similarity index 100% rename from phoenix/cocoa/message-window.cpp rename to hiro/cocoa/message-window.cpp diff --git a/phoenix/cocoa/message-window.hpp b/hiro/cocoa/message-window.hpp similarity index 100% rename from phoenix/cocoa/message-window.hpp rename to hiro/cocoa/message-window.hpp diff --git a/phoenix/cocoa/monitor.cpp b/hiro/cocoa/monitor.cpp similarity index 100% rename from phoenix/cocoa/monitor.cpp rename to hiro/cocoa/monitor.cpp diff --git a/phoenix/cocoa/monitor.hpp b/hiro/cocoa/monitor.hpp similarity index 100% rename from phoenix/cocoa/monitor.hpp rename to hiro/cocoa/monitor.hpp diff --git a/phoenix/cocoa/mouse.cpp b/hiro/cocoa/mouse.cpp similarity index 100% rename from phoenix/cocoa/mouse.cpp rename to hiro/cocoa/mouse.cpp diff --git a/phoenix/cocoa/mouse.hpp b/hiro/cocoa/mouse.hpp similarity index 100% rename from phoenix/cocoa/mouse.hpp rename to hiro/cocoa/mouse.hpp diff --git a/phoenix/cocoa/object.cpp b/hiro/cocoa/object.cpp similarity index 100% rename from phoenix/cocoa/object.cpp rename to hiro/cocoa/object.cpp diff --git a/phoenix/cocoa/object.hpp b/hiro/cocoa/object.hpp similarity index 100% rename from phoenix/cocoa/object.hpp rename to hiro/cocoa/object.hpp diff --git a/phoenix/cocoa/platform.cpp b/hiro/cocoa/platform.cpp similarity index 100% rename from phoenix/cocoa/platform.cpp rename to hiro/cocoa/platform.cpp diff --git a/phoenix/cocoa/platform.hpp b/hiro/cocoa/platform.hpp similarity index 100% rename from phoenix/cocoa/platform.hpp rename to hiro/cocoa/platform.hpp diff --git a/phoenix/cocoa/timer.cpp b/hiro/cocoa/timer.cpp similarity index 100% rename from phoenix/cocoa/timer.cpp rename to hiro/cocoa/timer.cpp diff --git a/phoenix/cocoa/timer.hpp b/hiro/cocoa/timer.hpp similarity index 100% rename from phoenix/cocoa/timer.hpp rename to hiro/cocoa/timer.hpp diff --git a/phoenix/cocoa/utility.cpp b/hiro/cocoa/utility.cpp similarity index 100% rename from phoenix/cocoa/utility.cpp rename to hiro/cocoa/utility.cpp diff --git a/phoenix/cocoa/widget/button.cpp b/hiro/cocoa/widget/button.cpp similarity index 94% rename from phoenix/cocoa/widget/button.cpp rename to hiro/cocoa/widget/button.cpp index 950bffef..3114c7b1 100644 --- a/phoenix/cocoa/widget/button.cpp +++ b/hiro/cocoa/widget/button.cpp @@ -32,7 +32,10 @@ Size pButton::minimumSize() { size.height += button.state.image.height; } - return {size.width + 20, size.height + 4}; + return {size.width + (button.state.text ? 20 : 4), size.height + 4}; +} + +void pButton::setBordered(bool bordered) { } void pButton::setGeometry(Geometry geometry) { diff --git a/phoenix/cocoa/widget/button.hpp b/hiro/cocoa/widget/button.hpp similarity index 93% rename from phoenix/cocoa/widget/button.hpp rename to hiro/cocoa/widget/button.hpp index 98569454..62f16361 100644 --- a/phoenix/cocoa/widget/button.hpp +++ b/hiro/cocoa/widget/button.hpp @@ -13,6 +13,7 @@ struct pButton : public pWidget { CocoaButton* cocoaButton = nullptr; Size minimumSize(); + void setBordered(bool bordered); void setGeometry(Geometry geometry); void setImage(const image& image, Orientation orientation); void setText(string text); diff --git a/phoenix/cocoa/widget/canvas.cpp b/hiro/cocoa/widget/canvas.cpp similarity index 100% rename from phoenix/cocoa/widget/canvas.cpp rename to hiro/cocoa/widget/canvas.cpp diff --git a/phoenix/cocoa/widget/canvas.hpp b/hiro/cocoa/widget/canvas.hpp similarity index 100% rename from phoenix/cocoa/widget/canvas.hpp rename to hiro/cocoa/widget/canvas.hpp diff --git a/phoenix/cocoa/widget/check-button.cpp b/hiro/cocoa/widget/check-button.cpp similarity index 100% rename from phoenix/cocoa/widget/check-button.cpp rename to hiro/cocoa/widget/check-button.cpp diff --git a/phoenix/cocoa/widget/check-button.hpp b/hiro/cocoa/widget/check-button.hpp similarity index 100% rename from phoenix/cocoa/widget/check-button.hpp rename to hiro/cocoa/widget/check-button.hpp diff --git a/phoenix/cocoa/widget/check-label.cpp b/hiro/cocoa/widget/check-label.cpp similarity index 100% rename from phoenix/cocoa/widget/check-label.cpp rename to hiro/cocoa/widget/check-label.cpp diff --git a/phoenix/cocoa/widget/check-label.hpp b/hiro/cocoa/widget/check-label.hpp similarity index 100% rename from phoenix/cocoa/widget/check-label.hpp rename to hiro/cocoa/widget/check-label.hpp diff --git a/phoenix/cocoa/widget/combo-button.cpp b/hiro/cocoa/widget/combo-button.cpp similarity index 100% rename from phoenix/cocoa/widget/combo-button.cpp rename to hiro/cocoa/widget/combo-button.cpp diff --git a/phoenix/cocoa/widget/combo-button.hpp b/hiro/cocoa/widget/combo-button.hpp similarity index 100% rename from phoenix/cocoa/widget/combo-button.hpp rename to hiro/cocoa/widget/combo-button.hpp diff --git a/phoenix/cocoa/widget/console.cpp b/hiro/cocoa/widget/console.cpp similarity index 100% rename from phoenix/cocoa/widget/console.cpp rename to hiro/cocoa/widget/console.cpp diff --git a/phoenix/cocoa/widget/console.hpp b/hiro/cocoa/widget/console.hpp similarity index 100% rename from phoenix/cocoa/widget/console.hpp rename to hiro/cocoa/widget/console.hpp diff --git a/phoenix/cocoa/widget/frame.cpp b/hiro/cocoa/widget/frame.cpp similarity index 100% rename from phoenix/cocoa/widget/frame.cpp rename to hiro/cocoa/widget/frame.cpp diff --git a/phoenix/cocoa/widget/frame.hpp b/hiro/cocoa/widget/frame.hpp similarity index 100% rename from phoenix/cocoa/widget/frame.hpp rename to hiro/cocoa/widget/frame.hpp diff --git a/phoenix/cocoa/widget/hex-edit.cpp b/hiro/cocoa/widget/hex-edit.cpp similarity index 100% rename from phoenix/cocoa/widget/hex-edit.cpp rename to hiro/cocoa/widget/hex-edit.cpp diff --git a/phoenix/cocoa/widget/hex-edit.hpp b/hiro/cocoa/widget/hex-edit.hpp similarity index 100% rename from phoenix/cocoa/widget/hex-edit.hpp rename to hiro/cocoa/widget/hex-edit.hpp diff --git a/phoenix/cocoa/widget/horizontal-scroller.cpp b/hiro/cocoa/widget/horizontal-scroller.cpp similarity index 100% rename from phoenix/cocoa/widget/horizontal-scroller.cpp rename to hiro/cocoa/widget/horizontal-scroller.cpp diff --git a/phoenix/cocoa/widget/horizontal-scroller.hpp b/hiro/cocoa/widget/horizontal-scroller.hpp similarity index 100% rename from phoenix/cocoa/widget/horizontal-scroller.hpp rename to hiro/cocoa/widget/horizontal-scroller.hpp diff --git a/phoenix/cocoa/widget/horizontal-slider.cpp b/hiro/cocoa/widget/horizontal-slider.cpp similarity index 100% rename from phoenix/cocoa/widget/horizontal-slider.cpp rename to hiro/cocoa/widget/horizontal-slider.cpp diff --git a/phoenix/cocoa/widget/horizontal-slider.hpp b/hiro/cocoa/widget/horizontal-slider.hpp similarity index 100% rename from phoenix/cocoa/widget/horizontal-slider.hpp rename to hiro/cocoa/widget/horizontal-slider.hpp diff --git a/phoenix/cocoa/widget/label.cpp b/hiro/cocoa/widget/label.cpp similarity index 100% rename from phoenix/cocoa/widget/label.cpp rename to hiro/cocoa/widget/label.cpp diff --git a/phoenix/cocoa/widget/label.hpp b/hiro/cocoa/widget/label.hpp similarity index 100% rename from phoenix/cocoa/widget/label.hpp rename to hiro/cocoa/widget/label.hpp diff --git a/phoenix/cocoa/widget/layout.hpp b/hiro/cocoa/widget/layout.hpp similarity index 100% rename from phoenix/cocoa/widget/layout.hpp rename to hiro/cocoa/widget/layout.hpp diff --git a/phoenix/cocoa/widget/line-edit.cpp b/hiro/cocoa/widget/line-edit.cpp similarity index 100% rename from phoenix/cocoa/widget/line-edit.cpp rename to hiro/cocoa/widget/line-edit.cpp diff --git a/phoenix/cocoa/widget/line-edit.hpp b/hiro/cocoa/widget/line-edit.hpp similarity index 100% rename from phoenix/cocoa/widget/line-edit.hpp rename to hiro/cocoa/widget/line-edit.hpp diff --git a/phoenix/cocoa/widget/list-view.cpp b/hiro/cocoa/widget/list-view.cpp similarity index 100% rename from phoenix/cocoa/widget/list-view.cpp rename to hiro/cocoa/widget/list-view.cpp diff --git a/phoenix/cocoa/widget/list-view.hpp b/hiro/cocoa/widget/list-view.hpp similarity index 100% rename from phoenix/cocoa/widget/list-view.hpp rename to hiro/cocoa/widget/list-view.hpp diff --git a/phoenix/cocoa/widget/progress-bar.cpp b/hiro/cocoa/widget/progress-bar.cpp similarity index 100% rename from phoenix/cocoa/widget/progress-bar.cpp rename to hiro/cocoa/widget/progress-bar.cpp diff --git a/phoenix/cocoa/widget/progress-bar.hpp b/hiro/cocoa/widget/progress-bar.hpp similarity index 100% rename from phoenix/cocoa/widget/progress-bar.hpp rename to hiro/cocoa/widget/progress-bar.hpp diff --git a/phoenix/cocoa/widget/radio-button.cpp b/hiro/cocoa/widget/radio-button.cpp similarity index 100% rename from phoenix/cocoa/widget/radio-button.cpp rename to hiro/cocoa/widget/radio-button.cpp diff --git a/phoenix/cocoa/widget/radio-button.hpp b/hiro/cocoa/widget/radio-button.hpp similarity index 100% rename from phoenix/cocoa/widget/radio-button.hpp rename to hiro/cocoa/widget/radio-button.hpp diff --git a/phoenix/cocoa/widget/radio-label.cpp b/hiro/cocoa/widget/radio-label.cpp similarity index 100% rename from phoenix/cocoa/widget/radio-label.cpp rename to hiro/cocoa/widget/radio-label.cpp diff --git a/phoenix/cocoa/widget/radio-label.hpp b/hiro/cocoa/widget/radio-label.hpp similarity index 100% rename from phoenix/cocoa/widget/radio-label.hpp rename to hiro/cocoa/widget/radio-label.hpp diff --git a/phoenix/cocoa/widget/sizable.hpp b/hiro/cocoa/widget/sizable.hpp similarity index 100% rename from phoenix/cocoa/widget/sizable.hpp rename to hiro/cocoa/widget/sizable.hpp diff --git a/phoenix/cocoa/widget/tab-frame.cpp b/hiro/cocoa/widget/tab-frame.cpp similarity index 100% rename from phoenix/cocoa/widget/tab-frame.cpp rename to hiro/cocoa/widget/tab-frame.cpp diff --git a/phoenix/cocoa/widget/tab-frame.hpp b/hiro/cocoa/widget/tab-frame.hpp similarity index 100% rename from phoenix/cocoa/widget/tab-frame.hpp rename to hiro/cocoa/widget/tab-frame.hpp diff --git a/phoenix/cocoa/widget/text-edit.cpp b/hiro/cocoa/widget/text-edit.cpp similarity index 100% rename from phoenix/cocoa/widget/text-edit.cpp rename to hiro/cocoa/widget/text-edit.cpp diff --git a/phoenix/cocoa/widget/text-edit.hpp b/hiro/cocoa/widget/text-edit.hpp similarity index 100% rename from phoenix/cocoa/widget/text-edit.hpp rename to hiro/cocoa/widget/text-edit.hpp diff --git a/phoenix/cocoa/widget/vertical-scroller.cpp b/hiro/cocoa/widget/vertical-scroller.cpp similarity index 100% rename from phoenix/cocoa/widget/vertical-scroller.cpp rename to hiro/cocoa/widget/vertical-scroller.cpp diff --git a/phoenix/cocoa/widget/vertical-scroller.hpp b/hiro/cocoa/widget/vertical-scroller.hpp similarity index 100% rename from phoenix/cocoa/widget/vertical-scroller.hpp rename to hiro/cocoa/widget/vertical-scroller.hpp diff --git a/phoenix/cocoa/widget/vertical-slider.cpp b/hiro/cocoa/widget/vertical-slider.cpp similarity index 100% rename from phoenix/cocoa/widget/vertical-slider.cpp rename to hiro/cocoa/widget/vertical-slider.cpp diff --git a/phoenix/cocoa/widget/vertical-slider.hpp b/hiro/cocoa/widget/vertical-slider.hpp similarity index 100% rename from phoenix/cocoa/widget/vertical-slider.hpp rename to hiro/cocoa/widget/vertical-slider.hpp diff --git a/phoenix/cocoa/widget/viewport.cpp b/hiro/cocoa/widget/viewport.cpp similarity index 100% rename from phoenix/cocoa/widget/viewport.cpp rename to hiro/cocoa/widget/viewport.cpp diff --git a/phoenix/cocoa/widget/viewport.hpp b/hiro/cocoa/widget/viewport.hpp similarity index 100% rename from phoenix/cocoa/widget/viewport.hpp rename to hiro/cocoa/widget/viewport.hpp diff --git a/phoenix/cocoa/widget/widget.cpp b/hiro/cocoa/widget/widget.cpp similarity index 100% rename from phoenix/cocoa/widget/widget.cpp rename to hiro/cocoa/widget/widget.cpp diff --git a/phoenix/cocoa/widget/widget.hpp b/hiro/cocoa/widget/widget.hpp similarity index 100% rename from phoenix/cocoa/widget/widget.hpp rename to hiro/cocoa/widget/widget.hpp diff --git a/phoenix/cocoa/window.cpp b/hiro/cocoa/window.cpp similarity index 100% rename from phoenix/cocoa/window.cpp rename to hiro/cocoa/window.cpp diff --git a/phoenix/cocoa/window.hpp b/hiro/cocoa/window.hpp similarity index 100% rename from phoenix/cocoa/window.hpp rename to hiro/cocoa/window.hpp diff --git a/hiro/core/action/action.cpp b/hiro/core/action/action.cpp new file mode 100644 index 00000000..c4199296 --- /dev/null +++ b/hiro/core/action/action.cpp @@ -0,0 +1,12 @@ +auto mAction::allocate() -> pObject* { + return new pAction(*this); +} + +// + +auto mAction::remove() -> type& { + if(auto menu = parentMenu()) menu->remove(*this); + if(auto menuBar = parentMenuBar()) menuBar->remove((mMenu&)*this); + if(auto popupMenu = parentPopupMenu()) popupMenu->remove(*this); + return *this; +} diff --git a/hiro/core/action/menu-check-item.cpp b/hiro/core/action/menu-check-item.cpp new file mode 100644 index 00000000..4b2d6392 --- /dev/null +++ b/hiro/core/action/menu-check-item.cpp @@ -0,0 +1,33 @@ +auto mMenuCheckItem::allocate() -> pObject* { + return new pMenuCheckItem(*this); +} + +// + +auto mMenuCheckItem::checked() const -> bool { + return state.checked; +} + +auto mMenuCheckItem::doToggle() const -> void { + if(state.onToggle) return state.onToggle(); +} + +auto mMenuCheckItem::onToggle(const function& function) -> type& { + state.onToggle = function; + return *this; +} + +auto mMenuCheckItem::setChecked(bool checked) -> type& { + state.checked = checked; + signal(setChecked, checked); +} + +auto mMenuCheckItem::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mMenuCheckItem::text() const -> string { + return state.text; +} diff --git a/hiro/core/action/menu-item.cpp b/hiro/core/action/menu-item.cpp new file mode 100644 index 00000000..25a8ad8f --- /dev/null +++ b/hiro/core/action/menu-item.cpp @@ -0,0 +1,34 @@ +auto mMenuItem::allocate() -> pObject* { + return new pMenuItem(*this); +} + +// + +auto mMenuItem::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mMenuItem::icon() const -> image { + return state.icon; +} + +auto mMenuItem::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mMenuItem::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mMenuItem::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mMenuItem::text() const -> string { + return state.text; +} diff --git a/hiro/core/action/menu-radio-item.cpp b/hiro/core/action/menu-radio-item.cpp new file mode 100644 index 00000000..c4d940b8 --- /dev/null +++ b/hiro/core/action/menu-radio-item.cpp @@ -0,0 +1,51 @@ +auto mMenuRadioItem::allocate() -> pObject* { + return new pMenuRadioItem(*this); +} + +// + +auto mMenuRadioItem::group(const vector>& group) -> void { + for(auto& weak : group) { + if(auto item = weak.acquire()) item->state.group = group; + } + for(auto& weak : group) { + if(auto item = weak.acquire()) { + if(item->self()) item->self()->setGroup(group); + } + } + if(group.size()) { + if(auto item = group.first().acquire()) item->setChecked(); + } +} + +auto mMenuRadioItem::checked() const -> bool { + return state.checked; +} + +auto mMenuRadioItem::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mMenuRadioItem::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mMenuRadioItem::setChecked() -> type& { + for(auto& weak : state.group) { + if(auto item = weak.acquire()) item->state.checked = false; + } + state.checked = true; + signal(setChecked); + return *this; +} + +auto mMenuRadioItem::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mMenuRadioItem::text() const -> string { + return state.text; +} diff --git a/hiro/core/action/menu-separator.cpp b/hiro/core/action/menu-separator.cpp new file mode 100644 index 00000000..98246b1b --- /dev/null +++ b/hiro/core/action/menu-separator.cpp @@ -0,0 +1,3 @@ +auto mMenuSeparator::allocate() -> pObject* { + return new pMenuSeparator(*this); +} diff --git a/hiro/core/action/menu.cpp b/hiro/core/action/menu.cpp new file mode 100644 index 00000000..4cfeec33 --- /dev/null +++ b/hiro/core/action/menu.cpp @@ -0,0 +1,60 @@ +auto mMenu::allocate() -> pObject* { + return new pMenu(*this); +} + +auto mMenu::destruct() -> void { + for(auto& action : state.actions) action->destruct(); + mAction::destruct(); +} + +// + +auto mMenu::action(unsigned position) const -> sAction { + if(position >= actions()) throw; + return state.actions[position]; +} + +auto mMenu::actions() const -> unsigned { + return state.actions.size(); +} + +auto mMenu::append(sAction action) -> type& { + state.actions.append(action); + action->setParent(this, actions() - 1); + signal(append, *action); + return *this; +} + +auto mMenu::icon() const -> image { + return state.icon; +} + +auto mMenu::remove(sAction action) -> type& { + signal(remove, *action); + state.actions.remove(action->offset()); + for(auto n : range(action->offset(), actions())) { + state.actions[n]->offset(-1); + } + action->setParent(); +} + +auto mMenu::reset() -> type& { + while(state.actions) remove(state.actions.last()); + return *this; +} + +auto mMenu::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mMenu::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mMenu::text() const -> string { + return state.text; +} diff --git a/hiro/core/application.cpp b/hiro/core/application.cpp new file mode 100644 index 00000000..d6597aad --- /dev/null +++ b/hiro/core/application.cpp @@ -0,0 +1,97 @@ +auto Application::doMain() -> void { + if(state.onMain) return state.onMain(); +} + +auto Application::font() -> string { + return state.font; +} + +auto Application::name() -> string { + return state.name; +} + +auto Application::onMain(const nall::function& function) -> void { + state.onMain = function; +} + +auto Application::run() -> void { + return pApplication::run(); +} + +auto Application::pendingEvents() -> bool { + return pApplication::pendingEvents(); +} + +auto Application::processEvents() -> void { + return pApplication::processEvents(); +} + +auto Application::quit() -> void { + state.quit = true; + return pApplication::quit(); +} + +auto Application::setFont(const string& font) -> void { + state.font = font; +} + +auto Application::setName(const string& name) -> void { + state.name = name; +} + +//Windows +//======= + +auto Application::Windows::doModalChange(bool modal) -> void { + if(state.windows.onModalChange) return state.windows.onModalChange(modal); +} + +auto Application::Windows::onModalChange(const function& function) -> void { + state.windows.onModalChange = function; +} + +//Cocoa +//===== + +auto Application::Cocoa::doAbout() -> void { + if(state.cocoa.onAbout) return state.cocoa.onAbout(); +} + +auto Application::Cocoa::doActivate() -> void { + if(state.cocoa.onActivate) return state.cocoa.onActivate(); +} + +auto Application::Cocoa::doPreferences() -> void { + if(state.cocoa.onPreferences) return state.cocoa.onPreferences(); +} + +auto Application::Cocoa::doQuit() -> void { + if(state.cocoa.onQuit) return state.cocoa.onQuit(); +} + +auto Application::Cocoa::onAbout(const function& function) -> void { + state.cocoa.onAbout = function; +} + +auto Application::Cocoa::onActivate(const function& function) -> void { + state.cocoa.onActivate = function; +} + +auto Application::Cocoa::onPreferences(const function& function) -> void { + state.cocoa.onPreferences = function; +} + +auto Application::Cocoa::onQuit(const function& function) -> void { + state.cocoa.onQuit = function; +} + +//Internal +//======== + +auto Application::initialize() -> void { + static bool initialized = false; + if(initialized == false) { + initialized = true; + return pApplication::initialize(); + } +} diff --git a/hiro/core/browser-window.cpp b/hiro/core/browser-window.cpp new file mode 100644 index 00000000..7d24a1c5 --- /dev/null +++ b/hiro/core/browser-window.cpp @@ -0,0 +1,31 @@ +auto BrowserWindow::directory() -> string { + return pBrowserWindow::directory(state); +} + +auto BrowserWindow::open() -> string { + return pBrowserWindow::open(state); +} + +auto BrowserWindow::save() -> string { + return pBrowserWindow::save(state); +} + +auto BrowserWindow::setFilters(const lstring& filters) -> type& { + state.filters = filters; + return *this; +} + +auto BrowserWindow::setParent(shared_pointer parent) -> type& { + state.parent = parent; + return *this; +} + +auto BrowserWindow::setPath(const string& path) -> type& { + state.path = path; + return *this; +} + +auto BrowserWindow::setTitle(const string& title) -> type& { + state.title = title; + return *this; +} diff --git a/hiro/core/color.cpp b/hiro/core/color.cpp new file mode 100644 index 00000000..dd43696c --- /dev/null +++ b/hiro/core/color.cpp @@ -0,0 +1,83 @@ +Color::Color() { + setColor(0, 0, 0, 0); +} + +Color::Color(signed red, signed green, signed blue) { + setColor(255, red, green, blue); +} + +Color::Color(signed alpha, signed red, signed green, signed blue) { + setColor(alpha, red, green, blue); +} + +Color::operator bool() const { + return !empty(); +} + +auto Color::operator==(const Color& source) const -> bool { + return alpha() == source.alpha() && red() == source.red() && green() == source.green() && blue() == source.blue(); +} + +auto Color::operator!=(const Color& source) const -> bool { + return !operator==(source); +} + +auto Color::alpha() const -> uint8_t { + return state.alpha; +} + +auto Color::blue() const -> uint8_t { + return state.blue; +} + +auto Color::empty() const -> bool { + return state.alpha == 0 && state.red == 0 && state.green == 0 && state.blue == 0; +} + +auto Color::green() const -> uint8_t { + return state.green; +} + +auto Color::red() const -> uint8_t { + return state.red; +} + +auto Color::setAlpha(signed alpha) -> type& { + state.alpha = max(0, min(255, alpha)); + return *this; +} + +auto Color::setBlue(signed blue) -> type& { + state.blue = max(0, min(255, blue)); + return *this; +} + +auto Color::setColor(Color color) -> type& { + return setColor(color.alpha(), color.red(), color.green(), color.blue()); +} + +auto Color::setColor(signed red, signed green, signed blue) -> type& { + return setColor(255, red, green, blue); +} + +auto Color::setColor(signed alpha, signed red, signed green, signed blue) -> type& { + state.alpha = max(0, min(255, alpha)); + state.red = max(0, min(255, red )); + state.green = max(0, min(255, green)); + state.blue = max(0, min(255, blue )); + return *this; +} + +auto Color::setGreen(signed green) -> type& { + state.green = max(0, min(255, green)); + return *this; +} + +auto Color::setRed(signed red) -> type& { + state.red = max(0, min(255, red)); + return *this; +} + +auto Color::value() const -> uint32_t { + return (state.alpha << 24) + (state.red << 16) + (state.green << 8) + (state.blue << 0); +} diff --git a/hiro/core/core.cpp b/hiro/core/core.cpp new file mode 100644 index 00000000..531b94d7 --- /dev/null +++ b/hiro/core/core.cpp @@ -0,0 +1,100 @@ +#if defined(HIRO_WINDOWS) + #include "../windows/header.hpp" +#elif defined(HIRO_QT) + #include "../qt/header.hpp" +#elif defined(HIRO_GTK) + #include "../gtk/header.hpp" +#elif defined(HIRO_COCOA) + #include "../cocoa/header.hpp" +#elif defined(HIRO_REFERENCE) + #include "../reference/header.hpp" +#endif + +#include "core.hpp" +using namespace nall; + +namespace hiro { + Application::State Application::state; + Keyboard::State Keyboard::state; +} + +#if defined(HIRO_WINDOWS) + #include "../windows/platform.cpp" +#elif defined(HIRO_QT) + #include "../qt/platform.cpp" +#elif defined(HIRO_GTK) + #include "../gtk/platform.cpp" +#elif defined(HIRO_COCOA) + #include "../cocoa/platform.cpp" +#elif defined(HIRO_REFERENCE) + #include "../reference/platform.cpp" +#endif + +#define signal(function, ...) \ + (delegate ? self()->function(__VA_ARGS__) : decltype(self()->function(__VA_ARGS__))()) + +namespace hiro { + #include "application.cpp" + #include "color.cpp" + #include "position.cpp" + #include "size.cpp" + #include "geometry.cpp" + #include "font.cpp" + #include "desktop.cpp" + #include "monitor.cpp" + #include "keyboard.cpp" + #include "mouse.cpp" + #include "browser-window.cpp" + #include "message-window.cpp" + #include "object.cpp" + #include "hotkey.cpp" + #include "timer.cpp" + #include "window.cpp" + #include "status-bar.cpp" + #include "menu-bar.cpp" + #include "popup-menu.cpp" + + #include "action/action.cpp" + #include "action/menu.cpp" + #include "action/menu-separator.cpp" + #include "action/menu-item.cpp" + #include "action/menu-check-item.cpp" + #include "action/menu-radio-item.cpp" + + #include "sizable.cpp" + #include "layout.cpp" + + #include "widget/widget.cpp" + #include "widget/button.cpp" + #include "widget/canvas.cpp" + #include "widget/check-button.cpp" + #include "widget/check-label.cpp" + #include "widget/combo-button.cpp" + #include "widget/combo-button-item.cpp" + #include "widget/console.cpp" + #include "widget/frame.cpp" + #include "widget/hex-edit.cpp" + #include "widget/horizontal-scroller.cpp" + #include "widget/horizontal-slider.cpp" + #include "widget/icon-view.cpp" + #include "widget/icon-view-item.cpp" + #include "widget/label.cpp" + #include "widget/line-edit.cpp" + #include "widget/list-view.cpp" + #include "widget/list-view-column.cpp" + #include "widget/list-view-item.cpp" + #include "widget/progress-bar.cpp" + #include "widget/radio-button.cpp" + #include "widget/radio-label.cpp" + #include "widget/source-edit.cpp" + #include "widget/tab-frame.cpp" + #include "widget/tab-frame-item.cpp" + #include "widget/text-edit.cpp" + #include "widget/tree-view.cpp" + #include "widget/tree-view-item.cpp" + #include "widget/vertical-scroller.cpp" + #include "widget/vertical-slider.cpp" + #include "widget/viewport.cpp" +} + +#undef signal diff --git a/hiro/core/core.hpp b/hiro/core/core.hpp new file mode 100644 index 00000000..47e3d6e1 --- /dev/null +++ b/hiro/core/core.hpp @@ -0,0 +1,1571 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using nall::function; +using nall::image; +using nall::lstring; +using nall::maybe; +using nall::shared_pointer; +using nall::shared_pointer_weak; +using nall::string; +using nall::vector; + +namespace hiro { + +#define Declare(Name) \ + struct m##Name; \ + struct p##Name; \ + using s##Name = shared_pointer; \ + using w##Name = shared_pointer_weak; \ + +Declare(Keyboard) +Declare(Object) +Declare(Timer) +Declare(Hotkey) +Declare(Window) +Declare(StatusBar) +Declare(MenuBar) +Declare(PopupMenu) +Declare(Action) +Declare(Menu) +Declare(MenuSeparator) +Declare(MenuItem) +Declare(MenuCheckItem) +Declare(MenuRadioItem) +Declare(Sizable) +Declare(Layout) +Declare(Widget) +Declare(Button) +Declare(Canvas) +Declare(CheckButton) +Declare(CheckLabel) +Declare(ComboButton) +Declare(ComboButtonItem) +Declare(Console) +Declare(Frame) +Declare(HexEdit) +Declare(HorizontalScroller) +Declare(HorizontalSlider) +Declare(IconView) +Declare(IconViewItem) +Declare(Label) +Declare(LineEdit) +Declare(ListView) +Declare(ListViewColumn) +Declare(ListViewItem) +Declare(ProgressBar) +Declare(RadioButton) +Declare(RadioLabel) +Declare(SourceEdit) +Declare(TabFrame) +Declare(TabFrameItem) +Declare(TextEdit) +Declare(TreeView) +Declare(TreeViewItem) +Declare(VerticalScroller) +Declare(VerticalSlider) +Declare(Viewport) + +#undef Declare + +enum class Edge : unsigned { Top, Bottom, Left, Right }; + +enum class Orientation : unsigned { Horizontal, Vertical }; + +struct Application { + Application() = delete; + + static auto doMain() -> void; + static auto font() -> string; + static auto name() -> string; + static auto onMain(const function& function = {}) -> void; + static auto run() -> void; + static auto pendingEvents() -> bool; + static auto processEvents() -> void; + static auto quit() -> void; + static auto setFont(const string& font = "") -> void; + static auto setName(const string& name = "") -> void; + + struct Windows { + static auto doModalChange(bool modal) -> void; + static auto onModalChange(const function& function = {}) -> void; + }; + + struct Cocoa { + static auto doAbout() -> void; + static auto doActivate() -> void; + static auto doPreferences() -> void; + static auto doQuit() -> void; + static auto onAbout(const function& function = {}) -> void; + static auto onActivate(const function& function = {}) -> void; + static auto onPreferences(const function& function = {}) -> void; + static auto onQuit(const function& function = {}) -> void; + }; + +//private: + struct State { + string font; + string name; + function onMain; + bool quit = false; + + struct Windows { + function onModalChange; + } windows; + + struct Cocoa { + function onAbout; + function onActivate; + function onPreferences; + function onQuit; + } cocoa; + }; + static State state; + static auto initialize() -> void; +}; + +struct Color { + using type = Color; + + Color(); + Color(signed red, signed green, signed blue); + Color(signed alpha, signed red, signed green, signed blue); + + explicit operator bool() const; + auto operator==(const Color& source) const -> bool; + auto operator!=(const Color& source) const -> bool; + + auto alpha() const -> uint8_t; + auto blue() const -> uint8_t; + auto empty() const -> bool; + auto green() const -> uint8_t; + auto red() const -> uint8_t; + auto setAlpha(signed alpha) -> type&; + auto setBlue(signed blue) -> type&; + auto setColor(Color color = {}) -> type&; + auto setColor(signed red, signed green, signed blue) -> type&; + auto setColor(signed alpha, signed red, signed green, signed blue) -> type&; + auto setGreen(signed green) -> type&; + auto setRed(signed red) -> type&; + auto value() const -> uint32_t; + +//private: + struct State { + signed alpha; + signed red; + signed green; + signed blue; + } state; +}; + +struct Position { + using type = Position; + + Position(); + Position(signed x, signed y); + + auto operator==(const Position& source) const -> bool; + auto operator!=(const Position& source) const -> bool; + + auto setPosition(Position position = {}) -> type&; + auto setPosition(signed x, signed y) -> type&; + auto setX(signed x) -> type&; + auto setY(signed y) -> type&; + auto x() const -> signed; + auto y() const -> signed; + +//private: + struct State { + signed x; + signed y; + } state; +}; + +struct Size { + using type = Size; + + Size(); + Size(signed width, signed height); + + auto operator==(const Size& source) const -> bool; + auto operator!=(const Size& source) const -> bool; + + auto height() const -> signed; + auto setHeight(signed height) -> type&; + auto setSize(Size source = {}) -> type&; + auto setSize(signed width, signed height) -> type&; + auto setWidth(signed width) -> type&; + auto width() const -> signed; + + static const signed Maximum = ~0; //~0 == -1 + static const signed Minimum = 0; + +//private: + struct State { + signed width; + signed height; + } state; +}; + +struct Geometry { + using type = Geometry; + + Geometry(); + Geometry(Position position, Size size); + Geometry(signed x, signed y, signed width, signed height); + Geometry(const string& text); + + auto operator==(const Geometry& source) const -> bool; + auto operator!=(const Geometry& source) const -> bool; + + auto height() const -> signed; + auto position() const -> Position; + auto setGeometry(Geometry geometry = {}) -> type&; + auto setGeometry(Position position, Size size) -> type&; + auto setGeometry(signed x, signed y, signed width, signed height) -> type&; + auto setHeight(signed height) -> type&; + auto setPosition(Position position = {}) -> type&; + auto setPosition(signed x, signed y) -> type&; + auto setSize(Size size = {}) -> type&; + auto setSize(signed width, signed height) -> type&; + auto setWidth(signed width) -> type&; + auto setX(signed x) -> type&; + auto setY(signed y) -> type&; + auto size() const -> Size; + auto text() const -> string; + auto width() const -> signed; + auto x() const -> signed; + auto y() const -> signed; + +//private: + struct State { + signed x; + signed y; + signed width; + signed height; + } state; +}; + +struct Font { + Font() = delete; + + static auto serif(unsigned size = 0, const string& style = "") -> string; + static auto sans(unsigned size = 0, const string& style = "") -> string; + static auto monospace(unsigned size = 0, const string& style = "") -> string; + static auto size(const string& font, const string& text = " ") -> Size; +}; + +struct Desktop { + Desktop() = delete; + + static auto size() -> Size; + static auto workspace() -> Geometry; +}; + +struct Monitor { + Monitor() = delete; + + static auto count() -> unsigned; + static auto geometry(unsigned monitor) -> Geometry; + static auto primary() -> unsigned; +}; + +struct Keyboard { + Keyboard() = delete; + + static auto append(sHotkey hotkey) -> void; + static auto hotkey(unsigned position) -> sHotkey; + static auto hotkeys() -> unsigned; + static auto poll() -> vector; + static auto pressed(const string& key) -> bool; + static auto released(const string& key) -> bool; + static auto remove(sHotkey hotkey) -> void; + + static const vector keys; + +//private: + struct State { + vector hotkeys; + }; + static State state; +}; + +struct Mouse { + enum class Button : unsigned { Left, Middle, Right }; + + Mouse() = delete; + + static auto position() -> Position; + static auto pressed(Button) -> bool; + static auto released(Button) -> bool; +}; + +struct BrowserWindow { + using type = BrowserWindow; + + auto directory() -> string; + auto open() -> string; + auto save() -> string; + auto setFilters(const lstring& filters = {"*"}) -> type&; + auto setParent(sWindow parent) -> type&; + auto setPath(const string& path = "") -> type&; + auto setTitle(const string& title = "") -> type&; + +//private: + struct State { + lstring filters; + sWindow parent; + string path; + string title; + } state; +}; + +struct MessageWindow { + enum class Buttons : unsigned { Ok, OkCancel, YesNo, YesNoCancel }; + enum class Response : unsigned { Ok, Cancel, Yes, No }; + + using type = MessageWindow; + + MessageWindow(const string& text = ""); + + auto error(Buttons = Buttons::Ok) -> Response; + auto information(Buttons = Buttons::Ok) -> Response; + auto question(Buttons = Buttons::YesNo) -> Response; + auto setParent(sWindow parent) -> type&; + auto setText(const string& text = "") -> type&; + auto setTitle(const string& title = "") -> type&; + auto warning(Buttons = Buttons::Ok) -> Response; + +//private: + struct State { + MessageWindow::Buttons buttons = MessageWindow::Buttons::Ok; + sWindow parent; + string text; + string title; + } state; +}; + +#define Declare(Name) \ + using type = m##Name; \ + operator s##Name() const { return instance; } \ + auto self() -> p##Name* { return (p##Name*)delegate; } \ + auto self() const -> const p##Name* { return (const p##Name*)delegate; } \ + auto bind(const s##Name& instance) -> void { \ + this->instance = instance; \ + if(!abstract()) construct(); \ + } \ + auto unbind() -> void { \ + reset(); \ + destruct(); \ + instance.reset(); \ + } \ + virtual auto allocate() -> pObject*; \ + +struct mObject { + Declare(Object) + + mObject(); + virtual ~mObject(); + mObject(const mObject&) = delete; + mObject& operator=(const mObject&) = delete; + + auto abstract() const -> bool; + auto enabled(bool recursive = false) const -> bool; + virtual auto focused() const -> bool; + auto font(bool recursive = false) const -> string; + auto offset() const -> signed; + auto offset(signed displacement) -> type&; + auto parent() const -> mObject*; + auto parentComboButton(bool recursive = false) const -> mComboButton*; + auto parentFrame(bool recursive = false) const -> mFrame*; + auto parentIconView(bool recursive = false) const -> mIconView*; + auto parentLayout(bool recursive = false) const -> mLayout*; + auto parentListView(bool recursive = false) const -> mListView*; + auto parentMenu(bool recursive = false) const -> mMenu*; + auto parentMenuBar(bool recursive = false) const -> mMenuBar*; + auto parentPopupMenu(bool recursive = false) const -> mPopupMenu*; + auto parentSizable(bool recursive = false) const -> mSizable*; + auto parentTabFrame(bool recursive = false) const -> mTabFrame*; + auto parentTabFrameItem(bool recursive = false) const -> mTabFrameItem*; + auto parentTreeView(bool recursive = false) const -> mTreeView*; + auto parentTreeViewItem(bool recursive = false) const -> mTreeViewItem*; + auto parentWidget(bool recursive = false) const -> mWidget*; + auto parentWindow(bool recursive = false) const -> mWindow*; + virtual auto remove() -> type&; + virtual auto reset() -> type&; + virtual auto setEnabled(bool enabled = true) -> type&; + virtual auto setFocused() -> type&; + virtual auto setFont(const string& font = "") -> type&; + virtual auto setParent(mObject* parent = nullptr, signed offset = -1) -> type&; + virtual auto setVisible(bool visible = true) -> type&; + auto visible(bool recursive = false) const -> bool; + +//private: + struct State { + bool enabled = true; + string font; + signed offset = -1; + mObject* parent = nullptr; + bool visible = true; + } state; + + wObject instance; + pObject* delegate = nullptr; + + virtual auto construct() -> void; + virtual auto destruct() -> void; +}; + +struct mHotkey : mObject { + Declare(Hotkey) + + auto doPress() const -> void; + auto doRelease() const -> void; + auto onPress(const function& function = {}) -> type&; + auto onRelease(const function& function = {}) -> type&; + auto parent() const -> wObject; + auto remove() -> type& override; + auto sequence() const -> string; + auto setParent(sObject parent) -> type&; + auto setSequence(const string& sequence = "") -> type&; + +//private: + struct State { + bool active = false; + vector keys; + function onPress; + function onRelease; + wObject parent; + string sequence; + } state; +}; + +struct mTimer : mObject { + Declare(Timer) + + auto doActivate() const -> void; + auto interval() const -> unsigned; + auto onActivate(const function& function = {}) -> type&; + auto setInterval(unsigned interval = 0) -> type&; + +//private: + struct State { + unsigned interval = 0; + function onActivate; + } state; +}; + +struct mWindow : mObject { + Declare(Window) + using mObject::remove; + + auto append(sLayout layout) -> type&; + auto append(sMenuBar menuBar) -> type&; + auto append(sStatusBar statusBar) -> type&; + auto backgroundColor() const -> Color; + auto doClose() const -> void; + auto doDrop(lstring) const -> void; + auto doKeyPress(signed) const -> void; + auto doKeyRelease(signed) const -> void; + auto doMove() const -> void; + auto doSize() const -> void; + auto droppable() const -> bool; + auto frameGeometry() const -> Geometry; + auto fullScreen() const -> bool; + auto geometry() const -> Geometry; + auto layout() const -> sLayout; + auto menuBar() const -> sMenuBar; + auto modal() const -> bool; + auto onClose(const function& function = {}) -> type&; + auto onDrop(const function& function = {}) -> type&; + auto onKeyPress(const function& function = {}) -> type&; + auto onKeyRelease(const function& function = {}) -> type&; + auto onMove(const function& function = {}) -> type&; + auto onSize(const function& function = {}) -> type&; + auto remove(sLayout layout) -> type&; + auto remove(sMenuBar menuBar) -> type&; + auto remove(sStatusBar statusBar) -> type&; + auto reset() -> type& override; + auto resizable() const -> bool; + auto setBackgroundColor(Color color = {}) -> type&; + auto setCentered() -> type&; + auto setCentered(sWindow parent) -> type&; + auto setDroppable(bool droppable = true) -> type&; + auto setFrameGeometry(Geometry geometry) -> type&; + auto setFramePosition(Position position) -> type&; + auto setFrameSize(Size size) -> type&; + auto setFullScreen(bool fullScreen = true) -> type&; + auto setGeometry(Geometry geometry) -> type&; + auto setModal(bool modal = true) -> type&; + auto setPosition(Position position) -> type&; + auto setResizable(bool resizable = true) -> type&; + auto setSize(Size size) -> type&; + auto setTitle(const string& title = "") -> type&; + auto statusBar() const -> sStatusBar; + auto title() const -> string; + +//private: + struct State { + Color backgroundColor; + bool droppable = false; + bool fullScreen = false; + Geometry geometry = {128, 128, 256, 256}; + sLayout layout; + sMenuBar menuBar; + bool modal = false; + function onClose; + function onDrop; + function onKeyPress; + function onKeyRelease; + function onMove; + function onSize; + bool resizable = true; + sStatusBar statusBar; + string title; + } state; + + auto destruct() -> void; +}; + +struct mStatusBar : mObject { + Declare(StatusBar) + + auto remove() -> type& override; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + string text; + } state; +}; + +struct mMenuBar : mObject { + Declare(MenuBar) + + auto append(sMenu menu) -> type&; + auto menu(unsigned position) const -> sMenu; + auto menus() const -> unsigned; + auto remove() -> type& override; + auto remove(sMenu menu) -> type&; + auto reset() -> type&; + +//private: + struct State { + vector menus; + } state; + + auto destruct() -> void override; +}; + +struct mPopupMenu : mObject { + Declare(PopupMenu) + using mObject::remove; + + auto action(unsigned position) const -> sAction; + auto actions() const -> unsigned; + auto append(sAction action) -> type&; + auto remove(sAction action) -> type&; + auto reset() -> type&; + auto setVisible(bool visible = true) -> type& override; + +//private: + struct State { + vector actions; + } state; + + auto destruct() -> void override; +}; + +struct mAction : mObject { + Declare(Action) + + auto remove() -> type& override; + +//private: + struct State { + } state; +}; + +struct mMenu : mAction { + Declare(Menu) + using mObject::remove; + + auto action(unsigned position) const -> sAction; + auto actions() const -> unsigned; + auto append(sAction action) -> type&; + auto icon() const -> image; + auto remove(sAction action) -> type&; + auto reset() -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + vector actions; + image icon; + string text; + } state; + + auto destruct() -> void override; +}; + +struct mMenuSeparator : mAction { + Declare(MenuSeparator) + +//private: + struct State { + } state; +}; + +struct mMenuItem : mAction { + Declare(MenuItem) + + auto doActivate() const -> void; + auto icon() const -> image; + auto onActivate(const function& function = {}) -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + image icon; + function onActivate; + string text; + } state; +}; + +struct mMenuCheckItem : mAction { + Declare(MenuCheckItem) + + auto checked() const -> bool; + auto doToggle() const -> void; + auto onToggle(const function& function = {}) -> type&; + auto setChecked(bool checked = true) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + bool checked = false; + function onToggle; + string text; + } state; +}; + +struct mMenuRadioItem : mAction { + Declare(MenuRadioItem) + + auto checked() const -> bool; + auto doActivate() const -> void; + auto onActivate(const function& function = {}) -> type&; + auto setChecked() -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + + static auto group(const vector& group) -> void; + +//private: + struct State { + bool checked = true; + vector group; + function onActivate; + string text; + } state; +}; + +struct mSizable : mObject { + Declare(Sizable) + + auto geometry() const -> Geometry; + virtual auto minimumSize() const -> Size; + virtual auto setGeometry(Geometry geometry) -> type&; + +//private: + struct State { + Geometry geometry; + } state; +}; + +struct mLayout : mSizable { + Declare(Layout) + + virtual auto append(sSizable sizable) -> type&; + virtual auto remove() -> type& override; + virtual auto remove(sSizable sizable) -> type&; + virtual auto reset() -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; + auto sizable(unsigned position) const -> sSizable; + auto sizables() const -> unsigned; + +//private: + struct State { + vector sizables; + } state; + + auto destruct() -> void override; +}; + +struct mWidget : mSizable { + Declare(Widget) + + auto doSize() const -> void; + auto onSize(const function& function = {}) -> type&; + auto remove() -> type& override; + +//private: + struct State { + function onSize; + } state; +}; + +struct mButton : mWidget { + Declare(Button) + + auto bordered() const -> bool; + auto doActivate() const -> void; + auto icon() const -> image; + auto onActivate(const function& function = {}) -> type&; + auto orientation() const -> Orientation; + auto setBordered(bool bordered = true) -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + bool bordered = true; + image icon; + function onActivate; + Orientation orientation = Orientation::Horizontal; + string text; + } state; +}; + +struct mCanvas : mWidget { + Declare(Canvas) + + auto color() const -> Color; + auto data() -> uint32_t*; + auto droppable() const -> bool; + auto doDrop(lstring names) const -> void; + auto doMouseLeave() const -> void; + auto doMouseMove(Position position) const -> void; + auto doMousePress(Mouse::Button button) const -> void; + auto doMouseRelease(Mouse::Button button) const -> void; + auto gradient() const -> vector; + auto icon() const -> image; + auto onDrop(const function& function = {}) -> type&; + auto onMouseLeave(const function& function = {}) -> type&; + auto onMouseMove(const function& function = {}) -> type&; + auto onMousePress(const function& function = {}) -> type&; + auto onMouseRelease(const function& function = {}) -> type&; + auto setColor(Color color) -> type&; + auto setData(Size size) -> type&; + auto setDroppable(bool droppable = true) -> type&; + auto setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> type&; + auto setHorizontalGradient(Color left, Color right) -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setVerticalGradient(Color top, Color bottom) -> type&; + auto size() const -> Size; + auto update() -> type&; + +//private: + struct State { + Color color; + vector data; + bool droppable = false; + vector gradient = {{}, {}, {}, {}}; + image icon; + function onDrop; + function onMouseLeave; + function onMouseMove; + function onMousePress; + function onMouseRelease; + Size size; + } state; +}; + +struct mCheckButton : mWidget { + Declare(CheckButton) + + auto bordered() const -> bool; + auto checked() const -> bool; + auto doToggle() const -> void; + auto icon() const -> image; + auto onToggle(const function& function = {}) -> type&; + auto orientation() const -> Orientation; + auto setBordered(bool bordered = true) -> type&; + auto setChecked(bool checked = true) -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + bool bordered = false; + bool checked = false; + image icon; + function onToggle; + Orientation orientation = Orientation::Horizontal; + string text; + } state; +}; + +struct mCheckLabel : mWidget { + Declare(CheckLabel) + + auto checked() const -> bool; + auto doToggle() const -> void; + auto onToggle(const function& function = {}) -> type&; + auto setChecked(bool checked = true) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + bool checked = false; + function onToggle; + string text; + } state; +}; + +struct mComboButton : mWidget { + Declare(ComboButton) + using mObject::remove; + + auto append(sComboButtonItem item) -> type&; + auto doChange() const -> void; + auto item(unsigned position) const -> sComboButtonItem; + auto items() const -> unsigned; + auto onChange(const function& function = {}) -> type&; + auto remove(sComboButtonItem item) -> type&; + auto reset() -> type&; + auto selected() const -> sComboButtonItem; + +//private: + struct State { + vector items; + function onChange; + signed selected = -1; + } state; + + auto destruct() -> void override; +}; + +struct mComboButtonItem : mObject { + Declare(ComboButtonItem) + + auto icon() const -> image; + auto remove() -> type& override; + auto selected() const -> bool; + auto setIcon(const image& icon = {}) -> type&; + auto setSelected() -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + image icon; + string text; + } state; +}; + +struct mConsole : mWidget { + Declare(Console) + + auto backgroundColor() const -> Color; + auto doActivate(string) const -> void; + auto foregroundColor() const -> Color; + auto onActivate(const function& function = {}) -> type&; + auto print(const string& text) -> type&; + auto prompt() const -> string; + auto reset() -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setPrompt(const string& prompt = "") -> type&; + +//private: + struct State { + Color backgroundColor; + Color foregroundColor; + function onActivate; + string prompt; + } state; +}; + +struct mFrame : mWidget { + Declare(Frame) + using mObject::remove; + + auto append(sLayout layout) -> type&; + auto layout() const -> sLayout; + auto remove(sLayout layout) -> type&; + auto reset() -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + sLayout layout; + string text; + } state; + + auto destruct() -> void override; +}; + +struct mHexEdit : mWidget { + Declare(HexEdit) + + auto backgroundColor() const -> Color; + auto columns() const -> unsigned; + auto doRead(unsigned offset) const -> uint8_t; + auto doWrite(unsigned offset, uint8_t data) const -> void; + auto foregroundColor() const -> Color; + auto length() const -> unsigned; + auto offset() const -> unsigned; + auto onRead(const function& function = {}) -> type&; + auto onWrite(const function& function = {}) -> type&; + auto rows() const -> unsigned; + auto setBackgroundColor(Color color = {}) -> type&; + auto setColumns(unsigned columns = 16) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setLength(unsigned length) -> type&; + auto setOffset(unsigned offset) -> type&; + auto setRows(unsigned rows = 16) -> type&; + auto update() -> type&; + +//private: + struct State { + Color backgroundColor; + unsigned columns = 16; + Color foregroundColor; + unsigned length = 0; + unsigned offset = 0; + function onRead; + function onWrite; + unsigned rows = 16; + } state; +}; + +struct mHorizontalScroller : mWidget { + Declare(HorizontalScroller) + + auto doChange() const -> void; + auto length() const -> unsigned; + auto onChange(const function& function = {}) -> type&; + auto position() const -> unsigned; + auto setLength(unsigned length = 101) -> type&; + auto setPosition(unsigned position = 0) -> type&; + +//private: + struct State { + unsigned length = 101; + function onChange; + unsigned position = 0; + } state; +}; + +struct mHorizontalSlider : mWidget { + Declare(HorizontalSlider) + + auto doChange() const -> void; + auto length() const -> unsigned; + auto onChange(const function& function = {}) -> type&; + auto position() const -> unsigned; + auto setLength(unsigned length = 101) -> type&; + auto setPosition(unsigned position = 0) -> type&; + +//private: + struct State { + unsigned length = 101; + function onChange; + unsigned position = 0; + } state; +}; + +struct mIconView : mWidget { + Declare(IconView) + using mObject::remove; + + auto append(sIconViewItem item) -> type&; + auto backgroundColor() const -> Color; + auto doActivate() const -> void; + auto doChange() const -> void; + auto doContext() const -> void; + auto flow() const -> Orientation; + auto foregroundColor() const -> Color; + auto item(unsigned position) const -> sIconViewItem; + auto items() const -> unsigned; + auto multiSelect() const -> bool; + auto onActivate(const function& function = {}) -> type&; + auto onChange(const function& function = {}) -> type&; + auto onContext(const function& function = {}) -> type&; + auto orientation() const -> Orientation; + auto remove(sIconViewItem item) -> type&; + auto reset() -> type&; + auto selected() const -> maybe; + auto selectedItems() const -> vector; + auto setBackgroundColor(Color color = {}) -> type&; + auto setFlow(Orientation flow = Orientation::Vertical) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setMultiSelect(bool multipleSelections = true) -> type&; + auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; + auto setSelected(const vector& selections) -> type&; + +//private: + struct State { + Color backgroundColor; + Color foregroundColor; + Orientation flow = Orientation::Vertical; + vector items; + bool multiSelect = false; + function onActivate; + function onChange; + function onContext; + Orientation orientation = Orientation::Horizontal; + } state; + + auto destruct() -> void override; +}; + +struct mIconViewItem : mObject { + Declare(IconViewItem) + + auto icon() const -> image; + auto remove() -> type& override; + auto selected() const -> bool; + auto setIcon(const image& icon = {}) -> type&; + auto setSelected(bool selected = true) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + image icon; + bool selected = false; + string text; + } state; +}; + +struct mLabel : mWidget { + Declare(Label) + + auto horizontalAlignment() const -> double; + auto setHorizontalAlignment(double alignment = 0.0) -> type&; + auto setText(const string& text = "") -> type&; + auto setVerticalAlignment(double alignment = 0.5) -> type&; + auto text() const -> string; + auto verticalAlignment() const -> double; + +//private: + struct State { + double horizontalAlignment = 0.0; + string text; + double verticalAlignment = 0.5; + } state; +}; + +struct mLineEdit : mWidget { + Declare(LineEdit) + + auto backgroundColor() const -> Color; + auto doActivate() const -> void; + auto doChange() const -> void; + auto editable() const -> bool; + auto foregroundColor() const -> Color; + auto onActivate(const function& function = {}) -> type&; + auto onChange(const function& function = {}) -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setEditable(bool editable = true) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + Color backgroundColor; + bool editable = true; + Color foregroundColor; + function onActivate; + function onChange; + string text; + } state; +}; + +struct mListView : mWidget { + Declare(ListView) + using mObject::remove; + + auto append(sListViewColumn column) -> type&; + auto append(sListViewItem item) -> type&; + auto backgroundColor() const -> Color; + auto checkable() const -> bool; + auto checked() const -> vector; + auto column(unsigned position) const -> sListViewColumn; + auto columns() const -> unsigned; + auto doActivate() const -> void; + auto doChange() const -> void; + auto doContext() const -> void; + auto doEdit(sListViewItem item, sListViewColumn column) const -> void; + auto doSort(sListViewColumn column) const -> void; + auto doToggle(sListViewItem item) const -> void; + auto foregroundColor() const -> Color; + auto gridVisible() const -> bool; + auto headerVisible() const -> bool; + auto item(unsigned position) const -> sListViewItem; + auto items() const -> unsigned; + auto multiSelect() const -> bool; + auto onActivate(const function& function = {}) -> type&; + auto onChange(const function& function = {}) -> type&; + auto onContext(const function& function = {}) -> type&; + auto onEdit(const function& function = {}) -> type&; + auto onSort(const function& function = {}) -> type&; + auto onToggle(const function& function = {}) -> type&; + auto remove(sListViewColumn column) -> type&; + auto remove(sListViewItem item) -> type&; + auto reset() -> type&; + auto resizeColumns() -> type&; + auto selected() const -> sListViewItem; + auto selectedItems() const -> vector; + auto setBackgroundColor(Color color = {}) -> type&; + auto setCheckable(bool checkable = true) -> type&; + auto setChecked(bool checked = true) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setGridVisible(bool visible = true) -> type&; + auto setHeaderVisible(bool visible = true) -> type&; + auto setMultiSelect(bool multiSelect = true) -> type&; + auto setSelected(bool selected = true) -> type&; + +//private: + struct State { + unsigned activeColumn = 0; + Color backgroundColor; + bool checkable = false; + vector columns; + Color foregroundColor; + bool gridVisible = false; + bool headerVisible = false; + vector items; + bool multiSelect = false; + function onActivate; + function onChange; + function onContext; + function onEdit; + function onSort; + function onToggle; + } state; + + auto destruct() -> void override; +}; + +struct mListViewColumn : mObject { + Declare(ListViewColumn) + + auto active() const -> bool; + auto backgroundColor() const -> Color; + auto editable() const -> bool; + auto foregroundColor() const -> Color; + auto horizontalAlignment() const -> double; + auto icon() const -> image; + auto remove() -> type& override; + auto resizable() const -> bool; + auto setActive() -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setEditable(bool editable = true) -> type&; + auto setFont(const string& font = "") -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setHorizontalAlignment(double alignment = 0.0) -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setResizable(bool resizable = true) -> type&; + auto setSortable(bool sortable = true) -> type&; + auto setText(const string& text = "") -> type&; + auto setVerticalAlignment(double alignment = 0.5) -> type&; + auto setVisible(bool visible = true) -> type&; + auto setWidth(signed width = 0) -> type&; + auto sortable() const -> bool; + auto text() const -> string; + auto verticalAlignment() const -> double; + auto width() const -> signed; + +//private: + struct State { + Color backgroundColor; + bool editable = false; + string font; + Color foregroundColor; + double horizontalAlignment = 0.0; + image icon; + bool resizable = true; + bool sortable = false; + string text; + double verticalAlignment = 0.5; + bool visible = true; + signed width = 0; + } state; +}; + +struct mListViewItem : mObject { + Declare(ListViewItem) + + auto checked() const -> bool; + auto icon(unsigned column = 0) const -> image; + auto remove() -> type& override; + auto selected() const -> bool; + auto setChecked(bool checked = true) -> type&; + auto setFocused() -> type& override; + auto setIcon(unsigned column, const image& icon = {}) -> type&; + auto setSelected(bool selected = true) -> type&; + auto setText(const lstring& text) -> type&; + auto setText(unsigned column, const string& text = "") -> type&; + auto text(unsigned column = 0) const -> string; + +//private: + struct State { + bool checked = false; + vector icon; + bool selected = false; + lstring text; + } state; +}; + +struct mProgressBar : mWidget { + Declare(ProgressBar) + + auto position() const -> unsigned; + auto setPosition(unsigned position) -> type&; + +//private: + struct State { + unsigned position = 0; + } state; +}; + +struct mRadioButton : mWidget { + Declare(RadioButton) + + auto bordered() const -> bool; + auto checked() const -> bool; + auto doActivate() const -> void; + auto icon() const -> image; + auto onActivate(const function& function = {}) -> type&; + auto orientation() const -> Orientation; + auto setBordered(bool bordered = true) -> type&; + auto setChecked() -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + + static auto group(const vector& group) -> void; + +//private: + struct State { + bool bordered = true; + bool checked = true; + vector group; + image icon; + function onActivate; + Orientation orientation = Orientation::Horizontal; + string text; + } state; +}; + +struct mRadioLabel : mWidget { + Declare(RadioLabel) + + auto checked() const -> bool; + auto doActivate() const -> void; + auto onActivate(const function& function = {}) -> type&; + auto setChecked() -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + + static auto group(const vector& group) -> void; + +//private: + struct State { + bool checked = true; + vector group; + function onActivate; + string text; + } state; +}; + +struct mSourceEdit : mWidget { + Declare(SourceEdit) + + auto doChange() const -> void; + auto doMove() const -> void; + auto onChange(const function& function = {}) -> type&; + auto onMove(const function& function = {}) -> type&; + auto position() const -> unsigned; + auto setPosition(signed position) -> type&; + auto setSelected(Position selected) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + function onChange; + function onMove; + unsigned position = 0; + Position selected; + string text; + } state; +}; + +struct mTabFrame : mWidget { + Declare(TabFrame) + using mObject::remove; + friend class mTabFrameItem; + + auto append(sTabFrameItem item) -> type&; + auto doChange() const -> void; + auto doClose(sTabFrameItem item) const -> void; + auto doMove(sTabFrameItem from, sTabFrameItem to) const -> void; + auto edge() const -> Edge; + auto item(unsigned position) const -> sTabFrameItem; + auto items() const -> unsigned; + auto onChange(const function& function = {}) -> type&; + auto onClose(const function& function = {}) -> type&; + auto onMove(const function& function = {}) -> type&; + auto remove(sTabFrameItem item) -> type&; + auto reset() -> type&; + auto selected() const -> sTabFrameItem; + auto setEdge(Edge edge = Edge::Top) -> type&; + auto setParent(mObject* object = nullptr, signed offset = -1) -> type& override; + +//private: + struct State { + Edge edge = Edge::Top; + vector items; + function onChange; + function onClose; + function onMove; + unsigned selected = 0; + } state; + + auto destruct() -> void override; +}; + +struct mTabFrameItem : mObject { + Declare(TabFrameItem) + + auto append(sLayout layout) -> type&; + auto closable() const -> bool; + auto icon() const -> image; + auto layout() const -> sLayout; + auto movable() const -> bool; + auto remove() -> type& override; + auto remove(sLayout layout) -> type&; + auto reset() -> type&; + auto selected() const -> bool; + auto setClosable(bool closable = true) -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setMovable(bool movable = true) -> type&; + auto setParent(mObject* object = nullptr, signed offset = -1) -> type& override; + auto setSelected() -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + bool closable = false; + image icon; + sLayout layout; + bool movable = false; + string text; + } state; + + auto destruct() -> void override; +}; + +struct mTextEdit : mWidget { + Declare(TextEdit) + + auto backgroundColor() const -> Color; + auto cursorPosition() const -> unsigned; + auto doChange() const -> void; + auto doMove() const -> void; + auto editable() const -> bool; + auto foregroundColor() const -> Color; + auto onChange(const function& function = {}) -> type&; + auto onMove(const function& function = {}) -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setCursorPosition(unsigned position) -> type&; + auto setEditable(bool editable = true) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setText(const string& text = "") -> type&; + auto setWordWrap(bool wordWrap = true) -> type&; + auto text() const -> string; + auto wordWrap() const -> bool; + +//private: + struct State { + Color backgroundColor; + unsigned cursorPosition = 0; + bool editable = true; + Color foregroundColor; + function onChange; + function onMove; + string text; + bool wordWrap = true; + } state; +}; + +struct mTreeView : mWidget { + Declare(TreeView) + using mObject::remove; + + auto append(sTreeViewItem item) -> type&; + auto backgroundColor() const -> Color; + auto checkable() const -> bool; + auto collapse() -> type&; + auto doActivate() const -> void; + auto doChange() const -> void; + auto doContext() const -> void; + auto doToggle(sTreeViewItem item) const -> void; + auto expand() -> type&; + auto foregroundColor() const -> Color; + auto item(const string& path) const -> sTreeViewItem; + auto items() const -> unsigned; + auto onActivate(const function& function = {}) -> type&; + auto onChange(const function& function = {}) -> type&; + auto onContext(const function& function = {}) -> type&; + auto onToggle(const function& function = {}) -> type&; + auto remove(sTreeViewItem item) -> type&; + auto reset() -> type&; + auto selected() const -> sTreeViewItem; + auto setBackgroundColor(Color color = {}) -> type&; + auto setCheckable(bool checkable = true) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + +//private: + struct State { + Color backgroundColor; + bool checkable = false; + Color foregroundColor; + vector items; + function onActivate; + function onChange; + function onContext; + function onToggle; + string selectedPath; + } state; + + auto destruct() -> void override; +}; + +struct mTreeViewItem : mObject { + Declare(TreeViewItem) + + auto append(sTreeViewItem item) -> type&; + auto checked() const -> bool; + auto icon() const -> image; + auto item(const string& path) const -> sTreeViewItem; + auto items() const -> unsigned; + auto path() const -> string; + auto remove() -> type& override; + auto remove(sTreeViewItem item) -> type&; + auto selected() const -> bool; + auto setChecked(bool checked = true) -> type&; + auto setFocused() -> type& override; + auto setIcon(const image& icon = {}) -> type&; + auto setSelected() -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + bool checked = false; + image icon; + vector items; + string text; + } state; + + auto destruct() -> void override; +}; + +struct mVerticalScroller : mWidget { + Declare(VerticalScroller) + + auto doChange() const -> void; + auto length() const -> unsigned; + auto onChange(const function& function = {}) -> type&; + auto position() const -> unsigned; + auto setLength(unsigned length = 101) -> type&; + auto setPosition(unsigned position = 0) -> type&; + +//private: + struct State { + unsigned length = 101; + function onChange; + unsigned position = 0; + } state; +}; + +struct mVerticalSlider : mWidget { + Declare(VerticalSlider) + + auto doChange() const -> void; + auto length() const -> unsigned; + auto onChange(const function& function = {}) -> type&; + auto position() const -> unsigned; + auto setLength(unsigned length = 101) -> type&; + auto setPosition(unsigned position = 0) -> type&; + +//private: + struct State { + unsigned length = 101; + function onChange; + unsigned position = 0; + } state; +}; + +struct mViewport : mWidget { + Declare(Viewport) + + auto doDrop(lstring names) const -> void; + auto doMouseLeave() const -> void; + auto doMouseMove(Position position) const -> void; + auto doMousePress(Mouse::Button button) const -> void; + auto doMouseRelease(Mouse::Button button) const -> void; + auto droppable() const -> bool; + auto handle() const -> uintptr_t; + auto onDrop(const function& function = {}) -> type&; + auto onMouseLeave(const function& function = {}) -> type&; + auto onMouseMove(const function& function = {}) -> type&; + auto onMousePress(const function& function = {}) -> type&; + auto onMouseRelease(const function& function = {}) -> type&; + auto setDroppable(bool droppable = true) -> type&; + +//private: + struct State { + bool droppable = false; + function onDrop; + function onMouseLeave; + function onMouseMove; + function onMousePress; + function onMouseRelease; + } state; +}; + +#undef Declare + +} diff --git a/hiro/core/desktop.cpp b/hiro/core/desktop.cpp new file mode 100644 index 00000000..f8981629 --- /dev/null +++ b/hiro/core/desktop.cpp @@ -0,0 +1,7 @@ +auto Desktop::size() -> Size { + return pDesktop::size(); +} + +auto Desktop::workspace() -> Geometry { + return pDesktop::workspace(); +} diff --git a/hiro/core/font.cpp b/hiro/core/font.cpp new file mode 100644 index 00000000..0ca2deaf --- /dev/null +++ b/hiro/core/font.cpp @@ -0,0 +1,15 @@ +auto Font::serif(unsigned size, const string& style) -> string { + return pFont::serif(size, style); +} + +auto Font::sans(unsigned size, const string& style) -> string { + return pFont::sans(size, style); +} + +auto Font::monospace(unsigned size, const string& style) -> string { + return pFont::monospace(size, style); +} + +auto Font::size(const string& font, const string& text) -> Size { + return pFont::size(font, text); +} diff --git a/hiro/core/geometry.cpp b/hiro/core/geometry.cpp new file mode 100644 index 00000000..21cd32f5 --- /dev/null +++ b/hiro/core/geometry.cpp @@ -0,0 +1,112 @@ +Geometry::Geometry() { + setGeometry(0, 0, 0, 0); +} + +Geometry::Geometry(Position position, Size size) { + setGeometry(position, size); +} + +Geometry::Geometry(signed x, signed y, signed width, signed height) { + setGeometry(x, y, width, height); +} + +Geometry::Geometry(const string& text) { + lstring part = text.split(",").strip(); + state.x = integer(part(0)); + state.y = integer(part(1)); + state.width = integer(part(2)); + state.height = integer(part(3)); +} + +auto Geometry::operator==(const Geometry& source) const -> bool { + return x() == source.x() && y() == source.y() && width() == source.width() && height() == source.height(); +} + +auto Geometry::operator!=(const Geometry& source) const -> bool { + return !operator==(source); +} + +auto Geometry::height() const -> signed { + return state.height; +} + +auto Geometry::position() const -> Position { + return {state.x, state.y}; +} + +auto Geometry::setHeight(signed height) -> type& { + state.height = height; + return *this; +} + +auto Geometry::setGeometry(Geometry geometry) -> type& { + return setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height()); +} + +auto Geometry::setGeometry(Position position, Size size) -> type& { + setGeometry(position.x(), position.y(), size.width(), size.height()); + return *this; +} + +auto Geometry::setGeometry(signed x, signed y, signed width, signed height) -> type& { + state.x = x; + state.y = y; + state.width = width; + state.height = height; + return *this; +} + +auto Geometry::setPosition(Position position) -> type& { + return setPosition(position.x(), position.y()); +} + +auto Geometry::setPosition(signed x, signed y) -> type& { + state.x = x; + state.y = y; + return *this; +} + +auto Geometry::setSize(Size size) -> type& { + return setSize(size.width(), size.height()); +} + +auto Geometry::setSize(signed width, signed height) -> type& { + state.width = width; + state.height = height; + return *this; +} + +auto Geometry::setWidth(signed width) -> type& { + state.width = width; + return *this; +} + +auto Geometry::setX(signed x) -> type& { + state.x = x; + return *this; +} + +auto Geometry::setY(signed y) -> type& { + state.y = y; + return *this; +} + +auto Geometry::size() const -> Size { + return {state.width, state.height}; +} + +auto Geometry::text() const -> string { + return {state.x, ",", state.y, ",", state.width, ",", state.height}; +} + +auto Geometry::width() const -> signed { + return state.width; +} + +auto Geometry::x() const -> signed { + return state.x; +} + +auto Geometry::y() const -> signed { + return state.y; +} diff --git a/hiro/core/hotkey.cpp b/hiro/core/hotkey.cpp new file mode 100644 index 00000000..432fa659 --- /dev/null +++ b/hiro/core/hotkey.cpp @@ -0,0 +1,53 @@ +auto mHotkey::allocate() -> pObject* { + return new pHotkey(*this); +} + +// + +auto mHotkey::doPress() const -> void { + if(state.onPress) return state.onPress(); +} + +auto mHotkey::doRelease() const -> void { + if(state.onRelease) return state.onRelease(); +} + +auto mHotkey::onPress(const function& function) -> type& { + state.onPress = function; + return *this; +} + +auto mHotkey::onRelease(const function& function) -> type& { + state.onRelease = function; + return *this; +} + +auto mHotkey::parent() const -> wObject { + return state.parent; +} + +auto mHotkey::remove() -> type& { +//todo: remove from Keyboard::hotkeys + return *this; +} + +auto mHotkey::sequence() const -> string { + return state.sequence; +} + +auto mHotkey::setParent(sObject parent) -> type& { + state.parent = parent; + return *this; +} + +auto mHotkey::setSequence(const string& sequence) -> type& { + state.active = false; + state.sequence = sequence; + state.keys.reset(); + for(auto& key : sequence.split("+")) { + if(auto position = Keyboard::keys.find(key)) { + state.keys.append(*position); + } + } + return *this; +} diff --git a/hiro/core/keyboard.cpp b/hiro/core/keyboard.cpp new file mode 100644 index 00000000..4ab5d1ff --- /dev/null +++ b/hiro/core/keyboard.cpp @@ -0,0 +1,74 @@ +const vector Keyboard::keys = { + //physical keyboard buttons + "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", + "PrintScreen", "ScrollLock", "Pause", + "Insert", "Delete", "Home", "End", "PageUp", "PageDown", + "Up", "Down", "Left", "Right", + "Grave", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "Dash", "Equal", "Backspace", + "Tab", "CapsLock", "LeftEnter", "LeftShift", "RightShift", + "LeftControl", "RightControl", "LeftAlt", "RightAlt", "LeftSuper", "RightSuper", "Menu", "Space", + "OpenBracket", "CloseBracket", "Backslash", "Semicolon", "Apostrophe", "Comma", "Period", "Slash", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", + "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "NumLock", "Divide", "Multiply", "Subtract", "Add", "RightEnter", "Point", + "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Zero", + + //group aliases + "Shift", //"LeftShift" | "RightShift" + "Control", //"LeftControl" | "RightControl" + "Alt", //"LeftAlt" | "RightAlt" + "Super", //"LeftSuper" | "RightSuper" + "Enter", //"LeftEnter" | "RightEnter" +}; + +auto Keyboard::append(sHotkey hotkey) -> void { + state.hotkeys.append(hotkey); +} + +auto Keyboard::hotkey(unsigned position) -> sHotkey { + if(position >= hotkeys()) throw; + return state.hotkeys[position]; +} + +auto Keyboard::hotkeys() -> unsigned { + return state.hotkeys.size(); +} + +auto Keyboard::poll() -> vector { + auto pressed = pKeyboard::poll(); + + for(auto& hotkey : state.hotkeys) { + bool active = hotkey->state.sequence.size() > 0; + for(auto& key : hotkey->state.keys) { + if(pressed[key]) continue; + active = false; + break; + } + if(auto parent = hotkey->state.parent.acquire()) { + //todo: set active = false if parent no longer exists + active &= parent->focused(); + } + if(hotkey->state.active != active) { + hotkey->state.active = active; + if( active) hotkey->doPress(); + if(!active) hotkey->doRelease(); + } + } + + return pressed; +} + +auto Keyboard::pressed(const string& key) -> bool { + if(auto code = keys.find(key)) return pKeyboard::pressed(*code); + return false; +} + +auto Keyboard::released(const string& key) -> bool { + return !pressed(key); +} + +auto Keyboard::remove(sHotkey hotkey) -> void { + if(auto offset = state.hotkeys.find(hotkey)) { + state.hotkeys.remove(*offset); + } +} diff --git a/hiro/core/layout.cpp b/hiro/core/layout.cpp new file mode 100644 index 00000000..73a66996 --- /dev/null +++ b/hiro/core/layout.cpp @@ -0,0 +1,58 @@ +auto mLayout::allocate() -> pObject* { + return new pLayout(*this); +} + +auto mLayout::destruct() -> void { + for(auto& sizable : state.sizables) sizable->destruct(); + mSizable::destruct(); +} + +// + +auto mLayout::append(shared_pointer sizable) -> type& { + state.sizables.append(sizable); + sizable->setParent(this, sizables() - 1); + setGeometry(geometry()); + return *this; +} + +auto mLayout::remove() -> type& { + if(auto tabFrameItem = parentTabFrameItem()) tabFrameItem->remove(tabFrameItem->layout()); + if(auto layout = parentLayout()) layout->remove(layout->sizable(offset())); + if(auto window = parentWindow()) window->remove(window->layout()); + setParent(); + for(auto& sizable : state.sizables) sizable->setParent(this, sizable->offset()); + return *this; +} + +auto mLayout::remove(shared_pointer sizable) -> type& { + auto offset = sizable->offset(); + sizable->setParent(); + state.sizables.remove(offset); + for(auto n : range(offset, sizables())) { + state.sizables[n]->offset(-1); + } + setGeometry(geometry()); + return *this; +} + +auto mLayout::reset() -> type& { + while(state.sizables) remove(state.sizables.last()); + return *this; +} + +auto mLayout::setParent(mObject* parent, signed offset) -> type& { + for(auto& sizable : state.sizables) sizable->destruct(); + mObject::setParent(parent, offset); + for(auto& sizable : state.sizables) sizable->setParent(this, sizable->offset()); + return *this; +} + +auto mLayout::sizable(unsigned position) const -> shared_pointer { + if(position >= sizables()) throw; + return state.sizables[position]; +} + +auto mLayout::sizables() const -> unsigned { + return state.sizables.size(); +} diff --git a/hiro/core/menu-bar.cpp b/hiro/core/menu-bar.cpp new file mode 100644 index 00000000..c8559ddc --- /dev/null +++ b/hiro/core/menu-bar.cpp @@ -0,0 +1,47 @@ +auto mMenuBar::allocate() -> pObject* { + return new pMenuBar(*this); +} + +auto mMenuBar::destruct() -> void { + for(auto& menu : state.menus) menu->destruct(); + mObject::destruct(); +} + +// + +auto mMenuBar::append(shared_pointer menu) -> type& { + state.menus.append(menu); + menu->setParent(this, menus() - 1); + signal(append, menu); + return *this; +} + +auto mMenuBar::menu(unsigned position) const -> shared_pointer { + if(position >= menus()) throw; + return state.menus[position]; +} + +auto mMenuBar::menus() const -> unsigned { + return state.menus.size(); +} + +auto mMenuBar::remove() -> type& { + if(auto window = parentWindow()) window->remove(window->menuBar()); + return *this; +} + +auto mMenuBar::remove(shared_pointer menu) -> type& { + signed offset = menu->offset(); + signal(remove, *menu); + state.menus.remove(offset); + for(auto n : range(offset, menus())) { + state.menus[n]->offset(-1); + } + menu->setParent(); + return *this; +} + +auto mMenuBar::reset() -> type& { + while(state.menus) remove(state.menus.last()); + return *this; +} diff --git a/hiro/core/message-window.cpp b/hiro/core/message-window.cpp new file mode 100644 index 00000000..287e336d --- /dev/null +++ b/hiro/core/message-window.cpp @@ -0,0 +1,38 @@ +MessageWindow::MessageWindow(const string& text) { + state.text = text; +} + +auto MessageWindow::error(Buttons buttons) -> Response { + state.buttons = buttons; + return pMessageWindow::error(state); +} + +auto MessageWindow::information(Buttons buttons) -> Response { + state.buttons = buttons; + return pMessageWindow::information(state); +} + +auto MessageWindow::question(Buttons buttons) -> Response { + state.buttons = buttons; + return pMessageWindow::question(state); +} + +auto MessageWindow::setParent(shared_pointer parent) -> type& { + state.parent = parent; + return *this; +} + +auto MessageWindow::setText(const string& text) -> type& { + state.text = text; + return *this; +} + +auto MessageWindow::setTitle(const string& title) -> type& { + state.title = title; + return *this; +} + +auto MessageWindow::warning(MessageWindow::Buttons buttons) -> Response { + state.buttons = buttons; + return pMessageWindow::warning(state); +} diff --git a/hiro/core/monitor.cpp b/hiro/core/monitor.cpp new file mode 100644 index 00000000..6ca1984a --- /dev/null +++ b/hiro/core/monitor.cpp @@ -0,0 +1,11 @@ +auto Monitor::count() -> unsigned { + return pMonitor::count(); +} + +auto Monitor::geometry(unsigned monitor) -> Geometry { + return pMonitor::geometry(monitor); +} + +auto Monitor::primary() -> unsigned { + return pMonitor::primary(); +} diff --git a/hiro/core/mouse.cpp b/hiro/core/mouse.cpp new file mode 100644 index 00000000..49fe1574 --- /dev/null +++ b/hiro/core/mouse.cpp @@ -0,0 +1,11 @@ +auto Mouse::position() -> Position { + return pMouse::position(); +} + +auto Mouse::pressed(Mouse::Button button) -> bool { + return pMouse::pressed(button); +} + +auto Mouse::released(Mouse::Button button) -> bool { + return !pressed(button); +} diff --git a/hiro/core/object.cpp b/hiro/core/object.cpp new file mode 100644 index 00000000..3b97fe28 --- /dev/null +++ b/hiro/core/object.cpp @@ -0,0 +1,233 @@ +mObject::mObject() { + Application::initialize(); +} + +mObject::~mObject() { +} + +auto mObject::allocate() -> pObject* { + return new pObject(*this); +} + +auto mObject::construct() -> void { + if(delegate) return; + delegate = allocate(); + signal(construct); +} + +auto mObject::destruct() -> void { + if(!delegate) return; + signal(destruct); + delete delegate; + delegate = nullptr; +} + +// + +//this is used to control dynamic allocation of pObject delegates +//an mObject is abstract only if it has no top-level object (eg a Button not attached to any Window) +//if the mObject is not abstract, the pObject delegate is allocated immediately +//otherwise, the pObject is not allocated until it is attached to a non-abstract parent +auto mObject::abstract() const -> bool { + if(dynamic_cast(this)) return false; + if(dynamic_cast(this)) return false; + if(auto object = parent()) return object->abstract(); + return true; +} + +auto mObject::enabled(bool recursive) const -> bool { + if(!recursive || !state.enabled) return state.enabled; + if(auto object = parent()) return object->enabled(true); + return true; +} + +auto mObject::focused() const -> bool { + if(signal(focused)) return true; + return false; +} + +auto mObject::font(bool recursive) const -> string { + if(!recursive || state.font) return state.font; + if(auto object = parent()) return object->font(true); + return Application::font(); +} + +auto mObject::offset() const -> signed { + return state.offset; +} + +auto mObject::offset(signed displacement) -> type& { + state.offset += displacement; + return *this; +} + +auto mObject::parent() const -> mObject* { + return state.parent; +} + +auto mObject::parentComboButton(bool recursive) const -> mComboButton* { + if(auto comboButton = dynamic_cast(parent())) return comboButton; + if(recursive) { + if(auto object = parent()) return object->parentComboButton(true); + } + return nullptr; +} + +auto mObject::parentFrame(bool recursive) const -> mFrame* { + if(auto frame = dynamic_cast(parent())) return frame; + if(recursive) { + if(auto object = parent()) return object->parentFrame(true); + } + return nullptr; +} + +auto mObject::parentIconView(bool recursive) const -> mIconView* { + if(auto iconView = dynamic_cast(parent())) return iconView; + if(recursive) { + if(auto object = parent()) return object->parentIconView(true); + } + return nullptr; +} + +auto mObject::parentLayout(bool recursive) const -> mLayout* { + if(auto layout = dynamic_cast(parent())) return layout; + if(recursive) { + if(auto object = parent()) return object->parentLayout(true); + } + return nullptr; +} + +auto mObject::parentListView(bool recursive) const -> mListView* { + if(auto listView = dynamic_cast(parent())) return listView; + if(recursive) { + if(auto object = parent()) return object->parentListView(true); + } + return nullptr; +} + +auto mObject::parentMenu(bool recursive) const -> mMenu* { + if(auto menu = dynamic_cast(parent())) return menu; + if(recursive) { + if(auto object = parent()) return object->parentMenu(true); + } + return nullptr; +} + +auto mObject::parentMenuBar(bool recursive) const -> mMenuBar* { + if(auto menuBar = dynamic_cast(parent())) return menuBar; + if(recursive) { + if(auto object = parent()) return object->parentMenuBar(true); + } + return nullptr; +} + +auto mObject::parentPopupMenu(bool recursive) const -> mPopupMenu* { + if(auto popupMenu = dynamic_cast(parent())) return popupMenu; + if(recursive) { + if(auto object = parent()) return object->parentPopupMenu(true); + } + return nullptr; +} + +auto mObject::parentSizable(bool recursive) const -> mSizable* { + if(auto sizable = dynamic_cast(parent())) return sizable; + if(recursive) { + if(auto object = parent()) return object->parentSizable(true); + } + return nullptr; +} + +auto mObject::parentTabFrame(bool recursive) const -> mTabFrame* { + if(auto tabFrame = dynamic_cast(parent())) return tabFrame; + if(recursive) { + if(auto object = parent()) return object->parentTabFrame(true); + } + return nullptr; +} + +auto mObject::parentTabFrameItem(bool recursive) const -> mTabFrameItem* { + if(auto tabFrameItem = dynamic_cast(parent())) return tabFrameItem; + if(recursive) { + if(auto object = parent()) return object->parentTabFrameItem(true); + } + return nullptr; +} + +auto mObject::parentTreeView(bool recursive) const -> mTreeView* { + if(auto treeView = dynamic_cast(parent())) return treeView; + if(recursive) { + if(auto object = parent()) return object->parentTreeView(true); + } + return nullptr; +} + +auto mObject::parentTreeViewItem(bool recursive) const -> mTreeViewItem* { + if(auto treeViewItem = dynamic_cast(parent())) return treeViewItem; + if(recursive) { + if(auto object = parent()) return object->parentTreeViewItem(true); + } + return nullptr; +} + +auto mObject::parentWidget(bool recursive) const -> mWidget* { + if(auto widget = dynamic_cast(parent())) return widget; + if(recursive) { + if(auto object = parent()) return object->parentWidget(true); + } + return nullptr; +} + +auto mObject::parentWindow(bool recursive) const -> mWindow* { + if(auto window = dynamic_cast(parent())) return window; + if(recursive) { + if(auto object = parent()) return object->parentWindow(true); + } + return nullptr; +} + +auto mObject::remove() -> type& { + signal(remove); + return *this; +} + +auto mObject::reset() -> type& { + signal(reset); + return *this; +} + +auto mObject::setEnabled(bool enabled) -> type& { + state.enabled = enabled; + signal(setEnabled, this->enabled(true)); + return *this; +} + +auto mObject::setFocused() -> type& { + signal(setFocused); + return *this; +} + +auto mObject::setFont(const string& font) -> type& { + state.font = font; + signal(setFont, this->font(true)); + return *this; +} + +auto mObject::setParent(mObject* parent, signed offset) -> type& { + destruct(); + state.parent = parent; + state.offset = offset; + if(!abstract()) construct(); + return *this; +} + +auto mObject::setVisible(bool visible) -> type& { + state.visible = visible; + signal(setVisible, this->visible(true)); + return *this; +} + +auto mObject::visible(bool recursive) const -> bool { + if(!recursive || !state.visible) return state.visible; + if(auto object = parent()) return object->visible(true); + return true; +} diff --git a/hiro/core/popup-menu.cpp b/hiro/core/popup-menu.cpp new file mode 100644 index 00000000..6e74fd7f --- /dev/null +++ b/hiro/core/popup-menu.cpp @@ -0,0 +1,47 @@ +auto mPopupMenu::allocate() -> pObject* { + return new pPopupMenu(*this); +} + +auto mPopupMenu::destruct() -> void { + for(auto& action : state.actions) action->destruct(); + mObject::destruct(); +} + +// + +auto mPopupMenu::action(unsigned position) const -> sAction { + if(position >= actions()) throw; + return state.actions[position]; +} + +auto mPopupMenu::actions() const -> unsigned { + return state.actions.size(); +} + +auto mPopupMenu::append(sAction action) -> type& { + state.actions.append(action); + action->setParent(this, actions() - 1); + signal(append, action); + return *this; +} + +auto mPopupMenu::remove(sAction action) -> type& { + signed offset = action->offset(); + signal(remove, action); + state.actions.remove(offset); + for(auto n : range(offset, actions())) { + state.actions[n]->offset(-1); + } + action->setParent(); + return *this; +} + +auto mPopupMenu::reset() -> type& { + while(state.actions) remove(state.actions.last()); + return *this; +} + +auto mPopupMenu::setVisible(bool visible) -> type& { + signal(setVisible, visible); + return *this; +} diff --git a/hiro/core/position.cpp b/hiro/core/position.cpp new file mode 100644 index 00000000..f878fc01 --- /dev/null +++ b/hiro/core/position.cpp @@ -0,0 +1,43 @@ +Position::Position() { + setPosition(0, 0); +} + +Position::Position(signed x, signed y) { + setPosition(x, y); +} + +auto Position::operator==(const Position& source) const -> bool { + return x() == source.x() && y() == source.y(); +} + +auto Position::operator!=(const Position& source) const -> bool { + return !operator==(source); +} + +auto Position::setPosition(Position position) -> type& { + return setPosition(position.x(), position.y()); +} + +auto Position::setPosition(signed x, signed y) -> type& { + state.x = x; + state.y = y; + return *this; +} + +auto Position::setX(signed x) -> type& { + state.x = x; + return *this; +} + +auto Position::setY(signed y) -> type& { + state.y = y; + return *this; +} + +auto Position::x() const -> signed { + return state.x; +} + +auto Position::y() const -> signed { + return state.y; +} diff --git a/hiro/core/sizable.cpp b/hiro/core/sizable.cpp new file mode 100644 index 00000000..210226fd --- /dev/null +++ b/hiro/core/sizable.cpp @@ -0,0 +1,17 @@ +auto mSizable::allocate() -> pObject* { + return new pSizable(*this); +} + +auto mSizable::geometry() const -> Geometry { + return state.geometry; +} + +auto mSizable::minimumSize() const -> Size { + return signal(minimumSize); +} + +auto mSizable::setGeometry(Geometry geometry) -> type& { + state.geometry = geometry; + signal(setGeometry, geometry); + return *this; +} diff --git a/hiro/core/size.cpp b/hiro/core/size.cpp new file mode 100644 index 00000000..950189b4 --- /dev/null +++ b/hiro/core/size.cpp @@ -0,0 +1,43 @@ +Size::Size() { + setSize(0, 0); +} + +Size::Size(signed width, signed height) { + setSize(width, height); +} + +auto Size::operator==(const Size& source) const -> bool { + return width() == source.width() && height() == source.height(); +} + +auto Size::operator!=(const Size& source) const -> bool { + return !operator==(source); +} + +auto Size::height() const -> signed { + return state.height; +} + +auto Size::setHeight(signed height) -> type& { + state.height = height; + return *this; +} + +auto Size::setSize(Size size) -> type& { + return setSize(size.width(), size.height()); +} + +auto Size::setSize(signed width, signed height) -> type& { + state.width = width; + state.height = height; + return *this; +} + +auto Size::setWidth(signed width) -> type& { + state.width = width; + return *this; +} + +auto Size::width() const -> signed { + return state.width; +} diff --git a/hiro/core/status-bar.cpp b/hiro/core/status-bar.cpp new file mode 100644 index 00000000..2f5cf46b --- /dev/null +++ b/hiro/core/status-bar.cpp @@ -0,0 +1,20 @@ +auto mStatusBar::allocate() -> pObject* { + return new pStatusBar(*this); +} + +// + +auto mStatusBar::remove() -> type& { + if(auto window = parentWindow()) window->remove(window->statusBar()); + return *this; +} + +auto mStatusBar::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mStatusBar::text() const -> string { + return state.text; +} diff --git a/hiro/core/timer.cpp b/hiro/core/timer.cpp new file mode 100644 index 00000000..e8488c5e --- /dev/null +++ b/hiro/core/timer.cpp @@ -0,0 +1,24 @@ +auto mTimer::allocate() -> pObject* { + return new pTimer(*this); +} + +// + +auto mTimer::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mTimer::interval() const -> unsigned { + return state.interval; +} + +auto mTimer::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mTimer::setInterval(unsigned interval) -> type& { + state.interval = interval; + signal(setInterval, interval); + return *this; +} diff --git a/hiro/core/widget/button.cpp b/hiro/core/widget/button.cpp new file mode 100644 index 00000000..6382bf0f --- /dev/null +++ b/hiro/core/widget/button.cpp @@ -0,0 +1,54 @@ +auto mButton::allocate() -> pObject* { + return new pButton(*this); +} + +// + +auto mButton::bordered() const -> bool { + return state.bordered; +} + +auto mButton::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mButton::icon() const -> image { + return state.icon; +} + +auto mButton::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mButton::orientation() const -> Orientation { + return state.orientation; +} + +auto mButton::setBordered(bool bordered) -> type& { + state.bordered = bordered; + signal(setBordered, bordered); + return *this; +} + +auto mButton::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mButton::setOrientation(Orientation orientation) -> type& { + state.orientation = orientation; + signal(setOrientation, orientation); + return *this; +} + +auto mButton::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mButton::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/canvas.cpp b/hiro/core/widget/canvas.cpp new file mode 100644 index 00000000..4499e0e1 --- /dev/null +++ b/hiro/core/widget/canvas.cpp @@ -0,0 +1,125 @@ +auto mCanvas::allocate() -> pObject* { + return new pCanvas(*this); +} + +// + +auto mCanvas::color() const -> Color { + return state.color; +} + +auto mCanvas::data() -> uint32_t* { + return state.data.data(); +} + +auto mCanvas::droppable() const -> bool { + return state.droppable; +} + +auto mCanvas::doDrop(lstring names) const -> void { + if(state.onDrop) return state.onDrop(names); +} + +auto mCanvas::doMouseLeave() const -> void { + if(state.onMouseLeave) return state.onMouseLeave(); +} + +auto mCanvas::doMouseMove(Position position) const -> void { + if(state.onMouseMove) return state.onMouseMove(position); +} + +auto mCanvas::doMousePress(Mouse::Button button) const -> void { + if(state.onMousePress) return state.onMousePress(button); +} + +auto mCanvas::doMouseRelease(Mouse::Button button) const -> void { + if(state.onMouseRelease) return state.onMouseRelease(button); +} + +auto mCanvas::gradient() const -> vector { + return state.gradient; +} + +auto mCanvas::icon() const -> image { + return state.icon; +} + +auto mCanvas::onDrop(const function& function) -> type& { + state.onDrop = function; + return *this; +} + +auto mCanvas::onMouseLeave(const function& function) -> type& { + state.onMouseLeave = function; + return *this; +} + +auto mCanvas::onMouseMove(const function& function) -> type& { + state.onMouseMove = function; + return *this; +} + +auto mCanvas::onMousePress(const function& function) -> type& { + state.onMousePress = function; + return *this; +} + +auto mCanvas::onMouseRelease(const function& function) -> type& { + state.onMouseRelease = function; + return *this; +} + +auto mCanvas::setColor(Color color) -> type& { + state.size = {}; + state.color = color; + signal(setColor, color); + return *this; +} + +auto mCanvas::setData(Size size) -> type& { + state.size = size; + state.data.resize(size.width() * size.height()); + memory::fill(state.data.data(), size.width() * size.height() * sizeof(uint32_t)); + signal(setData, size); + return *this; +} + +auto mCanvas::setDroppable(bool droppable) -> type& { + state.droppable = droppable; + signal(setDroppable, droppable); + return *this; +} + +auto mCanvas::setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> type& { + state.size = {}; + state.gradient[0] = topLeft; + state.gradient[1] = topRight; + state.gradient[2] = bottomLeft; + state.gradient[3] = bottomRight; + signal(setGradient, topLeft, topRight, bottomLeft, bottomRight); + return *this; +} + +auto mCanvas::setHorizontalGradient(Color left, Color right) -> type& { + return setGradient(left, right, left, right); +} + +auto mCanvas::setIcon(const image& icon) -> type& { + state.size = {(signed)icon.width, (signed)icon.height}; + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mCanvas::setVerticalGradient(Color top, Color bottom) -> type& { + return setGradient(top, top, bottom, bottom); +} + +auto mCanvas::size() const -> Size { + return state.size; +} + +auto mCanvas::update() -> type& { + signal(update); + return *this; +} diff --git a/hiro/core/widget/check-button.cpp b/hiro/core/widget/check-button.cpp new file mode 100644 index 00000000..16411d80 --- /dev/null +++ b/hiro/core/widget/check-button.cpp @@ -0,0 +1,64 @@ +auto mCheckButton::allocate() -> pObject* { + return new pCheckButton(*this); +} + +// + +auto mCheckButton::bordered() const -> bool { + return state.bordered; +} + +auto mCheckButton::checked() const -> bool { + return state.checked; +} + +auto mCheckButton::doToggle() const -> void { + if(state.onToggle) return state.onToggle(); +} + +auto mCheckButton::icon() const -> image { + return state.icon; +} + +auto mCheckButton::onToggle(const function& function) -> type& { + state.onToggle = function; + return *this; +} + +auto mCheckButton::orientation() const -> Orientation { + return state.orientation; +} + +auto mCheckButton::setBordered(bool bordered) -> type& { + state.bordered = bordered; + signal(setBordered, bordered); + return *this; +} + +auto mCheckButton::setChecked(bool checked) -> type& { + state.checked = checked; + signal(setChecked, checked); + return *this; +} + +auto mCheckButton::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mCheckButton::setOrientation(Orientation orientation) -> type& { + state.orientation = orientation; + signal(setOrientation, orientation); + return *this; +} + +auto mCheckButton::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mCheckButton::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/check-label.cpp b/hiro/core/widget/check-label.cpp new file mode 100644 index 00000000..7f072545 --- /dev/null +++ b/hiro/core/widget/check-label.cpp @@ -0,0 +1,34 @@ +auto mCheckLabel::allocate() -> pObject* { + return new pCheckLabel(*this); +} + +// + +auto mCheckLabel::checked() const -> bool { + return state.checked; +} + +auto mCheckLabel::doToggle() const -> void { + if(state.onToggle) return state.onToggle(); +} + +auto mCheckLabel::onToggle(const function& function) -> type& { + state.onToggle = function; + return *this; +} + +auto mCheckLabel::setChecked(bool checked) -> type& { + state.checked = checked; + signal(setChecked, checked); + return *this; +} + +auto mCheckLabel::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mCheckLabel::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/combo-button-item.cpp b/hiro/core/widget/combo-button-item.cpp new file mode 100644 index 00000000..e2b7422b --- /dev/null +++ b/hiro/core/widget/combo-button-item.cpp @@ -0,0 +1,43 @@ +auto mComboButtonItem::allocate() -> pObject* { + return new pComboButtonItem(*this); +} + +// + +auto mComboButtonItem::icon() const -> image { + return state.icon; +} + +auto mComboButtonItem::remove() -> type& { + if(auto comboButton = parentComboButton()) comboButton->remove(*this); + return *this; +} + +auto mComboButtonItem::selected() const -> bool { + if(auto comboButton = parentComboButton()) return comboButton->state.selected == offset(); + return false; +} + +auto mComboButtonItem::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mComboButtonItem::setSelected() -> type& { + if(auto parent = parentComboButton()) { + parent->state.selected = offset(); + signal(setSelected); + } + return *this; +} + +auto mComboButtonItem::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mComboButtonItem::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/combo-button.cpp b/hiro/core/widget/combo-button.cpp new file mode 100644 index 00000000..daf3f68a --- /dev/null +++ b/hiro/core/widget/combo-button.cpp @@ -0,0 +1,61 @@ +auto mComboButton::allocate() -> pObject* { + return new pComboButton(*this); +} + +auto mComboButton::destruct() -> void { + for(auto& item : state.items) item->destruct(); + mWidget::destruct(); +} + +// + +auto mComboButton::append(sComboButtonItem item) -> type& { + state.items.append(item); + item->setParent(this, items() - 1); + signal(append, item); + if(state.selected < 0) item->setSelected(); + return *this; +} + +auto mComboButton::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mComboButton::item(unsigned position) const -> sComboButtonItem { + if(position < items()) return state.items[position]; + return {}; +} + +auto mComboButton::items() const -> unsigned { + return state.items.size(); +} + +auto mComboButton::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mComboButton::remove(sComboButtonItem item) -> type& { + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(item->offset(), items())) { + state.items[n]->offset(-1); + } + item->setParent(); + return *this; +} + +auto mComboButton::reset() -> type& { + signal(reset); + for(auto& item : state.items) { + item->setParent(); + } + state.items.reset(); + state.selected = -1; + return *this; +} + +auto mComboButton::selected() const -> sComboButtonItem { + if(state.selected >= 0) return state.items[state.selected]; + return {}; +} diff --git a/hiro/core/widget/console.cpp b/hiro/core/widget/console.cpp new file mode 100644 index 00000000..2db0408c --- /dev/null +++ b/hiro/core/widget/console.cpp @@ -0,0 +1,54 @@ +auto mConsole::allocate() -> pObject* { + return new pConsole(*this); +} + +// + +auto mConsole::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mConsole::doActivate(string command) const -> void { + if(state.onActivate) return state.onActivate(command); +} + +auto mConsole::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mConsole::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mConsole::print(const string& text) -> type& { + signal(print, text); + return *this; +} + +auto mConsole::prompt() const -> string { + return state.prompt; +} + +auto mConsole::reset() -> type& { + signal(reset); + return *this; +} + +auto mConsole::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mConsole::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mConsole::setPrompt(const string& prompt) -> type& { + state.prompt = prompt; + signal(setPrompt, prompt); + return *this; +} diff --git a/hiro/core/widget/frame.cpp b/hiro/core/widget/frame.cpp new file mode 100644 index 00000000..b6abe85c --- /dev/null +++ b/hiro/core/widget/frame.cpp @@ -0,0 +1,42 @@ +auto mFrame::allocate() -> pObject* { + return new pFrame(*this); +} + +auto mFrame::destruct() -> void { + if(auto& layout = state.layout) layout->destruct(); + mWidget::destruct(); +} + +// + +auto mFrame::append(shared_pointer layout) -> type& { + if(auto& layout = state.layout) remove(layout); + state.layout = layout; + layout->setParent(this, 0); + return *this; +} + +auto mFrame::layout() const -> shared_pointer { + return state.layout; +} + +auto mFrame::remove(shared_pointer layout) -> type& { + layout->setParent(); + state.layout.reset(); + return *this; +} + +auto mFrame::reset() -> type& { + if(auto& layout = state.layout) remove(layout); + return *this; +} + +auto mFrame::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mFrame::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/hex-edit.cpp b/hiro/core/widget/hex-edit.cpp new file mode 100644 index 00000000..3a9d5a10 --- /dev/null +++ b/hiro/core/widget/hex-edit.cpp @@ -0,0 +1,89 @@ +auto mHexEdit::allocate() -> pObject* { + return new pHexEdit(*this); +} + +// + +auto mHexEdit::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mHexEdit::columns() const -> unsigned { + return state.columns; +} + +auto mHexEdit::doRead(unsigned offset) const -> uint8_t { + if(state.onRead) return state.onRead(offset); + return 0x00; +} + +auto mHexEdit::doWrite(unsigned offset, uint8_t data) const -> void { + if(state.onWrite) return state.onWrite(offset, data); +} + +auto mHexEdit::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mHexEdit::length() const -> unsigned { + return state.length; +} + +auto mHexEdit::offset() const -> unsigned { + return state.offset; +} + +auto mHexEdit::onRead(const function& function) -> type& { + state.onRead = function; + return *this; +} + +auto mHexEdit::onWrite(const function& function) -> type& { + state.onWrite = function; + return *this; +} + +auto mHexEdit::rows() const -> unsigned { + return state.rows; +} + +auto mHexEdit::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mHexEdit::setColumns(unsigned columns) -> type& { + state.columns = columns; + signal(setColumns, columns); + return *this; +} + +auto mHexEdit::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mHexEdit::setLength(unsigned length) -> type& { + state.length = length; + signal(setLength, length); + return *this; +} + +auto mHexEdit::setOffset(unsigned offset) -> type& { + state.offset = offset; + signal(setOffset, offset); + return *this; +} + +auto mHexEdit::setRows(unsigned rows) -> type& { + state.rows = rows; + signal(setRows, rows); + return *this; +} + +auto mHexEdit::update() -> type& { + signal(update); + return *this; +} diff --git a/hiro/core/widget/horizontal-scroller.cpp b/hiro/core/widget/horizontal-scroller.cpp new file mode 100644 index 00000000..6af6856e --- /dev/null +++ b/hiro/core/widget/horizontal-scroller.cpp @@ -0,0 +1,34 @@ +auto mHorizontalScroller::allocate() -> pObject* { + return new pHorizontalScroller(*this); +} + +// + +auto mHorizontalScroller::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mHorizontalScroller::length() const -> unsigned { + return state.length; +} + +auto mHorizontalScroller::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mHorizontalScroller::position() const -> unsigned { + return state.position; +} + +auto mHorizontalScroller::setLength(unsigned length) -> type& { + state.length = length; + signal(setLength, length); + return *this; +} + +auto mHorizontalScroller::setPosition(unsigned position) -> type& { + state.position = position; + signal(setPosition, position); + return *this; +} diff --git a/hiro/core/widget/horizontal-slider.cpp b/hiro/core/widget/horizontal-slider.cpp new file mode 100644 index 00000000..f9a9c04d --- /dev/null +++ b/hiro/core/widget/horizontal-slider.cpp @@ -0,0 +1,34 @@ +auto mHorizontalSlider::allocate() -> pObject* { + return new pHorizontalSlider(*this); +} + +// + +auto mHorizontalSlider::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mHorizontalSlider::length() const -> unsigned { + return state.length; +} + +auto mHorizontalSlider::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mHorizontalSlider::position() const -> unsigned { + return state.position; +} + +auto mHorizontalSlider::setLength(unsigned length) -> type& { + state.length = length; + signal(setLength, length); + return *this; +} + +auto mHorizontalSlider::setPosition(unsigned position) -> type& { + state.position = position; + signal(setPosition, position); + return *this; +} diff --git a/hiro/core/widget/icon-view-item.cpp b/hiro/core/widget/icon-view-item.cpp new file mode 100644 index 00000000..db6dac33 --- /dev/null +++ b/hiro/core/widget/icon-view-item.cpp @@ -0,0 +1,40 @@ +auto mIconViewItem::allocate() -> pObject* { + return new pIconViewItem(*this); +} + +// + +auto mIconViewItem::icon() const -> image { + return state.icon; +} + +auto mIconViewItem::remove() -> type& { + if(auto iconView = parentIconView()) iconView->remove(*this); + return *this; +} + +auto mIconViewItem::selected() const -> bool { + return state.selected; +} + +auto mIconViewItem::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mIconViewItem::setSelected(bool selected) -> type& { + state.selected = selected; + signal(setSelected, selected); + return *this; +} + +auto mIconViewItem::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mIconViewItem::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/icon-view.cpp b/hiro/core/widget/icon-view.cpp new file mode 100644 index 00000000..283e1cc9 --- /dev/null +++ b/hiro/core/widget/icon-view.cpp @@ -0,0 +1,148 @@ +auto mIconView::allocate() -> pObject* { + return new pIconView(*this); +} + +auto mIconView::destruct() -> void { + for(auto& item : state.items) item->destruct(); + mWidget::destruct(); +} + +// + +auto mIconView::append(shared_pointer item) -> type& { + state.items.append(item); + item->setParent(this, items() - 1); + signal(append, item); + return *this; +} + +auto mIconView::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mIconView::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mIconView::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mIconView::doContext() const -> void { + if(state.onContext) return state.onContext(); +} + +auto mIconView::flow() const -> Orientation { + return state.flow; +} + +auto mIconView::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mIconView::item(unsigned position) const -> shared_pointer { + if(position >= items()) throw; + return state.items[position]; +} + +auto mIconView::items() const -> unsigned { + return state.items.size(); +} + +auto mIconView::multiSelect() const -> bool { + return state.multiSelect; +} + +auto mIconView::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mIconView::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mIconView::onContext(const function& function) -> type& { + state.onContext = function; + return *this; +} + +auto mIconView::orientation() const -> Orientation { + return state.orientation; +} + +auto mIconView::remove(shared_pointer item) -> type& { + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(item->offset(), items())) { + state.items[n]->offset(-1); + } + item->setParent(); + return *this; +} + +auto mIconView::reset() -> type& { + signal(reset); + for(auto& item : state.items) item->setParent(); + state.items.reset(); + return *this; +} + +auto mIconView::selected() const -> maybe { + for(auto& item : state.items) { + if(item->selected()) return (unsigned)item->offset(); + } + return nothing; +} + +auto mIconView::selectedItems() const -> vector { + vector result; + for(auto& item : state.items) { + if(item->selected()) result.append(item->offset()); + } + return result; +} + +auto mIconView::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mIconView::setFlow(Orientation flow) -> type& { + state.flow = flow; + signal(setFlow, flow); + return *this; +} + +auto mIconView::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mIconView::setMultiSelect(bool multiSelect) -> type& { + state.multiSelect = multiSelect; + signal(setMultiSelect, multiSelect); + return *this; +} + +auto mIconView::setOrientation(Orientation orientation) -> type& { + state.orientation = orientation; + signal(setOrientation, orientation); + return *this; +} + +auto mIconView::setSelected(const vector& selections) -> type& { + bool selectAll = selections(0, 0) == ~0; + for(auto& item : state.items) item->state.selected = selectAll; + if(selectAll) return signal(setItemSelectedAll), *this; + if(!selections) return signal(setItemSelectedNone), *this; + for(auto& position : selections) { + if(position >= items()) continue; + state.items[position]->state.selected = true; + } + signal(setItemSelected, selections); + return *this; +} diff --git a/hiro/core/widget/label.cpp b/hiro/core/widget/label.cpp new file mode 100644 index 00000000..d0e2df91 --- /dev/null +++ b/hiro/core/widget/label.cpp @@ -0,0 +1,37 @@ +auto mLabel::allocate() -> pObject* { + return new pLabel(*this); +} + +// + +auto mLabel::horizontalAlignment() const -> double { + return state.horizontalAlignment; +} + +auto mLabel::setHorizontalAlignment(double alignment) -> type& { + alignment = max(0.0, min(1.0, alignment)); + state.horizontalAlignment = alignment; + signal(setHorizontalAlignment, alignment); + return *this; +} + +auto mLabel::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mLabel::setVerticalAlignment(double alignment) -> type& { + alignment = max(0.0, min(1.0, alignment)); + state.verticalAlignment = alignment; + signal(setVerticalAlignment, alignment); + return *this; +} + +auto mLabel::text() const -> string { + return state.text; +} + +auto mLabel::verticalAlignment() const -> double { + return state.verticalAlignment; +} diff --git a/hiro/core/widget/line-edit.cpp b/hiro/core/widget/line-edit.cpp new file mode 100644 index 00000000..96672fe5 --- /dev/null +++ b/hiro/core/widget/line-edit.cpp @@ -0,0 +1,63 @@ +auto mLineEdit::allocate() -> pObject* { + return new pLineEdit(*this); +} + +// + +auto mLineEdit::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mLineEdit::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mLineEdit::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mLineEdit::editable() const -> bool { + return state.editable; +} + +auto mLineEdit::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mLineEdit::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mLineEdit::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mLineEdit::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mLineEdit::setEditable(bool editable) -> type& { + state.editable = editable; + signal(setEditable, editable); + return *this; +} + +auto mLineEdit::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mLineEdit::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mLineEdit::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/list-view-column.cpp b/hiro/core/widget/list-view-column.cpp new file mode 100644 index 00000000..cb180748 --- /dev/null +++ b/hiro/core/widget/list-view-column.cpp @@ -0,0 +1,135 @@ +auto mListViewColumn::allocate() -> pObject* { + return new pListViewColumn(*this); +} + +// + +auto mListViewColumn::active() const -> bool { + if(auto listView = parentListView()) return listView->state.activeColumn == offset(); + return false; +} + +auto mListViewColumn::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mListViewColumn::editable() const -> bool { + return state.editable; +} + +auto mListViewColumn::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mListViewColumn::horizontalAlignment() const -> double { + return state.horizontalAlignment; +} + +auto mListViewColumn::icon() const -> image { + return state.icon; +} + +auto mListViewColumn::remove() -> type& { + if(auto listView = parentListView()) listView->remove(*this); + return *this; +} + +auto mListViewColumn::resizable() const -> bool { + return state.resizable; +} + +auto mListViewColumn::setActive() -> type& { + if(auto listView = parentListView()) listView->state.activeColumn = offset(); + signal(setActive); + return *this; +} + +auto mListViewColumn::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mListViewColumn::setEditable(bool editable) -> type& { + state.editable = editable; + signal(setEditable, editable); + return *this; +} + +auto mListViewColumn::setFont(const string& font) -> type& { + state.font = font; + signal(setFont, this->font(true)); + return *this; +} + +auto mListViewColumn::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mListViewColumn::setHorizontalAlignment(double alignment) -> type& { + alignment = max(0.0, min(1.0, alignment)); + state.horizontalAlignment = alignment; + signal(setHorizontalAlignment, alignment); + return *this; +} + +auto mListViewColumn::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mListViewColumn::setResizable(bool resizable) -> type& { + state.resizable = resizable; + signal(setResizable, resizable); + return *this; +} + +auto mListViewColumn::setSortable(bool sortable) -> type& { + state.sortable = sortable; + signal(setSortable, sortable); + return *this; +} + +auto mListViewColumn::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mListViewColumn::setVerticalAlignment(double alignment) -> type& { + alignment = max(0.0, min(1.0, alignment)); + state.verticalAlignment = alignment; + signal(setVerticalAlignment, alignment); + return *this; +} + +auto mListViewColumn::setVisible(bool visible) -> type& { + state.visible = visible; + signal(setVisible, visible); + return *this; +} + +auto mListViewColumn::setWidth(signed width) -> type& { + state.width = width; + signal(setWidth, width); + return *this; +} + +auto mListViewColumn::sortable() const -> bool { + return state.sortable; +} + +auto mListViewColumn::text() const -> string { + return state.text; +} + +auto mListViewColumn::verticalAlignment() const -> double { + return state.verticalAlignment; +} + +auto mListViewColumn::width() const -> signed { + return state.width; +} diff --git a/hiro/core/widget/list-view-item.cpp b/hiro/core/widget/list-view-item.cpp new file mode 100644 index 00000000..bdc5ad88 --- /dev/null +++ b/hiro/core/widget/list-view-item.cpp @@ -0,0 +1,65 @@ +auto mListViewItem::allocate() -> pObject* { + return new pListViewItem(*this); +} + +// + +auto mListViewItem::checked() const -> bool { + return state.checked; +} + +auto mListViewItem::icon(unsigned column) const -> image { + return state.icon(column, {}); +} + +auto mListViewItem::remove() -> type& { + if(auto listView = parentListView()) listView->remove(*this); + return *this; +} + +auto mListViewItem::selected() const -> bool { + return state.selected; +} + +auto mListViewItem::setChecked(bool checked) -> type& { + state.checked = checked; + signal(setChecked, checked); + return *this; +} + +auto mListViewItem::setFocused() -> type& { + signal(setFocused); + return *this; +} + +auto mListViewItem::setIcon(unsigned column, const image& icon) -> type& { + state.icon(column) = icon; + signal(setIcon, column, icon); + return *this; +} + +auto mListViewItem::setSelected(bool selected) -> type& { + state.selected = selected; + signal(setSelected, selected); + return *this; +} + +auto mListViewItem::setText(const lstring& text) -> type& { + state.text = text; + if(auto listView = parentListView()) { + for(auto column : range(listView->columns())) { + setText(column, text(column, "")); + } + } + return *this; +} + +auto mListViewItem::setText(unsigned column, const string& text) -> type& { + state.text(column) = text; + signal(setText, column, text); + return *this; +} + +auto mListViewItem::text(unsigned column) const -> string { + return state.text(column, ""); +} diff --git a/hiro/core/widget/list-view.cpp b/hiro/core/widget/list-view.cpp new file mode 100644 index 00000000..7c9e915d --- /dev/null +++ b/hiro/core/widget/list-view.cpp @@ -0,0 +1,228 @@ +auto mListView::allocate() -> pObject* { + return new pListView(*this); +} + +auto mListView::destruct() -> void { + for(auto& item : state.items) item->destruct(); + for(auto& column : state.columns) column->destruct(); + mWidget::destruct(); +} + +// + +auto mListView::append(sListViewColumn column) -> type& { + state.columns.append(column); + column->setParent(this, columns() - 1); + signal(append, column); + return *this; +} + +auto mListView::append(sListViewItem item) -> type& { + state.items.append(item); + item->setParent(this, items() - 1); + signal(append, item); + return *this; +} + +auto mListView::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mListView::checkable() const -> bool { + return state.checkable; +} + +auto mListView::checked() const -> vector { + vector items; + for(auto& item : state.items) { + if(item->checked()) items.append(item); + } + return items; +} + +auto mListView::column(unsigned position) const -> sListViewColumn { + if(position < columns()) return state.columns[position]; + return {}; +} + +auto mListView::columns() const -> unsigned { + return state.columns.size(); +} + +auto mListView::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mListView::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mListView::doContext() const -> void { + if(state.onContext) return state.onContext(); +} + +auto mListView::doEdit(sListViewItem item, sListViewColumn column) const -> void { + if(state.onEdit) return state.onEdit(item, column); +} + +auto mListView::doSort(sListViewColumn column) const -> void { + if(state.onSort) return state.onSort(column); +} + +auto mListView::doToggle(sListViewItem item) const -> void { + if(state.onToggle) return state.onToggle(item); +} + +auto mListView::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mListView::gridVisible() const -> bool { + return state.gridVisible; +} + +auto mListView::headerVisible() const -> bool { + return state.headerVisible; +} + +auto mListView::item(unsigned position) const -> sListViewItem { + if(position < items()) return state.items[position]; + return {}; +} + +auto mListView::items() const -> unsigned { + return state.items.size(); +} + +auto mListView::multiSelect() const -> bool { + return state.multiSelect; +} + +auto mListView::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mListView::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mListView::onContext(const function& function) -> type& { + state.onContext = function; + return *this; +} + +auto mListView::onEdit(const function& function) -> type& { + state.onEdit = function; + return *this; +} + +auto mListView::onSort(const function& function) -> type& { + state.onSort = function; + return *this; +} + +auto mListView::onToggle(const function& function) -> type& { + state.onToggle = function; + return *this; +} + +auto mListView::remove(sListViewColumn column) -> type& { + signal(remove, column); + for(auto& item : state.items) item->setParent(); + state.items.reset(); + state.columns.remove(column->offset()); + for(auto n : range(column->offset(), columns())) { + state.columns[n]->offset(-1); + } + column->setParent(); + return *this; +} + +auto mListView::remove(sListViewItem item) -> type& { + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(item->offset(), items())) { + state.items[n]->offset(-1); + } + item->setParent(); + return *this; +} + +auto mListView::reset() -> type& { + signal(reset); + for(auto& column : state.columns) column->setParent(); + state.columns.reset(); + for(auto& item : state.items) item->setParent(); + state.items.reset(); + return *this; +} + +auto mListView::resizeColumns() -> type& { + signal(resizeColumns); + return *this; +} + +auto mListView::selected() const -> sListViewItem { + for(auto& item : state.items) { + if(item->selected()) return item; + } + return {}; +} + +auto mListView::selectedItems() const -> vector { + vector items; + for(auto& item : state.items) { + if(item->selected()) items.append(item); + } + return items; +} + +auto mListView::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mListView::setCheckable(bool checkable) -> type& { + state.checkable = checkable; + signal(setCheckable, checkable); + return *this; +} + +auto mListView::setChecked(bool checked) -> type& { + for(auto& item : state.items) item->state.checked = checked; + signal(setChecked, checked); + return *this; +} + +auto mListView::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mListView::setGridVisible(bool visible) -> type& { + state.gridVisible = visible; + signal(setGridVisible, visible); + return *this; +} + +auto mListView::setHeaderVisible(bool visible) -> type& { + state.headerVisible = visible; + signal(setHeaderVisible, visible); + return *this; +} + +auto mListView::setMultiSelect(bool multiSelect) -> type& { + state.multiSelect = multiSelect; + signal(setMultiSelect, multiSelect); + return *this; +} + +auto mListView::setSelected(bool selected) -> type& { + for(auto& item : state.items) item->state.selected = selected; + signal(setSelected, selected); + return *this; +} diff --git a/hiro/core/widget/progress-bar.cpp b/hiro/core/widget/progress-bar.cpp new file mode 100644 index 00000000..726cfaec --- /dev/null +++ b/hiro/core/widget/progress-bar.cpp @@ -0,0 +1,15 @@ +auto mProgressBar::allocate() -> pObject* { + return new pProgressBar(*this); +} + +// + +auto mProgressBar::position() const -> unsigned { + return state.position; +} + +auto mProgressBar::setPosition(unsigned position) -> type& { + state.position = position; + signal(setPosition, position); + return *this; +} diff --git a/hiro/core/widget/radio-button.cpp b/hiro/core/widget/radio-button.cpp new file mode 100644 index 00000000..cf64cfd8 --- /dev/null +++ b/hiro/core/widget/radio-button.cpp @@ -0,0 +1,81 @@ +auto mRadioButton::allocate() -> pObject* { + return new pRadioButton(*this); +} + +// + +auto mRadioButton::group(const vector>& group) -> void { + for(auto& weak : group) { + if(auto item = weak.acquire()) item->state.group = group; + } + for(auto& weak : group) { + if(auto item = weak.acquire()) { + if(item->self()) item->self()->setGroup(group); + } + } + if(group.size()) { + if(auto item = group.first().acquire()) item->setChecked(); + } +} + +auto mRadioButton::bordered() const -> bool { + return state.bordered; +} + +auto mRadioButton::checked() const -> bool { + return state.checked; +} + +auto mRadioButton::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mRadioButton::icon() const -> image { + return state.icon; +} + +auto mRadioButton::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mRadioButton::orientation() const -> Orientation { + return state.orientation; +} + +auto mRadioButton::setBordered(bool bordered) -> type& { + state.bordered = bordered; + signal(setBordered, bordered); + return *this; +} + +auto mRadioButton::setChecked() -> type& { + for(auto& weak : state.group) { + if(auto item = weak.acquire()) item->state.checked = false; + } + state.checked = true; + signal(setChecked); + return *this; +} + +auto mRadioButton::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mRadioButton::setOrientation(Orientation orientation) -> type& { + state.orientation = orientation; + signal(setOrientation, orientation); + return *this; +} + +auto mRadioButton::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mRadioButton::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/radio-label.cpp b/hiro/core/widget/radio-label.cpp new file mode 100644 index 00000000..9142643f --- /dev/null +++ b/hiro/core/widget/radio-label.cpp @@ -0,0 +1,51 @@ +auto mRadioLabel::allocate() -> pObject* { + return new pRadioLabel(*this); +} + +// + +auto mRadioLabel::group(const vector>& group) -> void { + for(auto& weak : group) { + if(auto item = weak.acquire()) item->state.group = group; + } + for(auto& weak : group) { + if(auto item = weak.acquire()) { + if(item->self()) item->self()->setGroup(group); + } + } + if(group.size()) { + if(auto item = group.first().acquire()) item->setChecked(); + } +} + +auto mRadioLabel::checked() const -> bool { + return state.checked; +} + +auto mRadioLabel::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mRadioLabel::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mRadioLabel::setChecked() -> type& { + for(auto& weak : state.group) { + if(auto item = weak.acquire()) item->state.checked = false; + } + state.checked = true; + signal(setChecked); + return *this; +} + +auto mRadioLabel::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mRadioLabel::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/source-edit.cpp b/hiro/core/widget/source-edit.cpp new file mode 100644 index 00000000..d9dd0f8e --- /dev/null +++ b/hiro/core/widget/source-edit.cpp @@ -0,0 +1,52 @@ +auto mSourceEdit::allocate() -> pObject* { + return new pSourceEdit(*this); +} + +// + +auto mSourceEdit::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mSourceEdit::doMove() const -> void { + if(state.onMove) return state.onMove(); +} + +auto mSourceEdit::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mSourceEdit::onMove(const function& function) -> type& { + state.onMove = function; + return *this; +} + +auto mSourceEdit::position() const -> unsigned { + return state.position; +} + +auto mSourceEdit::setPosition(signed position) -> type& { + state.position = position; + signal(setPosition, position); + return *this; +} + +auto mSourceEdit::setSelected(Position selected) -> type& { + if(selected.x() < 0) return *this; + if(selected.y() < 0) selected.setY(-1); + else if(selected.x() > selected.y()) return *this; + state.selected = selected; + signal(setSelected, selected); + return *this; +} + +auto mSourceEdit::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mSourceEdit::text() const -> string { + return signal(text); +} diff --git a/hiro/core/widget/tab-frame-item.cpp b/hiro/core/widget/tab-frame-item.cpp new file mode 100644 index 00000000..0eae926a --- /dev/null +++ b/hiro/core/widget/tab-frame-item.cpp @@ -0,0 +1,95 @@ +auto mTabFrameItem::allocate() -> pObject* { + return new pTabFrameItem(*this); +} + +auto mTabFrameItem::destruct() -> void { + if(auto& layout = state.layout) layout->destruct(); + mObject::destruct(); +} + +// + +auto mTabFrameItem::append(sLayout layout) -> type& { + if(auto& layout = state.layout) remove(layout); + state.layout = layout; + layout->setParent(this, 0); + return *this; +} + +auto mTabFrameItem::closable() const -> bool { + return state.closable; +} + +auto mTabFrameItem::icon() const -> image { + return state.icon; +} + +auto mTabFrameItem::layout() const -> sLayout { + return state.layout; +} + +auto mTabFrameItem::movable() const -> bool { + return state.movable; +} + +auto mTabFrameItem::remove() -> type& { + if(auto tabFrame = parentTabFrame()) tabFrame->remove(*this); + return *this; +} + +auto mTabFrameItem::remove(sLayout layout) -> type& { + layout->setParent(); + state.layout.reset(); + return *this; +} + +auto mTabFrameItem::reset() -> type& { + if(auto layout = state.layout) remove(layout); + return *this; +} + +auto mTabFrameItem::selected() const -> bool { + if(auto tabFrame = parentTabFrame()) return offset() == tabFrame->state.selected; + return false; +} + +auto mTabFrameItem::setClosable(bool closable) -> type& { + state.closable = closable; + signal(setClosable, closable); + return *this; +} + +auto mTabFrameItem::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mTabFrameItem::setMovable(bool movable) -> type& { + state.movable = movable; + signal(setMovable, movable); + return *this; +} + +auto mTabFrameItem::setParent(mObject* parent, signed offset) -> type& { + if(auto layout = state.layout) layout->destruct(); + mObject::setParent(parent, offset); + if(auto layout = state.layout) layout->setParent(this, layout->offset()); + return *this; +} + +auto mTabFrameItem::setSelected() -> type& { + if(auto tabFrame = parentTabFrame()) tabFrame->state.selected = offset(); + signal(setSelected); + return *this; +} + +auto mTabFrameItem::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mTabFrameItem::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/tab-frame.cpp b/hiro/core/widget/tab-frame.cpp new file mode 100644 index 00000000..c50ff819 --- /dev/null +++ b/hiro/core/widget/tab-frame.cpp @@ -0,0 +1,90 @@ +auto mTabFrame::allocate() -> pObject* { + return new pTabFrame(*this); +} + +auto mTabFrame::destruct() -> void { + for(auto& item : state.items) item->destruct(); + mWidget::destruct(); +} + +// + +auto mTabFrame::append(sTabFrameItem item) -> type& { + state.items.append(item); + item->setParent(this, items() - 1); + signal(append, item); + return *this; +} + +auto mTabFrame::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mTabFrame::doClose(sTabFrameItem item) const -> void { + if(state.onClose) return state.onClose(item); +} + +auto mTabFrame::doMove(sTabFrameItem from, sTabFrameItem to) const -> void { + if(state.onMove) return state.onMove(from, to); +} + +auto mTabFrame::edge() const -> Edge { + return state.edge; +} + +auto mTabFrame::item(unsigned position) const -> sTabFrameItem { + if(position < items()) return state.items[position]; + return {}; +} + +auto mTabFrame::items() const -> unsigned { + return state.items.size(); +} + +auto mTabFrame::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mTabFrame::onClose(const function& function) -> type& { + state.onClose = function; + return *this; +} + +auto mTabFrame::onMove(const function& function) -> type& { + state.onMove = function; + return *this; +} + +auto mTabFrame::remove(sTabFrameItem item) -> type& { + auto offset = item->offset(); + item->setParent(); + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(offset, items())) { + state.items[n]->offset(-1); + } + return *this; +} + +auto mTabFrame::reset() -> type& { + while(state.items) remove(state.items.last()); + return *this; +} + +auto mTabFrame::selected() const -> sTabFrameItem { + return state.items[state.selected]; +} + +auto mTabFrame::setEdge(Edge edge) -> type& { + state.edge = edge; + signal(setEdge, edge); + return *this; +} + +auto mTabFrame::setParent(mObject* parent, signed offset) -> type& { + for(auto& item : state.items) item->destruct(); + mObject::setParent(parent, offset); + for(auto& item : state.items) item->setParent(this, item->offset()); + return *this; +} diff --git a/hiro/core/widget/text-edit.cpp b/hiro/core/widget/text-edit.cpp new file mode 100644 index 00000000..ae0982b4 --- /dev/null +++ b/hiro/core/widget/text-edit.cpp @@ -0,0 +1,83 @@ +auto mTextEdit::allocate() -> pObject* { + return new pTextEdit(*this); +} + +// + +auto mTextEdit::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mTextEdit::cursorPosition() const -> unsigned { + return state.cursorPosition; +} + +auto mTextEdit::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mTextEdit::doMove() const -> void { + if(state.onMove) return state.onMove(); +} + +auto mTextEdit::editable() const -> bool { + return state.editable; +} + +auto mTextEdit::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mTextEdit::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mTextEdit::onMove(const function& function) -> type& { + state.onMove = function; + return *this; +} + +auto mTextEdit::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mTextEdit::setCursorPosition(unsigned position) -> type& { + state.cursorPosition = position; + signal(setCursorPosition, position); + return *this; +} + +auto mTextEdit::setEditable(bool editable) -> type& { + state.editable = editable; + signal(setEditable, editable); + return *this; +} + +auto mTextEdit::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mTextEdit::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mTextEdit::setWordWrap(bool wordWrap) -> type& { + state.wordWrap = wordWrap; + signal(setWordWrap, wordWrap); + return *this; +} + +auto mTextEdit::text() const -> string { + return signal(text); +} + +auto mTextEdit::wordWrap() const -> bool { + return state.wordWrap; +} diff --git a/hiro/core/widget/tree-view-item.cpp b/hiro/core/widget/tree-view-item.cpp new file mode 100644 index 00000000..40995fdf --- /dev/null +++ b/hiro/core/widget/tree-view-item.cpp @@ -0,0 +1,98 @@ +auto mTreeViewItem::allocate() -> pObject* { + return new pTreeViewItem(*this); +} + +auto mTreeViewItem::destruct() -> void { + for(auto& item : state.items) item->destruct(); + mObject::destruct(); +} + +// + +auto mTreeViewItem::append(sTreeViewItem item) -> type& { + state.items.append(item); + item->setParent(this, items() - 1); + signal(append, item); + return *this; +} + +auto mTreeViewItem::checked() const -> bool { + return state.checked; +} + +auto mTreeViewItem::icon() const -> image { + return state.icon; +} + +auto mTreeViewItem::item(const string& path) const -> sTreeViewItem { + if(path.empty()) return {}; + auto paths = path.split("/"); + unsigned position = decimal(paths.takeFirst()); + if(position >= items()) return {}; + if(paths.empty()) return state.items[position]; + return state.items[position]->item(paths.merge("/")); +} + +auto mTreeViewItem::items() const -> unsigned { + return state.items.size(); +} + +auto mTreeViewItem::path() const -> string { + if(auto treeViewItem = parentTreeViewItem()) return {treeViewItem->path(), "/", offset()}; + return {offset()}; +} + +auto mTreeViewItem::remove() -> type& { + if(auto treeView = parentTreeView()) treeView->remove(*this); + if(auto treeViewItem = parentTreeViewItem()) treeViewItem->remove(*this); + return *this; +} + +auto mTreeViewItem::remove(sTreeViewItem item) -> type& { + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(item->offset(), items())) { + state.items[n]->offset(-1); + } + item->setParent(); + return *this; +} + +auto mTreeViewItem::selected() const -> bool { + if(auto treeView = parentTreeView(true)) { + return path() == treeView->state.selectedPath; + } + return false; +} + +auto mTreeViewItem::setChecked(bool checked) -> type& { + state.checked = checked; + signal(setChecked, checked); + return *this; +} + +auto mTreeViewItem::setFocused() -> type& { + signal(setFocused); + return *this; +} + +auto mTreeViewItem::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mTreeViewItem::setSelected() -> type& { + signal(setSelected); + return *this; +} + +auto mTreeViewItem::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mTreeViewItem::text() const -> string { + return state.text; +} diff --git a/hiro/core/widget/tree-view.cpp b/hiro/core/widget/tree-view.cpp new file mode 100644 index 00000000..217638e2 --- /dev/null +++ b/hiro/core/widget/tree-view.cpp @@ -0,0 +1,128 @@ +auto mTreeView::allocate() -> pObject* { + return new pTreeView(*this); +} + +auto mTreeView::destruct() -> void { + for(auto& item : state.items) item->destruct(); + mWidget::destruct(); +} + +// + +auto mTreeView::append(sTreeViewItem item) -> type& { + state.items.append(item); + item->setParent(this, items() - 1); + signal(append, item); + return *this; +} + +auto mTreeView::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mTreeView::checkable() const -> bool { + return state.checkable; +} + +auto mTreeView::collapse() -> type& { + signal(collapse); + return *this; +} + +auto mTreeView::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mTreeView::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mTreeView::doContext() const -> void { + if(state.onContext) return state.onContext(); +} + +auto mTreeView::doToggle(sTreeViewItem item) const -> void { + if(state.onToggle) return state.onToggle(item); +} + +auto mTreeView::expand() -> type& { + signal(expand); + return *this; +} + +auto mTreeView::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mTreeView::item(const string& path) const -> sTreeViewItem { + if(path.empty()) return {}; + auto paths = path.split("/"); + unsigned position = decimal(paths.takeFirst()); + if(position >= items()) return {}; + if(paths.empty()) return state.items[position]; + return state.items[position]->item(paths.merge("/")); +} + +auto mTreeView::items() const -> unsigned { + return state.items.size(); +} + +auto mTreeView::onActivate(const function& function) -> type& { + state.onActivate = function; + return *this; +} + +auto mTreeView::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mTreeView::onContext(const function& function) -> type& { + state.onContext = function; + return *this; +} + +auto mTreeView::onToggle(const function& function) -> type& { + state.onToggle = function; + return *this; +} + +auto mTreeView::remove(sTreeViewItem item) -> type& { + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(item->offset(), items())) { + state.items[n]->offset(-1); + } + item->setParent(); + return *this; +} + +auto mTreeView::reset() -> type& { + state.selectedPath.reset(); + signal(reset); + for(auto& item : state.items) item->setParent(); + state.items.reset(); + return *this; +} + +auto mTreeView::selected() const -> sTreeViewItem { + return item(state.selectedPath); +} + +auto mTreeView::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mTreeView::setCheckable(bool checkable) -> type& { + state.checkable = checkable; + signal(setCheckable, checkable); + return *this; +} + +auto mTreeView::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} diff --git a/hiro/core/widget/vertical-scroller.cpp b/hiro/core/widget/vertical-scroller.cpp new file mode 100644 index 00000000..fb7f41ad --- /dev/null +++ b/hiro/core/widget/vertical-scroller.cpp @@ -0,0 +1,34 @@ +auto mVerticalScroller::allocate() -> pObject* { + return new pVerticalScroller(*this); +} + +// + +auto mVerticalScroller::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mVerticalScroller::length() const -> unsigned { + return state.length; +} + +auto mVerticalScroller::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mVerticalScroller::position() const -> unsigned { + return state.position; +} + +auto mVerticalScroller::setLength(unsigned length) -> type& { + state.length = length; + signal(setLength, length); + return *this; +} + +auto mVerticalScroller::setPosition(unsigned position) -> type& { + state.position = position; + signal(setPosition, position); + return *this; +} diff --git a/hiro/core/widget/vertical-slider.cpp b/hiro/core/widget/vertical-slider.cpp new file mode 100644 index 00000000..e9f51a8c --- /dev/null +++ b/hiro/core/widget/vertical-slider.cpp @@ -0,0 +1,34 @@ +auto mVerticalSlider::allocate() -> pObject* { + return new pVerticalSlider(*this); +} + +// + +auto mVerticalSlider::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mVerticalSlider::length() const -> unsigned { + return state.length; +} + +auto mVerticalSlider::onChange(const function& function) -> type& { + state.onChange = function; + return *this; +} + +auto mVerticalSlider::position() const -> unsigned { + return state.position; +} + +auto mVerticalSlider::setLength(unsigned length) -> type& { + state.length = length; + signal(setLength, length); + return *this; +} + +auto mVerticalSlider::setPosition(unsigned position) -> type& { + state.position = position; + signal(setPosition, position); + return *this; +} diff --git a/hiro/core/widget/viewport.cpp b/hiro/core/widget/viewport.cpp new file mode 100644 index 00000000..b60ec9d9 --- /dev/null +++ b/hiro/core/widget/viewport.cpp @@ -0,0 +1,64 @@ +auto mViewport::allocate() -> pObject* { + return new pViewport(*this); +} + +// + +auto mViewport::doDrop(lstring names) const -> void { + if(state.onDrop) return state.onDrop(names); +} + +auto mViewport::doMouseLeave() const -> void { + if(state.onMouseLeave) return state.onMouseLeave(); +} + +auto mViewport::doMouseMove(Position position) const -> void { + if(state.onMouseMove) return state.onMouseMove(position); +} + +auto mViewport::doMousePress(Mouse::Button button) const -> void { + if(state.onMousePress) return state.onMousePress(button); +} + +auto mViewport::doMouseRelease(Mouse::Button button) const -> void { + if(state.onMouseRelease) return state.onMouseRelease(button); +} + +auto mViewport::droppable() const -> bool { + return state.droppable; +} + +auto mViewport::handle() const -> uintptr_t { + return signal(handle); +} + +auto mViewport::onDrop(const function& function) -> type& { + state.onDrop = function; + return *this; +} + +auto mViewport::onMouseLeave(const function& function) -> type& { + state.onMouseLeave = function; + return *this; +} + +auto mViewport::onMouseMove(const function& function) -> type& { + state.onMouseMove = function; + return *this; +} + +auto mViewport::onMousePress(const function& function) -> type& { + state.onMousePress = function; + return *this; +} + +auto mViewport::onMouseRelease(const function& function) -> type& { + state.onMouseRelease = function; + return *this; +} + +auto mViewport::setDroppable(bool droppable) -> type& { + state.droppable = droppable; + signal(setDroppable, droppable); + return *this; +} diff --git a/hiro/core/widget/widget.cpp b/hiro/core/widget/widget.cpp new file mode 100644 index 00000000..599fdac4 --- /dev/null +++ b/hiro/core/widget/widget.cpp @@ -0,0 +1,20 @@ +auto mWidget::allocate() -> pObject* { + return new pWidget(*this); +} + +// + +auto mWidget::doSize() const -> void { + if(state.onSize) return state.onSize(); +} + +auto mWidget::onSize(const function& function) -> type& { + state.onSize = function; + return *this; +} + +auto mWidget::remove() -> type& { + if(auto layout = parentLayout()) layout->remove(layout->sizable(offset())); + setParent(); + return *this; +} diff --git a/hiro/core/window.cpp b/hiro/core/window.cpp new file mode 100644 index 00000000..964ae940 --- /dev/null +++ b/hiro/core/window.cpp @@ -0,0 +1,271 @@ +auto mWindow::allocate() -> pObject* { + return new pWindow(*this); +} + +auto mWindow::destruct() -> void { + if(auto& layout = state.layout) layout->destruct(); + if(auto& menuBar = state.menuBar) menuBar->destruct(); + if(auto& statusBar = state.statusBar) statusBar->destruct(); + mObject::destruct(); +} + +// + +auto mWindow::append(shared_pointer layout) -> type& { + if(auto& layout = state.layout) remove(layout); + state.layout = layout; + layout->setGeometry(geometry().setPosition(0, 0)); + layout->setParent(this, 0); + layout->setGeometry(geometry().setPosition(0, 0)); + return *this; +} + +auto mWindow::append(shared_pointer menuBar) -> type& { + if(auto& menuBar = state.menuBar) remove(menuBar); + menuBar->setParent(this, 0); + state.menuBar = menuBar; + signal(append, menuBar); + return *this; +} + +auto mWindow::append(shared_pointer statusBar) -> type& { + if(auto& statusBar = state.statusBar) remove(statusBar); + statusBar->setParent(this, 0); + state.statusBar = statusBar; + signal(append, statusBar); + return *this; +} + +auto mWindow::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mWindow::doClose() const -> void { + if(state.onClose) return state.onClose(); +} + +auto mWindow::doDrop(lstring names) const -> void { + if(state.onDrop) return state.onDrop(names); +} + +auto mWindow::doKeyPress(signed key) const -> void { + if(state.onKeyPress) return state.onKeyPress(key); +} + +auto mWindow::doKeyRelease(signed key) const -> void { + if(state.onKeyRelease) return state.onKeyRelease(key); +} + +auto mWindow::doMove() const -> void { + if(state.onMove) return state.onMove(); +} + +auto mWindow::doSize() const -> void { + if(state.onSize) return state.onSize(); +} + +auto mWindow::droppable() const -> bool { + return state.droppable; +} + +auto mWindow::frameGeometry() const -> Geometry { + Geometry margin = signal(frameMargin); + return { + state.geometry.x() - margin.x(), state.geometry.y() - margin.y(), + state.geometry.width() + margin.width(), state.geometry.height() + margin.height() + }; +} + +auto mWindow::fullScreen() const -> bool { + return state.fullScreen; +} + +auto mWindow::geometry() const -> Geometry { + return state.geometry; +} + +auto mWindow::layout() const -> shared_pointer { + return state.layout; +} + +auto mWindow::menuBar() const -> shared_pointer { + return state.menuBar; +} + +auto mWindow::modal() const -> bool { + return state.modal; +} + +auto mWindow::onClose(const function& function) -> type& { + state.onClose = function; + return *this; +} + +auto mWindow::onDrop(const function& function) -> type& { + state.onDrop = function; + return *this; +} + +auto mWindow::onKeyPress(const function& function) -> type& { + state.onKeyPress = function; + return *this; +} + +auto mWindow::onKeyRelease(const function& function) -> type& { + state.onKeyRelease = function; + return *this; +} + +auto mWindow::onMove(const function& function) -> type& { + state.onMove = function; + return *this; +} + +auto mWindow::onSize(const function& function) -> type& { + state.onSize = function; + return *this; +} + +auto mWindow::remove(shared_pointer layout) -> type& { + layout->setParent(); + state.layout.reset(); + return *this; +} + +auto mWindow::remove(shared_pointer menuBar) -> type& { + signal(remove, menuBar); + menuBar->reset(); + menuBar->setParent(); + state.menuBar.reset(); + return *this; +} + +auto mWindow::remove(shared_pointer statusBar) -> type& { + signal(remove, statusBar); + statusBar->setParent(); + state.statusBar.reset(); + return *this; +} + +auto mWindow::reset() -> type& { + if(auto& layout = state.layout) remove(layout); + if(auto& menuBar = state.menuBar) remove(menuBar); + if(auto& statusBar = state.statusBar) remove(statusBar); + return *this; +} + +auto mWindow::resizable() const -> bool { + return state.resizable; +} + +auto mWindow::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mWindow::setCentered() -> type& { + Geometry workspace = Desktop::workspace(); + Geometry geometry = frameGeometry(); + signed x = workspace.x(); + signed y = workspace.y(); + if(workspace.width() > geometry.width()) x += (workspace.width() - geometry.width()) / 2; + if(workspace.height() > geometry.height()) y += (workspace.height() - geometry.height()) / 2; + return setFrameGeometry({x, y, geometry.width(), geometry.height()}); +} + +auto mWindow::setCentered(shared_pointer parent) -> type& { + if(!parent) return setCentered(); + Geometry workspace = parent->frameGeometry(); + Geometry geometry = frameGeometry(); + signed x = workspace.x(); + signed y = workspace.y(); + if(workspace.width() > geometry.width()) x += (workspace.width() - geometry.width()) / 2; + if(workspace.height() > geometry.height()) y += (workspace.height() - geometry.height()) / 2; + return setFrameGeometry({x, y, geometry.width(), geometry.height()}); +} + +auto mWindow::setDroppable(bool droppable) -> type& { + state.droppable = droppable; + signal(setDroppable, droppable); + return *this; +} + +auto mWindow::setFrameGeometry(Geometry geometry) -> type& { + Geometry margin = signal(frameMargin); + return setGeometry({ + geometry.x() + margin.x(), geometry.y() + margin.y(), + geometry.width() - margin.width(), geometry.height() - margin.height() + }); +} + +auto mWindow::setFramePosition(Position position) -> type& { + Geometry margin = signal(frameMargin); + return setGeometry({ + position.x() + margin.x(), position.y() + margin.y(), + state.geometry.width(), state.geometry.height() + }); +} + +auto mWindow::setFrameSize(Size size) -> type& { + Geometry margin = signal(frameMargin); + return setGeometry({ + state.geometry.x(), state.geometry.y(), + size.width() - margin.width(), size.height() - margin.height() + }); +} + +auto mWindow::setFullScreen(bool fullScreen) -> type& { + state.fullScreen = fullScreen; + signal(setFullScreen, fullScreen); + return *this; +} + +auto mWindow::setGeometry(Geometry geometry) -> type& { + state.geometry = geometry; + signal(setGeometry, geometry); + if(auto& layout = state.layout) { + layout->setGeometry(geometry.setPosition(0, 0)); + } + return *this; +} + +auto mWindow::setModal(bool modal) -> type& { + state.modal = modal; + signal(setModal, modal); + return *this; +} + +auto mWindow::setPosition(Position position) -> type& { + return setGeometry({ + position.x(), position.y(), + state.geometry.width(), state.geometry.height() + }); +} + +auto mWindow::setResizable(bool resizable) -> type& { + state.resizable = resizable; + signal(setResizable, resizable); + return *this; +} + +auto mWindow::setSize(Size size) -> type& { + return setGeometry({ + state.geometry.x(), state.geometry.y(), + size.width(), size.height() + }); +} + +auto mWindow::setTitle(const string& title) -> type& { + state.title = title; + signal(setTitle, title); + return *this; +} + +auto mWindow::statusBar() const -> shared_pointer { + return state.statusBar; +} + +auto mWindow::title() const -> string { + return state.title; +} diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp new file mode 100644 index 00000000..232cb2b6 --- /dev/null +++ b/hiro/extension/browser-dialog.cpp @@ -0,0 +1,231 @@ +struct BrowserDialogWindow { + BrowserDialogWindow(BrowserDialog::State& state) : state(state) {} + auto accept() -> void; + auto activate() -> void; + auto change() -> void; + auto isFolder(const string& name) -> bool; + auto run() -> lstring; + auto setPath(string path) -> void; + +private: + Window window; + VerticalLayout layout{&window}; + HorizontalLayout pathLayout{&layout, Size{~0, 0}, 8}; + LineEdit pathName{&pathLayout, Size{~0, 0}, 0}; + Button pathHome{&pathLayout, Size{0, 0}, 0}; + Button pathRefresh{&pathLayout, Size{0, 0}, 0}; + Button pathUp{&pathLayout, Size{0, 0}, 0}; + ListView view{&layout, Size{~0, ~0}, 8}; + HorizontalLayout controlLayout{&layout, Size{~0, 0}}; + ComboButton filterList{&controlLayout, Size{120, 0}, 8}; + LineEdit fileName{&controlLayout, Size{~0, 0}, 8}; + Button acceptButton{&controlLayout, Size{80, 0}, 8}; + Button cancelButton{&controlLayout, Size{80, 0}, 8}; + + BrowserDialog::State& state; +}; + +//accept button clicked, or enter pressed on file name line edit +//also called by list view activate after special case handling +auto BrowserDialogWindow::accept() -> void { + auto selectedItems = view.selectedItems(); + + if(state.action == "openFile" && selectedItems) { + string name = selectedItems.first()->text(0); + if(isFolder(name)) return setPath({state.path, name}); + state.response.append(string{state.path, name}); + } + + if(state.action == "openFiles") { + for(auto selectedItem : selectedItems) { + string name = selectedItem->text(0); + state.response.append(string{state.path, name, isFolder(name) ? "/" : ""}); + } + } + + if(state.action == "saveFile") { + string name = fileName.text(); + if(!name && selectedItems) name = selectedItems.first()->text(0); + if(!name || isFolder(name)) return; + if(file::exists({state.path, name})) { + if(MessageDialog("File already exists; overwrite it?").question() != 0) return; + } + state.response.append(string{state.path, name}); + } + + if(state.action == "selectFolder" && selectedItems) { + string name = selectedItems.first()->text(0); + if(isFolder(name)) state.response.append(string{state.path, name, "/"}); + } + + if(state.response) window.setModal(false); +} + +//list view item double-clicked, or enter pressed on selected list view item +auto BrowserDialogWindow::activate() -> void { + auto selectedItem = view.selected(); + if(state.action == "saveFile" && selectedItem) { + string name = selectedItem->text(0); + if(isFolder(name)) return setPath({state.path, name}); + fileName.setText(isFolder(name) ? "" : name); + } + if(state.action == "selectFolder" && selectedItem) { + string name = selectedItem->text(0); + if(isFolder(name)) return setPath({state.path, name}); + } + accept(); +} + +//list view item changed +auto BrowserDialogWindow::change() -> void { + fileName.setText(""); + if(state.action == "saveFile") { + if(auto selectedItem = view.selected()) { + string name = selectedItem->text(0); + if(!isFolder(name)) fileName.setText(name); + } + } +} + +auto BrowserDialogWindow::isFolder(const string& name) -> bool { + return directory::exists({state.path, name}); +} + +auto BrowserDialogWindow::run() -> lstring { + state.response.reset(); + + layout.setMargin(8); + pathName.onActivate([&] { setPath(pathName.text()); }); + pathHome.onActivate([&] { setPath(userpath()); }); + pathHome.setBordered(false).setIcon(Icon::Go::Home); + pathRefresh.onActivate([&] { setPath(state.path); }); + pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh); + pathUp.onActivate([&] { setPath(state.path.dirname()); }); + pathUp.setBordered(false).setIcon(Icon::Go::Up); + view.onActivate([&] { activate(); }); + view.onChange([&] { change(); }); + view.setMultiSelect(state.action == "openFiles"); + filterList.onChange([&] { setPath(state.path); }); + for(auto& filter : state.filters) { + auto part = filter.split<1>("|"); + filterList.append(ComboButtonItem().setText(part.first())); + } + filterList.setVisible(state.action != "selectFolder"); + fileName.onActivate([&] { accept(); }); + fileName.setVisible(state.action == "saveFile"); + acceptButton.onActivate([&] { accept(); }); + if(state.action == "openFile" || state.action == "openFiles") acceptButton.setText("Open"); + if(state.action == "saveFile") acceptButton.setText("Save"); + if(state.action == "selectFolder") acceptButton.setText("Select"); + cancelButton.onActivate([&] { window.setModal(false); }); + cancelButton.setText("Cancel"); + + setPath(state.path); + + window.onClose([&] { window.setModal(false); }); + window.onSize([&] { view.resizeColumns(); }); + window.setTitle(state.title); + window.setSize({640, 480}); + window.setCentered(state.parent); + window.setVisible(); + view.resizeColumns(); + window.setModal(); + window.setVisible(false); + + return state.response; +} + +auto BrowserDialogWindow::setPath(string path) -> void { + path.transform("\\", "/"); + if(!path.endsWith("/")) path.append("/"); + pathName.setText(state.path = path); + + view.reset(); + view.append(ListViewColumn().setWidth(~0)); + view.append(ListViewColumn().setWidth( 0).setForegroundColor({192, 128, 128})); + + for(auto& folder : directory::folders(path)) { + ListViewItem item{&view}; + item.setIcon(0, Icon::Emblem::Folder); + item.setText(0, folder.rtrim("/")); + item.setText(1, octal<3>(storage::mode({path, folder}) & 0777)); + } + + if(state.action != "selectFolder") { //don't show files during folder selection + string filter = "*"; + if(auto selected = filterList.selected()) { + auto part = state.filters[selected->offset()].split<1>("|"); + filter = part.last(); + } + + for(auto& file : directory::files(path)) { + if(!file.match(filter)) continue; + ListViewItem item{&view}; + item.setIcon(0, Icon::Emblem::File); + item.setText(0, file); + item.setText(1, octal<3>(storage::mode({path, file}) & 0777)); + } + } + + if(view.items()) view.setSelected({0}); + Application::processEvents(); + view.resizeColumns().setFocused().doChange(); +} + +// + +BrowserDialog::BrowserDialog() { +} + +auto BrowserDialog::openFile() -> string { + state.action = "openFile"; + if(!state.title) state.title = "Open File"; + if(auto result = _run()) return result.first(); + return {}; +} + +auto BrowserDialog::openFiles() -> lstring { + state.action = "openFiles"; + if(!state.title) state.title = "Open Files"; + if(auto result = _run()) return result; + return {}; +}; + +auto BrowserDialog::saveFile() -> string { + state.action = "saveFile"; + if(!state.title) state.title = "Save File"; + if(auto result = _run()) return result.first(); + return {}; +} + +auto BrowserDialog::selectFolder() -> string { + state.action = "selectFolder"; + if(!state.title) state.title = "Select Folder"; + if(auto result = _run()) return result.first(); + return {}; +} + +auto BrowserDialog::setFilters(const lstring& filters) -> type& { + state.filters = filters; + return *this; +} + +auto BrowserDialog::setParent(const shared_pointer& parent) -> type& { + state.parent = parent; + return *this; +} + +auto BrowserDialog::setPath(const string& path) -> type& { + state.path = path; + return *this; +} + +auto BrowserDialog::setTitle(const string& title) -> type& { + state.title = title; + return *this; +} + +auto BrowserDialog::_run() -> lstring { + if(!state.path) state.path = userpath(); + return BrowserDialogWindow(state).run(); +} diff --git a/hiro/extension/browser-dialog.hpp b/hiro/extension/browser-dialog.hpp new file mode 100644 index 00000000..510ab697 --- /dev/null +++ b/hiro/extension/browser-dialog.hpp @@ -0,0 +1,29 @@ +struct BrowserDialogWindow; + +struct BrowserDialog { + using type = BrowserDialog; + + BrowserDialog(); + auto openFile() -> nall::string; //one existing file + auto openFiles() -> nall::lstring; //any existing files or folders + auto saveFile() -> nall::string; //one file + auto selectFolder() -> nall::string; //one existing folder + auto setFilters(const nall::lstring& filters = {"All|*"}) -> type&; + auto setParent(const nall::shared_pointer& parent) -> type&; + auto setPath(const nall::string& path = "") -> type&; + auto setTitle(const nall::string& title = "") -> type&; + +private: + struct State { + nall::string action; + nall::lstring filters = {"*"}; + nall::shared_pointer parent; + nall::string path; + nall::lstring response; + nall::string title; + } state; + + auto _run() -> nall::lstring; + + friend class BrowserDialogWindow; +}; diff --git a/hiro/extension/extension.cpp b/hiro/extension/extension.cpp new file mode 100644 index 00000000..aa46d451 --- /dev/null +++ b/hiro/extension/extension.cpp @@ -0,0 +1,11 @@ +#include "extension.hpp" +using namespace nall; + +namespace hiro { + #include "../resource/resource.cpp" + #include "fixed-layout.cpp" + #include "horizontal-layout.cpp" + #include "vertical-layout.cpp" + #include "browser-dialog.cpp" + #include "message-dialog.cpp" +} diff --git a/hiro/extension/extension.hpp b/hiro/extension/extension.hpp new file mode 100644 index 00000000..f3655abe --- /dev/null +++ b/hiro/extension/extension.hpp @@ -0,0 +1,9 @@ +namespace hiro { + #include "../resource/resource.hpp" + #include "fixed-layout.hpp" + #include "horizontal-layout.hpp" + #include "vertical-layout.hpp" + #include "shared.hpp" + #include "browser-dialog.hpp" + #include "message-dialog.hpp" +} diff --git a/hiro/extension/fixed-layout.cpp b/hiro/extension/fixed-layout.cpp new file mode 100644 index 00000000..bb976269 --- /dev/null +++ b/hiro/extension/fixed-layout.cpp @@ -0,0 +1,51 @@ +auto mFixedLayout::append(shared_pointer sizable, Geometry geometry) -> type& { + properties.append({geometry}); + mLayout::append(sizable); + sizable->setGeometry(geometry); + return *this; +} + +auto mFixedLayout::minimumSize() const -> Size { + signed width = Size::Minimum, height = Size::Minimum; + for(auto n : range(sizables())) { + width = max(width, sizable(n)->minimumSize().width()); + height = max(height, sizable(n)->minimumSize().height()); + } + return {width, height}; +} + +auto mFixedLayout::remove(shared_pointer sizable) -> type& { + properties.remove(sizable->offset()); + mLayout::remove(sizable); + return *this; +} + +auto mFixedLayout::reset() -> type& { + mLayout::reset(); + properties.reset(); + return *this; +} + +auto mFixedLayout::setEnabled(bool enabled) -> type& { + mLayout::setEnabled(enabled); + for(auto n : range(sizables())) { + sizable(n)->setEnabled(sizable(n)->enabled(true)); + } + return *this; +} + +auto mFixedLayout::setFont(const string& font) -> type& { + mLayout::setFont(font); + for(auto n : range(sizables())) { + sizable(n)->setFont(sizable(n)->font(true)); + } + return *this; +} + +auto mFixedLayout::setVisible(bool visible) -> type& { + mLayout::setVisible(visible); + for(auto n : range(sizables())) { + sizable(n)->setVisible(sizable(n)->visible(true)); + } + return *this; +} diff --git a/hiro/extension/fixed-layout.hpp b/hiro/extension/fixed-layout.hpp new file mode 100644 index 00000000..37f50ada --- /dev/null +++ b/hiro/extension/fixed-layout.hpp @@ -0,0 +1,18 @@ +struct mFixedLayout : mLayout { + using type = mFixedLayout; + using mLayout::append; + using mLayout::remove; + + auto append(nall::shared_pointer sizable, Geometry geometry) -> type&; + auto minimumSize() const -> Size override; + auto remove(nall::shared_pointer sizable) -> type& override; + auto reset() -> type& override; + auto setEnabled(bool enabled = true) -> type& override; + auto setFont(const nall::string& font = "") -> type& override; + auto setVisible(bool visible = true) ->type& override; + + struct Properties { + Geometry geometry; + }; + nall::vector properties; +}; diff --git a/hiro/extension/horizontal-layout.cpp b/hiro/extension/horizontal-layout.cpp new file mode 100644 index 00000000..4d50d4c5 --- /dev/null +++ b/hiro/extension/horizontal-layout.cpp @@ -0,0 +1,125 @@ +auto mHorizontalLayout::append(shared_pointer sizable, Size size, signed spacing) -> type& { + properties.append({size.width(), size.height(), spacing < 0 ? settings.spacing : spacing}); + mLayout::append(sizable); + return *this; +} + +auto mHorizontalLayout::minimumSize() const -> Size { + signed width = 0, height = 0; + + for(auto n : range(sizables())) { + auto& child = properties[sizable(n)->offset()]; + if(child.width == Size::Minimum || child.width == Size::Maximum) { + width += sizable(n)->minimumSize().width(); + } else { + width += child.width; + } + if(&child != &properties.last()) width += child.spacing; + } + + for(auto n : range(sizables())) { + auto& child = properties[sizable(n)->offset()]; + if(child.height == Size::Minimum || child.height == Size::Maximum) { + height = max(height, sizable(n)->minimumSize().height()); + continue; + } + height = max(height, child.height); + } + + return {settings.margin * 2 + width, settings.margin * 2 + height}; +} + +auto mHorizontalLayout::remove(shared_pointer sizable) -> type& { + properties.remove(sizable->offset()); + mLayout::remove(sizable); + return *this; +} + +auto mHorizontalLayout::reset() -> type& { + mLayout::reset(); + properties.reset(); + return *this; +} + +auto mHorizontalLayout::setAlignment(double alignment) -> type& { + settings.alignment = max(0.0, min(1.0, alignment)); + return *this; +} + +auto mHorizontalLayout::setEnabled(bool enabled) -> type& { + mLayout::setEnabled(enabled); + for(auto n : range(sizables())) { + sizable(n)->setEnabled(sizable(n)->enabled(true)); + } + return *this; +} + +auto mHorizontalLayout::setFont(const string& font) -> type& { + mLayout::setFont(font); + for(auto n : range(sizables())) { + sizable(n)->setFont(sizable(n)->font(true)); + } + return *this; +} + +auto mHorizontalLayout::setGeometry(Geometry containerGeometry) -> type& { + mLayout::setGeometry(containerGeometry); + + auto properties = this->properties; + for(auto n : range(sizables())) { + auto& child = properties[sizable(n)->offset()]; + if(child.width == Size::Minimum) child.width = sizable(n)->minimumSize().width(); + if(child.height == Size::Minimum) child.height = sizable(n)->minimumSize().height(); + } + + Geometry geometry = containerGeometry; + geometry.setX (geometry.x() + settings.margin ); + geometry.setY (geometry.y() + settings.margin ); + geometry.setWidth (geometry.width() - settings.margin * 2); + geometry.setHeight(geometry.height() - settings.margin * 2); + + signed minimumWidth = 0, maximumWidthCounter = 0; + for(auto& child : properties) { + if(child.width == Size::Maximum) maximumWidthCounter++; + if(child.width != Size::Maximum) minimumWidth += child.width; + if(&child != &properties.last()) minimumWidth += child.spacing; + } + + for(auto& child : properties) { + if(child.width == Size::Maximum) child.width = (geometry.width() - minimumWidth) / maximumWidthCounter; + if(child.height == Size::Maximum) child.height = geometry.height(); + } + + signed maximumHeight = 0; + for(auto& child : properties) maximumHeight = max(maximumHeight, child.height); + + for(auto n : range(sizables())) { + auto& child = properties[sizable(n)->offset()]; + signed pivot = (maximumHeight - child.height) * settings.alignment; + Geometry childGeometry = {geometry.x(), geometry.y() + pivot, child.width, child.height}; + if(childGeometry.width() < 1) childGeometry.setWidth (1); + if(childGeometry.height() < 1) childGeometry.setHeight(1); + sizable(n)->setGeometry(childGeometry); + + geometry.setX (geometry.x() + child.width + child.spacing); + geometry.setWidth(geometry.width() - child.width + child.spacing); + } +} + +auto mHorizontalLayout::setMargin(signed margin) -> type& { + settings.margin = margin; + return *this; +} + +auto mHorizontalLayout::setSpacing(signed spacing) -> type& { + settings.spacing = spacing; + return *this; +} + +auto mHorizontalLayout::setVisible(bool visible) -> type& { + mLayout::setVisible(visible); + for(auto n : range(sizables())) { + sizable(n)->setVisible(sizable(n)->visible(true)); + } + return *this; +} diff --git a/hiro/extension/horizontal-layout.hpp b/hiro/extension/horizontal-layout.hpp new file mode 100644 index 00000000..9a941dc2 --- /dev/null +++ b/hiro/extension/horizontal-layout.hpp @@ -0,0 +1,30 @@ +struct mHorizontalLayout : mLayout { + using type = mHorizontalLayout; + using mLayout::append; + using mLayout::remove; + + auto append(nall::shared_pointer sizable, Size size, signed spacing = 5) -> type&; + auto minimumSize() const -> Size override; + auto remove(nall::shared_pointer sizable) -> type& override; + auto reset() -> type& override; + auto setAlignment(double alignment = 0.5) -> type&; + auto setEnabled(bool enabled = true) -> type& override; + auto setFont(const nall::string& font = "") -> type& override; + auto setGeometry(Geometry geometry) -> type& override; + auto setMargin(signed margin = 0) -> type&; + auto setSpacing(signed spacing = 5) -> type&; + auto setVisible(bool visible = true) -> type&; + + struct Settings { + double alignment = 0.5; + signed margin = 0; + signed spacing = 5; + } settings; + + struct Property { + signed width; + signed height; + signed spacing; + }; + nall::vector properties; +}; diff --git a/hiro/extension/message-dialog.cpp b/hiro/extension/message-dialog.cpp new file mode 100644 index 00000000..2745e37a --- /dev/null +++ b/hiro/extension/message-dialog.cpp @@ -0,0 +1,77 @@ +MessageDialog::MessageDialog(const string& text) { + state.text = text; +} + +auto MessageDialog::error(const lstring& buttons) -> signed { + state.buttons = buttons; + state.icon = Icon::Prompt::Error; + return _run(); +} + +auto MessageDialog::information(const lstring& buttons) -> signed { + state.buttons = buttons; + state.icon = Icon::Prompt::Information; + return _run(); +} + +auto MessageDialog::question(const lstring& buttons) -> signed { + state.buttons = buttons; + state.icon = Icon::Prompt::Question; + return _run(); +} + +auto MessageDialog::setParent(shared_pointer parent) -> type& { + state.parent = parent; + return *this; +} + +auto MessageDialog::setText(const string& text) -> type& { + state.text = text; + return *this; +} + +auto MessageDialog::setTitle(const string& title) -> type& { + state.title = title; + return *this; +} + +auto MessageDialog::warning(const lstring& buttons) -> signed { + state.buttons = buttons; + state.icon = Icon::Prompt::Warning; + return _run(); +} + +auto MessageDialog::_run() -> signed { + Window window; + VerticalLayout layout{&window}; + HorizontalLayout messageLayout{&layout, Size{~0, 0}, 8}; + Canvas messageIcon{&messageLayout, Size{16, 16}, 8}; + Label messageText{&messageLayout, Size{~0, 0}}; + HorizontalLayout controlLayout{&layout, Size{~0, 0}}; + Widget controlSpacer{&controlLayout, Size{~0, 0}}; + + layout.setMargin(8); + messageIcon.setIcon(state.icon); + messageText.setText(state.text); + for(auto n : range(state.buttons)) { + Button button{&controlLayout, Size{80, 0}, 8}; + button.onActivate([&, n] { state.response = n; window.setModal(false); }); + button.setText(state.buttons[n]); + button.setFocused(); //the last button will have effective focus + } + + signed widthMessage = 8 + 16 + 8 + Font::size(Font::sans(), state.text).width() + 8; + signed widthButtons = 8 + state.buttons.size() * 88; + signed width = max(320, widthMessage, widthButtons); + + window.onClose([&] { state.response = -1; window.setModal(false); }); + window.setTitle(state.title); + window.setResizable(false); + window.setSize({width, layout.minimumSize().height()}); + window.setCentered(state.parent); + window.setVisible(); + window.setModal(); + window.setVisible(false); + + return state.response; +} diff --git a/hiro/extension/message-dialog.hpp b/hiro/extension/message-dialog.hpp new file mode 100644 index 00000000..0f3627c2 --- /dev/null +++ b/hiro/extension/message-dialog.hpp @@ -0,0 +1,24 @@ +struct MessageDialog { + using type = MessageDialog; + + MessageDialog(const nall::string& text = ""); + auto error(const nall::lstring& buttons = {"Ok"}) -> signed; + auto information(const nall::lstring& buttons = {"Ok"}) -> signed; + auto question(const nall::lstring& buttons = {"Yes", "No"}) -> signed; + auto setParent(nall::shared_pointer parent = {}) -> type&; + auto setText(const nall::string& text = "") -> type&; + auto setTitle(const nall::string& title = "") -> type&; + auto warning(const nall::lstring& buttons = {"Ok"}) -> signed; + +private: + struct State { + nall::lstring buttons; + nall::vector icon; + nall::shared_pointer parent; + signed response = -1; + nall::string text; + nall::string title; + } state; + + auto _run() -> signed; +}; diff --git a/hiro/extension/shared.hpp b/hiro/extension/shared.hpp new file mode 100644 index 00000000..0572e862 --- /dev/null +++ b/hiro/extension/shared.hpp @@ -0,0 +1,768 @@ +#define Declare(Name) \ + using type = Name; \ + Name() : s##Name(new m##Name, [](m##Name* p) { \ + p->unbind(); \ + delete p; \ + }) { \ + (*this)->bind(*this); \ + } \ + template Name(T* parent, P&&... p) : Name() { \ + if(parent && *parent) (*parent)->append(*this, std::forward

(p)...); \ + } \ + auto self() const -> m##Name& { return (m##Name&)operator*(); } \ + +#define DeclareObject(Name) \ + Declare(Name) \ + auto enabled(bool recursive = false) const -> bool { return self().enabled(recursive); } \ + auto focused() const -> bool { return self().focused(); } \ + auto font(bool recursive = false) const -> string { return self().font(recursive); } \ + auto remove() -> type& { return self().remove(), *this; } \ + auto setEnabled(bool enabled = true) -> type& { return self().setEnabled(enabled), *this; } \ + auto setFocused() -> type& { return self().setFocused(), *this; } \ + auto setFont(const string& font = "") -> type& { return self().setFont(font), *this; } \ + auto setVisible(bool visible = true) -> type& { return self().setVisible(visible), *this; } \ + auto visible(bool recursive = false) const -> bool { return self().visible(recursive); } \ + +#define DeclareAction(Name) \ + DeclareObject(Name) \ + +#define DeclareSizable(Name) \ + DeclareObject(Name) \ + auto geometry() const -> Geometry { return self().geometry(); } \ + auto minimumSize() const -> Size { return self().minimumSize(); } \ + auto setGeometry(Geometry geometry) -> type& { return self().setGeometry(geometry), *this; } \ + +#define DeclareLayout(Name) \ + DeclareSizable(Name) \ + auto append(sSizable sizable) -> type& { return self().append(sizable), *this; } \ + auto remove(sSizable sizable) -> type& { return self().remove(sizable), *this; } \ + auto reset() -> type& { return self().reset(), *this; } \ + auto sizable(unsigned position) -> sSizable { return self().sizable(position); } \ + auto sizables() const -> unsigned { return self().sizables(); } \ + +#define DeclareWidget(Name) \ + DeclareSizable(Name) \ + auto doSize() const -> void { return self().doSize(); } \ + auto onSize(const function& function = {}) -> type& { return self().onSize(function), *this; } \ + +struct Object : sObject { + DeclareObject(Object) +}; + +struct Hotkey : sHotkey { + DeclareObject(Hotkey) + + auto doPress() const -> void { return self().doPress(); } + auto doRelease() const -> void { return self().doRelease(); } + auto onPress(const function& function = {}) -> type& { return self().onPress(function), *this; } + auto onRelease(const function& function = {}) -> type& { return self().onRelease(function), *this; } + auto parent() const -> wObject { return self().parent(); } + auto sequence() const -> string { return self().sequence(); } + auto setParent(sObject object) -> type& { return self().setParent(object), *this; } + auto setSequence(const string& sequence = "") -> type& { return self().setSequence(sequence), *this; } +}; + +struct Timer : sTimer { + DeclareObject(Timer) + + auto doActivate() const -> void { return self().doActivate(); } + auto interval() const -> unsigned { return self().interval(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto setInterval(unsigned interval = 0) -> type& { return self().setInterval(interval), *this; } +}; + +struct Window : sWindow { + DeclareObject(Window) + + auto append(sLayout layout) -> type& { return self().append(layout), *this; } + auto append(sMenuBar menuBar) -> type& { return self().append(menuBar), *this; } + auto append(sStatusBar statusBar) -> type& { return self().append(statusBar), *this; } + auto backgroundColor() const -> Color { return self().backgroundColor(); } + auto doClose() const -> void { return self().doClose(); } + auto doDrop(lstring names) const -> void { return self().doDrop(names); } + auto doKeyPress(signed key) const -> void { return self().doKeyPress(key); } + auto doKeyRelease(signed key) const -> void { return self().doKeyRelease(key); } + auto doMove() const -> void { return self().doMove(); } + auto doSize() const -> void { return self().doSize(); } + auto droppable() const -> bool { return self().droppable(); } + auto frameGeometry() const -> Geometry { return self().frameGeometry(); } + auto fullScreen() const -> bool { return self().fullScreen(); } + auto geometry() const -> Geometry { return self().geometry(); } + auto layout() const -> sLayout { return self().layout(); } + auto menuBar() const -> sMenuBar { return self().menuBar(); } + auto modal() const -> bool { return self().modal(); } + auto onClose(const function& function = {}) -> type& { return self().onClose(function), *this; } + auto onDrop(const function& function = {}) -> type& { return self().onDrop(function), *this; } + auto onKeyPress(const function& function = {}) -> type& { return self().onKeyPress(function), *this; } + auto onKeyRelease(const function& function = {}) -> type& { return self().onKeyRelease(function), *this; } + auto onMove(const function& function = {}) -> type& { return self().onMove(function), *this; } + auto onSize(const function& function = {}) -> type& { return self().onSize(function), *this; } + auto remove(sLayout layout) -> type& { return self().remove(layout), *this; } + auto remove(sMenuBar menuBar) -> type& { return self().remove(menuBar), *this; } + auto remove(sStatusBar statusBar) -> type& { return self().remove(statusBar), *this; } + auto reset() -> type& { return self().reset(), *this; } + auto resizable() const -> bool { return self().resizable(); } + auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } + auto setCentered() -> type& { return self().setCentered(), *this; } + auto setCentered(sWindow parent) -> type& { return self().setCentered(parent), *this; } + auto setDroppable(bool droppable = true) -> type& { return self().setDroppable(droppable), *this; } + auto setFrameGeometry(Geometry geometry) -> type& { return self().setFrameGeometry(geometry), *this; } + auto setFramePosition(Position position) -> type& { return self().setFramePosition(position), *this; } + auto setFrameSize(Size size) -> type& { return self().setFrameSize(size), *this; } + auto setFullScreen(bool fullScreen = true) -> type& { return self().setFullScreen(fullScreen), *this; } + auto setGeometry(Geometry geometry) -> type& { return self().setGeometry(geometry), *this; } + auto setModal(bool modal = true) -> type& { return self().setModal(modal), *this; } + auto setPosition(Position position) -> type& { return self().setPosition(position), *this; } + auto setResizable(bool resizable = true) -> type& { return self().setResizable(resizable), *this; } + auto setSize(Size size) -> type& { return self().setSize(size), *this; } + auto setTitle(const string& title = "") -> type& { return self().setTitle(title), *this; } + auto statusBar() const -> sStatusBar { return self().statusBar(); } + auto title() const -> string { return self().title(); } +}; + +struct StatusBar : sStatusBar { + DeclareObject(StatusBar) + + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct MenuBar : sMenuBar { + DeclareObject(MenuBar) + + auto append(sMenu menu) -> type& { return self().append(menu), *this; } + auto menu(unsigned position) const -> sMenu { return self().menu(position); } + auto menus() const -> unsigned { return self().menus(); } + auto remove(sMenu menu) -> type& { return self().remove(menu), *this; } + auto reset() -> type& { return self().reset(), *this; } +}; + +struct PopupMenu : sPopupMenu { + DeclareObject(PopupMenu) + + auto action(unsigned position) const -> sAction { return self().action(position); } + auto actions() const -> unsigned { return self().actions(); } + auto append(sAction action) -> type& { return self().append(action), *this; } + auto remove(sAction action) -> type& { return self().remove(action), *this; } + auto reset() -> type& { return self().reset(), *this; } +}; + +struct Action : sAction { + DeclareAction(Action) +}; + +struct Menu : sMenu { + DeclareAction(Menu) + + auto action(unsigned position) const -> sAction { return self().action(position); } + auto actions() const -> unsigned { return self().actions(); } + auto append(sAction action) -> type& { return self().append(action), *this; } + auto icon() const -> image { return self().icon(); } + auto remove(sAction action) -> type& { return self().remove(action), *this; } + auto reset() -> type& { return self().reset(), *this; } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct MenuSeparator : sMenuSeparator { + DeclareAction(MenuSeparator) +}; + +struct MenuItem : sMenuItem { + DeclareAction(MenuItem) + + auto doActivate() const -> void { return self().doActivate(); } + auto icon() const -> image { return self().icon(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct MenuCheckItem : sMenuCheckItem { + DeclareAction(MenuCheckItem) + + auto checked() const -> bool { return self().checked(); } + auto doToggle() const -> void { return self().doToggle(); } + auto onToggle(const function& function = {}) -> type& { return self().onToggle(function), *this; } + auto setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct MenuRadioItem : sMenuRadioItem { + DeclareAction(MenuRadioItem) + + auto checked() const -> bool { return self().checked(); } + auto doActivate() const -> void { return self().doActivate(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto setChecked() -> type& { return self().setChecked(), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } + + static auto group(const vector& group) -> void { return mMenuRadioItem::group(group); } +}; + +struct Sizable : sSizable { + DeclareSizable(Sizable) +}; + +struct Layout : sLayout { + DeclareLayout(Layout) +}; + +struct Widget : sWidget { + DeclareWidget(Widget) +}; + +struct Button : sButton { + DeclareWidget(Button) + + auto bordered() const -> bool { return self().bordered(); } + auto doActivate() const -> void { return self().doActivate(); } + auto icon() const -> image { return self().icon(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto orientation() const -> Orientation { return self().orientation(); } + auto setBordered(bool bordered = true) -> type& { return self().setBordered(bordered), *this; } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type& { return self().setOrientation(orientation), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct Canvas : sCanvas { + DeclareWidget(Canvas) + + auto color() const -> Color { return self().color(); } + auto data() -> uint32_t* { return self().data(); } + auto droppable() const -> bool { return self().droppable(); } + auto doDrop(lstring names) -> void { return self().doDrop(names); } + auto doMouseLeave() const -> void { return self().doMouseLeave(); } + auto doMouseMove(Position position) const -> void { return self().doMouseMove(position); } + auto doMousePress(Mouse::Button button) const -> void { return self().doMousePress(button); } + auto doMouseRelease(Mouse::Button button) const -> void { return self().doMouseRelease(button); } + auto gradient() const -> vector { return self().gradient(); } + auto icon() const -> image { return self().icon(); } + auto onDrop(const function& function = {}) -> type& { return self().onDrop(function), *this; } + auto onMouseLeave(const function& function = {}) -> type& { return self().onMouseLeave(function), *this; } + auto onMouseMove(const function& function = {}) -> type& { return self().onMouseMove(function), *this; } + auto onMousePress(const function& function = {}) -> type& { return self().onMousePress(function), *this; } + auto onMouseRelease(const function& function = {}) -> type& { return self().onMouseRelease(function), *this; } + auto setColor(Color color) -> type& { return self().setColor(color), *this; } + auto setData(Size size) -> type& { return self().setData(size), *this; } + auto setDroppable(bool droppable = true) -> type& { return self().setDroppable(droppable), *this; } + auto setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> type& { return self().setGradient(topLeft, topRight, bottomLeft, bottomRight), *this; } + auto setHorizontalGradient(Color left, Color right) -> type& { return self().setGradient(left, right, left, right), *this; } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setVerticalGradient(Color top, Color bottom) -> type& { return self().setGradient(top, top, bottom, bottom), *this; } + auto size() const -> Size { return self().size(); } + auto update() -> type& { return self().update(), *this; } +}; + +struct CheckButton : sCheckButton { + DeclareWidget(CheckButton) + + auto bordered() const -> bool { return self().bordered(); } + auto checked() const -> bool { return self().checked(); } + auto doToggle() const -> void { return self().doToggle(); } + auto icon() const -> image { return self().icon(); } + auto onToggle(const function& function = {}) -> type& { return self().onToggle(function), *this; } + auto orientation() const -> Orientation { return self().orientation(); } + auto setBordered(bool bordered = true) -> type& { return self().setBordered(bordered), *this; } + auto setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type& { return self().setOrientation(orientation), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct CheckLabel : sCheckLabel { + DeclareWidget(CheckLabel) + + auto checked() const -> bool { return self().checked(); } + auto doToggle() const -> void { return self().doToggle(); } + auto onToggle(const function& function = {}) -> type& { return self().onToggle(function), *this; } + auto setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct ComboButton : sComboButton { + DeclareWidget(ComboButton) + + auto append(sComboButtonItem item) -> type& { return self().append(item), *this; } + auto doChange() const -> void { return self().doChange(); } + auto item(unsigned position) const -> sComboButtonItem { return self().item(position); } + auto items() const -> unsigned { return self().items(); } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto remove(sComboButtonItem item) -> type& { return self().remove(item), *this; } + auto reset() -> type& { return self().reset(), *this; } + auto selected() const -> sComboButtonItem { return self().selected(); } +}; + +struct ComboButtonItem : sComboButtonItem { + DeclareObject(ComboButtonItem) + + auto icon() const -> image { return self().icon(); } + auto selected() const -> bool { return self().selected(); } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setSelected() -> type& { return self().setSelected(), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct Console : sConsole { + DeclareWidget(Console) + + auto backgroundColor() const -> Color { return self().backgroundColor(); } + auto doActivate(string command) const -> void { return self().doActivate(command); } + auto foregroundColor() const -> Color { return self().foregroundColor(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto print(const string& text) -> type& { return self().print(text), *this; } + auto prompt() const -> string { return self().prompt(); } + auto reset() -> type& { return self().reset(), *this; } + auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } + auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } + auto setPrompt(const string& prompt = "") -> type& { return self().setPrompt(prompt), *this; } +}; + +struct Frame : sFrame { + DeclareWidget(Frame) + + auto append(sLayout layout) -> type& { return self().append(layout), *this; } + auto layout() const -> sLayout { return self().layout(); } + auto remove(sLayout layout) -> type& { return self().remove(layout), *this; } + auto reset() -> type& { return self().reset(), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct HexEdit : sHexEdit { + DeclareWidget(HexEdit) + + auto backgroundColor() const -> Color { return self().backgroundColor(); } + auto columns() const -> unsigned { return self().columns(); } + auto doRead(unsigned offset) const -> uint8_t { return self().doRead(offset); } + auto doWrite(unsigned offset, uint8_t data) const -> void { return self().doWrite(offset, data); } + auto foregroundColor() const -> Color { return self().foregroundColor(); } + auto length() const -> unsigned { return self().length(); } + auto offset() const -> unsigned { return self().offset(); } + auto onRead(const function& function = {}) -> type& { return self().onRead(function), *this; } + auto onWrite(const function& function = {}) -> type& { return self().onWrite(function), *this; } + auto rows() const -> unsigned { return self().rows(); } + auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } + auto setColumns(unsigned columns = 16) -> type& { return self().setColumns(columns), *this; } + auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } + auto setLength(unsigned length) -> type& { return self().setLength(length), *this; } + auto setOffset(unsigned offset) -> type& { return self().setOffset(offset), *this; } + auto setRows(unsigned rows = 16) -> type& { return self().setRows(rows), *this; } + auto update() -> type& { return self().update(), *this; } +}; + +struct HorizontalScroller : sHorizontalScroller { + DeclareWidget(HorizontalScroller) + + auto doChange() const -> void { return self().doChange(); } + auto length() const -> unsigned { return self().length(); } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto position() const -> unsigned { return self().position(); } + auto setLength(unsigned length = 101) -> type& { return self().setLength(length), *this; } + auto setPosition(unsigned position = 0) -> type& { return self().setPosition(position), *this; } +}; + +struct HorizontalSlider : sHorizontalSlider { + DeclareWidget(HorizontalSlider) + + auto doChange() const -> void { return self().doChange(); } + auto length() const -> unsigned { return self().length(); } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto position() const -> unsigned { return self().position(); } + auto setLength(unsigned length = 101) -> type& { return self().setLength(length), *this; } + auto setPosition(unsigned position = 0) -> type& { return self().setPosition(position), *this; } +}; + +struct IconView : sIconView { + DeclareWidget(IconView) + + auto append(sIconViewItem item) -> type& { return self().append(item), *this; } + auto backgroundColor() const -> Color { return self().backgroundColor(); } + auto doActivate() const -> void { return self().doActivate(); } + auto doChange() const -> void { return self().doChange(); } + auto doContext() const -> void { return self().doContext(); } + auto flow() const -> Orientation { return self().flow(); } + auto foregroundColor() const -> Color { return self().foregroundColor(); } + auto item(unsigned position) const -> sIconViewItem { return self().item(position); } + auto items() const -> unsigned { return self().items(); } + auto multiSelect() const -> bool { return self().multiSelect(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto onContext(const function& function = {}) -> type& { return self().onContext(function), *this; } + auto orientation() const -> Orientation { return self().orientation(); } + auto remove(sIconViewItem item) -> type& { return self().remove(item), *this; } + auto reset() -> type& { return self().reset(), *this; } + auto selected() const -> maybe { return self().selected(); } + auto selectedItems() const -> vector { return self().selectedItems(); } + auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } + auto setFlow(Orientation orientation = Orientation::Vertical) -> type& { return self().setFlow(orientation), *this; } + auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } + auto setMultiSelect(bool multiSelect = true) -> type& { return self().setMultiSelect(multiSelect), *this; } + auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type& { return self().setOrientation(orientation), *this; } + auto setSelected(const vector& selections) -> type& { return self().setSelected(selections), *this; } +}; + +struct IconViewItem : sIconViewItem { + DeclareObject(IconViewItem) + + auto icon() const -> image { return self().icon(); } + auto selected() const -> bool { return self().selected(); } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setSelected(bool selected = true) -> type& { return self().setSelected(selected), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct Label : sLabel { + DeclareWidget(Label) + + auto horizontalAlignment() const -> double { return self().horizontalAlignment(); } + auto setHorizontalAlignment(double alignment = 0.0) -> type& { return self().setHorizontalAlignment(alignment), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto setVerticalAlignment(double alignment = 0.5) -> type& { return self().setVerticalAlignment(alignment), *this; } + auto text() const -> string { return self().text(); } + auto verticalAlignment() const -> double { return self().verticalAlignment(); } +}; + +struct LineEdit : sLineEdit { + DeclareWidget(LineEdit) + + auto backgroundColor() const -> Color { return self().backgroundColor(); } + auto doActivate() const -> void { return self().doActivate(); } + auto doChange() const -> void { return self().doChange(); } + auto editable() const -> bool { return self().editable(); } + auto foregroundColor() const -> Color { return self().foregroundColor(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } + auto setEditable(bool editable = true) -> type& { return self().setEditable(editable), *this; } + auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct ListView : sListView { + DeclareWidget(ListView) + + auto append(sListViewColumn column) -> type& { return self().append(column), *this; } + auto append(sListViewItem item) -> type& { return self().append(item), *this; } + auto backgroundColor() const -> Color { return self().backgroundColor(); } + auto checkable() const -> bool { return self().checkable(); } + auto checked() const -> vector { return self().checked(); } + auto column(unsigned position) -> sListViewColumn { return self().column(position); } + auto columns() const -> unsigned { return self().columns(); } + auto doActivate() const -> void { return self().doActivate(); } + auto doChange() const -> void { return self().doChange(); } + auto doContext() const -> void { return self().doContext(); } + auto doEdit(sListViewItem item, sListViewColumn column) const -> void { return self().doEdit(item, column); } + auto doSort(sListViewColumn column) const -> void { return self().doSort(column); } + auto doToggle(sListViewItem item) const -> void { return self().doToggle(item); } + auto foregroundColor() const -> Color { return self().foregroundColor(); } + auto gridVisible() const -> bool { return self().gridVisible(); } + auto headerVisible() const -> bool { return self().headerVisible(); } + auto item(unsigned position) -> sListViewItem { return self().item(position); } + auto items() const -> unsigned { return self().items(); } + auto multiSelect() const -> bool { return self().multiSelect(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto onContext(const function& function = {}) -> type& { return self().onContext(function), *this; } + auto onEdit(const function& function = {}) -> type& { return self().onEdit(function), *this; } + auto onSort(const function& function = {}) -> type& { return self().onSort(function), *this; } + auto onToggle(const function& function = {}) -> type& { return self().onToggle(function), *this; } + auto remove(sListViewColumn column) -> type& { return self().remove(column), *this; } + auto remove(sListViewItem item) -> type& { return self().remove(item), *this; } + auto reset() -> type& { return self().reset(), *this; } + auto resizeColumns() -> type& { return self().resizeColumns(), *this; } + auto selected() const -> sListViewItem { return self().selected(); } + auto selectedItems() const -> vector { return self().selectedItems(); } + auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } + auto setCheckable(bool checkable = true) -> type& { return self().setCheckable(checkable), *this; } + auto setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; } + auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } + auto setGridVisible(bool visible = true) -> type& { return self().setGridVisible(visible), *this; } + auto setHeaderVisible(bool visible = true) -> type& { return self().setHeaderVisible(visible), *this; } + auto setMultiSelect(bool multiSelect = true) -> type& { return self().setMultiSelect(multiSelect), *this; } + auto setSelected(bool selected = true) -> type& { return self().setSelected(selected), *this; } +}; + +struct ListViewColumn : sListViewColumn { + DeclareObject(ListViewColumn) + + auto active() const -> bool { return self().active(); } + auto backgroundColor() const -> Color { return self().backgroundColor(); } + auto editable() const -> bool { return self().editable(); } + auto foregroundColor() const -> Color { return self().foregroundColor(); } + auto horizontalAlignment() const -> double { return self().horizontalAlignment(); } + auto icon() const -> image { return self().icon(); } + auto resizable() const -> bool { return self().resizable(); } + auto setActive() -> type& { return self().setActive(), *this; } + auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } + auto setEditable(bool editable = true) -> type& { return self().setEditable(editable), *this; } + auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } + auto setHorizontalAlignment(double alignment = 0.0) -> type& { return self().setHorizontalAlignment(alignment), *this; } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setResizable(bool resizable = true) -> type& { return self().setResizable(resizable), *this; } + auto setSortable(bool sortable = true) -> type& { return self().setSortable(sortable), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto setVerticalAlignment(double alignment = 0.5) -> type& { return self().setVerticalAlignment(alignment), *this; } + auto setWidth(signed width = 0) -> type& { return self().setWidth(width), *this; } + auto sortable() const -> bool { return self().sortable(); } + auto text() const -> string { return self().text(); } + auto verticalAlignment() const -> double { return self().verticalAlignment(); } + auto width() const -> signed { return self().width(); } +}; + +struct ListViewItem : sListViewItem { + DeclareObject(ListViewItem) + + auto checked() const -> bool { return self().checked(); } + auto icon(unsigned column = 0) const -> image { return self().icon(column); } + auto selected() const -> bool { return self().selected(); } + auto setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; } + auto setIcon(unsigned column, const image& icon = {}) -> type& { return self().setIcon(column, icon), *this; } + auto setSelected(bool selected = true) -> type& { return self().setSelected(selected), *this; } + auto setText(const lstring& text) -> type& { return self().setText(text), *this; } + auto setText(unsigned column, const string& text = "") -> type& { return self().setText(column, text), *this; } + auto text(unsigned column = 0) const -> string { return self().text(column); } +}; + +struct ProgressBar : sProgressBar { + DeclareWidget(ProgressBar) + + auto position() const -> unsigned { return self().position(); } + auto setPosition(unsigned position = 0) -> type& { return self().setPosition(position), *this; } +}; + +struct RadioButton : sRadioButton { + DeclareWidget(RadioButton) + + auto bordered() const -> bool { return self().bordered(); } + auto checked() const -> bool { return self().checked(); } + auto doActivate() const -> void { return self().doActivate(); } + auto icon() const -> image { return self().icon(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto orientation() const -> Orientation { return self().orientation(); } + auto setBordered(bool bordered = true) -> type& { return self().setBordered(bordered), *this; } + auto setChecked() -> type& { return self().setChecked(), *this; } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type& { return self().setOrientation(orientation), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } + + static auto group(const vector& group) -> void { return mRadioButton::group(group); } +}; + +struct RadioLabel : sRadioLabel { + DeclareWidget(RadioLabel) + + auto checked() const -> bool { return self().checked(); } + auto doActivate() const -> void { return self().doActivate(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto setChecked() -> type& { return self().setChecked(), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } + + static auto group(const vector& group) -> void { return mRadioLabel::group(group); } +}; + +struct SourceEdit : sSourceEdit { + DeclareWidget(SourceEdit) + + auto doChange() const -> void { return self().doChange(); } + auto doMove() const -> void { return self().doMove(); } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto onMove(const function& function = {}) -> type& { return self().onMove(function), *this; } + auto position() const -> unsigned { return self().position(); } + auto setPosition(signed position) -> type& { return self().setPosition(position), *this; } + auto setSelected(Position selected) -> type& { return self().setSelected(selected), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct TabFrame : sTabFrame { + DeclareWidget(TabFrame) + + auto append(sTabFrameItem item) -> type& { return self().append(item), *this; } + auto doChange() const -> void { return self().doChange(); } + auto doClose(sTabFrameItem item) const -> void { return self().doClose(item); } + auto doMove(sTabFrameItem from, sTabFrameItem to) const -> void { return self().doMove(from, to); } + auto edge() const -> Edge; + auto item(unsigned position) const -> sTabFrameItem { return self().item(position); } + auto items() const -> unsigned { return self().items(); } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto onClose(const function& function = {}) -> type& { return self().onClose(function), *this; } + auto onMove(const function& function = {}) -> type& { return self().onMove(function), *this; } + auto remove(sTabFrameItem item) -> type& { return self().remove(item), *this; } + auto reset() -> type& { return self().reset(), *this; } + auto selected() const -> sTabFrameItem { return self().selected(); } + auto setEdge(Edge edge = Edge::Top) -> type& { return self().setEdge(edge), *this; } +}; + +struct TabFrameItem : sTabFrameItem { + DeclareObject(TabFrameItem) + + auto append(sLayout layout) -> type& { return self().append(layout), *this; } + auto closable() const -> bool { return self().closable(); } + auto icon() const -> image { return self().icon(); } + auto layout() const -> sLayout { return self().layout(); } + auto movable() const -> bool { return self().movable(); } + auto remove(sLayout layout) -> type& { return self().remove(layout), *this; } + auto reset() -> type& { return self().reset(), *this; } + auto selected() const -> bool { return self().selected(); } + auto setClosable(bool closable = true) -> type& { return self().setClosable(closable), *this; } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setMovable(bool movable = true) -> type& { return self().setMovable(movable), *this; } + auto setSelected() -> type& { return self().setSelected(), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct TextEdit : sTextEdit { + DeclareWidget(TextEdit) + + auto backgroundColor() const -> Color { return self().backgroundColor(); } + auto cursorPosition() const -> unsigned { return self().cursorPosition(); } + auto doChange() const -> void { return self().doChange(); } + auto doMove() const -> void { return self().doMove(); } + auto editable() const -> bool { return self().editable(); } + auto foregroundColor() const -> Color { return self().foregroundColor(); } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto onMove(const function& function = {}) -> type& { return self().onMove(function), *this; } + auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } + auto setCursorPosition(unsigned position) -> type& { return self().setCursorPosition(position), *this; } + auto setEditable(bool editable = true) -> type& { return self().setEditable(editable), *this; } + auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto setWordWrap(bool wordWrap = true) -> type& { return self().setWordWrap(wordWrap), *this; } + auto text() const -> string { return self().text(); } + auto wordWrap() const -> bool { return self().wordWrap(); } +}; + +struct TreeView : sTreeView { + DeclareWidget(TreeView) + + auto append(sTreeViewItem item) -> type& { return self().append(item), *this; } + auto backgroundColor() const -> Color { return self().backgroundColor(); } + auto checkable() const -> bool { return self().checkable(); } + auto collapse() -> type& { return self().collapse(), *this; } + auto doActivate() const -> void { return self().doActivate(); } + auto doChange() const -> void { return self().doChange(); } + auto doContext() const -> void { return self().doContext(); } + auto doToggle(sTreeViewItem item) const -> void { return self().doToggle(item); } + auto expand() -> type& { return self().expand(), *this; } + auto foregroundColor() const -> Color { return self().foregroundColor(); } + auto item(const string& path) const -> sTreeViewItem { return self().item(path); } + auto items() const -> unsigned { return self().items(); } + auto onActivate(const function& function = {}) -> type& { return self().onActivate(function), *this; } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto onContext(const function& function = {}) -> type& { return self().onContext(function), *this; } + auto onToggle(const function& function = {}) -> type& { return self().onToggle(function), *this; } + auto remove(sTreeViewItem item) -> type& { return self().remove(item), *this; } + auto reset() -> type& { return self().reset(), *this; } + auto selected() const -> sTreeViewItem { return self().selected(); } + auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } + auto setCheckable(bool checkable = true) -> type& { return self().setCheckable(checkable), *this; } + auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } +}; + +struct TreeViewItem : sTreeViewItem { + DeclareObject(TreeViewItem) + + auto append(sTreeViewItem item) -> type& { return self().append(item), *this; } + auto checked() const -> bool { return self().checked(); } + auto icon() const -> image { return self().icon(); } + auto item(const string& path) const -> sTreeViewItem { return self().item(path); } + auto items() const -> unsigned { return self().items(); } + auto path() const -> string { return self().path(); } + auto remove(sTreeViewItem item) -> type& { return self().remove(item), *this; } + auto selected() const -> bool { return self().selected(); } + auto setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; } + auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } + auto setSelected() -> type& { return self().setSelected(), *this; } + auto setText(const string& text = "") -> type& { return self().setText(text), *this; } + auto text() const -> string { return self().text(); } +}; + +struct VerticalScroller : sVerticalScroller { + DeclareWidget(VerticalScroller) + + auto doChange() const -> void { return self().doChange(); } + auto length() const -> unsigned { return self().length(); } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto position() const -> unsigned { return self().position(); } + auto setLength(unsigned length = 101) -> type& { return self().setLength(length), *this; } + auto setPosition(unsigned position = 0) -> type& { return self().setPosition(position), *this; } +}; + +struct VerticalSlider : sVerticalSlider { + DeclareWidget(VerticalSlider) + + auto doChange() const -> void { return self().doChange(); } + auto length() const -> unsigned { return self().length(); } + auto onChange(const function& function = {}) -> type& { return self().onChange(function), *this; } + auto position() const -> unsigned { return self().position(); } + auto setLength(unsigned length = 101) -> type& { return self().setLength(length), *this; } + auto setPosition(unsigned position = 0) -> type& { return self().setPosition(position), *this; } +}; + +struct Viewport : sViewport { + DeclareWidget(Viewport) + + auto doDrop(lstring names) const -> void { return self().doDrop(names); } + auto doMouseLeave() const -> void { return self().doMouseLeave(); } + auto doMouseMove(Position position) const -> void { return self().doMouseMove(position); } + auto doMousePress(Mouse::Button button) const -> void { return self().doMousePress(button); } + auto doMouseRelease(Mouse::Button button) const -> void { return self().doMouseRelease(button); } + auto droppable() const -> bool { return self().droppable(); } + auto handle() const -> uintptr_t { return self().handle(); } + auto onDrop(const function& function = {}) -> type& { return self().onDrop(function), *this; } + auto onMouseLeave(const function& function = {}) -> type& { return self().onMouseLeave(function), *this; } + auto onMouseMove(const function& function = {}) -> type& { return self().onMouseMove(function), *this; } + auto onMousePress(const function& function = {}) -> type& { return self().onMousePress(function), *this; } + auto onMouseRelease(const function& function = {}) -> type& { return self().onMouseRelease(function), *this; } + auto setDroppable(bool droppable = true) -> type& { return self().setDroppable(droppable), *this; } +}; + +using sFixedLayout = shared_pointer; +using sHorizontalLayout = shared_pointer; +using sVerticalLayout = shared_pointer; + +struct FixedLayout : sFixedLayout { + DeclareLayout(FixedLayout) + + auto append(sSizable sizable, Geometry geometry) -> type& { return self().append(sizable, geometry), *this; } +}; + +struct HorizontalLayout : sHorizontalLayout { + DeclareLayout(HorizontalLayout) + + auto append(sSizable sizable, Size size, signed spacing = 5) -> type& { return self().append(sizable, size, spacing), *this; } + auto setAlignment(double alignment = 0.5) -> type& { return self().setAlignment(alignment), *this; } + auto setMargin(signed margin = 0) -> type& { return self().setMargin(margin), *this; } + auto setSpacing(signed spacing = 5) -> type& { return self().setSpacing(spacing), *this; } +}; + +struct VerticalLayout : sVerticalLayout { + DeclareLayout(VerticalLayout) + + auto append(sSizable sizable, Size size, signed spacing = 5) -> type& { return self().append(sizable, size, spacing), *this; } + auto setAlignment(double alignment = 0.0) -> type& { return self().setAlignment(alignment), *this; } + auto setMargin(signed margin = 0) -> type& { return self().setMargin(margin), *this; } + auto setSpacing(signed spacing = 5) -> type& { return self().setSpacing(spacing), *this; } +}; + +#undef Declare +#undef DeclareObject +#undef DeclareAction +#undef DeclareSizable +#undef DeclareLayout +#undef DeclareWidget diff --git a/hiro/extension/vertical-layout.cpp b/hiro/extension/vertical-layout.cpp new file mode 100644 index 00000000..1c2c86d1 --- /dev/null +++ b/hiro/extension/vertical-layout.cpp @@ -0,0 +1,127 @@ +auto mVerticalLayout::append(shared_pointer sizable, Size size, signed spacing) -> type& { + properties.append({size.width(), size.height(), spacing < 0 ? settings.spacing : spacing}); + mLayout::append(sizable); + return *this; +} + +auto mVerticalLayout::minimumSize() const -> Size { + signed width = 0, height = 0; + + for(auto n : range(sizables())) { + auto& child = properties[sizable(n)->offset()]; + if(child.width == Size::Minimum || child.width == Size::Maximum) { + width = max(width, sizable(n)->minimumSize().width()); + continue; + } + width = max(width, child.width); + } + + for(auto n : range(sizables())) { + auto& child = properties[sizable(n)->offset()]; + if(child.height == Size::Minimum || child.height == Size::Maximum) { + height += sizable(n)->minimumSize().height(); + } else { + height += child.height; + } + if(&child != &properties.last()) height += child.spacing; + } + + return {settings.margin * 2 + width, settings.margin * 2 + height}; +} + +auto mVerticalLayout::remove(shared_pointer sizable) -> type& { + properties.remove(sizable->offset()); + mLayout::remove(sizable); + return *this; +} + +auto mVerticalLayout::reset() -> type& { + mLayout::reset(); + properties.reset(); + return *this; +} + +auto mVerticalLayout::setAlignment(double alignment) -> type& { + settings.alignment = max(0.0, min(1.0, alignment)); + return *this; +} + +auto mVerticalLayout::setEnabled(bool enabled) -> type& { + mLayout::setEnabled(enabled); + for(auto n : range(sizables())) { + sizable(n)->setEnabled(sizable(n)->enabled(true)); + } + return *this; +} + +auto mVerticalLayout::setFont(const string& font) -> type& { + mLayout::setFont(font); + for(auto n : range(sizables())) { + sizable(n)->setFont(sizable(n)->font(true)); + } + return *this; +} + +auto mVerticalLayout::setGeometry(Geometry containerGeometry) -> type& { + mLayout::setGeometry(containerGeometry); + + auto properties = this->properties; + for(auto n : range(sizables())) { + auto& child = properties[sizable(n)->offset()]; + if(child.width == Size::Minimum) child.width = sizable(n)->minimumSize().width(); + if(child.height == Size::Minimum) child.height = sizable(n)->minimumSize().height(); + } + + Geometry geometry = containerGeometry; + geometry.setX (geometry.x() + settings.margin ); + geometry.setY (geometry.y() + settings.margin ); + geometry.setWidth (geometry.width() - settings.margin * 2); + geometry.setHeight(geometry.height() - settings.margin * 2); + + signed minimumHeight = 0, maximumHeightCounter = 0; + for(auto& child : properties) { + if(child.height == Size::Maximum) maximumHeightCounter++; + if(child.height != Size::Maximum) minimumHeight += child.height; + if(&child != &properties.last()) minimumHeight += child.spacing; + } + + for(auto& child : properties) { + if(child.width == Size::Maximum) child.width = geometry.width(); + if(child.height == Size::Maximum) child.height = (geometry.height() - minimumHeight) / maximumHeightCounter; + } + + signed maximumWidth = 0; + for(auto& child : properties) maximumWidth = max(maximumWidth, child.width); + + for(auto n : range(sizables())) { + auto& child = properties[sizable(n)->offset()]; + signed pivot = (maximumWidth - child.width) * settings.alignment; + Geometry childGeometry = {geometry.x() + pivot, geometry.y(), child.width, child.height}; + if(childGeometry.width() < 1) childGeometry.setWidth (1); + if(childGeometry.height() < 1) childGeometry.setHeight(1); + sizable(n)->setGeometry(childGeometry); + + geometry.setY (geometry.y() + child.height + child.spacing); + geometry.setHeight(geometry.height() - child.height + child.spacing); + } + + return *this; +} + +auto mVerticalLayout::setMargin(signed margin) -> type& { + settings.margin = margin; + return *this; +} + +auto mVerticalLayout::setSpacing(signed spacing) -> type& { + settings.spacing = spacing; + return *this; +} + +auto mVerticalLayout::setVisible(bool visible) -> type& { + mLayout::setVisible(visible); + for(auto n : range(sizables())) { + sizable(n)->setVisible(sizable(n)->visible(true)); + } + return *this; +} diff --git a/hiro/extension/vertical-layout.hpp b/hiro/extension/vertical-layout.hpp new file mode 100644 index 00000000..e3ec666c --- /dev/null +++ b/hiro/extension/vertical-layout.hpp @@ -0,0 +1,30 @@ +struct mVerticalLayout : mLayout { + using type = mVerticalLayout; + using mLayout::append; + using mLayout::remove; + + auto append(nall::shared_pointer sizable, Size size, signed spacing = 5) -> type&; + auto minimumSize() const -> Size override; + auto remove(nall::shared_pointer sizable) -> type& override; + auto reset() -> type& override; + auto setAlignment(double alignment = 0.0) -> type&; + auto setEnabled(bool enabled = true) -> type& override; + auto setFont(const nall::string& font = "") -> type& override; + auto setGeometry(Geometry geometry) -> type& override; + auto setMargin(signed margin = 0) -> type&; + auto setSpacing(signed spacing = 5) -> type&; + auto setVisible(bool visible = true) -> type& override; + + struct Settings { + double alignment = 0.0; + signed margin = 0; + signed spacing = 5; + } settings; + + struct Properties { + signed width; + signed height; + signed spacing; + }; + nall::vector properties; +}; diff --git a/phoenix/gtk/action/action.cpp b/hiro/gtk/action/action.cpp similarity index 56% rename from phoenix/gtk/action/action.cpp rename to hiro/gtk/action/action.cpp index 978b9747..f28a97a7 100644 --- a/phoenix/gtk/action/action.cpp +++ b/hiro/gtk/action/action.cpp @@ -1,22 +1,26 @@ -namespace phoenix { +namespace hiro { -void pAction::setEnabled(bool enabled) { +auto pAction::construct() -> void { +} + +auto pAction::destruct() -> void { +} + +auto pAction::setEnabled(bool enabled) -> void { gtk_widget_set_sensitive(widget, enabled); } -void pAction::setVisible(bool visible) { +auto pAction::setFont(const string& font) -> void { + pFont::setFont(widget, font); +} + +auto pAction::setVisible(bool visible) -> void { gtk_widget_set_visible(widget, visible); } -void pAction::constructor() { -} - -void pAction::orphan() { -} - //GTK+ uses _ for mnemonics, __ for _ //transform so that & is used for mnemonics, && for & -string pAction::mnemonic(string text) { +auto pAction::_mnemonic(string text) -> string { text.transform("&_", "\x01\x02"); text.replace("\x01\x01", "&"); text.transform("\x01", "_"); @@ -24,8 +28,4 @@ string pAction::mnemonic(string text) { return text; } -void pAction::setFont(string font) { - pFont::setFont(widget, font); -} - } diff --git a/hiro/gtk/action/action.hpp b/hiro/gtk/action/action.hpp new file mode 100644 index 00000000..2a28d5a3 --- /dev/null +++ b/hiro/gtk/action/action.hpp @@ -0,0 +1,15 @@ +namespace hiro { + +struct pAction : pObject { + Declare(Action, Object) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const string& font) -> void override; + auto setVisible(bool visible) -> void override; + + auto _mnemonic(string text) -> string; + + GtkWidget* widget = nullptr; +}; + +} diff --git a/hiro/gtk/action/menu-check-item.cpp b/hiro/gtk/action/menu-check-item.cpp new file mode 100644 index 00000000..e262cf8d --- /dev/null +++ b/hiro/gtk/action/menu-check-item.cpp @@ -0,0 +1,34 @@ +namespace hiro { + +static auto MenuCheckItem_toggle(GtkCheckMenuItem* gtkCheckMenuItem, pMenuCheckItem* p) -> void { + p->state().checked = gtk_check_menu_item_get_active(gtkCheckMenuItem); + if(!p->locked()) p->self().doToggle(); +} + +auto pMenuCheckItem::construct() -> void { + widget = gtk_check_menu_item_new_with_mnemonic(""); + setChecked(state().checked); + setText(state().text); + g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(MenuCheckItem_toggle), (gpointer)this); +} + +auto pMenuCheckItem::destruct() -> void { + gtk_widget_destroy(widget); +} + +auto pMenuCheckItem::orphan() -> void { + destruct(); + construct(); +} + +auto pMenuCheckItem::setChecked(bool checked) -> void { + lock(); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), checked); + unlock(); +} + +auto pMenuCheckItem::setText(const string& text) -> void { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), _mnemonic(text)); +} + +} diff --git a/hiro/gtk/action/menu-check-item.hpp b/hiro/gtk/action/menu-check-item.hpp new file mode 100644 index 00000000..b342de84 --- /dev/null +++ b/hiro/gtk/action/menu-check-item.hpp @@ -0,0 +1,11 @@ +namespace hiro { + +struct pMenuCheckItem : pAction { + Declare(MenuCheckItem, Action) + auto orphan() -> void; + + auto setChecked(bool checked) -> void; + auto setText(const string& text) -> void; +}; + +} diff --git a/hiro/gtk/action/menu-item.cpp b/hiro/gtk/action/menu-item.cpp new file mode 100644 index 00000000..39d1dba4 --- /dev/null +++ b/hiro/gtk/action/menu-item.cpp @@ -0,0 +1,30 @@ +namespace hiro { + +static auto MenuItem_activate(GtkMenuItem*, pMenuItem* p) -> void { + p->self().doActivate(); +} + +auto pMenuItem::construct() -> void { + widget = gtk_image_menu_item_new_with_mnemonic(""); + g_signal_connect(G_OBJECT(widget), "activate", G_CALLBACK(MenuItem_activate), (gpointer)this); + setText(state().text); +} + +auto pMenuItem::destruct() -> void { + if(widget) gtk_widget_destroy(widget), widget = nullptr; +} + +auto pMenuItem::setIcon(const image& icon) -> void { + if(icon) { + GtkImage* gtkImage = CreateImage(icon, true); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); + } else { + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); + } +} + +auto pMenuItem::setText(const string& text) -> void { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), _mnemonic(text)); +} + +} diff --git a/hiro/gtk/action/menu-item.hpp b/hiro/gtk/action/menu-item.hpp new file mode 100644 index 00000000..bf2e13db --- /dev/null +++ b/hiro/gtk/action/menu-item.hpp @@ -0,0 +1,10 @@ +namespace hiro { + +struct pMenuItem : pAction { + Declare(MenuItem, Action) + + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; +}; + +} diff --git a/hiro/gtk/action/menu-radio-item.cpp b/hiro/gtk/action/menu-radio-item.cpp new file mode 100644 index 00000000..a3f05076 --- /dev/null +++ b/hiro/gtk/action/menu-radio-item.cpp @@ -0,0 +1,75 @@ +namespace hiro { + +static auto MenuRadioItem_activate(GtkCheckMenuItem* gtkCheckMenuItem, pMenuRadioItem* p) -> void { + p->_doActivate(); +} + +auto pMenuRadioItem::construct() -> void { + widget = gtk_radio_menu_item_new_with_mnemonic(0, ""); + setGroup(state().group); + setText(state().text); + for(auto& weak : state().group) { + if(auto item = weak.acquire()) { + if(item->self()) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->self()->widget), item->checked()); + } + } + g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(MenuRadioItem_activate), (gpointer)this); +} + +auto pMenuRadioItem::destruct() -> void { + if(widget) gtk_widget_destroy(widget), widget = nullptr; +} + +auto pMenuRadioItem::setChecked() -> void { + _parent().lock(); + for(auto& weak : state().group) { + if(auto item = weak.acquire()) { + if(item->self()) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->self()->widget), false); + } + } + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), true); + _parent().unlock(); +} + +auto pMenuRadioItem::setGroup(const vector>& group) -> void { + _parent().lock(); + shared_pointer first; + for(auto& weak : group) { + if(!first) { + first = weak.acquire(); + continue; + } + if(auto item = weak.acquire()) { + if(item->self() && first->self()) { + GSList* currentGroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(first->self()->widget)); + if(currentGroup != gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item->self()->widget))) { + gtk_radio_menu_item_set_group(GTK_RADIO_MENU_ITEM(item->self()->widget), currentGroup); + } + } + } + } + _parent().unlock(); +} + +auto pMenuRadioItem::setText(const string& text) -> void { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), _mnemonic(text)); +} + +auto pMenuRadioItem::_doActivate() -> void { + if(!_parent().locked()) { + bool wasChecked = state().checked; + self().setChecked(); + if(!wasChecked) self().doActivate(); + } +} + +auto pMenuRadioItem::_parent() -> pMenuRadioItem& { + if(state().group.size()) { + if(auto item = state().group.first().acquire()) { + if(item->self()) return *item->self(); + } + } + return *this; +} + +} diff --git a/hiro/gtk/action/menu-radio-item.hpp b/hiro/gtk/action/menu-radio-item.hpp new file mode 100644 index 00000000..f129c1a6 --- /dev/null +++ b/hiro/gtk/action/menu-radio-item.hpp @@ -0,0 +1,14 @@ +namespace hiro { + +struct pMenuRadioItem : pAction { + Declare(MenuRadioItem, Action) + + auto setChecked() -> void; + auto setGroup(const vector>& group) -> void; + auto setText(const string& text) -> void; + + auto _doActivate() -> void; + auto _parent() -> pMenuRadioItem&; +}; + +} diff --git a/hiro/gtk/action/menu-separator.cpp b/hiro/gtk/action/menu-separator.cpp new file mode 100644 index 00000000..1344e93c --- /dev/null +++ b/hiro/gtk/action/menu-separator.cpp @@ -0,0 +1,11 @@ +namespace hiro { + +auto pMenuSeparator::construct() -> void { + widget = gtk_separator_menu_item_new(); +} + +auto pMenuSeparator::destruct() -> void { + if(widget) gtk_widget_destroy(widget), widget = nullptr; +} + +} diff --git a/hiro/gtk/action/menu-separator.hpp b/hiro/gtk/action/menu-separator.hpp new file mode 100644 index 00000000..5bf18a62 --- /dev/null +++ b/hiro/gtk/action/menu-separator.hpp @@ -0,0 +1,7 @@ +namespace hiro { + +struct pMenuSeparator : pAction { + Declare(MenuSeparator, Action) +}; + +} diff --git a/hiro/gtk/action/menu.cpp b/hiro/gtk/action/menu.cpp new file mode 100644 index 00000000..527a84ff --- /dev/null +++ b/hiro/gtk/action/menu.cpp @@ -0,0 +1,48 @@ +namespace hiro { + +auto pMenu::construct() -> void { + gtkMenu = gtk_menu_new(); + widget = gtk_image_menu_item_new_with_mnemonic(""); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), gtkMenu); + setText(state().text); + + for(auto& action : state().actions) append(*action); +} + +auto pMenu::destruct() -> void { + gtk_widget_destroy(gtkMenu); + gtk_widget_destroy(widget); +} + +auto pMenu::append(sAction action) -> void { + if(action->self()) { + gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), action->self()->widget); + action->self()->setFont(action->font(true)); + action->self()->setVisible(action->visible(true)); + } +} + +auto pMenu::remove(sAction action) -> void { +} + +auto pMenu::setFont(const string& font) -> void { + pAction::setFont(font); + for(auto& action : state().actions) { + if(action->self()) action->self()->setFont(action->font(true)); + } +} + +auto pMenu::setIcon(const image& icon) -> void { + if(icon) { + GtkImage* gtkImage = CreateImage(icon, true); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); + } else { + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); + } +} + +auto pMenu::setText(const string& text) -> void { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), _mnemonic(text)); +} + +} diff --git a/hiro/gtk/action/menu.hpp b/hiro/gtk/action/menu.hpp new file mode 100644 index 00000000..c0e199a7 --- /dev/null +++ b/hiro/gtk/action/menu.hpp @@ -0,0 +1,15 @@ +namespace hiro { + +struct pMenu : pAction { + Declare(Menu, Action) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setFont(const string& font) -> void override; + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + GtkWidget* gtkMenu = nullptr; +}; + +} diff --git a/hiro/gtk/application.cpp b/hiro/gtk/application.cpp new file mode 100644 index 00000000..14783989 --- /dev/null +++ b/hiro/gtk/application.cpp @@ -0,0 +1,84 @@ +namespace hiro { + +XlibDisplay* pApplication::display = nullptr; + +void pApplication::run() { + if(Application::state.onMain) { + while(Application::state.quit == false) { + processEvents(); + Application::doMain(); + } + } else { + gtk_main(); + } +} + +bool pApplication::pendingEvents() { + return gtk_events_pending(); +} + +void pApplication::processEvents() { + while(pendingEvents()) gtk_main_iteration_do(false); +} + +void pApplication::quit() { + //if gtk_main() was invoked, call gtk_main_quit() + if(gtk_main_level()) gtk_main_quit(); +} + +void pApplication::initialize() { + display = XOpenDisplay(nullptr); + + settings = new Settings; + settings->load(); + + //set WM_CLASS to Application::name() + if(Application::state.name) gdk_set_program_class(Application::state.name); + + #if 1 + int argc = 1; + char* argv[] = {new char[8], nullptr}; + strcpy(argv[0], "phoenix"); + #else + //--g-fatal-warnings will force a trap on Gtk-CRITICAL errors + //this allows gdb to perform a backtrace to find error origin point + int argc = 2; + char* argv[] = {new char[8], new char[19], nullptr}; + strcpy(argv[0], "phoenix"); + strcpy(argv[1], "--g-fatal-warnings"); + #endif + char** argvp = argv; + gtk_init(&argc, &argvp); + + GtkSettings* gtkSettings = gtk_settings_get_default(); + g_object_set(gtkSettings, "gtk-button-images", true, nullptr); + + gtk_rc_parse_string(R"( + style "PhoenixWindow" + { + GtkWindow::resize-grip-width = 0 + GtkWindow::resize-grip-height = 0 + } + class "GtkWindow" style "PhoenixWindow" + + style "PhoenixTreeView" + { + GtkTreeView::vertical-separator = 0 + } + class "GtkTreeView" style "PhoenixTreeView" + + style "PhoenixTabFrameCloseButton" + { + GtkWidget::focus-line-width = 0 + GtkWidget::focus-padding = 0 + GtkButton::default-border = {0, 0, 0, 0} + GtkButton::default-outer-border = {0, 0, 0, 0} + GtkButton::inner-border = {0, 1, 0, 0} + } + widget_class "*..." style "PhoenixTabFrameCloseButton" + )"); + + pKeyboard::initialize(); +} + +} diff --git a/hiro/gtk/application.hpp b/hiro/gtk/application.hpp new file mode 100644 index 00000000..4fd5d573 --- /dev/null +++ b/hiro/gtk/application.hpp @@ -0,0 +1,14 @@ +namespace hiro { + +struct pApplication { + static XlibDisplay* display; + + static void run(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + static void initialize(); +}; + +} diff --git a/phoenix/gtk/browser-window.cpp b/hiro/gtk/browser-window.cpp similarity index 78% rename from phoenix/gtk/browser-window.cpp rename to hiro/gtk/browser-window.cpp index e2c9b5c5..1ca5ef80 100644 --- a/phoenix/gtk/browser-window.cpp +++ b/hiro/gtk/browser-window.cpp @@ -1,21 +1,21 @@ -namespace phoenix { +namespace hiro { static void BrowserWindow_addFilters(GtkWidget* dialog, lstring filters) { for(auto& filter : filters) { GtkFileFilter* gtkFilter = gtk_file_filter_new(); gtk_file_filter_set_name(gtkFilter, filter); - lstring patterns = filter.split<1>("(")(1).rtrim<1>(")").split(","); - for(auto& pattern : patterns) gtk_file_filter_add_pattern(gtkFilter, pattern.strip()); + lstring patterns = filter.split<1>("(")(1).rtrim(")").split(",").strip(); + for(auto& pattern : patterns) gtk_file_filter_add_pattern(gtkFilter, pattern); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter); } } -string pBrowserWindow::directory(BrowserWindow::State& state) { +auto pBrowserWindow::directory(BrowserWindow::State& state) -> string { string name; GtkWidget* dialog = gtk_file_chooser_dialog_new( state.title ? state.title : "Select Directory", - state.parent ? GTK_WINDOW(state.parent->p.widget) : (GtkWindow*)nullptr, + state.parent && state.parent->self() ? GTK_WINDOW(state.parent->self()->widget) : (GtkWindow*)nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, @@ -35,12 +35,12 @@ string pBrowserWindow::directory(BrowserWindow::State& state) { return name; } -string pBrowserWindow::open(BrowserWindow::State& state) { +auto pBrowserWindow::open(BrowserWindow::State& state) -> string { string name; GtkWidget* dialog = gtk_file_chooser_dialog_new( state.title ? state.title : "Open File", - state.parent ? GTK_WINDOW(state.parent->p.widget) : (GtkWindow*)nullptr, + state.parent && state.parent->self() ? GTK_WINDOW(state.parent->self()->widget) : (GtkWindow*)nullptr, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, @@ -60,12 +60,12 @@ string pBrowserWindow::open(BrowserWindow::State& state) { return name; } -string pBrowserWindow::save(BrowserWindow::State& state) { +auto pBrowserWindow::save(BrowserWindow::State& state) -> string { string name; GtkWidget* dialog = gtk_file_chooser_dialog_new( state.title ? state.title : "Save File", - state.parent ? GTK_WINDOW(state.parent->p.widget) : (GtkWindow*)nullptr, + state.parent && state.parent->self() ? GTK_WINDOW(state.parent->self()->widget) : (GtkWindow*)nullptr, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, diff --git a/hiro/gtk/browser-window.hpp b/hiro/gtk/browser-window.hpp new file mode 100644 index 00000000..964acea4 --- /dev/null +++ b/hiro/gtk/browser-window.hpp @@ -0,0 +1,9 @@ +namespace hiro { + +struct pBrowserWindow { + static auto directory(BrowserWindow::State& state) -> string; + static auto open(BrowserWindow::State& state) -> string; + static auto save(BrowserWindow::State& state) -> string; +}; + +} diff --git a/phoenix/gtk/desktop.cpp b/hiro/gtk/desktop.cpp similarity index 88% rename from phoenix/gtk/desktop.cpp rename to hiro/gtk/desktop.cpp index 700d081d..25b03fee 100644 --- a/phoenix/gtk/desktop.cpp +++ b/hiro/gtk/desktop.cpp @@ -1,4 +1,4 @@ -namespace phoenix { +namespace hiro { Size pDesktop::size() { return { @@ -27,7 +27,7 @@ Geometry pDesktop::workspace() { if(result == Success && returnAtom == XA_CARDINAL && format == 32 && items == 4) { unsigned long *workarea = (unsigned long*)data; - return {(signed)workarea[0], (signed)workarea[1], (unsigned)workarea[2], (unsigned)workarea[3]}; + return {(signed)workarea[0], (signed)workarea[1], (signed)workarea[2], (signed)workarea[3]}; } return { diff --git a/hiro/gtk/desktop.hpp b/hiro/gtk/desktop.hpp new file mode 100644 index 00000000..d063450a --- /dev/null +++ b/hiro/gtk/desktop.hpp @@ -0,0 +1,8 @@ +namespace hiro { + +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +} diff --git a/phoenix/gtk/font.cpp b/hiro/gtk/font.cpp similarity index 95% rename from phoenix/gtk/font.cpp rename to hiro/gtk/font.cpp index 41232cbd..fcd6c23f 100644 --- a/phoenix/gtk/font.cpp +++ b/hiro/gtk/font.cpp @@ -1,4 +1,4 @@ -namespace phoenix { +namespace hiro { string pFont::serif(unsigned size, string style) { if(size == 0) size = 8; @@ -25,9 +25,7 @@ Size pFont::size(string font, string text) { } PangoFontDescription* pFont::create(string description) { - lstring part; - part.split<2>(",", description); - for(auto& item : part) item.trim(" "); + lstring part = description.split<2>(",").strip(); string family = "Sans"; unsigned size = 8u; diff --git a/hiro/gtk/font.hpp b/hiro/gtk/font.hpp new file mode 100644 index 00000000..8dbd17e9 --- /dev/null +++ b/hiro/gtk/font.hpp @@ -0,0 +1,16 @@ +namespace hiro { + +struct pFont { + static string serif(unsigned size, string style); + static string sans(unsigned size, string style); + static string monospace(unsigned size, string style); + static Size size(string font, string text); + + static PangoFontDescription* create(string description); + static void free(PangoFontDescription* font); + static Size size(PangoFontDescription* font, string text); + static void setFont(GtkWidget* widget, string font); + static void setFont(GtkWidget* widget, gpointer font); +}; + +} diff --git a/phoenix/gtk/header.hpp b/hiro/gtk/header.hpp similarity index 56% rename from phoenix/gtk/header.hpp rename to hiro/gtk/header.hpp index 036cabde..8e691ab5 100644 --- a/phoenix/gtk/header.hpp +++ b/hiro/gtk/header.hpp @@ -1,8 +1,11 @@ #include -#include #include #include #include +#include +#include +#include +#include #include #include #include diff --git a/hiro/gtk/hotkey.cpp b/hiro/gtk/hotkey.cpp new file mode 100644 index 00000000..73879ddb --- /dev/null +++ b/hiro/gtk/hotkey.cpp @@ -0,0 +1,9 @@ +namespace hiro { + +auto pHotkey::construct() -> void { +} + +auto pHotkey::destruct() -> void { +} + +} diff --git a/hiro/gtk/hotkey.hpp b/hiro/gtk/hotkey.hpp new file mode 100644 index 00000000..4f476cdc --- /dev/null +++ b/hiro/gtk/hotkey.hpp @@ -0,0 +1,7 @@ +namespace hiro { + +struct pHotkey : pObject { + Declare(Hotkey, Object) +}; + +} diff --git a/hiro/gtk/keyboard.cpp b/hiro/gtk/keyboard.cpp new file mode 100644 index 00000000..0223ccf3 --- /dev/null +++ b/hiro/gtk/keyboard.cpp @@ -0,0 +1,344 @@ +namespace hiro { + +auto pKeyboard::poll() -> vector { + vector result; + char state[256]; + XQueryKeymap(pApplication::display, state); + for(auto& code : settings->keycodes) { + result.append(_pressed(state, code)); + } + return result; +} + +auto pKeyboard::pressed(unsigned code) -> bool { + char state[256]; + XQueryKeymap(pApplication::display, state); + return _pressed(state, code); +} + +auto pKeyboard::_pressed(char* state, uint16_t code) -> bool { + uint8_t lo = code >> 0; + uint8_t hi = code >> 8; + if(lo && state[lo >> 3] & (1 << (lo & 7))) return true; + if(hi && state[hi >> 3] & (1 << (hi & 7))) return true; + return false; +} + +auto pKeyboard::_translate(unsigned code) -> signed { + switch(code) { + case GDK_Escape: return 0; + case GDK_F1: return 0; + case GDK_F2: return 0; + case GDK_F3: return 0; + case GDK_F4: return 0; + case GDK_F5: return 0; + case GDK_F6: return 0; + case GDK_F7: return 0; + case GDK_F8: return 0; + case GDK_F9: return 0; + case GDK_F10: return 0; + case GDK_F11: return 0; + case GDK_F12: return 0; + + case GDK_Print: return 0; + case GDK_Scroll_Lock: return 0; + case GDK_Pause: return 0; + + case GDK_Insert: return 0; + case GDK_Delete: return 0; + case GDK_Home: return 0; + case GDK_End: return 0; + case GDK_Prior: return 0; + case GDK_Next: return 0; + + case GDK_Up: return 0; + case GDK_Down: return 0; + case GDK_Left: return 0; + case GDK_Right: return 0; + + case GDK_grave: return '`'; + case GDK_1: return '1'; + case GDK_2: return '2'; + case GDK_3: return '3'; + case GDK_4: return '4'; + case GDK_5: return '5'; + case GDK_6: return '6'; + case GDK_7: return '7'; + case GDK_8: return '8'; + case GDK_9: return '9'; + case GDK_0: return '0'; + case GDK_minus: return '-'; + case GDK_equal: return '='; + case GDK_BackSpace: return '\b'; + + case GDK_asciitilde: return '~'; + case GDK_exclam: return '!'; + case GDK_at: return '@'; + case GDK_numbersign: return '#'; + case GDK_dollar: return '$'; + case GDK_percent: return '%'; + case GDK_asciicircum: return '^'; + case GDK_ampersand: return '&'; + case GDK_asterisk: return '*'; + case GDK_parenleft: return '('; + case GDK_parenright: return ')'; + case GDK_underscore: return '_'; + case GDK_plus: return '+'; + + case GDK_Tab: return '\t'; + case GDK_Caps_Lock: return 0; + case GDK_Return: return '\n'; + case GDK_Shift_L: return 0; + case GDK_Shift_R: return 0; + case GDK_Control_L: return 0; + case GDK_Control_R: return 0; + case GDK_Alt_L: return 0; + case GDK_Alt_R: return 0; + case GDK_Super_L: return 0; + case GDK_Super_R: return 0; + case GDK_Menu: return 0; + case GDK_space: return ' '; + + case GDK_bracketleft: return '['; + case GDK_bracketright: return ']'; + case GDK_backslash: return '\\'; + case GDK_semicolon: return ';'; + case GDK_apostrophe: return '\''; + case GDK_comma: return ','; + case GDK_period: return '.'; + case GDK_slash: return '/'; + + case GDK_braceleft: return '{'; + case GDK_braceright: return '}'; + case GDK_bar: return '|'; + case GDK_colon: return ':'; + case GDK_quotedbl: return '\"'; + case GDK_less: return '<'; + case GDK_greater: return '>'; + case GDK_question: return '?'; + + case GDK_A: return 'A'; + case GDK_B: return 'B'; + case GDK_C: return 'C'; + case GDK_D: return 'D'; + case GDK_E: return 'E'; + case GDK_F: return 'F'; + case GDK_G: return 'G'; + case GDK_H: return 'H'; + case GDK_I: return 'I'; + case GDK_J: return 'J'; + case GDK_K: return 'K'; + case GDK_L: return 'L'; + case GDK_M: return 'M'; + case GDK_N: return 'N'; + case GDK_O: return 'O'; + case GDK_P: return 'P'; + case GDK_Q: return 'Q'; + case GDK_R: return 'R'; + case GDK_S: return 'S'; + case GDK_T: return 'T'; + case GDK_U: return 'U'; + case GDK_V: return 'V'; + case GDK_W: return 'W'; + case GDK_X: return 'X'; + case GDK_Y: return 'Y'; + case GDK_Z: return 'Z'; + + case GDK_a: return 'a'; + case GDK_b: return 'b'; + case GDK_c: return 'c'; + case GDK_d: return 'd'; + case GDK_e: return 'e'; + case GDK_f: return 'f'; + case GDK_g: return 'g'; + case GDK_h: return 'h'; + case GDK_i: return 'i'; + case GDK_j: return 'j'; + case GDK_k: return 'k'; + case GDK_l: return 'l'; + case GDK_m: return 'm'; + case GDK_n: return 'n'; + case GDK_o: return 'o'; + case GDK_p: return 'p'; + case GDK_q: return 'q'; + case GDK_r: return 'r'; + case GDK_s: return 's'; + case GDK_t: return 't'; + case GDK_u: return 'u'; + case GDK_v: return 'v'; + case GDK_w: return 'w'; + case GDK_x: return 'x'; + case GDK_y: return 'y'; + case GDK_z: return 'z'; + + case GDK_Num_Lock: return 0; + case GDK_KP_Divide: return '/'; + case GDK_KP_Multiply: return '*'; + case GDK_KP_Subtract: return '-'; + case GDK_KP_Add: return '+'; + case GDK_KP_Enter: return '\n'; + case GDK_KP_Decimal: return '.'; + + case GDK_KP_1: return '1'; + case GDK_KP_2: return '2'; + case GDK_KP_3: return '3'; + case GDK_KP_4: return '4'; + case GDK_KP_5: return '5'; + case GDK_KP_6: return '6'; + case GDK_KP_7: return '7'; + case GDK_KP_8: return '8'; + case GDK_KP_9: return '9'; + case GDK_KP_0: return '0'; + + case GDK_KP_Home: return 0; + case GDK_KP_End: return 0; + case GDK_KP_Page_Up: return 0; + case GDK_KP_Page_Down: return 0; + case GDK_KP_Up: return 0; + case GDK_KP_Down: return 0; + case GDK_KP_Left: return 0; + case GDK_KP_Right: return 0; + case GDK_KP_Begin: return 0; + case GDK_KP_Insert: return 0; + case GDK_KP_Delete: return 0; + } + + return 0; +} + +auto pKeyboard::initialize() -> void { + auto append = [](unsigned lo, unsigned hi = 0) { + lo = lo ? (uint8_t)XKeysymToKeycode(pApplication::display, lo) : 0; + hi = hi ? (uint8_t)XKeysymToKeycode(pApplication::display, hi) : 0; + settings->keycodes.append(lo | (hi << 8)); + }; + + #define map(name, ...) if(key == name) { append(__VA_ARGS__); continue; } + for(auto& key : Keyboard::keys) { + map("Escape", XK_Escape); + map("F1", XK_F1); + map("F2", XK_F2); + map("F3", XK_F3); + map("F4", XK_F4); + map("F5", XK_F5); + map("F6", XK_F6); + map("F7", XK_F7); + map("F8", XK_F8); + map("F9", XK_F9); + map("F10", XK_F10); + map("F11", XK_F11); + map("F12", XK_F12); + + map("PrintScreen", XK_Print); + map("ScrollLock", XK_Scroll_Lock); + map("Pause", XK_Pause); + + map("Insert", XK_Insert); + map("Delete", XK_Delete); + map("Home", XK_Home); + map("End", XK_End); + map("PageUp", XK_Prior); + map("PageDown", XK_Next); + + map("Up", XK_Up); + map("Down", XK_Down); + map("Left", XK_Left); + map("Right", XK_Right); + + map("Grave", XK_asciitilde); + map("1", XK_1); + map("2", XK_2); + map("3", XK_3); + map("4", XK_4); + map("5", XK_5); + map("6", XK_6); + map("7", XK_7); + map("8", XK_8); + map("9", XK_9); + map("0", XK_0); + map("Dash", XK_minus); + map("Equal", XK_equal); + map("Backspace", XK_BackSpace); + + map("Tab", XK_Tab); + map("CapsLock", XK_Caps_Lock); + map("LeftEnter", XK_Return); + map("LeftShift", XK_Shift_L); + map("RightShift", XK_Shift_R); + map("LeftControl", XK_Control_L); + map("RightControl", XK_Control_R); + map("LeftAlt", XK_Alt_L); + map("RightAlt", XK_Alt_R); + map("LeftSuper", XK_Super_L); + map("RightSuper", XK_Super_R); + map("Menu", XK_Menu); + map("Space", XK_space); + + map("OpenBracket", XK_bracketleft); + map("CloseBracket", XK_bracketright); + map("Backslash", XK_backslash); + map("Semicolon", XK_semicolon); + map("Apostrophe", XK_apostrophe); + map("Comma", XK_comma); + map("Period", XK_period); + map("Slash", XK_slash); + + map("A", XK_A); + map("B", XK_B); + map("C", XK_C); + map("D", XK_D); + map("E", XK_E); + map("F", XK_F); + map("G", XK_G); + map("H", XK_H); + map("I", XK_I); + map("J", XK_J); + map("K", XK_K); + map("L", XK_L); + map("M", XK_M); + map("N", XK_N); + map("O", XK_O); + map("P", XK_P); + map("Q", XK_Q); + map("R", XK_R); + map("S", XK_S); + map("T", XK_T); + map("U", XK_U); + map("V", XK_V); + map("W", XK_W); + map("X", XK_X); + map("Y", XK_Y); + map("Z", XK_Z); + + map("NumLock", XK_Num_Lock); + map("Divide", XK_KP_Divide); + map("Multiply", XK_KP_Multiply); + map("Subtract", XK_KP_Subtract); + map("Add", XK_KP_Add); + map("RightEnter", XK_KP_Enter); + map("Point", XK_KP_Decimal); + + map("One", XK_KP_1); + map("Two", XK_KP_2); + map("Three", XK_KP_3); + map("Four", XK_KP_4); + map("Five", XK_KP_5); + map("Six", XK_KP_6); + map("Seven", XK_KP_7); + map("Eight", XK_KP_8); + map("Nine", XK_KP_9); + map("Zero", XK_KP_0); + + map("Shift", XK_Shift_L, XK_Shift_R); + map("Control", XK_Control_L, XK_Control_R); + map("Alt", XK_Alt_L, XK_Alt_R); + map("Super", XK_Super_L, XK_Super_R); + map("Enter", XK_Return, XK_KP_Enter); + + print("[phoenix/gtk] error: unhandled key: ", key, "\n"); + append(0); + } + #undef map +} + +} diff --git a/hiro/gtk/keyboard.hpp b/hiro/gtk/keyboard.hpp new file mode 100644 index 00000000..06e5387c --- /dev/null +++ b/hiro/gtk/keyboard.hpp @@ -0,0 +1,13 @@ +namespace hiro { + +struct pKeyboard { + static auto poll() -> vector; + static auto pressed(unsigned code) -> bool; + + static auto _pressed(char* state, uint16_t code) -> bool; + static auto _translate(unsigned code) -> signed; + + static auto initialize() -> void; +}; + +} diff --git a/hiro/gtk/layout.cpp b/hiro/gtk/layout.cpp new file mode 100644 index 00000000..607b0cf2 --- /dev/null +++ b/hiro/gtk/layout.cpp @@ -0,0 +1,29 @@ +namespace hiro { + +auto pLayout::construct() -> void { + for(auto& sizable : state().sizables) sizable->construct(); +} + +auto pLayout::destruct() -> void { + for(auto& sizable : state().sizables) sizable->destruct(); +} + +auto pLayout::setEnabled(bool enabled) -> void { + for(auto& sizable : state().sizables) { + if(sizable->self()) sizable->self()->setEnabled(sizable->enabled(true)); + } +} + +auto pLayout::setFont(const string& font) -> void { + for(auto& sizable : state().sizables) { + if(sizable->self()) sizable->self()->setFont(sizable->font(true)); + } +} + +auto pLayout::setVisible(bool visible) -> void { + for(auto& sizable : state().sizables) { + if(sizable->self()) sizable->self()->setVisible(sizable->visible(true)); + } +} + +} diff --git a/hiro/gtk/layout.hpp b/hiro/gtk/layout.hpp new file mode 100644 index 00000000..f77bfc84 --- /dev/null +++ b/hiro/gtk/layout.hpp @@ -0,0 +1,11 @@ +namespace hiro { + +struct pLayout : pSizable { + Declare(Layout, Sizable) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const string& font) -> void override; + auto setVisible(bool visible) -> void override; +}; + +} diff --git a/hiro/gtk/menu-bar.cpp b/hiro/gtk/menu-bar.cpp new file mode 100644 index 00000000..94127d2d --- /dev/null +++ b/hiro/gtk/menu-bar.cpp @@ -0,0 +1,45 @@ +namespace hiro { + +auto pMenuBar::construct() -> void { +} + +auto pMenuBar::destruct() -> void { +} + +auto pMenuBar::append(shared_pointer menu) -> void { + if(auto parent = _parent()) { + parent->_append(*menu); + if(menu->self()) { + menu->self()->setFont(menu->font(true)); + menu->self()->setVisible(menu->visible(true)); + } + } +} + +auto pMenuBar::remove(shared_pointer menu) -> void { +} + +auto pMenuBar::setEnabled(bool enabled) -> void { + if(auto parent = _parent()) { + parent->_setMenuEnabled(enabled); + } +} + +auto pMenuBar::setFont(const string& font) -> void { + if(auto parent = _parent()) { + parent->_setMenuFont(font); + } +} + +auto pMenuBar::setVisible(bool visible) -> void { + if(auto parent = _parent()) { + parent->_setMenuVisible(visible); + } +} + +auto pMenuBar::_parent() -> pWindow* { + if(auto parent = self().parentWindow()) return parent->self(); + return nullptr; +} + +} diff --git a/hiro/gtk/menu-bar.hpp b/hiro/gtk/menu-bar.hpp new file mode 100644 index 00000000..7c1897cf --- /dev/null +++ b/hiro/gtk/menu-bar.hpp @@ -0,0 +1,15 @@ +namespace hiro { + +struct pMenuBar : pObject { + Declare(MenuBar, Object) + + auto append(shared_pointer menu) -> void; + auto remove(shared_pointer menu) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const string& font) -> void override; + auto setVisible(bool visible) -> void override; + + auto _parent() -> pWindow*; +}; + +} diff --git a/phoenix/gtk/message-window.cpp b/hiro/gtk/message-window.cpp similarity index 73% rename from phoenix/gtk/message-window.cpp rename to hiro/gtk/message-window.cpp index 2b542a19..88e3874c 100644 --- a/phoenix/gtk/message-window.cpp +++ b/hiro/gtk/message-window.cpp @@ -1,13 +1,13 @@ -namespace phoenix { +namespace hiro { -static MessageWindow::Response Message(MessageWindow::State& state, GtkMessageType messageStyle) { +static auto Message(MessageWindow::State& state, GtkMessageType messageStyle) -> MessageWindow::Response { GtkWidget* dialog = gtk_message_dialog_new( - state.parent ? GTK_WINDOW(state.parent->p.widget) : (GtkWindow*)nullptr, + state.parent && state.parent->self() ? GTK_WINDOW(state.parent->self()->widget) : (GtkWindow*)nullptr, GTK_DIALOG_MODAL, messageStyle, GTK_BUTTONS_NONE, "%s", (const char*)state.text ); if(state.title) gtk_window_set_title(GTK_WINDOW(dialog), state.title); - else if(applicationState.name) gtk_window_set_title(GTK_WINDOW(dialog), applicationState.name); + else if(Application::state.name) gtk_window_set_title(GTK_WINDOW(dialog), Application::state.name); switch(state.buttons) { case MessageWindow::Buttons::Ok: @@ -41,19 +41,19 @@ static MessageWindow::Response Message(MessageWindow::State& state, GtkMessageTy throw; } -MessageWindow::Response pMessageWindow::error(MessageWindow::State& state) { +auto pMessageWindow::error(MessageWindow::State& state) -> MessageWindow::Response { return Message(state, GTK_MESSAGE_ERROR); } -MessageWindow::Response pMessageWindow::information(MessageWindow::State& state) { +auto pMessageWindow::information(MessageWindow::State& state) -> MessageWindow::Response { return Message(state, GTK_MESSAGE_INFO); } -MessageWindow::Response pMessageWindow::question(MessageWindow::State& state) { +auto pMessageWindow::question(MessageWindow::State& state) -> MessageWindow::Response { return Message(state, GTK_MESSAGE_QUESTION); } -MessageWindow::Response pMessageWindow::warning(MessageWindow::State& state) { +auto pMessageWindow::warning(MessageWindow::State& state) -> MessageWindow::Response { return Message(state, GTK_MESSAGE_WARNING); } diff --git a/hiro/gtk/message-window.hpp b/hiro/gtk/message-window.hpp new file mode 100644 index 00000000..4daadc3d --- /dev/null +++ b/hiro/gtk/message-window.hpp @@ -0,0 +1,10 @@ +namespace hiro { + +struct pMessageWindow { + static auto error(MessageWindow::State& state) -> MessageWindow::Response; + static auto information(MessageWindow::State& state) -> MessageWindow::Response; + static auto question(MessageWindow::State& state) -> MessageWindow::Response; + static auto warning(MessageWindow::State& state) -> MessageWindow::Response; +}; + +} diff --git a/phoenix/gtk/monitor.cpp b/hiro/gtk/monitor.cpp similarity index 95% rename from phoenix/gtk/monitor.cpp rename to hiro/gtk/monitor.cpp index ccea2ebf..649c0823 100644 --- a/phoenix/gtk/monitor.cpp +++ b/hiro/gtk/monitor.cpp @@ -1,4 +1,4 @@ -namespace phoenix { +namespace hiro { unsigned pMonitor::count() { return gdk_screen_get_n_monitors(gdk_screen_get_default()); diff --git a/hiro/gtk/monitor.hpp b/hiro/gtk/monitor.hpp new file mode 100644 index 00000000..c616d6a8 --- /dev/null +++ b/hiro/gtk/monitor.hpp @@ -0,0 +1,9 @@ +namespace hiro { + +struct pMonitor { + static unsigned count(); + static Geometry geometry(unsigned monitor); + static unsigned primary(); +}; + +} diff --git a/phoenix/gtk/mouse.cpp b/hiro/gtk/mouse.cpp similarity index 86% rename from phoenix/gtk/mouse.cpp rename to hiro/gtk/mouse.cpp index 2e2a4021..0e6a6c94 100644 --- a/phoenix/gtk/mouse.cpp +++ b/hiro/gtk/mouse.cpp @@ -1,6 +1,6 @@ -namespace phoenix { +namespace hiro { -Position pMouse::position() { +auto pMouse::position() -> Position { XlibWindow root, child; int rootx, rooty, winx, winy; unsigned int mask; @@ -8,7 +8,7 @@ Position pMouse::position() { return {rootx, rooty}; } -bool pMouse::pressed(Mouse::Button button) { +auto pMouse::pressed(Mouse::Button button) -> bool { XlibWindow root, child; int rootx, rooty, winx, winy; unsigned int mask; diff --git a/hiro/gtk/mouse.hpp b/hiro/gtk/mouse.hpp new file mode 100644 index 00000000..805671fa --- /dev/null +++ b/hiro/gtk/mouse.hpp @@ -0,0 +1,8 @@ +namespace hiro { + +struct pMouse { + static auto position() -> Position; + static auto pressed(Mouse::Button button) -> bool; +}; + +} diff --git a/hiro/gtk/object.cpp b/hiro/gtk/object.cpp new file mode 100644 index 00000000..0eb9c64a --- /dev/null +++ b/hiro/gtk/object.cpp @@ -0,0 +1,31 @@ +namespace hiro { + +auto pObject::construct() -> void { +} + +auto pObject::destruct() -> void { +} + +auto pObject::focused() const -> bool { + return false; +} + +auto pObject::remove() -> void { +} + +auto pObject::reset() -> void { +} + +auto pObject::setEnabled(bool enabled) -> void { +} + +auto pObject::setFocused() -> void { +} + +auto pObject::setFont(const string& font) -> void { +} + +auto pObject::setVisible(bool visible) -> void { +} + +} diff --git a/hiro/gtk/object.hpp b/hiro/gtk/object.hpp new file mode 100644 index 00000000..45cfe490 --- /dev/null +++ b/hiro/gtk/object.hpp @@ -0,0 +1,27 @@ +namespace hiro { + +struct pObject { + pObject(mObject& reference) : reference(reference) {} + virtual ~pObject() {} + auto self() const -> mObject& { return (mObject&)reference; } + auto state() const -> mObject::State& { return self().state; } + virtual auto construct() -> void; + virtual auto destruct() -> void; + + virtual auto focused() const -> bool; + virtual auto remove() -> void; + virtual auto reset() -> void; + virtual auto setEnabled(bool enabled) -> void; + virtual auto setFocused() -> void; + virtual auto setFont(const string& font) -> void; + virtual auto setVisible(bool visible) -> void; + + auto locked() const -> bool { return locks != 0; } + auto lock() -> void { ++locks; } + auto unlock() -> void { --locks; } + + mObject& reference; + signed locks = 0; +}; + +} diff --git a/phoenix/gtk/platform.cpp b/hiro/gtk/platform.cpp similarity index 63% rename from phoenix/gtk/platform.cpp rename to hiro/gtk/platform.cpp index 9d6cdf70..63868a21 100644 --- a/phoenix/gtk/platform.cpp +++ b/hiro/gtk/platform.cpp @@ -1,24 +1,30 @@ #include "platform.hpp" - #include "utility.cpp" -#include "settings.cpp" +#include "font.cpp" #include "desktop.cpp" #include "monitor.cpp" #include "keyboard.cpp" #include "mouse.cpp" #include "browser-window.cpp" #include "message-window.cpp" -#include "font.cpp" +#include "object.cpp" +#include "hotkey.cpp" #include "timer.cpp" #include "window.cpp" +#include "status-bar.cpp" +#include "menu-bar.cpp" +#include "popup-menu.cpp" #include "action/action.cpp" #include "action/menu.cpp" -#include "action/separator.cpp" -#include "action/item.cpp" -#include "action/check-item.cpp" -#include "action/radio-item.cpp" +#include "action/menu-separator.cpp" +#include "action/menu-item.cpp" +#include "action/menu-check-item.cpp" +#include "action/menu-radio-item.cpp" + +#include "sizable.cpp" +#include "layout.cpp" #include "widget/widget.cpp" #include "widget/button.cpp" @@ -26,21 +32,31 @@ #include "widget/check-button.cpp" #include "widget/check-label.cpp" #include "widget/combo-button.cpp" +#include "widget/combo-button-item.cpp" #include "widget/console.cpp" #include "widget/frame.cpp" #include "widget/hex-edit.cpp" #include "widget/horizontal-scroller.cpp" #include "widget/horizontal-slider.cpp" +#include "widget/icon-view.cpp" +#include "widget/icon-view-item.cpp" #include "widget/label.cpp" #include "widget/line-edit.cpp" #include "widget/list-view.cpp" +#include "widget/list-view-column.cpp" +#include "widget/list-view-item.cpp" #include "widget/progress-bar.cpp" #include "widget/radio-button.cpp" #include "widget/radio-label.cpp" +#include "widget/source-edit.cpp" #include "widget/tab-frame.cpp" +#include "widget/tab-frame-item.cpp" #include "widget/text-edit.cpp" +#include "widget/tree-view.cpp" +#include "widget/tree-view-item.cpp" #include "widget/vertical-scroller.cpp" #include "widget/vertical-slider.cpp" #include "widget/viewport.cpp" #include "application.cpp" +#include "settings.cpp" diff --git a/hiro/gtk/platform.hpp b/hiro/gtk/platform.hpp new file mode 100644 index 00000000..06b3f5ea --- /dev/null +++ b/hiro/gtk/platform.hpp @@ -0,0 +1,75 @@ +namespace hiro { + struct pWindow; + struct pMenu; + struct pLayout; + struct pWidget; +}; + +#define Declare(Name, Base) \ + p##Name(m##Name& reference) : p##Base(reference) {} \ + auto self() const -> m##Name& { return (m##Name&)reference; } \ + auto state() const -> m##Name::State& { return self().state; } \ + auto construct() -> void override; \ + auto destruct() -> void override; \ + +#include "font.hpp" +#include "desktop.hpp" +#include "monitor.hpp" +#include "keyboard.hpp" +#include "mouse.hpp" +#include "browser-window.hpp" +#include "message-window.hpp" +#include "object.hpp" +#include "hotkey.hpp" +#include "timer.hpp" +#include "window.hpp" +#include "status-bar.hpp" +#include "menu-bar.hpp" +#include "popup-menu.hpp" + +#include "action/action.hpp" +#include "action/menu.hpp" +#include "action/menu-separator.hpp" +#include "action/menu-item.hpp" +#include "action/menu-check-item.hpp" +#include "action/menu-radio-item.hpp" + +#include "sizable.hpp" +#include "layout.hpp" + +#include "widget/widget.hpp" +#include "widget/button.hpp" +#include "widget/canvas.hpp" +#include "widget/check-button.hpp" +#include "widget/check-label.hpp" +#include "widget/combo-button.hpp" +#include "widget/combo-button-item.hpp" +#include "widget/console.hpp" +#include "widget/frame.hpp" +#include "widget/hex-edit.hpp" +#include "widget/horizontal-scroller.hpp" +#include "widget/horizontal-slider.hpp" +#include "widget/icon-view.hpp" +#include "widget/icon-view-item.hpp" +#include "widget/label.hpp" +#include "widget/line-edit.hpp" +#include "widget/list-view.hpp" +#include "widget/list-view-column.hpp" +#include "widget/list-view-item.hpp" +#include "widget/progress-bar.hpp" +#include "widget/radio-button.hpp" +#include "widget/radio-label.hpp" +#include "widget/source-edit.hpp" +#include "widget/tab-frame.hpp" +#include "widget/tab-frame-item.hpp" +#include "widget/text-edit.hpp" +#include "widget/tree-view.hpp" +#include "widget/tree-view-item.hpp" +#include "widget/vertical-scroller.hpp" +#include "widget/vertical-slider.hpp" +#include "widget/viewport.hpp" + +#undef Declare + +#include "application.hpp" +#include "settings.hpp" diff --git a/hiro/gtk/popup-menu.cpp b/hiro/gtk/popup-menu.cpp new file mode 100644 index 00000000..752d0877 --- /dev/null +++ b/hiro/gtk/popup-menu.cpp @@ -0,0 +1,32 @@ +namespace hiro { + +auto pPopupMenu::construct() -> void { + gtkMenu = gtk_menu_new(); +} + +auto pPopupMenu::destruct() -> void { + gtk_widget_destroy(gtkMenu); +} + +auto pPopupMenu::append(sAction action) -> void { + if(action->self()) { + gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), action->self()->widget); + action->self()->setFont(action->font(true)); + action->self()->setVisible(action->visible(true)); + } +} + +auto pPopupMenu::remove(sAction action) -> void { +} + +auto pPopupMenu::setFont(const string& font) -> void { + for(auto& action : state().actions) { + if(action->self()) action->self()->setFont(action->font(true)); + } +} + +auto pPopupMenu::setVisible(bool visible) -> void { + if(visible) gtk_menu_popup(GTK_MENU(gtkMenu), nullptr, nullptr, nullptr, nullptr, 0, gtk_get_current_event_time()); +} + +} diff --git a/hiro/gtk/popup-menu.hpp b/hiro/gtk/popup-menu.hpp new file mode 100644 index 00000000..03548cfb --- /dev/null +++ b/hiro/gtk/popup-menu.hpp @@ -0,0 +1,14 @@ +namespace hiro { + +struct pPopupMenu : pObject { + Declare(PopupMenu, Object) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setFont(const string& font) -> void override; + auto setVisible(bool visible) -> void; + + GtkWidget* gtkMenu = nullptr; +}; + +} diff --git a/phoenix/gtk/settings.cpp b/hiro/gtk/settings.cpp similarity index 93% rename from phoenix/gtk/settings.cpp rename to hiro/gtk/settings.cpp index 6c411c36..c1754dae 100644 --- a/phoenix/gtk/settings.cpp +++ b/hiro/gtk/settings.cpp @@ -1,6 +1,4 @@ -namespace phoenix { - -static Settings* settings = nullptr; +namespace hiro { void Settings::load() { string path = {userpath(), ".config/phoenix/"}; diff --git a/hiro/gtk/settings.hpp b/hiro/gtk/settings.hpp new file mode 100644 index 00000000..df69ac2d --- /dev/null +++ b/hiro/gtk/settings.hpp @@ -0,0 +1,26 @@ +namespace hiro { + +struct Settings : Configuration::Document { + vector keycodes; + + struct Geometry : Configuration::Node { + signed frameX; + signed frameY; + signed frameWidth; + signed frameHeight; + signed menuHeight; + signed statusHeight; + } geometry; + + struct Window : Configuration::Node { + unsigned backgroundColor; + } window; + + void load(); + void save(); + Settings(); +}; + +static Settings* settings = nullptr; + +} diff --git a/hiro/gtk/sizable.cpp b/hiro/gtk/sizable.cpp new file mode 100644 index 00000000..c882be2b --- /dev/null +++ b/hiro/gtk/sizable.cpp @@ -0,0 +1,16 @@ +namespace hiro { + +auto pSizable::construct() -> void { +} + +auto pSizable::destruct() -> void { +} + +auto pSizable::minimumSize() const -> Size { + return {0, 0}; +} + +auto pSizable::setGeometry(Geometry geometry) -> void { +} + +} diff --git a/hiro/gtk/sizable.hpp b/hiro/gtk/sizable.hpp new file mode 100644 index 00000000..12dfc9f0 --- /dev/null +++ b/hiro/gtk/sizable.hpp @@ -0,0 +1,10 @@ +namespace hiro { + +struct pSizable : pObject { + Declare(Sizable, Object) + + virtual auto minimumSize() const -> Size; + virtual auto setGeometry(Geometry geometry) -> void; +}; + +} diff --git a/hiro/gtk/status-bar.cpp b/hiro/gtk/status-bar.cpp new file mode 100644 index 00000000..02ffafbf --- /dev/null +++ b/hiro/gtk/status-bar.cpp @@ -0,0 +1,38 @@ +namespace hiro { + +auto pStatusBar::construct() -> void { +} + +auto pStatusBar::destruct() -> void { +} + +auto pStatusBar::setEnabled(bool enabled) -> void { + if(auto parent = _parent()) { + parent->_setStatusEnabled(enabled); + } +} + +auto pStatusBar::setFont(const string& font) -> void { + if(auto parent = _parent()) { + parent->_setStatusFont(font); + } +} + +auto pStatusBar::setText(const string& text) -> void { + if(auto parent = _parent()) { + parent->_setStatusText(text); + } +} + +auto pStatusBar::setVisible(bool visible) -> void { + if(auto parent = _parent()) { + parent->_setStatusVisible(visible); + } +} + +auto pStatusBar::_parent() -> pWindow* { + if(auto parent = self().parentWindow()) return parent->self(); + return nullptr; +} + +} diff --git a/hiro/gtk/status-bar.hpp b/hiro/gtk/status-bar.hpp new file mode 100644 index 00000000..7f178dc5 --- /dev/null +++ b/hiro/gtk/status-bar.hpp @@ -0,0 +1,14 @@ +namespace hiro { + +struct pStatusBar : pObject { + Declare(StatusBar, Object) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const string& font) -> void override; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> pWindow*; +}; + +} diff --git a/hiro/gtk/timer.cpp b/hiro/gtk/timer.cpp new file mode 100644 index 00000000..49dee689 --- /dev/null +++ b/hiro/gtk/timer.cpp @@ -0,0 +1,31 @@ +namespace hiro { + +static auto Timer_trigger(pTimer* p) -> signed { + //timer may have been disabled prior to triggering, so check state + if(p->self().enabled(true)) p->self().doActivate(); + + //callback may have disabled timer, so check state again + if(p->self().enabled(true)) { + g_timeout_add(p->state().interval, (GSourceFunc)Timer_trigger, (gpointer)p); + } + + //kill this timer instance (it is spawned above if needed again) + return false; +} + +auto pTimer::construct() -> void { +} + +auto pTimer::destruct() -> void { +} + +auto pTimer::setEnabled(bool enabled) -> void { + if(enabled) { + g_timeout_add(state().interval, (GSourceFunc)Timer_trigger, (gpointer)this); + } +} + +auto pTimer::setInterval(unsigned interval) -> void { +} + +} diff --git a/hiro/gtk/timer.hpp b/hiro/gtk/timer.hpp new file mode 100644 index 00000000..d09565e0 --- /dev/null +++ b/hiro/gtk/timer.hpp @@ -0,0 +1,10 @@ +namespace hiro { + +struct pTimer : pObject { + Declare(Timer, Object) + + auto setEnabled(bool enabled) -> void; + auto setInterval(unsigned interval) -> void; +}; + +} diff --git a/hiro/gtk/utility.cpp b/hiro/gtk/utility.cpp new file mode 100644 index 00000000..1fbdbd36 --- /dev/null +++ b/hiro/gtk/utility.cpp @@ -0,0 +1,49 @@ +namespace hiro { + +static auto CreateColor(const Color& color) -> GdkColor { + GdkColor gdkColor; + gdkColor.pixel = (color.red() << 16) | (color.green() << 8) | (color.blue() << 0); + gdkColor.red = (color.red() << 8) | (color.red() << 0); + gdkColor.green = (color.green() << 8) | (color.green() << 0); + gdkColor.blue = (color.blue() << 8) | (color.blue() << 0); + return gdkColor; +} + +static auto CreatePixbuf(const nall::image& image, bool scale = false) -> GdkPixbuf* { + nall::image gdkImage = image; + gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); + if(scale) gdkImage.scale(15, 15); + + GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, gdkImage.width, gdkImage.height); + memcpy(gdk_pixbuf_get_pixels(pixbuf), gdkImage.data, gdkImage.width * gdkImage.height * 4); + + return pixbuf; +} + +static auto CreateImage(const nall::image& image, bool scale = false) -> GtkImage* { + GdkPixbuf* pixbuf = CreatePixbuf(image, scale); + GtkImage* gtkImage = (GtkImage*)gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + return gtkImage; +} + +static auto DropPaths(GtkSelectionData* data) -> lstring { + gchar** uris = gtk_selection_data_get_uris(data); + if(uris == nullptr) return {}; + + lstring paths; + for(unsigned n = 0; uris[n] != nullptr; n++) { + gchar* pathname = g_filename_from_uri(uris[n], nullptr, nullptr); + if(pathname == nullptr) continue; + + string path = pathname; + g_free(pathname); + if(directory::exists(path) && !path.endsWith("/")) path.append("/"); + paths.append(path); + } + + g_strfreev(uris); + return paths; +} + +} diff --git a/hiro/gtk/widget/button.cpp b/hiro/gtk/widget/button.cpp new file mode 100644 index 00000000..7c1e5872 --- /dev/null +++ b/hiro/gtk/widget/button.cpp @@ -0,0 +1,68 @@ +namespace hiro { + +static auto Button_activate(GtkButton* gtkButton, pButton* p) -> void { p->_doActivate(); } + +auto pButton::construct() -> void { + gtkWidget = gtk_button_new(); + gtkButton = GTK_BUTTON(gtkWidget); + + setBordered(state().bordered); + setIcon(state().icon); + setOrientation(state().orientation); + setText(state().text); + + g_signal_connect(G_OBJECT(gtkButton), "clicked", G_CALLBACK(Button_activate), (gpointer)this); + + pWidget::construct(); +} + +auto pButton::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pButton::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + + if(state().orientation == Orientation::Horizontal) { + size.setWidth(size.width() + state().icon.width); + size.setHeight(max(size.height(), state().icon.height)); + } + + if(state().orientation == Orientation::Vertical) { + size.setWidth(max(size.width(), state().icon.width)); + size.setHeight(size.height() + state().icon.height); + } + + return {size.width() + (state().text ? 24 : 12), size.height() + 12}; +} + +auto pButton::setBordered(bool bordered) -> void { + gtk_button_set_relief(gtkButton, bordered ? GTK_RELIEF_NORMAL : GTK_RELIEF_NONE); +} + +auto pButton::setIcon(const image& icon) -> void { + if(icon) { + auto gtkImage = CreateImage(icon); + gtk_button_set_image(gtkButton, (GtkWidget*)gtkImage); + } else { + gtk_button_set_image(gtkButton, nullptr); + } +} + +auto pButton::setOrientation(Orientation orientation) -> void { + switch(orientation) { + case Orientation::Horizontal: gtk_button_set_image_position(gtkButton, GTK_POS_LEFT); break; + case Orientation::Vertical: gtk_button_set_image_position(gtkButton, GTK_POS_TOP); break; + } +} + +auto pButton::setText(const string& text) -> void { + gtk_button_set_label(gtkButton, text); + setFont(self().font(true)); //gtk_button_set_label() recreates label, which destroys currently assigned font +} + +auto pButton::_doActivate() -> void { + self().doActivate(); +} + +} diff --git a/hiro/gtk/widget/button.hpp b/hiro/gtk/widget/button.hpp new file mode 100644 index 00000000..9cabea5d --- /dev/null +++ b/hiro/gtk/widget/button.hpp @@ -0,0 +1,17 @@ +namespace hiro { + +struct pButton : pWidget { + Declare(Button, Widget) + + auto minimumSize() const -> Size override; + auto setBordered(bool bordered) -> void; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + + auto _doActivate() -> void; + + GtkButton* gtkButton = nullptr; +}; + +} diff --git a/hiro/gtk/widget/canvas.cpp b/hiro/gtk/widget/canvas.cpp new file mode 100644 index 00000000..e40c3baf --- /dev/null +++ b/hiro/gtk/widget/canvas.cpp @@ -0,0 +1,212 @@ +namespace hiro { + +static auto Canvas_drop(GtkWidget* widget, GdkDragContext* context, signed x, signed y, +GtkSelectionData* data, unsigned type, unsigned timestamp, pCanvas* p) -> void { + if(!p->state().droppable) return; + lstring paths = DropPaths(data); + if(paths.empty()) return; + p->self().doDrop(paths); +} + +static auto Canvas_expose(GtkWidget* widget, GdkEventExpose* event, pCanvas* p) -> signed { + p->_onExpose(event); + return true; +} + +static auto Canvas_mouseLeave(GtkWidget* widget, GdkEventButton* event, pCanvas* p) -> signed { + p->self().doMouseLeave(); + return true; +} + +static auto Canvas_mouseMove(GtkWidget* widget, GdkEventButton* event, pCanvas* p) -> signed { + p->self().doMouseMove({(signed)event->x, (signed)event->y}); + return true; +} + +static auto Canvas_mousePress(GtkWidget* widget, GdkEventButton* event, pCanvas* p) -> signed { + switch(event->button) { + case 1: p->self().doMousePress(Mouse::Button::Left); break; + case 2: p->self().doMousePress(Mouse::Button::Middle); break; + case 3: p->self().doMousePress(Mouse::Button::Right); break; + } + return true; +} + +static auto Canvas_mouseRelease(GtkWidget* widget, GdkEventButton* event, pCanvas* p) -> signed { + switch(event->button) { + case 1: p->self().doMouseRelease(Mouse::Button::Left); break; + case 2: p->self().doMouseRelease(Mouse::Button::Middle); break; + case 3: p->self().doMouseRelease(Mouse::Button::Right); break; + } + return true; +} + +auto pCanvas::construct() -> void { + gtkWidget = gtk_drawing_area_new(); + gtk_widget_add_events(gtkWidget, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); + + setDroppable(state().droppable); + _rasterize(); + _redraw(); + + //todo: need to work around GTK+ library bug: + //after calling destruct(), construct() with state.droppable == true; + //GTK+ will throw SIGBUS inside g_signal_connect_data() on one of the below connections + + g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Canvas_mousePress), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Canvas_mouseRelease), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Canvas_drop), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "expose-event", G_CALLBACK(Canvas_expose), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Canvas_mouseLeave), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "motion-notify-event", G_CALLBACK(Canvas_mouseMove), (gpointer)this); + + pWidget::construct(); +} + +auto pCanvas::destruct() -> void { + _release(); + if(gtkWidget) gtk_widget_destroy(gtkWidget), gtkWidget = nullptr; + gtkParent = nullptr; +} + +auto pCanvas::minimumSize() const -> Size { + return {max(0, state().size.width()), max(0, state().size.height())}; +} + +auto pCanvas::setColor(Color color) -> void { + mode = Mode::Color; + update(); +} + +auto pCanvas::setData(Size size) -> void { + mode = Mode::Data; + update(); +} + +auto pCanvas::setDroppable(bool droppable) -> void { + if(droppable) { + gtk_drag_dest_set(gtkWidget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY); + gtk_drag_dest_add_uri_targets(gtkWidget); + } +} + +auto pCanvas::setGeometry(Geometry geometry) -> void { + update(); + pWidget::setGeometry(geometry); +} + +auto pCanvas::setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> void { + mode = Mode::Gradient; + update(); +} + +auto pCanvas::setIcon(const image& icon) -> void { + mode = Mode::Icon; + update(); +} + +auto pCanvas::update() -> void { + _rasterize(); + _redraw(); +} + +auto pCanvas::_onExpose(GdkEventExpose* expose) -> void { + if(surface == nullptr) return; + + signed sx = 0, sy = 0, dx = 0, dy = 0; + signed width = surfaceWidth; + signed height = surfaceHeight; + auto geometry = pSizable::state().geometry; + + if(width <= geometry.width()) { + sx = 0; + dx = (geometry.width() - width) / 2; + } else { + sx = (width - geometry.width()) / 2; + dx = 0; + width = geometry.width(); + } + + if(height <= geometry.height()) { + sy = 0; + dy = (geometry.height() - height) / 2; + } else { + sy = (height - geometry.height()) / 2; + dy = 0; + height = geometry.height(); + } + + gdk_draw_pixbuf(gtk_widget_get_window(gtkWidget), nullptr, surface, sx, sy, dx, dy, width, height, GDK_RGB_DITHER_NONE, 0, 0); +} + +auto pCanvas::_rasterize() -> void { + signed width = 0; + signed height = 0; + + if(mode == Mode::Color || mode == Mode::Gradient) { + width = pSizable::state().geometry.width(); + height = pSizable::state().geometry.height(); + } else { + width = state().size.width(); + height = state().size.height(); + } + + if(width <= 0 || height <= 0) return; + + if(width != surfaceWidth || height != surfaceHeight) _release(); + surfaceWidth = width; + surfaceHeight = height; + + if(!surface) surface = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height); + uint32_t* buffer = (uint32_t*)gdk_pixbuf_get_pixels(surface); + + if(mode == Mode::Color) { + uint32_t color = state().color.value(); + for(auto n : range(width * height)) buffer[n] = color; + } + + if(mode == Mode::Gradient) { + image fill; + fill.allocate(width, height); + fill.gradient( + state().gradient[0].value(), state().gradient[1].value(), state().gradient[2].value(), state().gradient[3].value() + ); + memory::copy(buffer, fill.data, fill.size); + } + + if(mode == Mode::Icon) { + auto icon = state().icon; + icon.scale(width, height); + icon.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + memory::copy(buffer, icon.data, icon.size); + } + + if(mode == Mode::Data) { + memory::copy(buffer, state().data.data(), state().data.size() * sizeof(uint32_t)); + } + + //ARGB -> ABGR conversion + for(auto n : range(width * height)) { + uint32_t color = *buffer; + color = (color & 0xff00ff00) | ((color & 0xff0000) >> 16) | ((color & 0x0000ff) << 16); + *buffer++ = color; + } +} + +auto pCanvas::_redraw() -> void { + if(gtk_widget_get_realized(gtkWidget)) { + gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), nullptr, true); + } +} + +auto pCanvas::_release() -> void { + if(surface) { + g_object_unref(surface); + surface = nullptr; + } + surfaceWidth = 0; + surfaceHeight = 0; +} + +} diff --git a/hiro/gtk/widget/canvas.hpp b/hiro/gtk/widget/canvas.hpp new file mode 100644 index 00000000..99e9b03d --- /dev/null +++ b/hiro/gtk/widget/canvas.hpp @@ -0,0 +1,28 @@ +namespace hiro { + +struct pCanvas : pWidget { + Declare(Canvas, Widget) + + auto minimumSize() const -> Size; + auto setColor(Color color) -> void; + auto setData(Size size) -> void; + auto setDroppable(bool droppable) -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> void; + auto setIcon(const image& icon) -> void; + auto update() -> void; + + enum class Mode : unsigned { Color, Data, Gradient, Icon }; + + auto _onExpose(GdkEventExpose* event) -> void; + auto _rasterize() -> void; + auto _redraw() -> void; + auto _release() -> void; + + GdkPixbuf* surface = nullptr; + unsigned surfaceWidth = 0; + unsigned surfaceHeight = 0; + Mode mode = Mode::Color; +}; + +} diff --git a/hiro/gtk/widget/check-button.cpp b/hiro/gtk/widget/check-button.cpp new file mode 100644 index 00000000..41c7a51f --- /dev/null +++ b/hiro/gtk/widget/check-button.cpp @@ -0,0 +1,73 @@ +namespace hiro { + +static auto CheckButton_toggle(GtkToggleButton* toggleButton, pCheckButton* p) -> void { + p->state().checked = gtk_toggle_button_get_active(toggleButton); + if(!p->locked()) p->self().doToggle(); +} + +auto pCheckButton::construct() -> void { + gtkWidget = gtk_toggle_button_new(); + + setBordered(state().bordered); + setChecked(state().checked); + setIcon(state().icon); + setOrientation(state().orientation); + setText(state().text); + + g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(CheckButton_toggle), (gpointer)this); + + pWidget::construct(); +} + +auto pCheckButton::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pCheckButton::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + + if(state().orientation == Orientation::Horizontal) { + size.setWidth(size.width() + state().icon.width); + size.setHeight(max(size.height(), state().icon.height)); + } + + if(state().orientation == Orientation::Vertical) { + size.setWidth(max(size.width(), state().icon.width)); + size.setHeight(size.height() + state().icon.height); + } + + return {size.width() + 24, size.height() + 12}; +} + +auto pCheckButton::setBordered(bool bordered) -> void { + gtk_button_set_relief(GTK_BUTTON(gtkWidget), bordered ? GTK_RELIEF_NORMAL : GTK_RELIEF_NONE); +} + +auto pCheckButton::setChecked(bool checked) -> void { + lock(); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), checked); + unlock(); +} + +auto pCheckButton::setIcon(const image& icon) -> void { + if(icon) { + GtkImage* gtkImage = CreateImage(icon); + gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); + } else { + gtk_button_set_image(GTK_BUTTON(gtkWidget), nullptr); + } +} + +auto pCheckButton::setOrientation(Orientation orientation) -> void { + switch(orientation) { + case Orientation::Horizontal: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_LEFT); break; + case Orientation::Vertical: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_TOP); break; + } +} + +auto pCheckButton::setText(const string& text) -> void { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); + setFont(self().font(true)); //gtk_button_set_label() recreates label, which destroys currently assigned font +} + +} diff --git a/hiro/gtk/widget/check-button.hpp b/hiro/gtk/widget/check-button.hpp new file mode 100644 index 00000000..3b31d917 --- /dev/null +++ b/hiro/gtk/widget/check-button.hpp @@ -0,0 +1,14 @@ +namespace hiro { + +struct pCheckButton : pWidget { + Declare(CheckButton, Widget) + + auto minimumSize() const -> Size override; + auto setBordered(bool bordered) -> void; + auto setChecked(bool checked) -> void; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; +}; + +} diff --git a/hiro/gtk/widget/check-label.cpp b/hiro/gtk/widget/check-label.cpp new file mode 100644 index 00000000..c9dbd0a7 --- /dev/null +++ b/hiro/gtk/widget/check-label.cpp @@ -0,0 +1,39 @@ +namespace hiro { + +static auto CheckLabel_toggle(GtkToggleButton* toggleButton, pCheckLabel* p) -> void { + p->state().checked = gtk_toggle_button_get_active(toggleButton); + if(!p->locked()) p->self().doToggle(); +} + +auto pCheckLabel::construct() -> void { + gtkWidget = gtk_check_button_new_with_label(""); + + setChecked(state().checked); + setText(state().text); + + g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(CheckLabel_toggle), (gpointer)this); + + pWidget::construct(); +} + +auto pCheckLabel::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pCheckLabel::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + return {size.width() + 28, size.height() + 4}; +} + +auto pCheckLabel::setChecked(bool checked) -> void { + lock(); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), checked); + unlock(); +} + +auto pCheckLabel::setText(const string& text) -> void { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); + setFont(self().font(true)); //gtk_button_set_label() recreates label, which destroys currently assigned font +} + +} diff --git a/hiro/gtk/widget/check-label.hpp b/hiro/gtk/widget/check-label.hpp new file mode 100644 index 00000000..c84195f1 --- /dev/null +++ b/hiro/gtk/widget/check-label.hpp @@ -0,0 +1,11 @@ +namespace hiro { + +struct pCheckLabel : pWidget { + Declare(CheckLabel, Widget) + + auto minimumSize() const -> Size; + auto setChecked(bool checked) -> void; + auto setText(const string& text) -> void; +}; + +} diff --git a/hiro/gtk/widget/combo-button-item.cpp b/hiro/gtk/widget/combo-button-item.cpp new file mode 100644 index 00000000..2f6e79bc --- /dev/null +++ b/hiro/gtk/widget/combo-button-item.cpp @@ -0,0 +1,42 @@ +namespace hiro { + +auto pComboButtonItem::construct() -> void { +} + +auto pComboButtonItem::destruct() -> void { +} + +auto pComboButtonItem::setIcon(const image& icon) -> void { + if(auto parent = _parent()) { + if(icon) { + auto copy = icon; + auto size = pFont::size(self().font(true), " ").height(); + copy.scale(size, size); + auto pixbuf = CreatePixbuf(copy); + gtk_list_store_set(parent->gtkListStore, >kIter, 0, pixbuf, -1); + } else { + gtk_list_store_set(parent->gtkListStore, >kIter, 0, nullptr, -1); + } + } +} + +auto pComboButtonItem::setSelected() -> void { + if(auto parent = _parent()) { + parent->lock(); + gtk_combo_box_set_active(parent->gtkComboBox, self().offset()); + parent->unlock(); + } +} + +auto pComboButtonItem::setText(const string& text) -> void { + if(auto parent = _parent()) { + gtk_list_store_set(parent->gtkListStore, >kIter, 1, text.data(), -1); + } +} + +auto pComboButtonItem::_parent() -> pComboButton* { + if(auto parent = self().parentComboButton()) return parent->self(); + return nullptr; +} + +} diff --git a/hiro/gtk/widget/combo-button-item.hpp b/hiro/gtk/widget/combo-button-item.hpp new file mode 100644 index 00000000..d823b746 --- /dev/null +++ b/hiro/gtk/widget/combo-button-item.hpp @@ -0,0 +1,15 @@ +namespace hiro { + +struct pComboButtonItem : pObject { + Declare(ComboButtonItem, Object) + + auto setIcon(const image& icon) -> void; + auto setSelected() -> void; + auto setText(const string& text) -> void; + + auto _parent() -> pComboButton*; + + GtkTreeIter gtkIter; +}; + +} diff --git a/hiro/gtk/widget/combo-button.cpp b/hiro/gtk/widget/combo-button.cpp new file mode 100644 index 00000000..9b2ea147 --- /dev/null +++ b/hiro/gtk/widget/combo-button.cpp @@ -0,0 +1,91 @@ +namespace hiro { + +static auto ComboButton_change(GtkComboBox* comboBox, pComboButton* p) -> void { p->_updateSelected(); } + +auto pComboButton::construct() -> void { + gtkListStore = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING); + gtkTreeModel = GTK_TREE_MODEL(gtkListStore); + gtkWidget = gtk_combo_box_new_with_model(gtkTreeModel); + gtkComboBox = GTK_COMBO_BOX(gtkWidget); + + gtkCellIcon = gtk_cell_renderer_pixbuf_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkWidget), gtkCellIcon, false); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkWidget), gtkCellIcon, "pixbuf", 0, nullptr); + gtkCellText = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkWidget), gtkCellText, true); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkWidget), gtkCellText, "text", 1, nullptr); + + for(auto& item : state().items) { + append(item); + if(item->selected()) item->setSelected(); + } + + g_signal_connect(G_OBJECT(gtkWidget), "changed", G_CALLBACK(ComboButton_change), (gpointer)this); + + pWidget::construct(); +} + +auto pComboButton::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pComboButton::append(sComboButtonItem item) -> void { + lock(); + if(auto delegate = item->self()) { + gtk_list_store_append(gtkListStore, &delegate->gtkIter); + item->setIcon(item->state.icon); + item->setText(item->state.text); + } + unlock(); +} + +auto pComboButton::minimumSize() const -> Size { + string font = self().font(true); + signed maximumWidth = 0; + for(auto& item : state().items) { + maximumWidth = max(maximumWidth, + (item->state.icon ? 2 + pFont::size(font, " ").height() : 0) + + pFont::size(font, item->state.text).width() + ); + } + Size size = pFont::size(font, " "); + return {maximumWidth + 40, size.height() + 12}; +} + +auto pComboButton::remove(sComboButtonItem item) -> void { + lock(); + if(auto delegate = item->self()) { + gtk_list_store_remove(gtkListStore, &delegate->gtkIter); + //if the currently selected item is removed; GTK+ deselects everything + //detect this behavior and select the first item instead of nothing + if(gtk_combo_box_get_active(GTK_COMBO_BOX(gtkWidget)) < 0) { + if(gtk_tree_model_iter_n_children(gtkTreeModel, nullptr) > 0) { + gtk_combo_box_set_active(GTK_COMBO_BOX(gtkWidget), 0); + state().selected = 0; + } + } + } + unlock(); +} + +auto pComboButton::reset() -> void { + lock(); + gtk_list_store_clear(gtkListStore); + unlock(); +} + +auto pComboButton::setFont(const string& font) -> void { + pWidget::setFont(font); + auto fontDescription = pFont::create(font); + g_object_set(G_OBJECT(gtkCellText), "font-desc", fontDescription, nullptr); +} + +auto pComboButton::_updateSelected() -> void { + signed selected = gtk_combo_box_get_active(gtkComboBox); + if(selected >= 0) { + state().selected = selected; + if(!locked()) self().doChange(); + } +} + +} diff --git a/hiro/gtk/widget/combo-button.hpp b/hiro/gtk/widget/combo-button.hpp new file mode 100644 index 00000000..ff66df28 --- /dev/null +++ b/hiro/gtk/widget/combo-button.hpp @@ -0,0 +1,21 @@ +namespace hiro { + +struct pComboButton : pWidget { + Declare(ComboButton, Widget) + + auto append(sComboButtonItem item) -> void; + auto minimumSize() const -> Size override; + auto remove(sComboButtonItem item) -> void; + auto reset() -> void; + auto setFont(const string& font) -> void override; + + auto _updateSelected() -> void; + + GtkListStore* gtkListStore = nullptr; + GtkTreeModel* gtkTreeModel = nullptr; + GtkComboBox* gtkComboBox = nullptr; + GtkCellRenderer* gtkCellIcon = nullptr; + GtkCellRenderer* gtkCellText = nullptr; +}; + +} diff --git a/phoenix/gtk/widget/console.cpp b/hiro/gtk/widget/console.cpp similarity index 76% rename from phoenix/gtk/widget/console.cpp rename to hiro/gtk/widget/console.cpp index 722f1387..a72cd629 100644 --- a/phoenix/gtk/widget/console.cpp +++ b/hiro/gtk/widget/console.cpp @@ -1,34 +1,60 @@ -namespace phoenix { +namespace hiro { -static bool Console_keyPress(GtkWidget* widget, GdkEventKey* event, Console* self) { - return self->p.keyPress(event->keyval, event->state); +static auto Console_keyPress(GtkWidget*, GdkEventKey* event, pConsole* p) -> signed { + return p->_keyPress(event->keyval, event->state); } -void pConsole::print(string text) { +auto pConsole::construct() -> void { + gtkWidget = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); + + subWidget = gtk_text_view_new(); + gtk_widget_show(subWidget); + gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), false); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_NONE); + gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); + + textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); + + setBackgroundColor(state().backgroundColor); + setForegroundColor(state().foregroundColor); + + g_signal_connect(G_OBJECT(subWidget), "key-press-event", G_CALLBACK(Console_keyPress), (gpointer)this); + + pWidget::construct(); +} + +auto pConsole::destruct() -> void { + gtk_widget_destroy(subWidget); + gtk_widget_destroy(gtkWidget); +} + +auto pConsole::print(const string& text) -> void { //insert text before prompt and command GtkTextIter iter; gtk_text_buffer_get_iter_at_line_offset(textBuffer, &iter, gtk_text_buffer_get_line_count(textBuffer), 0); gtk_text_buffer_insert(textBuffer, &iter, text, -1); - seekToEnd(); + _seekToEnd(); } -void pConsole::reset() { +auto pConsole::reset() -> void { //flush history and redraw prompt - gtk_text_buffer_set_text(textBuffer, console.prompt(), -1); - seekToEnd(); + gtk_text_buffer_set_text(textBuffer, state().prompt, -1); + _seekToEnd(); } -void pConsole::setBackgroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, &gdkColor); +auto pConsole::setBackgroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); } -void pConsole::setForegroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, &gdkColor); +auto pConsole::setForegroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); } -void pConsole::setPrompt(string prompt) { +auto pConsole::setPrompt(const string& prompt) -> void { //erase previous prompt and replace it with new prompt GtkTextIter lhs, rhs; gtk_text_buffer_get_iter_at_line_offset(textBuffer, &lhs, gtk_text_buffer_get_line_count(textBuffer), 0); @@ -36,42 +62,15 @@ void pConsole::setPrompt(string prompt) { gtk_text_buffer_delete(textBuffer, &lhs, &rhs); gtk_text_buffer_get_iter_at_line_offset(textBuffer, &lhs, gtk_text_buffer_get_line_count(textBuffer), 0); gtk_text_buffer_insert(textBuffer, &lhs, previousPrompt = prompt, -1); - seekToEnd(); + _seekToEnd(); } -void pConsole::constructor() { - gtkWidget = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); - - subWidget = gtk_text_view_new(); - gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), false); - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_NONE); - gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); - - textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); - - g_signal_connect(G_OBJECT(subWidget), "key-press-event", G_CALLBACK(Console_keyPress), (gpointer)&console); - - gtk_widget_show(subWidget); -} - -void pConsole::destructor() { - gtk_widget_destroy(subWidget); - gtk_widget_destroy(gtkWidget); -} - -void pConsole::orphan() { - destructor(); - constructor(); -} - -bool pConsole::keyPress(unsigned scancode, unsigned mask) { +auto pConsole::_keyPress(unsigned scancode, unsigned mask) -> bool { if(mask & (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK)) return false; //allow actions such as Ctrl+C (copy) GtkTextMark* mark = gtk_text_buffer_get_mark(textBuffer, "insert"); GtkTextIter start, cursor, end; - gtk_text_buffer_get_iter_at_line_offset(textBuffer, &start, gtk_text_buffer_get_line_count(textBuffer), console.prompt().size()); + gtk_text_buffer_get_iter_at_line_offset(textBuffer, &start, gtk_text_buffer_get_line_count(textBuffer), state().prompt.size()); gtk_text_buffer_get_iter_at_mark(textBuffer, &cursor, mark); gtk_text_buffer_get_end_iter(textBuffer, &end); @@ -79,12 +78,12 @@ bool pConsole::keyPress(unsigned scancode, unsigned mask) { char* temp = gtk_text_buffer_get_text(textBuffer, &start, &end, true); string s = temp; g_free(temp); - gtk_text_buffer_insert(textBuffer, &end, string{"\n", console.prompt()}, -1); - if(console.onActivate) console.onActivate(s); + gtk_text_buffer_insert(textBuffer, &end, string{"\n", state().prompt}, -1); + self().doActivate(s); if(s) history.prepend(s); if(history.size() > 128) history.removeLast(); historyOffset = 0; - seekToEnd(); + _seekToEnd(); return true; } @@ -94,7 +93,7 @@ bool pConsole::keyPress(unsigned scancode, unsigned mask) { if(historyOffset < history.size()) { gtk_text_buffer_insert(textBuffer, &end, history[historyOffset++], -1); } - seekToEnd(); + _seekToEnd(); return true; } @@ -104,7 +103,7 @@ bool pConsole::keyPress(unsigned scancode, unsigned mask) { if(historyOffset > 0) { gtk_text_buffer_insert(textBuffer, &end, history[--historyOffset], -1); } - seekToEnd(); + _seekToEnd(); return true; } @@ -115,7 +114,7 @@ bool pConsole::keyPress(unsigned scancode, unsigned mask) { gtk_text_iter_set_offset(&cursor, gtk_text_iter_get_offset(&cursor) - 1); gtk_text_buffer_place_cursor(textBuffer, &cursor); } - seekToMark(); + _seekToMark(); return true; } @@ -126,19 +125,19 @@ bool pConsole::keyPress(unsigned scancode, unsigned mask) { gtk_text_iter_set_offset(&cursor, gtk_text_iter_get_offset(&cursor) + 1); gtk_text_buffer_place_cursor(textBuffer, &cursor); } - seekToMark(); + _seekToMark(); return true; } if(scancode == GDK_KEY_Home) { gtk_text_buffer_place_cursor(textBuffer, &start); - seekToMark(); + _seekToMark(); return true; } if(scancode == GDK_KEY_End) { gtk_text_buffer_place_cursor(textBuffer, &end); - seekToMark(); + _seekToMark(); return true; } @@ -147,7 +146,7 @@ bool pConsole::keyPress(unsigned scancode, unsigned mask) { GtkTextIter lhs = cursor; gtk_text_iter_set_offset(&lhs, gtk_text_iter_get_offset(&cursor) - 1); gtk_text_buffer_delete(textBuffer, &lhs, &cursor); - seekToMark(); + _seekToMark(); return true; } @@ -157,28 +156,28 @@ bool pConsole::keyPress(unsigned scancode, unsigned mask) { GtkTextIter rhs = cursor; gtk_text_iter_set_offset(&rhs, gtk_text_iter_get_offset(&cursor) + 1); gtk_text_buffer_delete(textBuffer, &cursor, &rhs); - seekToMark(); + _seekToMark(); return true; } if(scancode >= 0x20 && scancode <= 0x7e) { if(gtk_text_iter_get_offset(&cursor) < gtk_text_iter_get_offset(&start)) return true; gtk_text_buffer_insert(textBuffer, &cursor, string{(char)scancode}, -1); - seekToMark(); + _seekToMark(); return true; } return false; } -void pConsole::seekToEnd() { +auto pConsole::_seekToEnd() -> void { GtkTextIter iter; gtk_text_buffer_get_end_iter(textBuffer, &iter); gtk_text_buffer_place_cursor(textBuffer, &iter); - seekToMark(); + _seekToMark(); } -void pConsole::seekToMark() { +auto pConsole::_seekToMark() -> void { GtkTextMark* mark = gtk_text_buffer_get_mark(textBuffer, "insert"); gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(subWidget), mark); } diff --git a/hiro/gtk/widget/console.hpp b/hiro/gtk/widget/console.hpp new file mode 100644 index 00000000..0d32a476 --- /dev/null +++ b/hiro/gtk/widget/console.hpp @@ -0,0 +1,23 @@ +namespace hiro { + +struct pConsole : pWidget { + Declare(Console, Widget) + + auto print(const string& text) -> void; + auto reset() -> void; + auto setBackgroundColor(Color color) -> void; + auto setForegroundColor(Color color) -> void; + auto setPrompt(const string& prompt) -> void; + + auto _keyPress(unsigned scancode, unsigned mask) -> bool; + auto _seekToEnd() -> void; + auto _seekToMark() -> void; + + GtkWidget* subWidget = nullptr; + GtkTextBuffer* textBuffer = nullptr; + string previousPrompt; + lstring history; + unsigned historyOffset = 0; +}; + +} diff --git a/hiro/gtk/widget/frame.cpp b/hiro/gtk/widget/frame.cpp new file mode 100644 index 00000000..30a1b180 --- /dev/null +++ b/hiro/gtk/widget/frame.cpp @@ -0,0 +1,66 @@ +namespace hiro { + +auto pFrame::construct() -> void { + gtkWidget = gtk_frame_new(nullptr); + gtkLabel = gtk_label_new(""); + gtk_frame_set_label_widget(GTK_FRAME(gtkWidget), gtkLabel); + gtk_widget_show(gtkLabel); + + setText(state().text); + + pWidget::construct(); +} + +auto pFrame::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pFrame::append(shared_pointer layout) -> void { + if(auto layout = _layout()) layout->setFont(layout->self().font(true)); +} + +auto pFrame::container(mWidget& widget) -> GtkWidget* { + return gtk_widget_get_parent(gtkWidget); +} + +auto pFrame::remove(shared_pointer layout) -> void { +} + +auto pFrame::setEnabled(bool enabled) -> void { + if(auto layout = _layout()) layout->setEnabled(layout->self().enabled(true)); + pWidget::setEnabled(enabled); +} + +auto pFrame::setFont(const string& font) -> void { + if(auto layout = _layout()) layout->setFont(layout->self().font(true)); + pFont::setFont(gtkLabel, font); +} + +auto pFrame::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + if(auto layout = state().layout) { + Size size = pFont::size(self().font(true), state().text); + if(!state().text) size.setHeight(10); + geometry.setX(geometry.x() + 2); + geometry.setY(geometry.y() + (size.height() - 1)); + geometry.setWidth(geometry.width() - 5); + geometry.setHeight(geometry.height() - (size.height() + 2)); + layout->setGeometry(geometry); + } +} + +auto pFrame::setText(const string& text) -> void { + gtk_label_set_text(GTK_LABEL(gtkLabel), text); +} + +auto pFrame::setVisible(bool visible) -> void { + if(auto layout = _layout()) layout->setVisible(layout->self().visible(true)); + pWidget::setVisible(visible); +} + +auto pFrame::_layout() -> pLayout* { + if(auto layout = state().layout) return layout->self(); + return nullptr; +} + +} diff --git a/hiro/gtk/widget/frame.hpp b/hiro/gtk/widget/frame.hpp new file mode 100644 index 00000000..5d09750e --- /dev/null +++ b/hiro/gtk/widget/frame.hpp @@ -0,0 +1,20 @@ +namespace hiro { + +struct pFrame : pWidget { + Declare(Frame, Widget) + + auto append(shared_pointer layout) -> void; + auto container(mWidget& widget) -> GtkWidget* override; + auto remove(shared_pointer layout) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const string& font) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _layout() -> pLayout*; + + GtkWidget* gtkLabel = nullptr; +}; + +} diff --git a/phoenix/gtk/widget/hex-edit.cpp b/hiro/gtk/widget/hex-edit.cpp similarity index 57% rename from phoenix/gtk/widget/hex-edit.cpp rename to hiro/gtk/widget/hex-edit.cpp index 08c10a78..03805517 100644 --- a/phoenix/gtk/widget/hex-edit.cpp +++ b/hiro/gtk/widget/hex-edit.cpp @@ -1,103 +1,29 @@ -namespace phoenix { +namespace hiro { -static bool HexEdit_keyPress(GtkWidget* widget, GdkEventKey* event, HexEdit* self) { - return self->p.keyPress(event->keyval, event->state); +static auto HexEdit_keyPress(GtkWidget* widget, GdkEventKey* event, pHexEdit* p) -> signed { + return p->keyPress(event->keyval, event->state); } -static bool HexEdit_mouseScroll(GtkWidget* widget, GdkEventScroll* event, HexEdit* self) { - double position = gtk_range_get_value(GTK_RANGE(self->p.scrollBar)); +static auto HexEdit_mouseScroll(GtkWidget* widget, GdkEventScroll* event, pHexEdit* p) -> signed { + double position = gtk_range_get_value(GTK_RANGE(p->scrollBar)); if(event->direction == GDK_SCROLL_UP) { - self->p.scroll(position - 1); + p->scroll(position - 1); } if(event->direction == GDK_SCROLL_DOWN) { - self->p.scroll(position + 1); + p->scroll(position + 1); } return true; //do not propagate event further } -static bool HexEdit_scroll(GtkRange* range, GtkScrollType scroll, double value, HexEdit* self) { - self->p.scroll((signed)value); +static auto HexEdit_scroll(GtkRange* range, GtkScrollType scroll, double value, pHexEdit* p) -> signed { + p->scroll((signed)value); return true; //do not propagate event further } -bool pHexEdit::focused() { - return GTK_WIDGET_HAS_FOCUS(subWidget) || GTK_WIDGET_HAS_FOCUS(scrollBar); -} - -void pHexEdit::setBackgroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, &gdkColor); -} - -void pHexEdit::setColumns(unsigned columns) { - setScroll(); - update(); -} - -void pHexEdit::setForegroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, &gdkColor); -} - -void pHexEdit::setLength(unsigned length) { - setScroll(); - update(); -} - -void pHexEdit::setOffset(unsigned offset) { - setScroll(); - updateScroll(); - update(); -} - -void pHexEdit::setRows(unsigned rows) { - setScroll(); - update(); -} - -void pHexEdit::update() { - if(!hexEdit.onRead) { - gtk_text_buffer_set_text(textBuffer, "", -1); - return; - } - - unsigned position = cursorPosition(); - - string output; - unsigned offset = hexEdit.state.offset; - for(unsigned row = 0; row < hexEdit.state.rows; row++) { - output.append(hex<8>(offset)); - output.append(" "); - - string hexdata; - string ansidata = " "; - for(unsigned column = 0; column < hexEdit.state.columns; column++) { - if(offset < hexEdit.state.length) { - uint8_t data = hexEdit.onRead(offset++); - hexdata.append(hex<2>(data)); - hexdata.append(" "); - ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.'); - } else { - hexdata.append(" "); - ansidata.append(" "); - } - } - - output.append(hexdata); - output.append(ansidata); - if(offset >= hexEdit.state.length) break; - if(row != hexEdit.state.rows - 1) output.append("\n"); - } - - gtk_text_buffer_set_text(textBuffer, output, -1); - if(position == 0) position = 10; //start at first position where hex values can be entered - setCursorPosition(position); -} - -void pHexEdit::constructor() { +auto pHexEdit::construct() -> void { gtkWidget = gtk_hbox_new(false, 0); container = gtk_scrolled_window_new(0, 0); @@ -108,15 +34,11 @@ void pHexEdit::constructor() { gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), false); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_NONE); gtk_container_add(GTK_CONTAINER(container), subWidget); - g_signal_connect(G_OBJECT(subWidget), "key-press-event", G_CALLBACK(HexEdit_keyPress), (gpointer)&hexEdit); - g_signal_connect(G_OBJECT(subWidget), "scroll-event", G_CALLBACK(HexEdit_mouseScroll), (gpointer)&hexEdit); scrollBar = gtk_vscrollbar_new((GtkAdjustment*)nullptr); gtk_range_set_range(GTK_RANGE(scrollBar), 0, 255); gtk_range_set_increments(GTK_RANGE(scrollBar), 1, 16); gtk_widget_set_sensitive(scrollBar, false); - g_signal_connect(G_OBJECT(scrollBar), "change-value", G_CALLBACK(HexEdit_scroll), (gpointer)&hexEdit); - g_signal_connect(G_OBJECT(scrollBar), "scroll-event", G_CALLBACK(HexEdit_mouseScroll), (gpointer)&hexEdit); gtk_box_pack_start(GTK_BOX(gtkWidget), container, true, true, 0); gtk_box_pack_start(GTK_BOX(gtkWidget), scrollBar, false, false, 1); @@ -128,38 +50,117 @@ void pHexEdit::constructor() { gtk_widget_show(subWidget); gtk_widget_show(container); - setColumns(hexEdit.state.columns); - setRows(hexEdit.state.rows); - setLength(hexEdit.state.length); - setOffset(hexEdit.state.offset); + setBackgroundColor(state().backgroundColor); + setColumns(state().columns); + setForegroundColor(state().foregroundColor); + setRows(state().rows); + setLength(state().length); + setOffset(state().offset); update(); + + g_signal_connect(G_OBJECT(subWidget), "key-press-event", G_CALLBACK(HexEdit_keyPress), (gpointer)this); + g_signal_connect(G_OBJECT(subWidget), "scroll-event", G_CALLBACK(HexEdit_mouseScroll), (gpointer)this); + + g_signal_connect(G_OBJECT(scrollBar), "change-value", G_CALLBACK(HexEdit_scroll), (gpointer)this); + g_signal_connect(G_OBJECT(scrollBar), "scroll-event", G_CALLBACK(HexEdit_mouseScroll), (gpointer)this); + + pWidget::construct(); } -void pHexEdit::destructor() { +auto pHexEdit::destruct() -> void { gtk_widget_destroy(scrollBar); gtk_widget_destroy(subWidget); gtk_widget_destroy(container); gtk_widget_destroy(gtkWidget); } -void pHexEdit::orphan() { - destructor(); - constructor(); +auto pHexEdit::focused() const -> bool { + return GTK_WIDGET_HAS_FOCUS(subWidget) || GTK_WIDGET_HAS_FOCUS(scrollBar); } -unsigned pHexEdit::cursorPosition() { +auto pHexEdit::setBackgroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pHexEdit::setColumns(unsigned columns) -> void { + setScroll(); + update(); +} + +auto pHexEdit::setForegroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pHexEdit::setLength(unsigned length) -> void { + setScroll(); + update(); +} + +auto pHexEdit::setOffset(unsigned offset) -> void { + setScroll(); + updateScroll(); + update(); +} + +auto pHexEdit::setRows(unsigned rows) -> void { + setScroll(); + update(); +} + +auto pHexEdit::update() -> void { + if(!state().onRead) { + gtk_text_buffer_set_text(textBuffer, "", -1); + return; + } + + unsigned position = cursorPosition(); + + string output; + unsigned offset = state().offset; + for(auto row : range(state().rows)) { + output.append(hex<8>(offset)); + output.append(" "); + + string hexdata; + string ansidata = " "; + for(auto column : range(state().columns)) { + if(offset < state().length) { + uint8_t data = self().doRead(offset++); + hexdata.append(hex<2>(data)); + hexdata.append(" "); + ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.'); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(offset >= state().length) break; + if(row != state().rows - 1) output.append("\n"); + } + + gtk_text_buffer_set_text(textBuffer, output, -1); + if(position == 0) position = 10; //start at first position where hex values can be entered + setCursorPosition(position); +} + +auto pHexEdit::cursorPosition() -> unsigned { GtkTextIter iter; gtk_text_buffer_get_iter_at_mark(textBuffer, &iter, textCursor); return gtk_text_iter_get_offset(&iter); } -bool pHexEdit::keyPress(unsigned scancode, unsigned mask) { - if(!hexEdit.onRead) return false; +auto pHexEdit::keyPress(unsigned scancode, unsigned mask) -> bool { + if(!state().onRead) return false; if(mask & (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK)) return false; //allow actions such as Ctrl+C (copy) signed position = cursorPosition(); - signed lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 1; + signed lineWidth = 10 + (state().columns * 3) + 1 + state().columns + 1; signed cursorY = position / lineWidth; signed cursorX = position % lineWidth; @@ -169,16 +170,16 @@ bool pHexEdit::keyPress(unsigned scancode, unsigned mask) { } if(scancode == GDK_End) { - setCursorPosition(cursorY * lineWidth + 10 + (hexEdit.state.columns * 3 - 1)); + setCursorPosition(cursorY * lineWidth + 10 + (state().columns * 3 - 1)); return true; } if(scancode == GDK_Up) { if(cursorY != 0) return false; - signed newOffset = hexEdit.state.offset - hexEdit.state.columns; + signed newOffset = state().offset - state().columns; if(newOffset >= 0) { - hexEdit.setOffset(newOffset); + self().setOffset(newOffset); update(); } return true; @@ -186,36 +187,36 @@ bool pHexEdit::keyPress(unsigned scancode, unsigned mask) { if(scancode == GDK_Down) { if(cursorY >= rows() - 1) return true; - if(cursorY != hexEdit.state.rows - 1) return false; + if(cursorY != state().rows - 1) return false; - signed newOffset = hexEdit.state.offset + hexEdit.state.columns; - if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) { - hexEdit.setOffset(newOffset); + signed newOffset = state().offset + state().columns; + if(newOffset + state().columns * state().rows - (state().columns - 1) <= state().length) { + self().setOffset(newOffset); update(); } return true; } if(scancode == GDK_Page_Up) { - signed newOffset = hexEdit.state.offset - hexEdit.state.columns * hexEdit.state.rows; + signed newOffset = state().offset - state().columns * state().rows; if(newOffset >= 0) { - hexEdit.setOffset(newOffset); + self().setOffset(newOffset); } else { - hexEdit.setOffset(0); + self().setOffset(0); } update(); return true; } if(scancode == GDK_Page_Down) { - signed newOffset = hexEdit.state.offset + hexEdit.state.columns * hexEdit.state.rows; - for(unsigned n = 0; n < hexEdit.state.rows; n++) { - if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) { - hexEdit.setOffset(newOffset); + signed newOffset = state().offset + state().columns * state().rows; + for(auto n : range(state().rows)) { + if(newOffset + state().columns * state().rows - (state().columns - 1) <= state().length) { + self().setOffset(newOffset); update(); break; } - newOffset -= hexEdit.state.columns; + newOffset -= state().columns; } return true; } @@ -233,12 +234,12 @@ bool pHexEdit::keyPress(unsigned scancode, unsigned mask) { //not on a space bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low cursorX /= 3; - if(cursorX < hexEdit.state.columns) { + if(cursorX < state().columns) { //not in ANSI region - unsigned offset = hexEdit.state.offset + (cursorY * hexEdit.state.columns + cursorX); + unsigned offset = state().offset + (cursorY * state().columns + cursorX); - if(offset >= hexEdit.state.length) return false; //do not edit past end of data - uint8_t data = hexEdit.onRead(offset); + if(offset >= state().length) return false; //do not edit past end of data + uint8_t data = self().doRead(offset); //write modified value if(cursorNibble == 1) { @@ -246,11 +247,11 @@ bool pHexEdit::keyPress(unsigned scancode, unsigned mask) { } else { data = (data & 0x0f) | (scancode << 4); } - if(hexEdit.onWrite) hexEdit.onWrite(offset, data); + self().doWrite(offset, data); //auto-advance cursor to next nibble/byte position++; - if(cursorNibble && cursorX != hexEdit.state.columns - 1) position++; + if(cursorNibble && cursorX != state().columns - 1) position++; setCursorPosition(position); //refresh output to reflect modified data @@ -263,22 +264,22 @@ bool pHexEdit::keyPress(unsigned scancode, unsigned mask) { } //number of actual rows -signed pHexEdit::rows() { - return (max(1u, hexEdit.state.length) + hexEdit.state.columns - 1) / hexEdit.state.columns; +auto pHexEdit::rows() -> signed { + return (max(1u, state().length) + state().columns - 1) / state().columns; } //number of scrollable row positions -signed pHexEdit::rowsScrollable() { - return max(0u, rows() - hexEdit.state.rows); +auto pHexEdit::rowsScrollable() -> signed { + return max(0u, rows() - state().rows); } -void pHexEdit::scroll(signed position) { +auto pHexEdit::scroll(signed position) -> void { if(position > rowsScrollable()) position = rowsScrollable(); if(position < 0) position = 0; - hexEdit.setOffset(position * hexEdit.state.columns); + self().setOffset(position * state().columns); } -void pHexEdit::setCursorPosition(unsigned position) { +auto pHexEdit::setCursorPosition(unsigned position) -> void { GtkTextIter iter; gtk_text_buffer_get_iter_at_mark(textBuffer, &iter, textCursor); @@ -291,7 +292,7 @@ void pHexEdit::setCursorPosition(unsigned position) { gtk_text_buffer_place_cursor(textBuffer, &iter); } -void pHexEdit::setScroll() { +auto pHexEdit::setScroll() -> void { if(rowsScrollable() > 0) { gtk_range_set_range(GTK_RANGE(scrollBar), 0, rowsScrollable()); gtk_widget_set_sensitive(scrollBar, true); @@ -300,8 +301,8 @@ void pHexEdit::setScroll() { } } -void pHexEdit::updateScroll() { - unsigned row = hexEdit.state.offset / hexEdit.state.columns; +auto pHexEdit::updateScroll() -> void { + unsigned row = state().offset / state().columns; gtk_range_set_value(GTK_RANGE(scrollBar), row); } diff --git a/hiro/gtk/widget/hex-edit.hpp b/hiro/gtk/widget/hex-edit.hpp new file mode 100644 index 00000000..685d7d28 --- /dev/null +++ b/hiro/gtk/widget/hex-edit.hpp @@ -0,0 +1,31 @@ +namespace hiro { + +struct pHexEdit : pWidget { + Declare(HexEdit, Widget) + + auto focused() const -> bool override; + auto setBackgroundColor(Color color) -> void; + auto setColumns(unsigned columns) -> void; + auto setForegroundColor(Color color) -> void; + auto setLength(unsigned length) -> void; + auto setOffset(unsigned offset) -> void; + auto setRows(unsigned rows) -> void; + auto update() -> void; + + auto cursorPosition() -> unsigned; + auto keyPress(unsigned scancode, unsigned mask) -> bool; + auto rows() -> signed; + auto rowsScrollable() -> signed; + auto scroll(signed position) -> void; + auto setCursorPosition(unsigned position) -> void; + auto setScroll() -> void; + auto updateScroll() -> void; + + GtkWidget* container = nullptr; + GtkWidget* subWidget = nullptr; + GtkWidget* scrollBar = nullptr; + GtkTextBuffer* textBuffer = nullptr; + GtkTextMark* textCursor = nullptr; +}; + +} diff --git a/hiro/gtk/widget/horizontal-scroller.cpp b/hiro/gtk/widget/horizontal-scroller.cpp new file mode 100644 index 00000000..d8dc7ede --- /dev/null +++ b/hiro/gtk/widget/horizontal-scroller.cpp @@ -0,0 +1,41 @@ +namespace hiro { + +static auto HorizontalScroller_change(GtkRange* gtkRange, pHorizontalScroller* p) -> void { + auto position = (unsigned)gtk_range_get_value(gtkRange); + if(p->state().position == position) return; + p->state().position = position; + if(!p->locked()) p->self().doChange(); +} + +auto pHorizontalScroller::construct() -> void { + gtkWidget = gtk_hscrollbar_new(0); + + setLength(state().length); + setPosition(state().position); + + g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalScroller_change), (gpointer)this); + + pWidget::construct(); +} + +auto pHorizontalScroller::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pHorizontalScroller::minimumSize() const -> Size { + return {0, 20}; +} + +auto pHorizontalScroller::setLength(unsigned length) -> void { + lock(); + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); + unlock(); +} + +auto pHorizontalScroller::setPosition(unsigned position) -> void { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +} diff --git a/hiro/gtk/widget/horizontal-scroller.hpp b/hiro/gtk/widget/horizontal-scroller.hpp new file mode 100644 index 00000000..a522f0bb --- /dev/null +++ b/hiro/gtk/widget/horizontal-scroller.hpp @@ -0,0 +1,11 @@ +namespace hiro { + +struct pHorizontalScroller : pWidget { + Declare(HorizontalScroller, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; +}; + +} diff --git a/hiro/gtk/widget/horizontal-slider.cpp b/hiro/gtk/widget/horizontal-slider.cpp new file mode 100644 index 00000000..dbd2c379 --- /dev/null +++ b/hiro/gtk/widget/horizontal-slider.cpp @@ -0,0 +1,40 @@ +namespace hiro { + +static auto HorizontalSlider_change(GtkRange* gtkRange, pHorizontalSlider* p) -> void { + auto position = (unsigned)gtk_range_get_value(gtkRange); + if(p->state().position == position) return; + p->state().position = position; + if(!p->locked()) p->self().doChange(); +} + +auto pHorizontalSlider::construct() -> void { + gtkWidget = gtk_hscale_new_with_range(0, 100, 1); + gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); + + setLength(state().length); + setPosition(state().position); + + g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)this); + + pWidget::construct(); +} + +auto pHorizontalSlider::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pHorizontalSlider::minimumSize() const -> Size { + return {0, 20}; +} + +auto pHorizontalSlider::setLength(unsigned length) -> void { + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); +} + +auto pHorizontalSlider::setPosition(unsigned position) -> void { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +} diff --git a/hiro/gtk/widget/horizontal-slider.hpp b/hiro/gtk/widget/horizontal-slider.hpp new file mode 100644 index 00000000..c24fc004 --- /dev/null +++ b/hiro/gtk/widget/horizontal-slider.hpp @@ -0,0 +1,11 @@ +namespace hiro { + +struct pHorizontalSlider : pWidget { + Declare(HorizontalSlider, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; +}; + +} diff --git a/hiro/gtk/widget/icon-view-item.cpp b/hiro/gtk/widget/icon-view-item.cpp new file mode 100644 index 00000000..fa985855 --- /dev/null +++ b/hiro/gtk/widget/icon-view-item.cpp @@ -0,0 +1,32 @@ +namespace hiro { + +auto pIconViewItem::construct() -> void { +} + +auto pIconViewItem::destruct() -> void { +} + +auto pIconViewItem::setIcon(const image& icon) -> void { + if(auto parent = _parent()) { + parent->setItemIcon(self().offset(), icon); + } +} + +auto pIconViewItem::setSelected(bool selected) -> void { + if(auto parent = _parent()) { + parent->setItemSelected(self().offset(), selected); + } +} + +auto pIconViewItem::setText(const string& text) -> void { + if(auto parent = _parent()) { + parent->setItemText(self().offset(), text); + } +} + +auto pIconViewItem::_parent() -> pIconView* { + if(auto parent = self().parentIconView()) return parent->self(); + return nullptr; +} + +} diff --git a/hiro/gtk/widget/icon-view-item.hpp b/hiro/gtk/widget/icon-view-item.hpp new file mode 100644 index 00000000..4e8fad46 --- /dev/null +++ b/hiro/gtk/widget/icon-view-item.hpp @@ -0,0 +1,13 @@ +namespace hiro { + +struct pIconViewItem : pObject { + Declare(IconViewItem, Object) + + auto setIcon(const image& icon) -> void; + auto setSelected(bool selected) -> void; + auto setText(const string& text) -> void; + + auto _parent() -> pIconView*; +}; + +} diff --git a/hiro/gtk/widget/icon-view.cpp b/hiro/gtk/widget/icon-view.cpp new file mode 100644 index 00000000..73f242eb --- /dev/null +++ b/hiro/gtk/widget/icon-view.cpp @@ -0,0 +1,224 @@ +namespace hiro { + +static auto IconView_activate(GtkIconView* iconView, GtkTreePath* path, pIconView* p) -> void { + if(!p->locked()) p->self().doActivate(); +} + +static auto IconView_buttonEvent(GtkTreeView* treeView, GdkEventButton* event, pIconView* p) -> signed { + if(event->type == GDK_BUTTON_RELEASE && event->button == 3) { + if(!p->locked()) p->self().doContext(); + return false; + } + + return false; +} + +static auto IconView_change(GtkIconView* iconView, pIconView* p) -> void { + p->_updateSelected(); +} + +auto pIconView::construct() -> void { + gtkWidget = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); + + store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING); + subWidget = gtk_icon_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_icon_view_set_pixbuf_column(GTK_ICON_VIEW(subWidget), 0); + gtk_icon_view_set_text_column(GTK_ICON_VIEW(subWidget), 1); + gtk_icon_view_set_reorderable(GTK_ICON_VIEW(subWidget), false); + gtk_icon_view_set_margin(GTK_ICON_VIEW(subWidget), 0); + gtk_icon_view_set_spacing(GTK_ICON_VIEW(subWidget), 0); + gtk_icon_view_set_column_spacing(GTK_ICON_VIEW(subWidget), 0); + gtk_icon_view_set_row_spacing(GTK_ICON_VIEW(subWidget), 0); + gtk_icon_view_set_item_padding(GTK_ICON_VIEW(subWidget), 0); + gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); + + gtk_widget_show(subWidget); + + setBackgroundColor(state().backgroundColor); + setFlow(state().flow); + setForegroundColor(state().foregroundColor); + setMultiSelect(state().multiSelect); + setOrientation(state().orientation); + for(auto position : range(self().items())) { + auto& item = state().items[position]; + append(item); + } + _updateSelected(); + + g_signal_connect(G_OBJECT(subWidget), "button-press-event", G_CALLBACK(IconView_buttonEvent), (gpointer)this); + g_signal_connect(G_OBJECT(subWidget), "button-release-event", G_CALLBACK(IconView_buttonEvent), (gpointer)this); + g_signal_connect(G_OBJECT(subWidget), "item-activated", G_CALLBACK(IconView_activate), (gpointer)this); + g_signal_connect(G_OBJECT(subWidget), "selection-changed", G_CALLBACK(IconView_change), (gpointer)this); + + pWidget::construct(); +} + +auto pIconView::destruct() -> void { + gtk_widget_destroy(subWidget); + gtk_widget_destroy(gtkWidget); +} + +auto pIconView::append(sIconViewItem item) -> void { + GtkTreeIter iter; + gtk_list_store_append(store, &iter); + setItemIcon(item->offset(), item->state.icon); + setItemSelected(item->offset(), item->state.selected); + setItemText(item->offset(), item->state.text); +} + +auto pIconView::remove(sIconViewItem item) -> void { + lock(); + GtkTreeIter iter; + if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, string{item->offset()})) { + gtk_list_store_remove(store, &iter); + } + _updateSelected(); + unlock(); +} + +auto pIconView::reset() -> void { + lock(); + gtk_list_store_clear(store); + _updateSelected(); + unlock(); +} + +auto pIconView::setBackgroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pIconView::setFlow(Orientation flow) -> void { + //GTK+ does not support vertical flow ... the closest we can get is a horizontal flow with only one column + if(flow == Orientation::Horizontal) { + gtk_icon_view_set_columns(GTK_ICON_VIEW(subWidget), -1); + gtk_icon_view_set_item_width(GTK_ICON_VIEW(subWidget), -1); + } else { + gtk_icon_view_set_columns(GTK_ICON_VIEW(subWidget), 1); + gtk_icon_view_set_item_width(GTK_ICON_VIEW(subWidget), max(128, pSizable::state().geometry.width() - 64)); + } +} + +auto pIconView::setForegroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pIconView::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + if(state().flow == Orientation::Vertical) { + gtk_icon_view_set_item_width(GTK_ICON_VIEW(subWidget), max(128, pSizable::state().geometry.width() - 64)); + } +} + +auto pIconView::setItemIcon(unsigned position, const image& icon) -> void { + if(position >= self().items()) return; + GtkTreeIter iter; + if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, string{position})) { + if(icon) { + GdkPixbuf* pixbuf = CreatePixbuf(icon); + gtk_list_store_set(store, &iter, 0, pixbuf, -1); + } else { + gtk_list_store_set(store, &iter, 0, nullptr, -1); + } + } +} + +auto pIconView::setItemSelected(unsigned position, bool selected) -> void { + if(position >= self().items()) return; + lock(); + GtkTreePath* path = gtk_tree_path_new_from_string(string{position}); + if(selected) { + gtk_icon_view_select_path(GTK_ICON_VIEW(subWidget), path); + } else { + gtk_icon_view_unselect_path(GTK_ICON_VIEW(subWidget), path); + } + gtk_tree_path_free(path); + _updateSelected(); + unlock(); +} + +auto pIconView::setItemSelected(const vector& selections) -> void { + lock(); + setItemSelectedNone(); + for(auto& position : selections) setItemSelected(position, true); + _updateSelected(); + unlock(); +} + +auto pIconView::setItemSelectedAll() -> void { + lock(); + gtk_icon_view_select_all(GTK_ICON_VIEW(subWidget)); + _updateSelected(); + unlock(); +} + +auto pIconView::setItemSelectedNone() -> void { + lock(); + gtk_icon_view_unselect_all(GTK_ICON_VIEW(subWidget)); + _updateSelected(); + unlock(); +} + +auto pIconView::setItemText(unsigned position, const string& text) -> void { + if(position >= self().items()) return; + GtkTreeIter iter; + if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, string{position})) { + gtk_list_store_set(store, &iter, 1, (const char*)text, -1); + } +} + +auto pIconView::setMultiSelect(bool multiSelect) -> void { + gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(subWidget), + multiSelect ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE + ); +} + +auto pIconView::setOrientation(Orientation orientation) -> void { + gtk_icon_view_set_item_orientation(GTK_ICON_VIEW(subWidget), + orientation == Orientation::Horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL + ); +} + +auto pIconView::_updateSelected() -> void { + vector selected; + + GList* list = gtk_icon_view_get_selected_items(GTK_ICON_VIEW(subWidget)); + GList* p = list; + + while(p) { + auto path = (GtkTreePath*)p->data; + char* pathString = gtk_tree_path_to_string(path); + unsigned position = decimal(pathString); + g_free(pathString); + selected.append(position); + p = p->next; + } + + g_list_foreach(list, (GFunc)gtk_tree_path_free, nullptr); + g_list_free(list); + + bool identical = selected.size() == currentSelection.size(); + if(identical) { + for(unsigned n = 0; n < selected.size(); n++) { + if(selected[n] != currentSelection[n]) { + identical = false; + break; + } + } + } + if(identical) return; + + currentSelection = selected; + for(auto& item : state().items) item->state.selected = false; + for(auto& position : currentSelection) { + if(position >= self().items()) continue; + state().items[position]->state.selected = true; + } + + if(!locked()) self().doChange(); +} + +} diff --git a/hiro/gtk/widget/icon-view.hpp b/hiro/gtk/widget/icon-view.hpp new file mode 100644 index 00000000..41447b6b --- /dev/null +++ b/hiro/gtk/widget/icon-view.hpp @@ -0,0 +1,29 @@ +namespace hiro { + +struct pIconView : pWidget { + Declare(IconView, Widget) + + auto append(sIconViewItem item) -> void; + auto remove(sIconViewItem item) -> void; + auto reset() -> void; + auto setBackgroundColor(Color color) -> void; + auto setFlow(Orientation flow) -> void; + auto setForegroundColor(Color color) -> void; + auto setGeometry(Geometry geometry) -> void; + auto setItemIcon(unsigned position, const image& icon) -> void; + auto setItemSelected(unsigned position, bool selected) -> void; + auto setItemSelected(const vector& selections) -> void; + auto setItemSelectedAll() -> void; + auto setItemSelectedNone() -> void; + auto setItemText(unsigned position, const string& text) -> void; + auto setMultiSelect(bool multiSelect) -> void; + auto setOrientation(Orientation orientation) -> void; + + auto _updateSelected() -> void; + + GtkWidget* subWidget = nullptr; + GtkListStore* store = nullptr; + vector currentSelection; +}; + +} diff --git a/hiro/gtk/widget/label.cpp b/hiro/gtk/widget/label.cpp new file mode 100644 index 00000000..69766178 --- /dev/null +++ b/hiro/gtk/widget/label.cpp @@ -0,0 +1,41 @@ +namespace hiro { + +auto pLabel::construct() -> void { + gtkWidget = gtk_label_new(""); + + _setAlignment(); + setText(state().text); + + pWidget::construct(); +} + +auto pLabel::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pLabel::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + return {size.width(), size.height()}; +} + +auto pLabel::setHorizontalAlignment(double alignment) -> void { + _setAlignment(); +} + +auto pLabel::setText(const string& text) -> void { + gtk_label_set_text(GTK_LABEL(gtkWidget), text); +} + +auto pLabel::setVerticalAlignment(double alignment) -> void { + _setAlignment(); +} + +auto pLabel::_setAlignment() -> void { + gtk_misc_set_alignment(GTK_MISC(gtkWidget), state().horizontalAlignment, state().verticalAlignment); + auto justify = GTK_JUSTIFY_CENTER; + if(state().horizontalAlignment < 0.333) justify = GTK_JUSTIFY_LEFT; + if(state().horizontalAlignment > 0.666) justify = GTK_JUSTIFY_RIGHT; + gtk_label_set_justify(GTK_LABEL(gtkWidget), justify); +} + +} diff --git a/hiro/gtk/widget/label.hpp b/hiro/gtk/widget/label.hpp new file mode 100644 index 00000000..6a79bb14 --- /dev/null +++ b/hiro/gtk/widget/label.hpp @@ -0,0 +1,14 @@ +namespace hiro { + +struct pLabel : pWidget { + Declare(Label, Widget) + + auto minimumSize() const -> Size override; + auto setHorizontalAlignment(double alignment) -> void; + auto setText(const string& text) -> void; + auto setVerticalAlignment(double alignment) -> void; + + auto _setAlignment() -> void; +}; + +} diff --git a/hiro/gtk/widget/line-edit.cpp b/hiro/gtk/widget/line-edit.cpp new file mode 100644 index 00000000..0fb689b5 --- /dev/null +++ b/hiro/gtk/widget/line-edit.cpp @@ -0,0 +1,55 @@ +namespace hiro { + +static auto LineEdit_activate(GtkEntry*, pLineEdit* p) -> void { + p->self().doActivate(); +} + +static auto LineEdit_change(GtkEditable*, pLineEdit* p) -> void { + p->state().text = gtk_entry_get_text(GTK_ENTRY(p->gtkWidget)); + if(!p->locked()) p->self().doChange(); +} + +auto pLineEdit::construct() -> void { + gtkWidget = gtk_entry_new(); + + setBackgroundColor(state().backgroundColor); + setEditable(state().editable); + setForegroundColor(state().foregroundColor); + setText(state().text); + + g_signal_connect(G_OBJECT(gtkWidget), "activate", G_CALLBACK(LineEdit_activate), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "changed", G_CALLBACK(LineEdit_change), (gpointer)this); + + pWidget::construct(); +} + +auto pLineEdit::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pLineEdit::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + return {size.width() + 10, size.height() + 10}; +} + +auto pLineEdit::setBackgroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_base(gtkWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pLineEdit::setEditable(bool editable) -> void { + gtk_editable_set_editable(GTK_EDITABLE(gtkWidget), editable); +} + +auto pLineEdit::setForegroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_text(gtkWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pLineEdit::setText(const string& text) -> void { + lock(); + gtk_entry_set_text(GTK_ENTRY(gtkWidget), text); + unlock(); +} + +} diff --git a/hiro/gtk/widget/line-edit.hpp b/hiro/gtk/widget/line-edit.hpp new file mode 100644 index 00000000..243278d6 --- /dev/null +++ b/hiro/gtk/widget/line-edit.hpp @@ -0,0 +1,13 @@ +namespace hiro { + +struct pLineEdit : pWidget { + Declare(LineEdit, Widget) + + auto minimumSize() const -> Size; + auto setBackgroundColor(Color color) -> void; + auto setEditable(bool editable) -> void; + auto setForegroundColor(Color color) -> void; + auto setText(const string& text) -> void; +}; + +} diff --git a/hiro/gtk/widget/list-view-column.cpp b/hiro/gtk/widget/list-view-column.cpp new file mode 100644 index 00000000..ffe9ae24 --- /dev/null +++ b/hiro/gtk/widget/list-view-column.cpp @@ -0,0 +1,133 @@ +namespace hiro { + +auto pListViewColumn::construct() -> void { + unsigned offset = self().offset(); + + gtkHeader = gtk_hbox_new(false, 0); + + gtkHeaderIcon = gtk_image_new(); + gtk_box_pack_start(GTK_BOX(gtkHeader), gtkHeaderIcon, false, false, 0); + + gtkHeaderText = gtk_label_new(state().text); + gtk_box_pack_start(GTK_BOX(gtkHeader), gtkHeaderText, true, false, 2); + + gtkColumn = gtk_tree_view_column_new(); + gtk_tree_view_column_set_sizing(gtkColumn, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_title(gtkColumn, ""); + gtk_tree_view_column_set_widget(gtkColumn, gtkHeader); + + if(offset == 0) { + gtkCellToggle = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(gtkColumn, gtkCellToggle, false); + gtk_tree_view_column_set_attributes(gtkColumn, gtkCellToggle, "active", 0, nullptr); + } + + gtkCellIcon = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(gtkColumn, gtkCellIcon, false); + gtk_tree_view_column_set_attributes(gtkColumn, gtkCellIcon, "pixbuf", 1 + offset * 2 + 0, nullptr); + + gtkCellText = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(gtkColumn, gtkCellText, false); + gtk_tree_view_column_set_attributes(gtkColumn, gtkCellText, "text", 1 + offset * 2 + 1, nullptr); + + g_signal_connect(G_OBJECT(gtkColumn), "clicked", G_CALLBACK(ListView_headerActivate), (gpointer)_parent()); + g_signal_connect(G_OBJECT(gtkCellText), "edited", G_CALLBACK(ListView_edit), (gpointer)_parent()); + if(gtkCellToggle) g_signal_connect(G_OBJECT(gtkCellToggle), "toggled", G_CALLBACK(ListView_toggle), (gpointer)_parent()); +} + +auto pListViewColumn::destruct() -> void { +} + +auto pListViewColumn::setActive() -> void { + if(auto parent = _parent()) { + gtk_tree_view_set_search_column(parent->gtkTreeView, 1 + self().offset() * 2 + 1); + } +} + +auto pListViewColumn::setBackgroundColor(Color color) -> void { + if(color) { + GdkColor gdkColor = CreateColor(color); + if(gtkCellToggle) g_object_set(G_OBJECT(gtkCellToggle), "cell-background-gdk", &gdkColor, nullptr); + g_object_set(G_OBJECT(gtkCellIcon), "cell-background-gdk", &gdkColor, nullptr); + g_object_set(G_OBJECT(gtkCellText), "cell-background-gdk", &gdkColor, nullptr); + } else { + if(gtkCellToggle) g_object_set(G_OBJECT(gtkCellToggle), "cell-background-set", FALSE, nullptr); + g_object_set(G_OBJECT(gtkCellIcon), "cell-background-set", FALSE, nullptr); + g_object_set(G_OBJECT(gtkCellText), "cell-background-set", FALSE, nullptr); + } +} + +auto pListViewColumn::setEditable(bool editable) -> void { + g_object_set(G_OBJECT(gtkCellText), "editable", editable ? TRUE : FALSE, nullptr); +} + +auto pListViewColumn::setFont(const string& font) -> void { + pFont::setFont(gtkHeaderText, font); + auto fontDescription = pFont::create(font); + g_object_set(G_OBJECT(gtkCellText), "font-desc", fontDescription, nullptr); + pango_font_description_free(fontDescription); +} + +auto pListViewColumn::setForegroundColor(Color color) -> void { + if(color) { + GdkColor gdkColor = CreateColor(color); + g_object_set(G_OBJECT(gtkCellText), "foreground-gdk", &gdkColor, nullptr); + } else { + g_object_set(G_OBJECT(gtkCellText), "foreground-set", FALSE, nullptr); + } +} + +auto pListViewColumn::setHorizontalAlignment(double alignment) -> void { + _setAlignment(); +} + +auto pListViewColumn::setIcon(const image& icon) -> void { + if(icon) { + gtk_image_set_from_pixbuf(GTK_IMAGE(gtkHeaderIcon), CreatePixbuf(icon)); + } else { + gtk_image_clear(GTK_IMAGE(gtkHeaderIcon)); + } +} + +auto pListViewColumn::setResizable(bool resizable) -> void { + gtk_tree_view_column_set_resizable(gtkColumn, resizable); +} + +auto pListViewColumn::setSortable(bool sortable) -> void { + gtk_tree_view_column_set_clickable(gtkColumn, sortable); +} + +auto pListViewColumn::setText(const string& text) -> void { + gtk_label_set_text(GTK_LABEL(gtkHeaderText), text); +} + +auto pListViewColumn::setVerticalAlignment(double alignment) -> void { + _setAlignment(); +} + +auto pListViewColumn::setVisible(bool visible) -> void { + gtk_tree_view_column_set_visible(gtkColumn, visible); +} + +auto pListViewColumn::setWidth(signed width) -> void { + if(auto parent = _parent()) { + parent->resizeColumns(); + } +} + +auto pListViewColumn::_parent() -> pListView* { + if(auto parent = self().parentListView()) return parent->self(); + return nullptr; +} + +auto pListViewColumn::_setAlignment() -> void { + gtk_tree_view_column_set_alignment(gtkColumn, state().horizontalAlignment); + gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(gtkCellText), state().horizontalAlignment, state().verticalAlignment); + //set multi-line text alignment + auto pangoAlignment = PANGO_ALIGN_CENTER; + if(state().horizontalAlignment < 0.333) pangoAlignment = PANGO_ALIGN_LEFT; + if(state().horizontalAlignment > 0.666) pangoAlignment = PANGO_ALIGN_RIGHT; + g_object_set(G_OBJECT(gtkCellText), "alignment", pangoAlignment, nullptr); +} + +} diff --git a/hiro/gtk/widget/list-view-column.hpp b/hiro/gtk/widget/list-view-column.hpp new file mode 100644 index 00000000..42394ad1 --- /dev/null +++ b/hiro/gtk/widget/list-view-column.hpp @@ -0,0 +1,32 @@ +namespace hiro { + +struct pListViewColumn : pObject { + Declare(ListViewColumn, Object) + + auto setActive() -> void; + auto setBackgroundColor(Color color) -> void; + auto setEditable(bool editable) -> void; + auto setFont(const string& font) -> void override; + auto setForegroundColor(Color color) -> void; + auto setHorizontalAlignment(double alignment) -> void; + auto setIcon(const image& icon) -> void; + auto setResizable(bool resizable) -> void; + auto setSortable(bool sortable) -> void; + auto setText(const string& text) -> void; + auto setVerticalAlignment(double alignment) -> void; + auto setVisible(bool visible) -> void override; + auto setWidth(signed width) -> void; + + auto _parent() -> pListView*; + auto _setAlignment() -> void; + + GtkTreeViewColumn* gtkColumn = nullptr; + GtkWidget* gtkHeader = nullptr; + GtkWidget* gtkHeaderIcon = nullptr; + GtkWidget* gtkHeaderText = nullptr; + GtkCellRenderer* gtkCellToggle = nullptr; + GtkCellRenderer* gtkCellIcon = nullptr; + GtkCellRenderer* gtkCellText = nullptr; +}; + +} diff --git a/hiro/gtk/widget/list-view-item.cpp b/hiro/gtk/widget/list-view-item.cpp new file mode 100644 index 00000000..3e7617dd --- /dev/null +++ b/hiro/gtk/widget/list-view-item.cpp @@ -0,0 +1,59 @@ +namespace hiro { + +auto pListViewItem::construct() -> void { +} + +auto pListViewItem::destruct() -> void { +} + +auto pListViewItem::setChecked(bool checked) -> void { + if(auto parent = _parent()) { + gtk_list_store_set(parent->gtkListStore, >kIter, 0, checked, -1); + } +} + +auto pListViewItem::setFocused() -> void { + if(auto parent = _parent()) { + GtkTreePath* path = gtk_tree_path_new_from_string(string{self().offset()}); + gtk_tree_view_set_cursor(parent->gtkTreeView, path, nullptr, false); + gtk_tree_view_scroll_to_cell(parent->gtkTreeView, path, nullptr, true, 0.5, 0.0); + gtk_tree_path_free(path); + } +} + +auto pListViewItem::setIcon(unsigned column, const image& icon) -> void { + if(auto parent = _parent()) { + if(icon) { + auto pixbuf = CreatePixbuf(icon, true); + gtk_list_store_set(parent->gtkListStore, >kIter, 1 + column * 2, pixbuf, -1); + } else { + gtk_list_store_set(parent->gtkListStore, >kIter, 1 + column * 2, nullptr, -1); + } + } +} + +auto pListViewItem::setSelected(bool selected) -> void { + if(auto parent = _parent()) { + parent->lock(); + if(selected) { + gtk_tree_selection_select_iter(parent->gtkTreeSelection, >kIter); + } else { + gtk_tree_selection_unselect_iter(parent->gtkTreeSelection, >kIter); + } + parent->_updateSelected(); + parent->unlock(); + } +} + +auto pListViewItem::setText(unsigned column, const string& text) -> void { + if(auto parent = _parent()) { + gtk_list_store_set(parent->gtkListStore, >kIter, 1 + column * 2 + 1, text.data(), -1); + } +} + +auto pListViewItem::_parent() -> pListView* { + if(auto parent = self().parentListView()) return parent->self(); + return nullptr; +} + +} diff --git a/hiro/gtk/widget/list-view-item.hpp b/hiro/gtk/widget/list-view-item.hpp new file mode 100644 index 00000000..fd584e3b --- /dev/null +++ b/hiro/gtk/widget/list-view-item.hpp @@ -0,0 +1,17 @@ +namespace hiro { + +struct pListViewItem : pObject { + Declare(ListViewItem, Object) + + auto setChecked(bool checked) -> void; + auto setFocused() -> void; + auto setIcon(unsigned column, const image& icon) -> void; + auto setSelected(bool selected) -> void; + auto setText(unsigned column, const string& text) -> void; + + auto _parent() -> pListView*; + + GtkTreeIter gtkIter; +}; + +} diff --git a/hiro/gtk/widget/list-view.cpp b/hiro/gtk/widget/list-view.cpp new file mode 100644 index 00000000..79b75943 --- /dev/null +++ b/hiro/gtk/widget/list-view.cpp @@ -0,0 +1,369 @@ +namespace hiro { + +static auto ListView_activate(GtkTreeView*, GtkTreePath*, GtkTreeViewColumn*, pListView* p) -> void { return p->_doActivate(); } +static auto ListView_buttonEvent(GtkTreeView* treeView, GdkEventButton* event, pListView* p) -> signed { return p->_doEvent(event); } +static auto ListView_change(GtkTreeSelection*, pListView* p) -> void { return p->_doChange(); } +static auto ListView_edit(GtkCellRendererText* renderer, const char* path, const char* text, pListView* p) -> void { return p->_doEdit(renderer, path, text); } +static auto ListView_headerActivate(GtkTreeViewColumn* column, pListView* p) -> void { return p->_doHeaderActivate(column); } +static auto ListView_mouseMoveEvent(GtkWidget*, GdkEvent*, pListView* p) -> signed { return p->_doMouseMove(); } +static auto ListView_popup(GtkTreeView*, pListView* p) -> void { return p->_doContext(); } +static auto ListView_toggle(GtkCellRendererToggle*, const char* path, pListView* p) -> void { return p->_doToggle(path); } + +auto pListView::construct() -> void { + gtkWidget = gtk_scrolled_window_new(0, 0); + gtkScrolledWindow = GTK_SCROLLED_WINDOW(gtkWidget); + gtk_scrolled_window_set_policy(gtkScrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(gtkScrolledWindow, GTK_SHADOW_ETCHED_IN); + + gtkWidgetChild = gtk_tree_view_new(); + gtkTreeView = GTK_TREE_VIEW(gtkWidgetChild); + gtkTreeSelection = gtk_tree_view_get_selection(gtkTreeView); + gtk_container_add(GTK_CONTAINER(gtkWidget), gtkWidgetChild); + gtk_tree_view_set_rubber_banding(gtkTreeView, true); + + gtk_widget_show(gtkWidgetChild); + + setBackgroundColor(state().backgroundColor); + setCheckable(state().checkable); + setFont(self().font(true)); + setForegroundColor(state().foregroundColor); + setGridVisible(state().gridVisible); + setHeaderVisible(state().headerVisible); + setMultiSelect(state().multiSelect); + + g_signal_connect(G_OBJECT(gtkTreeView), "button-press-event", G_CALLBACK(ListView_buttonEvent), (gpointer)this); + g_signal_connect(G_OBJECT(gtkTreeView), "button-release-event", G_CALLBACK(ListView_buttonEvent), (gpointer)this); + g_signal_connect(G_OBJECT(gtkTreeView), "motion-notify-event", G_CALLBACK(ListView_mouseMoveEvent), (gpointer)this); + g_signal_connect(G_OBJECT(gtkTreeView), "popup-menu", G_CALLBACK(ListView_popup), (gpointer)this); + g_signal_connect(G_OBJECT(gtkTreeView), "row-activated", G_CALLBACK(ListView_activate), (gpointer)this); + g_signal_connect(G_OBJECT(gtkTreeSelection), "changed", G_CALLBACK(ListView_change), (gpointer)this); + + pWidget::construct(); +} + +auto pListView::destruct() -> void { + gtk_widget_destroy(gtkWidgetChild); + gtk_widget_destroy(gtkWidget); +} + +auto pListView::append(sListViewColumn column) -> void { + gtk_tree_view_append_column(gtkTreeView, column->self()->gtkColumn); + gtk_widget_show_all(column->self()->gtkHeader); + column->setFont(column->font()); + setCheckable(state().checkable); + _createModel(); + gtk_tree_view_set_rules_hint(gtkTreeView, self().columns() >= 2); //two or more columns + checkbutton column +} + +auto pListView::append(sListViewItem item) -> void { + gtk_list_store_append(gtkListStore, &item->self()->gtkIter); + + item->setChecked(item->checked()); + item->setSelected(item->selected()); + for(auto column : range(self().columns())) { + item->setIcon(column, item->state.icon(column, {})); + item->setText(column, item->state.text(column, "")); + } +} + +auto pListView::focused() -> bool { + return GTK_WIDGET_HAS_FOCUS(gtkTreeView); +} + +auto pListView::remove(sListViewColumn column) -> void { + if(auto delegate = column->self()) { + gtk_tree_view_remove_column(gtkTreeView, delegate->gtkColumn); + delegate->gtkColumn = nullptr; + } + _createModel(); + gtk_tree_view_set_rules_hint(gtkTreeView, self().columns() >= 2); //two or more columns + checkbutton column +} + +auto pListView::remove(sListViewItem item) -> void { + lock(); + if(auto delegate = item->self()) { + gtk_list_store_remove(gtkListStore, &delegate->gtkIter); + _updateSelected(); + } + unlock(); +} + +auto pListView::reset() -> void { + GList* list = gtk_tree_view_get_columns(gtkTreeView), *p = list; + while(p && p->data) { + gtk_tree_view_remove_column(gtkTreeView, (GtkTreeViewColumn*)p->data); + p = p->next; + } + g_list_free(list); + _createModel(); + gtk_tree_view_set_rules_hint(gtkTreeView, false); +} + +//column widths: +//< 0 = expanding (consume all remaining space) +// 0 = auto (resize to contents +//> 0 = fixed width +auto pListView::resizeColumns() -> void { + lock(); + + //compute the minimum width required for each column based upon the contents of all rows + vector minimumWidths; + for(auto column : range(self().columns())) { + signed maximumWidth = 1; + if(self().headerVisible()) { + maximumWidth = max(maximumWidth, 8 //margin + + state().columns[column]->state.icon.width + + Font::size(state().columns[column]->font(true), state().columns[column]->state.text).width() + ); + } + for(auto row : range(self().items())) { + maximumWidth = max(maximumWidth, 8 //margin + + (row == 0 && state().checkable ? 24 : 0) //check box + + state().items[row]->state.icon(column, {}).width + + Font::size(state().columns[column]->font(true), state().items[row]->state.text(column, "")).width() + ); + } + if(!state().columns[column]->visible()) maximumWidth = 1; + minimumWidths.append(maximumWidth); + } + + //subtract the widths of all non-expanding columns from the available widget space + signed expansions = 0; //count the number of expanded columns + signed emptyWidth = pSizable::state().geometry.width() - 5; //margin + for(auto column : range(self().columns())) { + signed width = state().columns[column]->width(); + if(!state().columns[column]->visible()) width = 1; + if(width < 0) { expansions++; continue; } + if(width == 0) width = minimumWidths[column]; + emptyWidth -= width; + } + + //the vertical scroll bar consumes header space when visible; subtract it from available space if needed + auto scrollBar = gtk_scrolled_window_get_vscrollbar(gtkScrolledWindow); + if(scrollBar && gtk_widget_get_visible(scrollBar)) { + emptyWidth -= scrollBar->allocation.width; + } + + //divide remaining space among all expanded columns + if(expansions && emptyWidth >= expansions) emptyWidth /= expansions; + else emptyWidth = 1; + + for(auto column : range(self().columns())) { + signed width = state().columns[column]->width(); + if(!state().columns[column]->visible()) width = 1; + if(width < 0) width = emptyWidth; + if(width == 0) width = minimumWidths[column]; + gtk_tree_view_column_set_fixed_width(_column(column)->gtkColumn, width); + } + + unlock(); +} + +auto pListView::setBackgroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pListView::setCheckable(bool checkable) -> void { + if(auto delegate = _column(0)) { + gtk_cell_renderer_set_visible(delegate->gtkCellToggle, checkable); + } +} + +auto pListView::setChecked(bool checked) -> void { + for(auto& item : state().items) { + if(auto delegate = item->self()) delegate->setChecked(checked); + } +} + +auto pListView::setFocused() -> void { + gtk_widget_grab_focus(gtkWidgetChild); +} + +auto pListView::setFont(const string& font) -> void { + for(auto& column : state().columns) { + if(auto delegate = column->self()) delegate->setFont(column->font(true)); + } +} + +auto pListView::setForegroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pListView::setGridVisible(bool visible) -> void { + gtk_tree_view_set_grid_lines(gtkTreeView, visible ? GTK_TREE_VIEW_GRID_LINES_BOTH : GTK_TREE_VIEW_GRID_LINES_NONE); +} + +auto pListView::setHeaderVisible(bool visible) -> void { + gtk_tree_view_set_headers_visible(gtkTreeView, visible); +} + +auto pListView::setMultiSelect(bool multiSelect) -> void { + gtk_tree_selection_set_mode(gtkTreeSelection, multiSelect ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE); +} + +auto pListView::setSelected(bool selected) -> void { + for(auto& item : state().items) { + if(auto delegate = item->self()) delegate->setSelected(selected); + } +} + +auto pListView::_column(unsigned column) -> pListViewColumn* { + if(auto delegate = self().column(column)) return delegate->self(); + return nullptr; +} + +auto pListView::_createModel() -> void { + gtk_tree_view_set_model(gtkTreeView, nullptr); + gtkListStore = nullptr; + gtkTreeModel = nullptr; + + vector types; + unsigned position = 0; + for(auto column : state().columns) { + if(!column->self()->gtkColumn) continue; //column is being removed + if(position++ == 0) types.append(G_TYPE_BOOLEAN); + types.append(GDK_TYPE_PIXBUF); + types.append(G_TYPE_STRING); + } + if(!types) return; //no columns available + + gtkListStore = gtk_list_store_newv(types.size(), types.data()); + gtkTreeModel = GTK_TREE_MODEL(gtkListStore); + gtk_tree_view_set_model(gtkTreeView, gtkTreeModel); +} + +auto pListView::_doActivate() -> void { + if(!locked()) self().doActivate(); +} + +auto pListView::_doChange() -> void { + if(!locked()) _updateSelected(); +} + +auto pListView::_doContext() -> void { + if(!locked()) self().doContext(); +} + +auto pListView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void { + for(auto& column : state().columns) { + if(auto delegate = column->self()) { + if(gtkCellRendererText = GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) { + if(auto item = self().item(decimal(path))) { + if(string{text} != item->text(column->offset())) { + item->setText(column->offset(), text); + if(!locked()) self().doEdit(item, column); + } + return; + } + } + } + } +} + +auto pListView::_doEvent(GdkEventButton* event) -> signed { + GtkTreePath* path = nullptr; + gtk_tree_view_get_path_at_pos(gtkTreeView, event->x, event->y, &path, nullptr, nullptr, nullptr); + + if(event->type == GDK_BUTTON_PRESS) { + //when clicking in empty space below the last list view item; GTK+ does not deselect all items; + //below code enables this functionality, to match behavior with all other UI toolkits (and because it's very convenient to have) + if(path == nullptr && gtk_tree_selection_count_selected_rows(gtkTreeSelection) > 0) { + self().setSelected({}); + self().doChange(); + return true; + } + } + + if(event->type == GDK_BUTTON_PRESS && event->button == 3) { + //this check prevents the loss of selection on other items if the item under the mouse cursor is currently selected + if(path && gtk_tree_selection_path_is_selected(gtkTreeSelection, path)) return true; + } + + if(event->type == GDK_BUTTON_RELEASE && event->button == 3) { + //handle action during right-click release; as button-press-event is sent prior to selection update + //without this, the callback handler would see the previous selection state instead + self().doContext(); + return false; + } + + return false; +} + +auto pListView::_doHeaderActivate(GtkTreeViewColumn* gtkTreeViewColumn) -> void { + for(auto& column : state().columns) { + if(auto delegate = column->self()) { + if(gtkTreeViewColumn == delegate->gtkColumn) { + if(!locked()) self().doSort(column); + return; + } + } + } +} + +//GtkTreeView::cursor-changed and GtkTreeSelection::changed do not send signals for changes during rubber-banding selection +//so here we capture motion-notify-event, and if the selections have changed, invoke ListView::onChange +auto pListView::_doMouseMove() -> signed { + if(gtk_tree_view_is_rubber_banding_active(gtkTreeView)) { + if(!locked()) _updateSelected(); + } + return false; +} + +auto pListView::_doToggle(const char* path) -> void { + if(auto item = self().item(decimal(path))) { + if(auto delegate = item->self()) { + item->state.checked = !item->state.checked; + delegate->setChecked(item->state.checked); + if(!locked()) self().doToggle(item); + } + } +} + +//compare currently selected items to previously selected items +//if different, invoke the onChange callback unless locked, and cache current selection +//this prevents firing an onChange event when the actual selection has not changed +//this is particularly important for the motion-notify-event binding +auto pListView::_updateSelected() -> void { + vector selected; + + GList* list = gtk_tree_selection_get_selected_rows(gtkTreeSelection, >kTreeModel); + GList* p = list; + + while(p) { + GtkTreeIter iter; + if(gtk_tree_model_get_iter(gtkTreeModel, &iter, (GtkTreePath*)p->data)) { + char* pathname = gtk_tree_model_get_string_from_iter(gtkTreeModel, &iter); + unsigned selection = decimal(pathname); + g_free(pathname); + selected.append(selection); + } + p = p->next; + } + + g_list_foreach(list, (GFunc)gtk_tree_path_free, nullptr); + g_list_free(list); + + bool identical = selected.size() == currentSelection.size(); + if(identical) { + for(auto n : range(selected)) { + if(selected[n] != currentSelection[n]) { + identical = false; + break; + } + } + } + if(identical) return; + + currentSelection = selected; + for(auto& item : state().items) item->state.selected = false; + for(auto& position : currentSelection) { + if(position >= self().items()) continue; + self().item(position)->state.selected = true; + } + + if(!locked()) self().doChange(); +} + +} diff --git a/hiro/gtk/widget/list-view.hpp b/hiro/gtk/widget/list-view.hpp new file mode 100644 index 00000000..576cde40 --- /dev/null +++ b/hiro/gtk/widget/list-view.hpp @@ -0,0 +1,45 @@ +namespace hiro { + +struct pListView : pWidget { + Declare(ListView, Widget) + + auto append(sListViewColumn column) -> void; + auto append(sListViewItem item) -> void; + auto focused() -> bool; + auto remove(sListViewColumn column) -> void; + auto remove(sListViewItem item) -> void; + auto reset() -> void; + auto resizeColumns() -> void; + auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; + auto setChecked(bool checked) -> void; + auto setFocused() -> void override; + auto setFont(const string& font) -> void override; + auto setForegroundColor(Color color) -> void; + auto setGridVisible(bool visible) -> void; + auto setHeaderVisible(bool visible) -> void; + auto setMultiSelect(bool multiSelect) -> void; + auto setSelected(bool selected) -> void; + + auto _column(unsigned column) -> pListViewColumn*; + auto _createModel() -> void; + auto _doActivate() -> void; + auto _doChange() -> void; + auto _doContext() -> void; + auto _doEdit(GtkCellRendererText* renderer, const char* path, const char* text) -> void; + auto _doEvent(GdkEventButton* event) -> signed; + auto _doHeaderActivate(GtkTreeViewColumn* column) -> void; + auto _doMouseMove() -> signed; + auto _doToggle(const char* path) -> void; + auto _updateSelected() -> void; + + GtkScrolledWindow* gtkScrolledWindow = nullptr; + GtkWidget* gtkWidgetChild = nullptr; + GtkTreeView* gtkTreeView = nullptr; + GtkTreeSelection* gtkTreeSelection = nullptr; + GtkListStore* gtkListStore = nullptr; + GtkTreeModel* gtkTreeModel = nullptr; + vector currentSelection; +}; + +} diff --git a/hiro/gtk/widget/progress-bar.cpp b/hiro/gtk/widget/progress-bar.cpp new file mode 100644 index 00000000..8e888d88 --- /dev/null +++ b/hiro/gtk/widget/progress-bar.cpp @@ -0,0 +1,24 @@ +namespace hiro { + +auto pProgressBar::construct() -> void { + gtkWidget = gtk_progress_bar_new(); + + setPosition(state().position); + + pWidget::construct(); +} + +auto pProgressBar::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pProgressBar::minimumSize() const -> Size { + return {0, 25}; +} + +auto pProgressBar::setPosition(unsigned position) -> void { + position = position <= 100 ? position : 0; + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkWidget), (double)position / 100.0); +} + +} diff --git a/hiro/gtk/widget/progress-bar.hpp b/hiro/gtk/widget/progress-bar.hpp new file mode 100644 index 00000000..14e677c1 --- /dev/null +++ b/hiro/gtk/widget/progress-bar.hpp @@ -0,0 +1,10 @@ +namespace hiro { + +struct pProgressBar : pWidget { + Declare(ProgressBar, Widget) + + auto minimumSize() const -> Size; + auto setPosition(unsigned position) -> void; +}; + +} diff --git a/hiro/gtk/widget/radio-button.cpp b/hiro/gtk/widget/radio-button.cpp new file mode 100644 index 00000000..97b5dd85 --- /dev/null +++ b/hiro/gtk/widget/radio-button.cpp @@ -0,0 +1,101 @@ +namespace hiro { + +static auto RadioButton_activate(GtkToggleButton*, pRadioButton* p) -> void { + if(p->_parent().locked()) return; + bool wasChecked = p->state().checked; + p->setChecked(); + if(!wasChecked) p->self().doActivate(); +} + +auto pRadioButton::construct() -> void { + gtkWidget = gtk_toggle_button_new(); + + setGroup(state().group); + setBordered(state().bordered); + setIcon(state().icon); + setOrientation(state().orientation); + setText(state().text); + + g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioButton_activate), (gpointer)this); + + pWidget::construct(); +} + +auto pRadioButton::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pRadioButton::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + + if(state().orientation == Orientation::Horizontal) { + size.setWidth(size.width() + state().icon.width); + size.setHeight(max(size.height(), state().icon.height)); + } + + if(state().orientation == Orientation::Vertical) { + size.setWidth(max(size.width(), state().icon.width)); + size.setHeight(size.height() + state().icon.height); + } + + return {size.width() + 24, size.height() + 12}; +} + +auto pRadioButton::setBordered(bool bordered) -> void { + gtk_button_set_relief(GTK_BUTTON(gtkWidget), bordered ? GTK_RELIEF_NORMAL : GTK_RELIEF_NONE); +} + +auto pRadioButton::setChecked() -> void { + _parent().lock(); + for(auto& weak : state().group) { + if(auto item = weak.acquire()) { + if(item->self()) { + bool checked = item->self() == this; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->self()->gtkWidget), item->state.checked = checked); + } + } + } + _parent().unlock(); +} + +auto pRadioButton::setGroup(const vector& group) -> void { + _parent().lock(); + for(auto& weak : state().group) { + if(auto item = weak.acquire()) { + if(item->self()) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->self()->gtkWidget), item->checked()); + } + } + _parent().unlock(); +} + +auto pRadioButton::setIcon(const image& icon) -> void { + if(icon) { + GtkImage* gtkImage = CreateImage(icon); + gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); + } else { + gtk_button_set_image(GTK_BUTTON(gtkWidget), nullptr); + } +} + +auto pRadioButton::setOrientation(Orientation orientation) -> void { + switch(orientation) { + case Orientation::Horizontal: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_LEFT); break; + case Orientation::Vertical: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_TOP); break; + } +} + +auto pRadioButton::setText(const string& text) -> void { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); + setFont(self().font(true)); //gtk_button_set_label() recreates label, which destroys currently assigned font +} + +auto pRadioButton::_parent() -> pRadioButton& { + if(state().group.size()) { + if(auto item = state().group.first().acquire()) { + if(item->self()) return *item->self(); + } + } + return *this; +} + +} diff --git a/hiro/gtk/widget/radio-button.hpp b/hiro/gtk/widget/radio-button.hpp new file mode 100644 index 00000000..f74ac141 --- /dev/null +++ b/hiro/gtk/widget/radio-button.hpp @@ -0,0 +1,17 @@ +namespace hiro { + +struct pRadioButton : pWidget { + Declare(RadioButton, Widget) + + auto minimumSize() const -> Size; + auto setBordered(bool bordered) -> void; + auto setChecked() -> void; + auto setGroup(const vector& group) -> void; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + + auto _parent() -> pRadioButton&; +}; + +} diff --git a/hiro/gtk/widget/radio-label.cpp b/hiro/gtk/widget/radio-label.cpp new file mode 100644 index 00000000..b3ec8c61 --- /dev/null +++ b/hiro/gtk/widget/radio-label.cpp @@ -0,0 +1,71 @@ +namespace hiro { + +static auto RadioLabel_activate(GtkToggleButton*, pRadioLabel* p) -> void { + if(p->_parent().locked()) return; + bool wasChecked = p->state().checked; + p->setChecked(); + if(!wasChecked) p->self().doActivate(); +} + +auto pRadioLabel::construct() -> void { + gtkWidget = gtk_radio_button_new_with_label(nullptr, ""); + + setGroup(state().group); + setText(state().text); + + g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioLabel_activate), (gpointer)this); + + pWidget::construct(); +} + +auto pRadioLabel::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pRadioLabel::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + return {size.width() + 28, size.height() + 4}; +} + +auto pRadioLabel::setChecked() -> void { + _parent().lock(); + for(auto& weak : state().group) { + if(auto item = weak.acquire()) item->state.checked = false; + } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), state().checked = true); + _parent().unlock(); +} + +auto pRadioLabel::setGroup(const vector>& group) -> void { + if(&_parent() == this) return; + _parent().lock(); + gtk_radio_button_set_group( + GTK_RADIO_BUTTON(gtkWidget), + gtk_radio_button_get_group(GTK_RADIO_BUTTON(_parent().gtkWidget)) + ); + for(auto& weak : state().group) { + if(auto item = weak.acquire()) { + if(item->self() && item->checked()) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->self()->gtkWidget), true); + break; + } + } + } + _parent().unlock(); +} + +auto pRadioLabel::setText(const string& text) -> void { + gtk_button_set_label(GTK_BUTTON(gtkWidget), text); + setFont(self().font(true)); //gtk_button_set_label() recreates label, which destroys currently assigned font +} + +auto pRadioLabel::_parent() -> pRadioLabel& { + if(state().group.size()) { + if(auto item = state().group.first().acquire()) { + if(item->self()) return *item->self(); + } + } + return *this; +} + +} diff --git a/hiro/gtk/widget/radio-label.hpp b/hiro/gtk/widget/radio-label.hpp new file mode 100644 index 00000000..758980ba --- /dev/null +++ b/hiro/gtk/widget/radio-label.hpp @@ -0,0 +1,14 @@ +namespace hiro { + +struct pRadioLabel : pWidget { + Declare(RadioLabel, Widget) + + auto minimumSize() const -> Size; + auto setChecked() -> void; + auto setGroup(const vector>& group) -> void; + auto setText(const string& text) -> void; + + auto _parent() -> pRadioLabel&; +}; + +} diff --git a/hiro/gtk/widget/source-edit.cpp b/hiro/gtk/widget/source-edit.cpp new file mode 100644 index 00000000..aacb9264 --- /dev/null +++ b/hiro/gtk/widget/source-edit.cpp @@ -0,0 +1,126 @@ +namespace hiro { + +static auto SourceEdit_change(GtkTextBuffer*, pSourceEdit* p) -> void { + if(!p->locked()) p->self().doChange(); +} + +static auto SourceEdit_move(GObject*, GParamSpec*, pSourceEdit* p) -> void { + signed position = 0; + g_object_get(G_OBJECT(p->gtkSourceBuffer), "cursor-position", &position, nullptr); + + if(p->state().position != position) { + p->state().position = position; + if(!p->locked()) p->self().doMove(); + } +} + +auto pSourceEdit::construct() -> void { + gtkScrolledWindow = (GtkScrolledWindow*)gtk_scrolled_window_new(0, 0); + gtkContainer = GTK_CONTAINER(gtkScrolledWindow); + gtkWidget = GTK_WIDGET(gtkScrolledWindow); + gtk_scrolled_window_set_policy(gtkScrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(gtkScrolledWindow, GTK_SHADOW_ETCHED_IN); + + gtkSourceLanguageManager = gtk_source_language_manager_get_default(); + gtkSourceLanguage = gtk_source_language_manager_get_language(gtkSourceLanguageManager, "cpp"); + + gtkSourceStyleSchemeManager = gtk_source_style_scheme_manager_get_default(); + gtkSourceStyleScheme = gtk_source_style_scheme_manager_get_scheme(gtkSourceStyleSchemeManager, "oblivion"); + + gtkSourceBuffer = gtk_source_buffer_new(nullptr); + gtkTextBuffer = GTK_TEXT_BUFFER(gtkSourceBuffer); + gtk_source_buffer_set_highlight_matching_brackets(gtkSourceBuffer, true); + gtk_source_buffer_set_highlight_syntax(gtkSourceBuffer, true); +//gtk_source_buffer_set_language(gtkSourceBuffer, gtkSourceLanguage); + gtk_source_buffer_set_style_scheme(gtkSourceBuffer, gtkSourceStyleScheme); + + gtkSourceView = (GtkSourceView*)gtk_source_view_new_with_buffer(gtkSourceBuffer); + gtkTextView = GTK_TEXT_VIEW(gtkSourceView); + gtkWidgetSourceView = GTK_WIDGET(gtkSourceView); + gtk_source_view_set_auto_indent(gtkSourceView, false); + gtk_source_view_set_draw_spaces(gtkSourceView, (GtkSourceDrawSpacesFlags)0); + gtk_source_view_set_highlight_current_line(gtkSourceView, true); + gtk_source_view_set_indent_on_tab(gtkSourceView, false); + gtk_source_view_set_indent_width(gtkSourceView, 4); + gtk_source_view_set_insert_spaces_instead_of_tabs(gtkSourceView, false); + gtk_source_view_set_right_margin_position(gtkSourceView, 80); + gtk_source_view_set_show_line_marks(gtkSourceView, false); + gtk_source_view_set_show_line_numbers(gtkSourceView, true); + gtk_source_view_set_show_right_margin(gtkSourceView, true); + gtk_source_view_set_smart_home_end(gtkSourceView, GTK_SOURCE_SMART_HOME_END_DISABLED); + gtk_source_view_set_tab_width(gtkSourceView, 4); + gtk_container_add(gtkContainer, gtkWidgetSourceView); + gtk_widget_show(gtkWidgetSourceView); + + setText(state().text); + + g_signal_connect(G_OBJECT(gtkSourceBuffer), "changed", G_CALLBACK(SourceEdit_change), (gpointer)this); + g_signal_connect(G_OBJECT(gtkSourceBuffer), "notify::cursor-position", G_CALLBACK(SourceEdit_move), (gpointer)this); + + pWidget::construct(); +} + +auto pSourceEdit::destruct() -> void { + state().text = text(); + gtk_widget_destroy(gtkWidgetSourceView); + gtk_widget_destroy(gtkWidget); +} + +auto pSourceEdit::setFocused() -> void { + gtk_widget_grab_focus(gtkWidgetSourceView); +} + +auto pSourceEdit::setPosition(signed position) -> void { + lock(); + GtkTextIter iter; + //note: iterators must be initialized via get_iter() before calling set_offset() + gtk_text_buffer_get_end_iter(gtkTextBuffer, &iter); + if(position >= 0) { + gtk_text_iter_set_offset(&iter, position); + } else { + state().position = gtk_text_iter_get_offset(&iter); + } + gtk_text_buffer_place_cursor(gtkTextBuffer, &iter); + auto mark = gtk_text_buffer_get_mark(gtkTextBuffer, "insert"); + gtk_text_view_scroll_mark_onscreen(gtkTextView, mark); + unlock(); +} + +auto pSourceEdit::setSelected(Position selected) -> void { + lock(); + GtkTextIter iter; + gtk_text_buffer_get_end_iter(gtkTextBuffer, &iter); + signed offset = gtk_text_iter_get_offset(&iter); + if(selected.x() < 0 || selected.x() > offset) selected.setX(offset); + if(selected.y() < 0 || selected.y() > offset) selected.setY(offset); + state().selected = selected; + GtkTextIter startIter; + gtk_text_buffer_get_start_iter(gtkTextBuffer, &startIter); + gtk_text_iter_set_offset(&startIter, selected.x()); + GtkTextIter endIter; + gtk_text_buffer_get_end_iter(gtkTextBuffer, &endIter); + gtk_text_iter_set_offset(&endIter, selected.y()); + gtk_text_buffer_select_range(gtkTextBuffer, &startIter, &endIter); + unlock(); +} + +auto pSourceEdit::setText(const string& text) -> void { + lock(); + gtk_text_buffer_set_text(gtkTextBuffer, text, -1); + unlock(); +} + +auto pSourceEdit::text() const -> string { + GtkTextIter startIter; + gtk_text_buffer_get_start_iter(gtkTextBuffer, &startIter); + + GtkTextIter endIter; + gtk_text_buffer_get_end_iter(gtkTextBuffer, &endIter); + + char* textBuffer = gtk_text_buffer_get_text(gtkTextBuffer, &startIter, &endIter, true); + string text = textBuffer; + g_free(textBuffer); + return text; +} + +} diff --git a/hiro/gtk/widget/source-edit.hpp b/hiro/gtk/widget/source-edit.hpp new file mode 100644 index 00000000..7c9c07e5 --- /dev/null +++ b/hiro/gtk/widget/source-edit.hpp @@ -0,0 +1,25 @@ +namespace hiro { + +struct pSourceEdit : pWidget { + Declare(SourceEdit, Widget) + + auto setFocused() -> void override; + auto setPosition(signed position) -> void; + auto setSelected(Position selected) -> void; + auto setText(const string& text) -> void; + auto text() const -> string; + + GtkScrolledWindow* gtkScrolledWindow = nullptr; + GtkContainer* gtkContainer = nullptr; + GtkSourceBuffer* gtkSourceBuffer = nullptr; + GtkTextBuffer* gtkTextBuffer = nullptr; + GtkSourceLanguageManager* gtkSourceLanguageManager = nullptr; + GtkSourceLanguage* gtkSourceLanguage = nullptr; + GtkSourceStyleSchemeManager* gtkSourceStyleSchemeManager = nullptr; + GtkSourceStyleScheme* gtkSourceStyleScheme = nullptr; + GtkSourceView* gtkSourceView = nullptr; + GtkTextView* gtkTextView = nullptr; + GtkWidget* gtkWidgetSourceView = nullptr; +}; + +} diff --git a/hiro/gtk/widget/tab-frame-item.cpp b/hiro/gtk/widget/tab-frame-item.cpp new file mode 100644 index 00000000..b202e4bb --- /dev/null +++ b/hiro/gtk/widget/tab-frame-item.cpp @@ -0,0 +1,46 @@ +namespace hiro { + +auto pTabFrameItem::construct() -> void { + if(auto layout = state().layout) layout->construct(); +} + +auto pTabFrameItem::destruct() -> void { + if(auto layout = state().layout) layout->destruct(); +} + +auto pTabFrameItem::setClosable(bool closable) -> void { + if(auto parent = _parent()) { + parent->setItemClosable(self().offset(), closable); + } +} + +auto pTabFrameItem::setIcon(const image& icon) -> void { + if(auto parent = _parent()) { + parent->setItemIcon(self().offset(), icon); + } +} + +auto pTabFrameItem::setMovable(bool movable) -> void { + if(auto parent = _parent()) { + parent->setItemMovable(self().offset(), movable); + } +} + +auto pTabFrameItem::setSelected() -> void { + if(auto parent = _parent()) { + parent->setItemSelected(self().offset()); + } +} + +auto pTabFrameItem::setText(const string& text) -> void { + if(auto parent = _parent()) { + parent->setItemText(self().offset(), text); + } +} + +auto pTabFrameItem::_parent() -> pTabFrame* { + if(auto parent = self().parentTabFrame()) return parent->self(); + return nullptr; +} + +} diff --git a/hiro/gtk/widget/tab-frame-item.hpp b/hiro/gtk/widget/tab-frame-item.hpp new file mode 100644 index 00000000..2f3ddd30 --- /dev/null +++ b/hiro/gtk/widget/tab-frame-item.hpp @@ -0,0 +1,15 @@ +namespace hiro { + +struct pTabFrameItem : pObject { + Declare(TabFrameItem, Object) + + auto setClosable(bool closable) -> void; + auto setIcon(const image& icon) -> void; + auto setMovable(bool movable) -> void; + auto setSelected() -> void; + auto setText(const string& text) -> void; + + auto _parent() -> pTabFrame*; +}; + +} diff --git a/hiro/gtk/widget/tab-frame.cpp b/hiro/gtk/widget/tab-frame.cpp new file mode 100644 index 00000000..0ffa1243 --- /dev/null +++ b/hiro/gtk/widget/tab-frame.cpp @@ -0,0 +1,265 @@ +namespace hiro { + +static auto TabFrame_change(GtkNotebook* notebook, GtkWidget* page, unsigned position, pTabFrame* p) -> void { + p->state().selected = position; + p->_synchronizeLayout(); + if(!p->locked()) p->self().doChange(); +} + +static auto TabFrame_close(GtkButton* button, pTabFrame* p) -> void { + maybe position; + for(auto n : range(p->tabs)) { + if(button == (GtkButton*)p->tabs[n].close) { + position = n; + break; + } + } + if(position) { + if(!p->locked()) p->self().doClose(p->self().item(*position)); + } +} + +static auto TabFrame_move(GtkNotebook* notebook, GtkWidget* page, unsigned moveTo, pTabFrame* p) -> void { + p->state().selected = gtk_notebook_get_current_page(notebook); + maybe moveFrom; + for(auto n : range(p->tabs)) { + if(page == p->tabs[n].child) { + moveFrom = n; + break; + } + } + if(moveFrom) { + p->state().items.insert(moveTo, p->state().items.take(*moveFrom)); + p->tabs.insert(moveTo, p->tabs.take(*moveFrom)); + if(!p->locked()) p->self().doMove(p->self().item(*moveFrom), p->self().item(moveTo)); + } +} + +auto pTabFrame::construct() -> void { + gtkWidget = gtk_notebook_new(); + gtk_notebook_set_show_border(GTK_NOTEBOOK(gtkWidget), false); + gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkWidget), GTK_POS_TOP); + + tabs.reset(); //todo: memory leak, need to release each tab + for(auto& item : state().items) append(item); + setEdge(state().edge); + setItemSelected(state().selected); + + g_signal_connect(G_OBJECT(gtkWidget), "page-reordered", G_CALLBACK(TabFrame_move), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "switch-page", G_CALLBACK(TabFrame_change), (gpointer)this); + + pWidget::construct(); +} + +auto pTabFrame::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pTabFrame::append(sTabFrameItem item) -> void { + lock(); + Tab tab; + tab.child = gtk_fixed_new(); + tab.container = gtk_hbox_new(false, 0); + tab.image = gtk_image_new(); + tab.title = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(tab.title), 0.0, 0.5); + tab.close = gtk_button_new_with_label("\u00d7"); //Unicode multiplication sign (looks better than 'X') + gtk_button_set_focus_on_click(GTK_BUTTON(tab.close), false); + gtk_button_set_relief(GTK_BUTTON(tab.close), GTK_RELIEF_NONE); + pFont::setFont(tab.close, Font::sans(9, "Bold")); + auto color = CreateColor({255, 0, 0}); + gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(tab.close)), GTK_STATE_PRELIGHT, &color); + tabs.append(tab); + + gtk_widget_show(tab.child); + gtk_widget_show(tab.container); + gtk_widget_show(tab.image); + gtk_widget_show(tab.title); + gtk_widget_show(tab.close); + gtk_box_pack_start(GTK_BOX(tab.container), tab.image, false, false, 0); + gtk_box_pack_start(GTK_BOX(tab.container), tab.title, true, true, 0); + gtk_box_pack_start(GTK_BOX(tab.container), tab.close, false, false, 0); + + g_signal_connect(G_OBJECT(tab.close), "clicked", G_CALLBACK(TabFrame_close), (gpointer)this); + gtk_notebook_append_page(GTK_NOTEBOOK(gtkWidget), tab.child, tab.container); + + setFont(self().font(true)); + setItemMovable(item->offset(), item->movable()); + _synchronizeTab(tabs.size() - 1); + setGeometry(self().geometry()); + unlock(); +} + +auto pTabFrame::container(mWidget& widget) -> GtkWidget* { + auto widgetLayout = widget.parentLayout(); + unsigned position = 0; + for(auto& item : state().items) { + if(item->state.layout.data() == widgetLayout) return tabs[position].child; + position++; + } + return nullptr; +} + +auto pTabFrame::remove(sTabFrameItem item) -> void { + lock(); + //if we are removing the current tab, we have to select another tab manually + if(item->offset() == gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkWidget))) { + //the new tab will be the one after this one + unsigned displacement = 1; + //... unless it's the last tab, in which case it's the one before it + if(item->offset() == self().items() - 1) displacement = -1; + //... unless there are no tabs left, in which case nothing is selected + if(self().items() > 1) { + setItemSelected(item->offset() + displacement); + } + } + tabs.remove(item->offset()); + gtk_notebook_remove_page(GTK_NOTEBOOK(gtkWidget), item->offset()); + state().selected = gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkWidget)); + unlock(); +} + +auto pTabFrame::setEdge(Edge edge) -> void { + GtkPositionType type; + switch(edge) { default: + case Edge::Top: type = GTK_POS_TOP; break; + case Edge::Bottom: type = GTK_POS_BOTTOM; break; + case Edge::Left: type = GTK_POS_LEFT; break; + case Edge::Right: type = GTK_POS_RIGHT; break; + } + gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkWidget), type); + setGeometry(self().geometry()); +} + +auto pTabFrame::setEnabled(bool enabled) -> void { + for(auto& item : state().items) { + if(auto layout = item->state.layout) { + if(layout->self()) layout->self()->setEnabled(layout->enabled(true)); + } + } + pWidget::setEnabled(enabled); +} + +auto pTabFrame::setFont(const string& font) -> void { + for(auto n : range(tabs.size())) { + pFont::setFont(tabs[n].title, font); + if(auto layout = state().items[n]->state.layout) { + if(layout->self()) layout->self()->setFont(layout->font(true)); + } + } +} + +auto pTabFrame::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + + geometry.setPosition(0, 0); + if(state().edge == Edge::Top || state().edge == Edge::Bottom) { + geometry.setWidth(geometry.width() - 6); + geometry.setHeight(geometry.height() - (15 + _tabHeight())); + } else { + geometry.setWidth(geometry.width() - (17 + _tabWidth())); + geometry.setHeight(geometry.height() - 6); + } + for(auto& item : state().items) { + if(item->state.layout) item->state.layout->setGeometry(geometry); + } +} + +auto pTabFrame::setItemClosable(unsigned position, bool closable) -> void { + _synchronizeTab(position); +} + +auto pTabFrame::setItemIcon(unsigned position, const image& icon) -> void { + _synchronizeTab(position); +} + +auto pTabFrame::setItemLayout(unsigned position, shared_pointer layout) -> void { +//if(layout->self()) layout->self()->setParent(); +} + +auto pTabFrame::setItemMovable(unsigned position, bool movable) -> void { + lock(); + gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(gtkWidget), tabs[position].child, movable); + unlock(); +} + +auto pTabFrame::setItemSelected(unsigned position) -> void { + lock(); + gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkWidget), position); + unlock(); +} + +auto pTabFrame::setItemText(unsigned position, const string& text) -> void { + _synchronizeTab(position); +} + +auto pTabFrame::setVisible(bool visible) -> void { + for(auto& item : state().items) { + if(auto layout = item->state.layout) { + if(layout->self()) { + layout->self()->setVisible(layout->visible(true)); + } + } + } + pWidget::setVisible(visible); +} + +auto pTabFrame::_synchronizeLayout() -> void { + unsigned position = 0; + for(auto& item : state().items) { + if(auto layout = item->state.layout) { + if(layout->self()) { + layout->self()->setVisible(layout->visible(true) && position == state().selected); + } + } + position++; + } +} + +auto pTabFrame::_synchronizeTab(unsigned position) -> void { + auto& item = state().items[position]; + auto& tab = tabs[position]; + gtk_widget_set_visible(tab.close, item->closable()); + if(auto copy = item->state.icon) { + unsigned size = pFont::size(self().font(true), " ").height(); + copy.scale(size, size); + auto pixbuf = CreatePixbuf(copy); + gtk_image_set_from_pixbuf(GTK_IMAGE(tab.image), pixbuf); + } else { + gtk_image_clear(GTK_IMAGE(tab.image)); + } + string text = { + item->state.icon && item->state.text ? " " : "", + item->state.text, + item->state.text && item->state.closable ? " " : "" + }; + gtk_label_set_text(GTK_LABEL(tab.title), text); +} + +//compute the height of the tallest tab for child layout geometry calculations +auto pTabFrame::_tabHeight() -> unsigned { + signed height = 1; + + for(auto n : range(self().items())) { + height = max(height, tabs[n].image->allocation.height); + height = max(height, tabs[n].title->allocation.height); + if(!state().items[n]->closable()) continue; + height = max(height, tabs[n].close->allocation.height); + } + + return height; +} + +auto pTabFrame::_tabWidth() -> unsigned { + signed width = 1; + + for(auto n : range(self().items())) { + width = max(width, tabs[n].image->allocation.width + tabs[n].title->allocation.width + + (state().items[n]->closable() ? tabs[n].close->allocation.width : 0) + ); + } + + return width; +} + +} diff --git a/hiro/gtk/widget/tab-frame.hpp b/hiro/gtk/widget/tab-frame.hpp new file mode 100644 index 00000000..4319fc94 --- /dev/null +++ b/hiro/gtk/widget/tab-frame.hpp @@ -0,0 +1,39 @@ +namespace hiro { + +struct pTabFrame : pWidget { + Declare(TabFrame, Widget) + + auto append(sTabFrameItem item) -> void; + auto container(mWidget& widget) -> GtkWidget* override; + auto remove(sTabFrameItem item) -> void; + auto setEdge(Edge edge) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const string& font) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setItemClosable(unsigned position, bool closable) -> void; + auto setItemIcon(unsigned position, const image& icon) -> void; + auto setItemLayout(unsigned position, sLayout layout) -> void; + auto setItemMovable(unsigned position, bool movable) -> void; + auto setItemSelected(unsigned position) -> void; + auto setItemText(unsigned position, const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _append(shared_pointer item) -> void; + auto _remove(shared_pointer item) -> void; + auto _synchronizeLayout() -> void; + auto _synchronizeTab(unsigned position) -> void; + auto _tabHeight() -> unsigned; + auto _tabWidth() -> unsigned; + + struct Tab { + GtkWidget* child = nullptr; + GtkWidget* container = nullptr; + GtkWidget* layout = nullptr; + GtkWidget* image = nullptr; + GtkWidget* title = nullptr; + GtkWidget* close = nullptr; + }; + vector tabs; +}; + +} diff --git a/hiro/gtk/widget/text-edit.cpp b/hiro/gtk/widget/text-edit.cpp new file mode 100644 index 00000000..758b782b --- /dev/null +++ b/hiro/gtk/widget/text-edit.cpp @@ -0,0 +1,100 @@ +namespace hiro { + +static auto TextEdit_change(GtkTextBuffer* textBuffer, pTextEdit* p) -> void { + if(!p->locked()) p->self().doChange(); +} + +static auto TextEdit_move(GObject* object, GParamSpec* spec, pTextEdit* p) -> void { + int position = 0; + g_object_get(p->textBuffer, "cursor-position", &position, nullptr); + + if(p->state().cursorPosition != position) { + p->state().cursorPosition = position; + if(!p->locked()) p->self().doMove(); + } +} + +auto pTextEdit::construct() -> void { + gtkWidget = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); + + subWidget = gtk_text_view_new(); + gtk_widget_show(subWidget); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_WORD_CHAR); + gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); + + textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); + + setBackgroundColor(state().backgroundColor); + setEditable(state().editable); + setForegroundColor(state().foregroundColor); + setText(state().text); + setWordWrap(state().wordWrap); + + g_signal_connect(G_OBJECT(textBuffer), "changed", G_CALLBACK(TextEdit_change), (gpointer)this); + g_signal_connect(G_OBJECT(textBuffer), "notify::cursor-position", G_CALLBACK(TextEdit_move), (gpointer)this); + + pWidget::construct(); +} + +auto pTextEdit::destruct() -> void { + state().text = text(); + gtk_widget_destroy(subWidget); + gtk_widget_destroy(gtkWidget); +} + +auto pTextEdit::focused() const -> bool { + return GTK_WIDGET_HAS_FOCUS(subWidget); +} + +auto pTextEdit::setBackgroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pTextEdit::setCursorPosition(unsigned position) -> void { + lock(); + GtkTextMark* mark = gtk_text_buffer_get_mark(textBuffer, "insert"); + GtkTextIter iter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + gtk_text_iter_set_offset(&iter, min(position, gtk_text_iter_get_offset(&iter))); + gtk_text_buffer_place_cursor(textBuffer, &iter); + gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(subWidget), mark); + unlock(); +} + +auto pTextEdit::setEditable(bool editable) -> void { + gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), editable); +} + +auto pTextEdit::setForegroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pTextEdit::setText(const string& text) -> void { + lock(); + textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); + gtk_text_buffer_set_text(textBuffer, text, -1); + unlock(); +} + +auto pTextEdit::setWordWrap(bool wordWrap) -> void { + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), wordWrap ? GTK_WRAP_WORD_CHAR : GTK_WRAP_NONE); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), + wordWrap ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS, + GTK_POLICY_ALWAYS); +} + +auto pTextEdit::text() const -> string { + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(textBuffer, &start); + gtk_text_buffer_get_end_iter(textBuffer, &end); + char* temp = gtk_text_buffer_get_text(textBuffer, &start, &end, true); + string text = temp; + g_free(temp); + return text; +} + +} diff --git a/hiro/gtk/widget/text-edit.hpp b/hiro/gtk/widget/text-edit.hpp new file mode 100644 index 00000000..5d04e346 --- /dev/null +++ b/hiro/gtk/widget/text-edit.hpp @@ -0,0 +1,19 @@ +namespace hiro { + +struct pTextEdit : pWidget { + Declare(TextEdit, Widget) + + auto focused() const -> bool override; + auto setBackgroundColor(Color color) -> void; + auto setCursorPosition(unsigned position) -> void; + auto setEditable(bool editable) -> void; + auto setForegroundColor(Color color) -> void; + auto setText(const string& text) -> void; + auto setWordWrap(bool wordWrap) -> void; + auto text() const -> string; + + GtkWidget* subWidget = nullptr; + GtkTextBuffer* textBuffer = nullptr; +}; + +} diff --git a/hiro/gtk/widget/tree-view-item.cpp b/hiro/gtk/widget/tree-view-item.cpp new file mode 100644 index 00000000..3648e9db --- /dev/null +++ b/hiro/gtk/widget/tree-view-item.cpp @@ -0,0 +1,82 @@ +namespace hiro { + +auto pTreeViewItem::construct() -> void { +} + +auto pTreeViewItem::destruct() -> void { +} + +// + +auto pTreeViewItem::append(sTreeViewItem item) -> void { + if(auto parentWidget = _parentWidget()) { + gtk_tree_store_append(parentWidget->gtkTreeStore, &item->self()->gtkIter, >kIter); + item->setChecked(item->checked()); + item->setIcon(item->icon()); + item->setText(item->text()); + } +} + +auto pTreeViewItem::remove(sTreeViewItem item) -> void { + if(auto parentWidget = _parentWidget()) { + gtk_tree_store_remove(parentWidget->gtkTreeStore, &item->self()->gtkIter); + } +} + +auto pTreeViewItem::setChecked(bool checked) -> void { + if(auto parentWidget = _parentWidget()) { + gtk_tree_store_set(parentWidget->gtkTreeStore, >kIter, 0, checked, -1); + } +} + +auto pTreeViewItem::setFocused() -> void { + if(auto parentWidget = _parentWidget()) { + GtkTreePath* path = gtk_tree_path_new_from_string(self().path().transform("/", ":")); + gtk_tree_view_set_cursor(parentWidget->gtkTreeView, path, nullptr, false); + gtk_tree_view_scroll_to_cell(parentWidget->gtkTreeView, path, nullptr, true, 0.5, 0.0); + gtk_tree_path_free(path); + } +} + +auto pTreeViewItem::setIcon(const image& icon) -> void { + if(auto parentWidget = _parentWidget()) { + if(icon) { + auto pixbuf = CreatePixbuf(icon, true); + gtk_tree_store_set(parentWidget->gtkTreeStore, >kIter, 1, pixbuf, -1); + } else { + gtk_tree_store_set(parentWidget->gtkTreeStore, >kIter, 1, nullptr, -1); + } + } +} + +auto pTreeViewItem::setSelected() -> void { + if(auto parentWidget = _parentWidget()) { + parentWidget->lock(); + //in order to select an item, it must first be visible + auto gtkPath = gtk_tree_model_get_path(parentWidget->gtkTreeModel, >kIter); + gtk_tree_view_expand_to_path(parentWidget->gtkTreeView, gtkPath); + gtk_tree_path_free(gtkPath); + gtk_tree_selection_select_iter(parentWidget->gtkTreeSelection, >kIter); + parentWidget->unlock(); + } +} + +auto pTreeViewItem::setText(const string& text) -> void { + if(auto parentWidget = _parentWidget()) { + gtk_tree_store_set(parentWidget->gtkTreeStore, >kIter, 2, (const char*)text, -1); + } +} + +// + +auto pTreeViewItem::_parentItem() -> pTreeViewItem* { + if(auto parentItem = self().parentTreeViewItem()) return parentItem->self(); + return nullptr; +} + +auto pTreeViewItem::_parentWidget() -> pTreeView* { + if(auto parentWidget = self().parentTreeView(true)) return parentWidget->self(); + return nullptr; +} + +} diff --git a/hiro/gtk/widget/tree-view-item.hpp b/hiro/gtk/widget/tree-view-item.hpp new file mode 100644 index 00000000..224d1197 --- /dev/null +++ b/hiro/gtk/widget/tree-view-item.hpp @@ -0,0 +1,20 @@ +namespace hiro { + +struct pTreeViewItem : pObject { + Declare(TreeViewItem, Object) + + auto append(sTreeViewItem item) -> void; + auto remove(sTreeViewItem item) -> void; + auto setChecked(bool checked) -> void; + auto setFocused() -> void; + auto setIcon(const image& icon) -> void; + auto setSelected() -> void; + auto setText(const string& text) -> void; + + auto _parentItem() -> pTreeViewItem*; + auto _parentWidget() -> pTreeView*; + + GtkTreeIter gtkIter; +}; + +} diff --git a/hiro/gtk/widget/tree-view.cpp b/hiro/gtk/widget/tree-view.cpp new file mode 100644 index 00000000..fc895a40 --- /dev/null +++ b/hiro/gtk/widget/tree-view.cpp @@ -0,0 +1,162 @@ +namespace hiro { + +static auto TreeView_activate(GtkTreeView*, GtkTreePath* gtkPath, GtkTreeViewColumn*, pTreeView* p) -> void { p->_activatePath(gtkPath); } +static auto TreeView_buttonEvent(GtkTreeView*, GdkEventButton* gdkEvent, pTreeView* p) -> signed { return p->_buttonEvent(gdkEvent); } +static auto TreeView_change(GtkTreeSelection*, pTreeView* p) -> void { p->_updateSelected(); } +static auto TreeView_context(GtkTreeView*, pTreeView* p) -> void { p->self().doContext(); } +static auto TreeView_toggle(GtkCellRendererToggle*, char* path, pTreeView* p) -> void { p->_togglePath(path); } + +auto pTreeView::construct() -> void { + gtkWidget = gtk_scrolled_window_new(0, 0); + gtkScrolledWindow = GTK_SCROLLED_WINDOW(gtkWidget); + gtk_scrolled_window_set_policy(gtkScrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(gtkScrolledWindow, GTK_SHADOW_ETCHED_IN); + + gtkTreeStore = gtk_tree_store_new(3, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING); + gtkTreeModel = GTK_TREE_MODEL(gtkTreeStore); + + gtkWidgetChild = gtk_tree_view_new_with_model(gtkTreeModel); + gtkTreeView = GTK_TREE_VIEW(gtkWidgetChild); + gtkTreeSelection = gtk_tree_view_get_selection(gtkTreeView); + gtk_tree_view_set_headers_visible(gtkTreeView, false); + gtk_container_add(GTK_CONTAINER(gtkWidget), gtkWidgetChild); + gtk_widget_show(gtkWidgetChild); + + gtkTreeViewColumn = gtk_tree_view_column_new(); + + gtkCellToggle = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(gtkTreeViewColumn, gtkCellToggle, false); + gtk_tree_view_column_set_attributes(gtkTreeViewColumn, gtkCellToggle, "active", 0, nullptr); + gtk_cell_renderer_set_visible(gtkCellToggle, state().checkable); + + gtkCellPixbuf = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(gtkTreeViewColumn, gtkCellPixbuf, false); + gtk_tree_view_column_set_attributes(gtkTreeViewColumn, gtkCellPixbuf, "pixbuf", 1, nullptr); + + gtkCellText = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(gtkTreeViewColumn, gtkCellText, true); + gtk_tree_view_column_set_attributes(gtkTreeViewColumn, gtkCellText, "text", 2, nullptr); + + gtk_tree_view_append_column(gtkTreeView, gtkTreeViewColumn); + gtk_tree_view_set_search_column(gtkTreeView, 2); + + setBackgroundColor(state().backgroundColor); + setForegroundColor(state().foregroundColor); + + g_signal_connect(G_OBJECT(gtkWidgetChild), "button-press-event", G_CALLBACK(TreeView_buttonEvent), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidgetChild), "button-release-event", G_CALLBACK(TreeView_buttonEvent), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidgetChild), "popup-menu", G_CALLBACK(TreeView_context), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidgetChild), "row-activated", G_CALLBACK(TreeView_activate), (gpointer)this); + g_signal_connect(G_OBJECT(gtkTreeSelection), "changed", G_CALLBACK(TreeView_change), (gpointer)this); + g_signal_connect(G_OBJECT(gtkCellToggle), "toggled", G_CALLBACK(TreeView_toggle), (gpointer)this); + + pWidget::construct(); +} + +auto pTreeView::destruct() -> void { + gtk_widget_destroy(gtkWidgetChild); + gtk_widget_destroy(gtkWidget); +} + +// + +auto pTreeView::append(sTreeViewItem item) -> void { + gtk_tree_store_append(gtkTreeStore, &item->self()->gtkIter, nullptr); + item->setChecked(item->checked()); + item->setIcon(item->icon()); + item->setText(item->text()); +} + +auto pTreeView::collapse() -> void { + gtk_tree_view_collapse_all(gtkTreeView); +} + +auto pTreeView::expand() -> void { + gtk_tree_view_expand_all(gtkTreeView); +} + +auto pTreeView::remove(sTreeViewItem item) -> void { + gtk_tree_store_remove(gtkTreeStore, &item->self()->gtkIter); +} + +auto pTreeView::reset() -> void { + gtk_tree_view_set_model(gtkTreeView, nullptr); + gtkTreeStore = gtk_tree_store_new(3, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING); + gtkTreeModel = GTK_TREE_MODEL(gtkTreeStore); + gtk_tree_view_set_model(gtkTreeView, gtkTreeModel); +} + +auto pTreeView::setBackgroundColor(Color color) -> void { + auto gdkColor = CreateColor(color); + gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pTreeView::setCheckable(bool checkable) -> void { + gtk_cell_renderer_set_visible(gtkCellToggle, checkable); +} + +auto pTreeView::setForegroundColor(Color color) -> void { + auto gdkColor = CreateColor(color); + gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +// + +auto pTreeView::_activatePath(GtkTreePath* gtkPath) -> void { + char* path = gtk_tree_path_to_string(gtkPath); + if(auto item = self().item(string{path}.transform(":", "/"))) { + if(!locked()) self().doActivate(); + } + g_free(path); +} + +auto pTreeView::_buttonEvent(GdkEventButton* gdkEvent) -> signed { + GtkTreePath* gtkPath = nullptr; + gtk_tree_view_get_path_at_pos(gtkTreeView, gdkEvent->x, gdkEvent->y, >kPath, nullptr, nullptr, nullptr); + + if(gdkEvent->type == GDK_BUTTON_PRESS) { + //detect when the empty space of the GtkTreeView is clicked; and clear the selection + if(gtkPath == nullptr && gtk_tree_selection_count_selected_rows(gtkTreeSelection) > 0) { + gtk_tree_selection_unselect_all(gtkTreeSelection); + state().selectedPath.reset(); + self().doChange(); + return true; + } + } + + if(gdkEvent->type == GDK_BUTTON_RELEASE && gdkEvent->button == 3) { + //handle right-click context menu + //have to detect on button release instead of press; as GTK+ does not update new selection prior to press event + self().doContext(); + return false; + } + + return false; +} + +auto pTreeView::_togglePath(string path) -> void { + if(auto item = self().item(path.transform(":", "/"))) { + bool checked = !item->checked(); + gtk_tree_store_set(gtkTreeStore, &item->self()->gtkIter, 0, checked, -1); + item->state.checked = checked; + if(!locked()) self().doToggle(item); + } +} + +auto pTreeView::_updateSelected() -> void { + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(gtkTreeSelection, >kTreeModel, &iter)) { + char* gtkPath = gtk_tree_model_get_string_from_iter(gtkTreeModel, &iter); + string path = string{gtkPath}.transform(":", "/"); + g_free(gtkPath); + if(state().selectedPath != path) { + state().selectedPath = path; + if(!locked()) self().doChange(); + } + } else if(state().selectedPath) { + state().selectedPath.reset(); + if(!locked()) self().doChange(); + } +} + +} diff --git a/hiro/gtk/widget/tree-view.hpp b/hiro/gtk/widget/tree-view.hpp new file mode 100644 index 00000000..e3abe189 --- /dev/null +++ b/hiro/gtk/widget/tree-view.hpp @@ -0,0 +1,32 @@ +namespace hiro { + +struct pTreeView : pWidget { + Declare(TreeView, Widget) + + auto append(sTreeViewItem item) -> void; + auto collapse() -> void; + auto expand() -> void; + auto remove(sTreeViewItem item) -> void; + auto reset() -> void; + auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; + auto setForegroundColor(Color color) -> void; + + auto _activatePath(GtkTreePath* gtkPath) -> void; + auto _buttonEvent(GdkEventButton* gdkEvent) -> signed; + auto _togglePath(string path) -> void; + auto _updateSelected() -> void; + + GtkScrolledWindow* gtkScrolledWindow = nullptr; + GtkWidget* gtkWidgetChild = nullptr; + GtkTreeStore* gtkTreeStore = nullptr; + GtkTreeModel* gtkTreeModel = nullptr; + GtkTreeSelection* gtkTreeSelection = nullptr; + GtkTreeView* gtkTreeView = nullptr; + GtkTreeViewColumn* gtkTreeViewColumn = nullptr; + GtkCellRenderer* gtkCellToggle = nullptr; + GtkCellRenderer* gtkCellPixbuf = nullptr; + GtkCellRenderer* gtkCellText = nullptr; +}; + +} diff --git a/hiro/gtk/widget/vertical-scroller.cpp b/hiro/gtk/widget/vertical-scroller.cpp new file mode 100644 index 00000000..0bd8ef86 --- /dev/null +++ b/hiro/gtk/widget/vertical-scroller.cpp @@ -0,0 +1,41 @@ +namespace hiro { + +static auto VerticalScroller_change(GtkRange* gtkRange, pVerticalScroller* p) -> void { + auto position = (unsigned)gtk_range_get_value(gtkRange); + if(p->state().position == position) return; + p->state().position = position; + if(!p->locked()) p->self().doChange(); +} + +auto pVerticalScroller::construct() -> void { + gtkWidget = gtk_vscrollbar_new(0); + + setLength(state().length); + setPosition(state().position); + + g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalScroller_change), (gpointer)this); + + pWidget::construct(); +} + +auto pVerticalScroller::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pVerticalScroller::minimumSize() const -> Size { + return {20, 0}; +} + +auto pVerticalScroller::setLength(unsigned length) -> void { + lock(); + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); + unlock(); +} + +auto pVerticalScroller::setPosition(unsigned position) -> void { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +} diff --git a/hiro/gtk/widget/vertical-scroller.hpp b/hiro/gtk/widget/vertical-scroller.hpp new file mode 100644 index 00000000..e4333c90 --- /dev/null +++ b/hiro/gtk/widget/vertical-scroller.hpp @@ -0,0 +1,11 @@ +namespace hiro { + +struct pVerticalScroller : pWidget { + Declare(VerticalScroller, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; +}; + +} diff --git a/hiro/gtk/widget/vertical-slider.cpp b/hiro/gtk/widget/vertical-slider.cpp new file mode 100644 index 00000000..25fed744 --- /dev/null +++ b/hiro/gtk/widget/vertical-slider.cpp @@ -0,0 +1,40 @@ +namespace hiro { + +static auto VerticalSlider_change(GtkRange* gtkRange, pVerticalSlider* p) -> void { + auto position = (unsigned)gtk_range_get_value(gtkRange); + if(p->state().position == position) return; + p->state().position = position; + if(!p->locked()) p->self().doChange(); +} + +auto pVerticalSlider::construct() -> void { + gtkWidget = gtk_vscale_new_with_range(0, 100, 1); + gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); + + setLength(state().length); + setPosition(state().position); + + g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)this); + + pWidget::construct(); +} + +auto pVerticalSlider::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pVerticalSlider::minimumSize() const -> Size { + return {20, 0}; +} + +auto pVerticalSlider::setLength(unsigned length) -> void { + length += length == 0; + gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); + gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); +} + +auto pVerticalSlider::setPosition(unsigned position) -> void { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +} diff --git a/hiro/gtk/widget/vertical-slider.hpp b/hiro/gtk/widget/vertical-slider.hpp new file mode 100644 index 00000000..58995857 --- /dev/null +++ b/hiro/gtk/widget/vertical-slider.hpp @@ -0,0 +1,11 @@ +namespace hiro { + +struct pVerticalSlider : pWidget { + Declare(VerticalSlider, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; +}; + +} diff --git a/hiro/gtk/widget/viewport.cpp b/hiro/gtk/widget/viewport.cpp new file mode 100644 index 00000000..f6a27c94 --- /dev/null +++ b/hiro/gtk/widget/viewport.cpp @@ -0,0 +1,78 @@ +namespace hiro { + +static auto Viewport_dropEvent(GtkWidget* widget, GdkDragContext* context, signed x, signed y, +GtkSelectionData* data, unsigned type, unsigned timestamp, pViewport* p) -> void { + if(!p->state().droppable) return; + lstring paths = DropPaths(data); + if(paths.empty()) return; + p->self().doDrop(paths); +} + +static auto Viewport_mouseLeave(GtkWidget* widget, GdkEventButton* event, pViewport* p) -> signed { + p->self().doMouseLeave(); + return true; +} + +static auto Viewport_mouseMove(GtkWidget* widget, GdkEventButton* event, pViewport* p) -> signed { + p->self().doMouseMove({(signed)event->x, (signed)event->y}); + return true; +} + +static auto Viewport_mousePress(GtkWidget* widget, GdkEventButton* event, pViewport* p) -> signed { + switch(event->button) { + case 1: p->self().doMousePress(Mouse::Button::Left); break; + case 2: p->self().doMousePress(Mouse::Button::Middle); break; + case 3: p->self().doMousePress(Mouse::Button::Right); break; + } + return true; +} + +static auto Viewport_mouseRelease(GtkWidget* widget, GdkEventButton* event, pViewport* p) -> signed { + switch(event->button) { + case 1: p->self().doMouseRelease(Mouse::Button::Left); break; + case 2: p->self().doMouseRelease(Mouse::Button::Middle); break; + case 3: p->self().doMouseRelease(Mouse::Button::Right); break; + } + return true; +} + +auto pViewport::construct() -> void { + gtkWidget = gtk_drawing_area_new(); + gtk_widget_add_events(gtkWidget, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); + + GdkColor color; + color.pixel = 0; + color.red = 0; + color.green = 0; + color.blue = 0; + gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, &color); + + setDroppable(state().droppable); + + g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Viewport_mousePress), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Viewport_mouseRelease), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Viewport_dropEvent), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Viewport_mouseLeave), (gpointer)this); + g_signal_connect(G_OBJECT(gtkWidget), "motion-notify-event", G_CALLBACK(Viewport_mouseMove), (gpointer)this); + + pWidget::construct(); +} + +auto pViewport::destruct() -> void { + if(gtkWidget) gtk_widget_destroy(gtkWidget), gtkWidget = nullptr; + gtkParent = nullptr; +} + +auto pViewport::handle() const -> uintptr_t { + return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget)); +} + +auto pViewport::setDroppable(bool droppable) -> void { + if(droppable) { + gtk_drag_dest_set(gtkWidget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY); + gtk_drag_dest_add_uri_targets(gtkWidget); + } +} + +} diff --git a/hiro/gtk/widget/viewport.hpp b/hiro/gtk/widget/viewport.hpp new file mode 100644 index 00000000..137d0b01 --- /dev/null +++ b/hiro/gtk/widget/viewport.hpp @@ -0,0 +1,10 @@ +namespace hiro { + +struct pViewport : pWidget { + Declare(Viewport, Widget) + + auto handle() const -> uintptr_t; + auto setDroppable(bool droppable) -> void; +}; + +} diff --git a/hiro/gtk/widget/widget.cpp b/hiro/gtk/widget/widget.cpp new file mode 100644 index 00000000..6c03f128 --- /dev/null +++ b/hiro/gtk/widget/widget.cpp @@ -0,0 +1,51 @@ +namespace hiro { + +auto pWidget::construct() -> void { + if(!gtkWidget) return; + if(auto window = self().parentWindow(true)) { + if(window->self()) window->self()->_append(self()); + setFont(self().font(true)); + setVisible(self().visible(true)); + } +} + +auto pWidget::destruct() -> void { +} + +auto pWidget::container(mWidget& widget) -> GtkWidget* { + return nullptr; +} + +auto pWidget::focused() const -> bool { + if(!gtkWidget) return false; + return GTK_WIDGET_HAS_FOCUS(gtkWidget); +} + +auto pWidget::setEnabled(bool enabled) -> void { + if(!gtkWidget) return; + gtk_widget_set_sensitive(gtkWidget, enabled); +} + +auto pWidget::setFocused() -> void { + if(!gtkWidget) return; + gtk_widget_grab_focus(gtkWidget); +} + +auto pWidget::setFont(const string& font) -> void { + if(!gtkWidget) return; + return pFont::setFont(gtkWidget, font); +} + +auto pWidget::setGeometry(Geometry geometry) -> void { + if(!gtkWidget) return; + if(gtkParent) gtk_fixed_move(GTK_FIXED(gtkParent), gtkWidget, geometry.x(), geometry.y()); + gtk_widget_set_size_request(gtkWidget, max(1, geometry.width()), max(1, geometry.height())); + self().doSize(); +} + +auto pWidget::setVisible(bool visible) -> void { + if(!gtkWidget) return; + gtk_widget_set_visible(gtkWidget, visible); +} + +} diff --git a/hiro/gtk/widget/widget.hpp b/hiro/gtk/widget/widget.hpp new file mode 100644 index 00000000..244361eb --- /dev/null +++ b/hiro/gtk/widget/widget.hpp @@ -0,0 +1,18 @@ +namespace hiro { + +struct pWidget : pSizable { + Declare(Widget, Sizable) + + virtual auto container(mWidget& widget) -> GtkWidget*; + virtual auto focused() const -> bool override; + auto setEnabled(bool enabled) -> void override; + virtual auto setFocused() -> void override; + auto setFont(const string& font) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setVisible(bool visible) -> void override; + + GtkWidget* gtkWidget = nullptr; + GtkWidget* gtkParent = nullptr; +}; + +} diff --git a/hiro/gtk/window.cpp b/hiro/gtk/window.cpp new file mode 100644 index 00000000..11de8a97 --- /dev/null +++ b/hiro/gtk/window.cpp @@ -0,0 +1,400 @@ +namespace hiro { + +static auto Window_close(GtkWidget* widget, GdkEvent* event, pWindow* p) -> signed { + if(p->state().onClose) { + p->self().doClose(); + } else { + p->self().setVisible(false); + } + if(p->state().modal && !p->pObject::state().visible) p->self().setModal(false); + return true; +} + +static auto Window_expose(GtkWidget* widget, GdkEvent* event, pWindow* p) -> signed { + if(auto color = p->state().backgroundColor) { + cairo_t* context = gdk_cairo_create(widget->window); + + double red = (double)color.red() / 255.0; + double green = (double)color.green() / 255.0; + double blue = (double)color.blue() / 255.0; + double alpha = (double)color.alpha() / 255.0; + + if(gdk_screen_is_composited(gdk_screen_get_default()) + && gdk_screen_get_rgba_colormap(gdk_screen_get_default()) + ) { + cairo_set_source_rgba(context, red, green, blue, alpha); + } else { + cairo_set_source_rgb(context, red, green, blue); + } + + cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); + cairo_paint(context); + cairo_destroy(context); + } + return false; +} + +static auto Window_configure(GtkWidget* widget, GdkEvent* event, pWindow* p) -> signed { + if(!gtk_widget_get_realized(p->widget)) return false; + if(!p->pObject::state().visible) return false; + GdkWindow* gdkWindow = gtk_widget_get_window(widget); + + GdkRectangle border, client; + gdk_window_get_frame_extents(gdkWindow, &border); + gdk_window_get_geometry(gdkWindow, nullptr, nullptr, &client.width, &client.height, nullptr); + gdk_window_get_origin(gdkWindow, &client.x, &client.y); + + if(!p->state().fullScreen) { + //update geometry settings + settings->geometry.frameX = client.x - border.x; + settings->geometry.frameY = client.y - border.y; + settings->geometry.frameWidth = border.width - client.width; + settings->geometry.frameHeight = border.height - client.height; + settings->save(); + } + + Geometry geometry = { + client.x, + client.y + p->_menuHeight(), + client.width, + client.height - p->_menuHeight() - p->_statusHeight() + }; + + //move + if(geometry.x() != p->state().geometry.x() || geometry.y() != p->state().geometry.y()) { + if(!p->state().fullScreen) { + p->state().geometry.setX(geometry.x()); + p->state().geometry.setY(geometry.y()); + } + if(!p->locked()) p->self().doMove(); + } + + //size + if(geometry.width() != p->state().geometry.width() || geometry.height() != p->state().geometry.height()) { + p->onSizePending = true; + } + + return false; +} + +static auto Window_drop(GtkWidget* widget, GdkDragContext* context, signed x, signed y, +GtkSelectionData* data, unsigned type, unsigned timestamp, pWindow* p) -> void { + if(!p->state().droppable) return; + lstring paths = DropPaths(data); + if(paths.empty()) return; + p->self().doDrop(paths); +} + +static auto Window_keyPress(GtkWidget* widget, GdkEventKey* event, pWindow* p) -> signed { + if(auto key = pKeyboard::_translate(event->keyval)) { + p->self().doKeyPress(key); + } + return false; +} + +static auto Window_keyRelease(GtkWidget* widget, GdkEventKey* event, pWindow* p) -> signed { + if(auto key = pKeyboard::_translate(event->keyval)) { + p->self().doKeyRelease(key); + } + return false; +} + +static auto Window_sizeAllocate(GtkWidget* widget, GtkAllocation* allocation, pWindow* p) -> void { + //size-allocate sent from gtk_fixed_move(); detect if layout unchanged and return + if(allocation->width == p->lastAllocation.width + && allocation->height == p->lastAllocation.height) return; + + p->state().geometry.setWidth(allocation->width); + p->state().geometry.setHeight(allocation->height); + + if(auto& layout = p->state().layout) { + layout->setGeometry(p->self().geometry().setPosition(0, 0)); + } + + if(!p->locked() && p->onSizePending) { + p->onSizePending = false; + p->self().doSize(); + } + + p->lastAllocation = *allocation; +} + +static auto Window_sizeRequest(GtkWidget* widget, GtkRequisition* requisition, pWindow* p) -> void { + requisition->width = p->state().geometry.width(); + requisition->height = p->state().geometry.height(); +} + +auto pWindow::construct() -> void { + lastAllocation.width = 0; + lastAllocation.height = 0; + onSizePending = false; + + widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_resizable(GTK_WINDOW(widget), true); + + //if program was given a name, try and set the window taskbar icon from one of the pixmaps folders + if(!Application::state.name); + else if(_setIcon({userpath(), ".local/share/icons/"})); + else if(_setIcon("/usr/local/share/pixmaps/")); + else if(_setIcon("/usr/share/pixmaps/")); + + GdkColormap* colormap = gdk_screen_get_rgba_colormap(gdk_screen_get_default()); + if(!colormap) colormap = gdk_screen_get_rgb_colormap(gdk_screen_get_default()); + if(colormap) gtk_widget_set_colormap(widget, colormap); + + gtk_widget_set_app_paintable(widget, true); + gtk_widget_add_events(widget, GDK_CONFIGURE); + + menuContainer = gtk_vbox_new(false, 0); + gtk_container_add(GTK_CONTAINER(widget), menuContainer); + gtk_widget_show(menuContainer); + + gtkMenu = gtk_menu_bar_new(); + gtk_box_pack_start(GTK_BOX(menuContainer), gtkMenu, false, false, 0); + + formContainer = gtk_fixed_new(); + gtk_box_pack_start(GTK_BOX(menuContainer), formContainer, true, true, 0); + gtk_widget_show(formContainer); + + statusContainer = gtk_event_box_new(); + gtkStatus = gtk_statusbar_new(); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(gtkStatus), true); + gtk_container_add(GTK_CONTAINER(statusContainer), gtkStatus); + gtk_box_pack_start(GTK_BOX(menuContainer), statusContainer, false, false, 0); + gtk_widget_show(statusContainer); + + setBackgroundColor(state().backgroundColor); + setDroppable(state().droppable); + setGeometry(state().geometry); + setResizable(state().resizable); + setTitle(state().title); + + g_signal_connect(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)this); + g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(Window_expose), (gpointer)this); + g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)this); + g_signal_connect(G_OBJECT(widget), "drag-data-received", G_CALLBACK(Window_drop), (gpointer)this); + g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(Window_keyPress), (gpointer)this); + g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(Window_keyRelease), (gpointer)this); + g_signal_connect(G_OBJECT(formContainer), "size-allocate", G_CALLBACK(Window_sizeAllocate), (gpointer)this); + g_signal_connect(G_OBJECT(formContainer), "size-request", G_CALLBACK(Window_sizeRequest), (gpointer)this); +} + +auto pWindow::destruct() -> void { +} + +auto pWindow::append(shared_pointer menuBar) -> void { +} + +auto pWindow::append(shared_pointer statusBar) -> void { + _setStatusEnabled(statusBar->enabled(true)); + _setStatusFont(statusBar->font(true)); + _setStatusText(statusBar->text()); + _setStatusVisible(statusBar->visible(true)); +} + +auto pWindow::focused() const -> bool { + return gtk_window_is_active(GTK_WINDOW(widget)); +} + +auto pWindow::frameMargin() const -> Geometry { + if(state().fullScreen) return { + 0, _menuHeight(), + 0, _menuHeight() + _statusHeight() + }; + + return { + settings->geometry.frameX, + settings->geometry.frameY + _menuHeight(), + settings->geometry.frameWidth, + settings->geometry.frameHeight + _menuHeight() + _statusHeight() + }; +} + +auto pWindow::remove(shared_pointer menuBar) -> void { + _setMenuVisible(false); +} + +auto pWindow::remove(shared_pointer statusBar) -> void { + _setStatusVisible(false); +} + +auto pWindow::setBackgroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pWindow::setDroppable(bool droppable) -> void { + gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY); + if(droppable) gtk_drag_dest_add_uri_targets(widget); +} + +auto pWindow::setEnabled(bool enabled) -> void { + if(auto& menuBar = state().menuBar) { + if(menuBar->self()) menuBar->self()->setEnabled(menuBar->enabled(true)); + } + + if(auto& statusBar = state().statusBar) { + if(statusBar->self()) statusBar->self()->setEnabled(statusBar->enabled(true)); + } + + if(auto& layout = state().layout) { + if(layout->self()) layout->self()->setEnabled(layout->enabled(true)); + } +} + +auto pWindow::setFocused() -> void { + gtk_window_present(GTK_WINDOW(widget)); +} + +auto pWindow::setFullScreen(bool fullScreen) -> void { + if(fullScreen == false) { + gtk_window_unfullscreen(GTK_WINDOW(widget)); + } else { + gtk_window_fullscreen(GTK_WINDOW(widget)); + } +} + +auto pWindow::setGeometry(Geometry geometry) -> void { + Geometry margin = frameMargin(); + gtk_window_move(GTK_WINDOW(widget), geometry.x() - margin.x(), geometry.y() - margin.y()); + + GdkGeometry geom; + geom.min_width = state().resizable ? 1 : state().geometry.width(); + geom.min_height = state().resizable ? 1 : state().geometry.height(); + gtk_window_set_geometry_hints(GTK_WINDOW(widget), GTK_WIDGET(widget), &geom, GDK_HINT_MIN_SIZE); + + gtk_widget_set_size_request(formContainer, geometry.width(), geometry.height()); + gtk_window_resize(GTK_WINDOW(widget), geometry.width(), geometry.height() + _menuHeight() + _statusHeight()); +} + +auto pWindow::setModal(bool modal) -> void { + if(modal) { + gtk_window_set_modal(GTK_WINDOW(widget), true); + while(state().modal) { + Application::processEvents(); + if(Application::state.onMain) { + Application::doMain(); + } else { + usleep(20 * 1000); + } + } + gtk_window_set_modal(GTK_WINDOW(widget), false); + } +} + +auto pWindow::setResizable(bool resizable) -> void { + gtk_window_set_resizable(GTK_WINDOW(widget), resizable); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(gtkStatus), resizable); +} + +auto pWindow::setTitle(const string& title) -> void { + gtk_window_set_title(GTK_WINDOW(widget), title ? title : " "); +} + +auto pWindow::setVisible(bool visible) -> void { + gtk_widget_set_visible(widget, visible); + + if(auto& menuBar = state().menuBar) { + if(menuBar->self()) menuBar->self()->setVisible(menuBar->visible(true)); + } + + if(auto& statusBar = state().statusBar) { + if(statusBar->self()) statusBar->self()->setVisible(statusBar->visible(true)); + } + + if(visible) { + if(gtk_widget_get_visible(gtkMenu)) { + GtkAllocation allocation; + gtk_widget_get_allocation(gtkMenu, &allocation); + settings->geometry.menuHeight = allocation.height; + } + + if(gtk_widget_get_visible(gtkStatus)) { + GtkAllocation allocation; + gtk_widget_get_allocation(gtkStatus, &allocation); + settings->geometry.statusHeight = allocation.height; + } + } + + if(auto& layout = state().layout) { + if(layout->self()) layout->self()->setVisible(layout->visible(true)); + Application::processEvents(); //todo: this should not be necessary + layout->setGeometry(self().geometry().setPosition(0, 0)); + } +} + +auto pWindow::_append(mWidget& widget) -> void { + if(!widget.self()) return; + if(auto parent = widget.parentWidget(true)) { + if(parent->self()) widget.self()->gtkParent = parent->self()->container(widget); + } else { + widget.self()->gtkParent = formContainer; + } + gtk_fixed_put(GTK_FIXED(widget.self()->gtkParent), widget.self()->gtkWidget, 0, 0); +} + +auto pWindow::_append(mMenu& menu) -> void { + if(menu.self()) gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), menu.self()->widget); +} + +auto pWindow::_menuHeight() const -> signed { + return gtk_widget_get_visible(gtkMenu) ? settings->geometry.menuHeight : 0; +} + +auto pWindow::_setIcon(const string& pathname) -> bool { + string filename; + + filename = {pathname, Application::state.name, ".svg"}; + if(file::exists(filename)) { + gtk_window_set_icon_from_file(GTK_WINDOW(widget), filename, nullptr); + return true; + } + + filename = {pathname, Application::state.name, ".png"}; + if(file::exists(filename)) { + //maximum image size GTK+ supports is 256x256; scale image down if necessary to prevent error + nall::image icon(filename); + icon.scale(min(256u, icon.width), min(256u, icon.height), true); + GdkPixbuf* pixbuf = CreatePixbuf(icon); + gtk_window_set_icon(GTK_WINDOW(widget), pixbuf); + g_object_unref(G_OBJECT(pixbuf)); + return true; + } + + return false; +} + +auto pWindow::_setMenuEnabled(bool enabled) -> void { + gtk_widget_set_sensitive(gtkMenu, enabled); +} + +auto pWindow::_setMenuFont(const string& font) -> void { + pFont::setFont(gtkMenu, font); +} + +auto pWindow::_setMenuVisible(bool visible) -> void { + gtk_widget_set_visible(gtkMenu, visible); +} + +auto pWindow::_setStatusEnabled(bool enabled) -> void { + gtk_widget_set_sensitive(gtkStatus, enabled); +} + +auto pWindow::_setStatusFont(const string& font) -> void { + pFont::setFont(gtkStatus, font); +} + +auto pWindow::_setStatusText(const string& text) -> void { + gtk_statusbar_pop(GTK_STATUSBAR(gtkStatus), 1); + gtk_statusbar_push(GTK_STATUSBAR(gtkStatus), 1, text); +} + +auto pWindow::_setStatusVisible(bool visible) -> void { + gtk_widget_set_visible(gtkStatus, visible); +} + +auto pWindow::_statusHeight() const -> signed { + return gtk_widget_get_visible(gtkStatus) ? settings->geometry.statusHeight : 0; +} + +} diff --git a/hiro/gtk/window.hpp b/hiro/gtk/window.hpp new file mode 100644 index 00000000..7f88ba8f --- /dev/null +++ b/hiro/gtk/window.hpp @@ -0,0 +1,46 @@ +namespace hiro { + +struct pWindow : pObject { + Declare(Window, Object) + + GtkWidget* widget = nullptr; + GtkWidget* menuContainer = nullptr; + GtkWidget* formContainer = nullptr; + GtkWidget* statusContainer = nullptr; + GtkWidget* gtkMenu = nullptr; + GtkWidget* gtkStatus = nullptr; + GtkAllocation lastAllocation = {0}; + bool onSizePending = false; + + auto append(shared_pointer menuBar) -> void; + auto append(shared_pointer statusBar) -> void; + auto focused() const -> bool override; + auto frameMargin() const -> Geometry; + auto remove(shared_pointer menuBar) -> void; + auto remove(shared_pointer statusBar) -> void; + auto setBackgroundColor(Color color) -> void; + auto setDroppable(bool droppable) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFocused() -> void override; + auto setFullScreen(bool fullScreen) -> void; + auto setGeometry(Geometry geometry) -> void; + auto setModal(bool modal) -> void; + auto setResizable(bool resizable) -> void; + auto setTitle(const string& title) -> void; + auto setVisible(bool visible) -> void override; + + auto _append(mWidget& widget) -> void; + auto _append(mMenu& menu) -> void; + auto _menuHeight() const -> signed; + auto _setIcon(const string& basename) -> bool; + auto _setMenuEnabled(bool enabled) -> void; + auto _setMenuFont(const string& font) -> void; + auto _setMenuVisible(bool visible) -> void; + auto _setStatusEnabled(bool enabled) -> void; + auto _setStatusFont(const string& font) -> void; + auto _setStatusText(const string& text) -> void; + auto _setStatusVisible(bool visible) -> void; + auto _statusHeight() const -> signed; +}; + +} diff --git a/hiro/hiro.cpp b/hiro/hiro.cpp new file mode 100644 index 00000000..ab89294f --- /dev/null +++ b/hiro/hiro.cpp @@ -0,0 +1,7 @@ +#ifndef HIRO_CPP +#define HIRO_CPP + +#include "core/core.cpp" +#include "extension/extension.cpp" + +#endif diff --git a/hiro/hiro.hpp b/hiro/hiro.hpp new file mode 100644 index 00000000..8adb9a69 --- /dev/null +++ b/hiro/hiro.hpp @@ -0,0 +1,16 @@ +/* hiro + * author: byuu + * license: ISC + * + * hiro is a cross-platform GUI toolkit + * it provides a consistent, minimal API wrapper to: Windows, Cocoa, GTK+ and Qt + * it also provides a reference wrapper for terminal applications with optional UIs + */ + +#ifndef HIRO_HPP +#define HIRO_HPP + +#include "core/core.hpp" +#include "extension/extension.hpp" + +#endif diff --git a/phoenix/qt/action/action.cpp b/hiro/qt/action/action.cpp similarity index 100% rename from phoenix/qt/action/action.cpp rename to hiro/qt/action/action.cpp diff --git a/phoenix/qt/action/check-item.cpp b/hiro/qt/action/check-item.cpp similarity index 100% rename from phoenix/qt/action/check-item.cpp rename to hiro/qt/action/check-item.cpp diff --git a/phoenix/qt/action/item.cpp b/hiro/qt/action/item.cpp similarity index 100% rename from phoenix/qt/action/item.cpp rename to hiro/qt/action/item.cpp diff --git a/phoenix/qt/action/menu.cpp b/hiro/qt/action/menu.cpp similarity index 96% rename from phoenix/qt/action/menu.cpp rename to hiro/qt/action/menu.cpp index efe5188a..0b258fa3 100644 --- a/phoenix/qt/action/menu.cpp +++ b/hiro/qt/action/menu.cpp @@ -18,7 +18,7 @@ void pMenu::remove(Action& action) { if(dynamic_cast(&action)) { //QMenu::removeMenu() does not exist qtMenu->clear(); - for(auto &action : menu.state.action) append(action); + for(auto& action : menu.state.action) append(action); } else if(dynamic_cast(&action)) { qtMenu->removeAction(((Separator&)action).p.qtAction); } else if(dynamic_cast(&action)) { diff --git a/phoenix/qt/action/radio-item.cpp b/hiro/qt/action/radio-item.cpp similarity index 89% rename from phoenix/qt/action/radio-item.cpp rename to hiro/qt/action/radio-item.cpp index e7c9974b..0dc16084 100644 --- a/phoenix/qt/action/radio-item.cpp +++ b/hiro/qt/action/radio-item.cpp @@ -1,13 +1,13 @@ namespace phoenix { void pRadioItem::setChecked() { - locked = true; + lock(); for(auto& item : radioItem.state.group) { bool checkState = item.p.qtAction == qtAction; item.state.checked = checkState; item.p.qtAction->setChecked(checkState); } - locked = false; + unlock(); } void pRadioItem::setGroup(const group& group) { @@ -35,7 +35,7 @@ void pRadioItem::destructor() { void pRadioItem::onActivate() { if(!radioItem.state.checked) { setChecked(); - if(!locked && radioItem.onActivate) radioItem.onActivate(); + if(!locked() && radioItem.onActivate) radioItem.onActivate(); } } diff --git a/phoenix/qt/action/separator.cpp b/hiro/qt/action/separator.cpp similarity index 100% rename from phoenix/qt/action/separator.cpp rename to hiro/qt/action/separator.cpp diff --git a/phoenix/qt/application.cpp b/hiro/qt/application.cpp similarity index 100% rename from phoenix/qt/application.cpp rename to hiro/qt/application.cpp diff --git a/phoenix/qt/browser-window.cpp b/hiro/qt/browser-window.cpp similarity index 100% rename from phoenix/qt/browser-window.cpp rename to hiro/qt/browser-window.cpp diff --git a/phoenix/qt/desktop.cpp b/hiro/qt/desktop.cpp similarity index 100% rename from phoenix/qt/desktop.cpp rename to hiro/qt/desktop.cpp diff --git a/phoenix/qt/font.cpp b/hiro/qt/font.cpp similarity index 93% rename from phoenix/qt/font.cpp rename to hiro/qt/font.cpp index 3c6fe572..58542f67 100644 --- a/phoenix/qt/font.cpp +++ b/hiro/qt/font.cpp @@ -23,9 +23,7 @@ Size pFont::size(string font, string text) { } QFont pFont::create(string description) { - lstring part; - part.split<2>(",", description); - for(auto& item : part) item.trim(" "); + lstring part = description.split<2>(",").strip(); string family = "Sans"; unsigned size = 8u; diff --git a/phoenix/qt/header.hpp b/hiro/qt/header.hpp similarity index 100% rename from phoenix/qt/header.hpp rename to hiro/qt/header.hpp diff --git a/phoenix/gtk/keyboard.cpp b/hiro/qt/keyboard.cpp similarity index 100% rename from phoenix/gtk/keyboard.cpp rename to hiro/qt/keyboard.cpp diff --git a/phoenix/qt/message-window.cpp b/hiro/qt/message-window.cpp similarity index 100% rename from phoenix/qt/message-window.cpp rename to hiro/qt/message-window.cpp diff --git a/phoenix/qt/monitor.cpp b/hiro/qt/monitor.cpp similarity index 100% rename from phoenix/qt/monitor.cpp rename to hiro/qt/monitor.cpp diff --git a/phoenix/qt/mouse.cpp b/hiro/qt/mouse.cpp similarity index 100% rename from phoenix/qt/mouse.cpp rename to hiro/qt/mouse.cpp diff --git a/phoenix/qt/platform.cpp b/hiro/qt/platform.cpp similarity index 95% rename from phoenix/qt/platform.cpp rename to hiro/qt/platform.cpp index 4547e362..849bd5b4 100644 --- a/phoenix/qt/platform.cpp +++ b/hiro/qt/platform.cpp @@ -13,6 +13,7 @@ #include "font.cpp" #include "timer.cpp" #include "window.cpp" +#include "popup-menu.cpp" #include "action/action.cpp" #include "action/menu.cpp" @@ -32,6 +33,7 @@ #include "widget/hex-edit.cpp" #include "widget/horizontal-scroller.cpp" #include "widget/horizontal-slider.cpp" +#include "widget/icon-view.cpp" #include "widget/label.cpp" #include "widget/line-edit.cpp" #include "widget/list-view.cpp" diff --git a/phoenix/qt/platform.moc b/hiro/qt/platform.moc similarity index 90% rename from phoenix/qt/platform.moc rename to hiro/qt/platform.moc index ccf22d32..7ff83e9b 100644 --- a/phoenix/qt/platform.moc +++ b/hiro/qt/platform.moc @@ -1,8 +1,7 @@ /**************************************************************************** ** Meta object code from reading C++ file 'platform.moc.hpp' ** -** Created: Fri Feb 14 13:37:55 2014 -** by: The Qt Meta Object Compiler version 63 (Qt 4.8.2) +** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.5) ** ** WARNING! All changes made in this file will be lost! *****************************************************************************/ @@ -10,7 +9,7 @@ #if !defined(Q_MOC_OUTPUT_REVISION) #error "The header file 'platform.moc.hpp' doesn't include ." #elif Q_MOC_OUTPUT_REVISION != 63 -#error "This file was generated using the moc from 4.8.2. It" +#error "This file was generated using the moc from 4.8.5. It" #error "cannot be used with the include files from this version of Qt." #error "(The moc has changed too much.)" #endif @@ -30,13 +29,13 @@ static const uint qt_meta_data_phoenix__pTimer[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 17, 16, 16, 16, 0x0a, + 16, 29, 29, 29, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pTimer[] = { - "phoenix::pTimer\0\0onActivate()\0" + "phoenix::pTimer\0onActivate()\0\0" }; void phoenix::pTimer::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -169,13 +168,13 @@ static const uint qt_meta_data_phoenix__pItem[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 16, 15, 15, 15, 0x0a, + 15, 28, 28, 28, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pItem[] = { - "phoenix::pItem\0\0onActivate()\0" + "phoenix::pItem\0onActivate()\0\0" }; void phoenix::pItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -245,13 +244,13 @@ static const uint qt_meta_data_phoenix__pCheckItem[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 21, 20, 20, 20, 0x0a, + 20, 31, 31, 31, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pCheckItem[] = { - "phoenix::pCheckItem\0\0onToggle()\0" + "phoenix::pCheckItem\0onToggle()\0\0" }; void phoenix::pCheckItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -321,13 +320,13 @@ static const uint qt_meta_data_phoenix__pRadioItem[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 21, 20, 20, 20, 0x0a, + 20, 33, 33, 33, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pRadioItem[] = { - "phoenix::pRadioItem\0\0onActivate()\0" + "phoenix::pRadioItem\0onActivate()\0\0" }; void phoenix::pRadioItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -397,13 +396,13 @@ static const uint qt_meta_data_phoenix__pButton[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 18, 17, 17, 17, 0x0a, + 17, 30, 30, 30, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pButton[] = { - "phoenix::pButton\0\0onActivate()\0" + "phoenix::pButton\0onActivate()\0\0" }; void phoenix::pButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -536,14 +535,14 @@ static const uint qt_meta_data_phoenix__pCheckButton[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 31, 23, 22, 22, 0x0a, + 22, 37, 45, 45, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pCheckButton[] = { - "phoenix::pCheckButton\0\0checked\0" - "onToggle(bool)\0" + "phoenix::pCheckButton\0onToggle(bool)\0" + "checked\0\0" }; void phoenix::pCheckButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -612,13 +611,13 @@ static const uint qt_meta_data_phoenix__pCheckLabel[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 22, 21, 21, 21, 0x0a, + 21, 32, 32, 32, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pCheckLabel[] = { - "phoenix::pCheckLabel\0\0onToggle()\0" + "phoenix::pCheckLabel\0onToggle()\0\0" }; void phoenix::pCheckLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -688,13 +687,13 @@ static const uint qt_meta_data_phoenix__pComboButton[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 23, 22, 22, 22, 0x0a, + 22, 33, 33, 33, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pComboButton[] = { - "phoenix::pComboButton\0\0onChange()\0" + "phoenix::pComboButton\0onChange()\0\0" }; void phoenix::pComboButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -890,13 +889,13 @@ static const uint qt_meta_data_phoenix__pHexEdit[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 19, 18, 18, 18, 0x0a, + 18, 29, 29, 29, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pHexEdit[] = { - "phoenix::pHexEdit\0\0onScroll()\0" + "phoenix::pHexEdit\0onScroll()\0\0" }; void phoenix::pHexEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -966,13 +965,14 @@ static const uint qt_meta_data_phoenix__pHorizontalScroller[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 30, 29, 29, 29, 0x0a, + 29, 40, 40, 40, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pHorizontalScroller[] = { - "phoenix::pHorizontalScroller\0\0onChange()\0" + "phoenix::pHorizontalScroller\0onChange()\0" + "\0" }; void phoenix::pHorizontalScroller::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -1042,13 +1042,14 @@ static const uint qt_meta_data_phoenix__pHorizontalSlider[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 28, 27, 27, 27, 0x0a, + 27, 38, 38, 38, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pHorizontalSlider[] = { - "phoenix::pHorizontalSlider\0\0onChange()\0" + "phoenix::pHorizontalSlider\0onChange()\0" + "\0" }; void phoenix::pHorizontalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -1104,6 +1105,87 @@ int phoenix::pHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void } return _id; } +static const uint qt_meta_data_phoenix__pIconView[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 3, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 19, 32, 32, 32, 0x0a, + 33, 32, 32, 32, 0x0a, + 44, 32, 32, 32, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_phoenix__pIconView[] = { + "phoenix::pIconView\0onActivate()\0\0" + "onChange()\0onContext()\0" +}; + +void phoenix::pIconView::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + pIconView *_t = static_cast(_o); + switch (_id) { + case 0: _t->onActivate(); break; + case 1: _t->onChange(); break; + case 2: _t->onContext(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData phoenix::pIconView::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject phoenix::pIconView::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pIconView, + qt_meta_data_phoenix__pIconView, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &phoenix::pIconView::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *phoenix::pIconView::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *phoenix::pIconView::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_phoenix__pIconView)) + return static_cast(const_cast< pIconView*>(this)); + if (!strcmp(_clname, "pWidget")) + return static_cast< pWidget*>(const_cast< pIconView*>(this)); + return QObject::qt_metacast(_clname); +} + +int phoenix::pIconView::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 3) + qt_static_metacall(this, _c, _id, _a); + _id -= 3; + } + return _id; +} static const uint qt_meta_data_phoenix__pLineEdit[] = { // content: @@ -1118,14 +1200,14 @@ static const uint qt_meta_data_phoenix__pLineEdit[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 20, 19, 19, 19, 0x0a, - 33, 19, 19, 19, 0x0a, + 19, 32, 32, 32, 0x0a, + 33, 32, 32, 32, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pLineEdit[] = { - "phoenix::pLineEdit\0\0onActivate()\0" + "phoenix::pLineEdit\0onActivate()\0\0" "onChange()\0" }; @@ -1189,7 +1271,7 @@ static const uint qt_meta_data_phoenix__pListView[] = { 6, // revision 0, // classname 0, 0, // classinfo - 3, 14, // methods + 6, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors @@ -1197,17 +1279,22 @@ static const uint qt_meta_data_phoenix__pListView[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 20, 19, 19, 19, 0x0a, - 38, 33, 19, 19, 0x0a, - 65, 33, 19, 19, 0x0a, + 19, 32, 32, 32, 0x0a, + 33, 32, 32, 32, 0x0a, + 44, 32, 32, 32, 0x0a, + 56, 68, 32, 32, 0x0a, + 75, 102, 32, 32, 0x0a, + 107, 141, 161, 32, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pListView[] = { - "phoenix::pListView\0\0onActivate()\0item\0" - "onChange(QTreeWidgetItem*)\0" - "onToggle(QTreeWidgetItem*)\0" + "phoenix::pListView\0onActivate()\0\0" + "onChange()\0onContext()\0onSort(int)\0" + "column\0onToggle(QTreeWidgetItem*)\0" + "item\0calculateAlignment(double,double)\0" + "horizontal,vertical\0int\0" }; void phoenix::pListView::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -1217,8 +1304,12 @@ void phoenix::pListView::qt_static_metacall(QObject *_o, QMetaObject::Call _c, i pListView *_t = static_cast(_o); switch (_id) { case 0: _t->onActivate(); break; - case 1: _t->onChange((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break; - case 2: _t->onToggle((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break; + case 1: _t->onChange(); break; + case 2: _t->onContext(); break; + case 3: _t->onSort((*reinterpret_cast< int(*)>(_a[1]))); break; + case 4: _t->onToggle((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break; + case 5: { int _r = _t->calculateAlignment((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2]))); + if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break; default: ; } } @@ -1258,9 +1349,9 @@ int phoenix::pListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a) if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { - if (_id < 3) + if (_id < 6) qt_static_metacall(this, _c, _id, _a); - _id -= 3; + _id -= 6; } return _id; } @@ -1278,13 +1369,13 @@ static const uint qt_meta_data_phoenix__pRadioLabel[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 22, 21, 21, 21, 0x0a, + 21, 34, 34, 34, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pRadioLabel[] = { - "phoenix::pRadioLabel\0\0onActivate()\0" + "phoenix::pRadioLabel\0onActivate()\0\0" }; void phoenix::pRadioLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -1354,13 +1445,13 @@ static const uint qt_meta_data_phoenix__pRadioButton[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 23, 22, 22, 22, 0x0a, + 22, 35, 35, 35, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pRadioButton[] = { - "phoenix::pRadioButton\0\0onActivate()\0" + "phoenix::pRadioButton\0onActivate()\0\0" }; void phoenix::pRadioButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -1430,14 +1521,14 @@ static const uint qt_meta_data_phoenix__pTabFrame[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 30, 20, 19, 19, 0x0a, + 19, 33, 43, 43, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pTabFrame[] = { - "phoenix::pTabFrame\0\0selection\0" - "onChange(int)\0" + "phoenix::pTabFrame\0onChange(int)\0" + "selection\0\0" }; void phoenix::pTabFrame::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -1506,13 +1597,13 @@ static const uint qt_meta_data_phoenix__pTextEdit[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 20, 19, 19, 19, 0x0a, + 19, 30, 30, 30, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pTextEdit[] = { - "phoenix::pTextEdit\0\0onChange()\0" + "phoenix::pTextEdit\0onChange()\0\0" }; void phoenix::pTextEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -1582,13 +1673,14 @@ static const uint qt_meta_data_phoenix__pVerticalScroller[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 28, 27, 27, 27, 0x0a, + 27, 38, 38, 38, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pVerticalScroller[] = { - "phoenix::pVerticalScroller\0\0onChange()\0" + "phoenix::pVerticalScroller\0onChange()\0" + "\0" }; void phoenix::pVerticalScroller::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -1658,13 +1750,14 @@ static const uint qt_meta_data_phoenix__pVerticalSlider[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 26, 25, 25, 25, 0x0a, + 25, 36, 36, 36, 0x0a, 0 // eod }; static const char qt_meta_stringdata_phoenix__pVerticalSlider[] = { - "phoenix::pVerticalSlider\0\0onChange()\0" + "phoenix::pVerticalSlider\0onChange()\0" + "\0" }; void phoenix::pVerticalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) diff --git a/phoenix/qt/platform.moc.hpp b/hiro/qt/platform.moc.hpp similarity index 83% rename from phoenix/qt/platform.moc.hpp rename to hiro/qt/platform.moc.hpp index 7a8a5677..ac1b96b7 100644 --- a/phoenix/qt/platform.moc.hpp +++ b/hiro/qt/platform.moc.hpp @@ -84,9 +84,13 @@ struct pMessageWindow { struct pObject { Object& object; - bool locked; + signed locks = 0; - pObject(Object& object) : object(object), locked(false) {} + bool locked() const { return locks != 0; } + void lock() { locks++; } + void unlock() { locks--; } + + pObject(Object& object) : object(object) {} virtual ~pObject() {} void constructor() {} void destructor() {} @@ -138,7 +142,6 @@ public: void append(Widget& widget); Geometry frameMargin(); bool focused(); - Geometry geometry(); void remove(Layout& layout); void remove(Menu& menu); void remove(Widget& widget); @@ -164,6 +167,19 @@ public: void updateFrameGeometry(); }; +struct pPopupMenu : public pObject { + PopupMenu& popupMenu; + QMenu* qtMenu; + + void append(Action& action); + void remove(Action& action); + void setVisible(); + + pPopupMenu(PopupMenu& popupMenu) : pObject(popupMenu), popupMenu(popupMenu) {} + void constructor(); + void destructor(); +}; + struct pAction : public pObject { Action& action; @@ -304,6 +320,7 @@ public: QToolButton* qtButton; Size minimumSize(); + void setBordered(bool bordered); void setImage(const image& image, Orientation orientation); void setText(string text); @@ -400,12 +417,11 @@ public: ComboButton& comboButton; QComboBox* qtComboButton; - void append(string text); + void append(); Size minimumSize(); void remove(unsigned selection); void reset(); - unsigned selection(); - void setSelection(unsigned selection); + void setSelected(unsigned selection); void setText(unsigned selection, string text); pComboButton(ComboButton& comboButton) : pWidget(comboButton), comboButton(comboButton) {} @@ -543,6 +559,42 @@ public slots: void onChange(); }; +struct pIconView : public QObject, public pWidget { + Q_OBJECT + +public: + IconView& iconView; + struct QtListWidget : public QListWidget { + void resizeEvent(QResizeEvent*); + }; + QtListWidget* qtIconView; + + void append(); + void remove(unsigned selection); + void reset(); + void setBackgroundColor(Color color); + void setFlow(Orientation flow); + void setForegroundColor(Color color); + void setImage(unsigned selection, const image& image); + void setOrientation(Orientation orientation); + void setSelected(unsigned selection, bool selected); + void setSelected(const vector& selections); + void setSelectedAll(); + void setSelectedNone(); + void setSingleSelection(bool singleSelection); + void setText(unsigned selection, const string& text); + + pIconView(IconView& iconView) : pWidget(iconView), iconView(iconView) {} + void constructor(); + void destructor(); + void orphan(); + +public slots: + void onActivate(); + void onChange(); + void onContext(); +}; + struct pLabel : public pWidget { Label& label; QLabel* qtLabel; @@ -585,22 +637,53 @@ struct pListView : public QObject, public pWidget { public: ListView& listView; - QTreeWidget* qtListView; + struct QtTreeWidget : public QTreeWidget { + pListView& self; + void mousePressEvent(QMouseEvent*); + QtTreeWidget(pListView& self); + }; + struct QtTreeWidgetDelegate : public QStyledItemDelegate { + pListView& self; + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + QtTreeWidgetDelegate(pListView& self); + }; + QtTreeWidget* qtListView; + QtTreeWidgetDelegate* qtListViewDelegate; - void append(const lstring& text); - void autoSizeColumns(); - void remove(unsigned selection); + void appendColumn(); + void appendItem(); + void removeColumn(unsigned position); + void removeItem(unsigned position); void reset(); + void resizeColumns(); + void setActiveColumn(unsigned column); void setBackgroundColor(Color color); void setCheckable(bool checkable); - void setChecked(unsigned selection, bool checked); + void setChecked(unsigned position, bool checked); + void setChecked(const vector& selections); + void setCheckedAll(); + void setCheckedNone(); + void setColumnBackgroundColor(unsigned position, maybe color); + void setColumnEditable(unsigned position, bool editable); + void setColumnFont(unsigned position, maybe font); + void setColumnForegroundColor(unsigned position, maybe color); + void setColumnHorizontalAlignment(unsigned position, double alignment); + void setColumnResizable(unsigned position, bool resizable); + void setColumnSortable(unsigned position, bool sortable); + void setColumnText(unsigned position, const string& text); + void setColumnVerticalAlignment(unsigned position, double alignment); + void setColumnVisible(unsigned position, bool visible); + void setColumnWidth(unsigned position, signed width); void setForegroundColor(Color color); - void setHeaderText(const lstring& text); + void setGridVisible(bool visible); void setHeaderVisible(bool visible); - void setImage(unsigned selection, unsigned position, const image& image); - void setSelected(bool selected); - void setSelection(unsigned selection); - void setText(unsigned selection, unsigned position, string text); + void setImage(unsigned row, unsigned column, const image& image); + void setSelected(unsigned position, bool selected); + void setSelected(const vector& selections); + void setSelectedAll(); + void setSelectedNone(); + void setSingleSelection(bool singleSelection); + void setText(unsigned row, unsigned column, string text); pListView(ListView& listView) : pWidget(listView), listView(listView) {} void constructor(); @@ -609,8 +692,11 @@ public: public slots: void onActivate(); - void onChange(QTreeWidgetItem* item); + void onChange(); + void onContext(); + void onSort(int column); void onToggle(QTreeWidgetItem* item); + int calculateAlignment(double horizontal, double vertical); }; struct pProgressBar : public pWidget { @@ -679,14 +765,14 @@ public: TabFrame& tabFrame; QTabWidget* qtTabFrame; - void append(string text, const image& image); + void append(); QWidget* container(Widget& widget); Position displacement(); void remove(unsigned selection); void setEnabled(bool enabled); void setGeometry(Geometry geometry); void setImage(unsigned selection, const image& image); - void setSelection(unsigned selection); + void setSelected(unsigned selection); void setText(unsigned selection, string text); void setVisible(bool visible); diff --git a/hiro/qt/popup-menu.cpp b/hiro/qt/popup-menu.cpp new file mode 100644 index 00000000..789765c6 --- /dev/null +++ b/hiro/qt/popup-menu.cpp @@ -0,0 +1,46 @@ +namespace phoenix { + +void pPopupMenu::append(Action& action) { + if(dynamic_cast(&action)) { + qtMenu->addMenu(((Menu&)action).p.qtMenu); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((Separator&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((Item&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((CheckItem&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->addAction(((RadioItem&)action).p.qtAction); + } +} + +void pPopupMenu::remove(Action& action) { + if(dynamic_cast(&action)) { + //QMenu::removeMenu() does not exist + qtMenu->clear(); + for(auto& action : popupMenu.state.action) append(action); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((Separator&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((Item&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((CheckItem&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((RadioItem&)action).p.qtAction); + } +} + +void pPopupMenu::setVisible() { + qtMenu->popup(QCursor::pos()); +} + +void pPopupMenu::constructor() { + qtMenu = new QMenu; +} + +void pPopupMenu::destructor() { + delete qtMenu; + qtMenu = nullptr; +} + +} diff --git a/phoenix/qt/settings.cpp b/hiro/qt/settings.cpp similarity index 100% rename from phoenix/qt/settings.cpp rename to hiro/qt/settings.cpp diff --git a/phoenix/qt/timer.cpp b/hiro/qt/timer.cpp similarity index 100% rename from phoenix/qt/timer.cpp rename to hiro/qt/timer.cpp diff --git a/phoenix/qt/utility.cpp b/hiro/qt/utility.cpp similarity index 99% rename from phoenix/qt/utility.cpp rename to hiro/qt/utility.cpp index 5e4f34c8..4a175807 100644 --- a/phoenix/qt/utility.cpp +++ b/hiro/qt/utility.cpp @@ -1,6 +1,7 @@ namespace phoenix { static QIcon CreateIcon(const nall::image& image, bool scale = false) { + if(image.empty()) return QIcon(); nall::image qtBuffer = image; qtBuffer.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); if(scale) qtBuffer.scale(16, 16, Interpolation::Linear); diff --git a/phoenix/qt/widget/button.cpp b/hiro/qt/widget/button.cpp similarity index 84% rename from phoenix/qt/widget/button.cpp rename to hiro/qt/widget/button.cpp index 32ad8463..083e5272 100644 --- a/phoenix/qt/widget/button.cpp +++ b/hiro/qt/widget/button.cpp @@ -13,7 +13,11 @@ Size pButton::minimumSize() { size.height += button.state.image.height; } - return {size.width + 20, size.height + 12}; + return {size.width + (button.state.text ? 20 : 12), size.height + 12}; +} + +void pButton::setBordered(bool bordered) { + qtButton->setAutoRaise(bordered == false); } void pButton::setImage(const image& image, Orientation orientation) { @@ -36,6 +40,8 @@ void pButton::constructor() { connect(qtButton, SIGNAL(released()), SLOT(onActivate())); pWidget::synchronizeState(); + setBordered(button.state.bordered); + setImage(button.state.image, button.state.orientation); setText(button.state.text); } diff --git a/phoenix/qt/widget/canvas.cpp b/hiro/qt/widget/canvas.cpp similarity index 100% rename from phoenix/qt/widget/canvas.cpp rename to hiro/qt/widget/canvas.cpp diff --git a/phoenix/qt/widget/check-button.cpp b/hiro/qt/widget/check-button.cpp similarity index 94% rename from phoenix/qt/widget/check-button.cpp rename to hiro/qt/widget/check-button.cpp index 921dc15d..6248ab51 100644 --- a/phoenix/qt/widget/check-button.cpp +++ b/hiro/qt/widget/check-button.cpp @@ -17,9 +17,9 @@ Size pCheckButton::minimumSize() { } void pCheckButton::setChecked(bool checked) { - locked = true; + lock(); qtCheckButton->setChecked(checked); - locked = false; + unlock(); } void pCheckButton::setImage(const image& image, Orientation orientation) { @@ -57,7 +57,7 @@ void pCheckButton::orphan() { void pCheckButton::onToggle(bool checked) { checkButton.state.checked = checked; - if(!locked && checkButton.onToggle) checkButton.onToggle(); + if(!locked() && checkButton.onToggle) checkButton.onToggle(); } } diff --git a/phoenix/qt/widget/check-label.cpp b/hiro/qt/widget/check-label.cpp similarity index 90% rename from phoenix/qt/widget/check-label.cpp rename to hiro/qt/widget/check-label.cpp index 4e88e5b6..b3246fa4 100644 --- a/phoenix/qt/widget/check-label.cpp +++ b/hiro/qt/widget/check-label.cpp @@ -6,9 +6,9 @@ Size pCheckLabel::minimumSize() { } void pCheckLabel::setChecked(bool checked) { - locked = true; + lock(); qtCheckLabel->setChecked(checked); - locked = false; + unlock(); } void pCheckLabel::setText(string text) { @@ -36,7 +36,7 @@ void pCheckLabel::orphan() { void pCheckLabel::onToggle() { checkLabel.state.checked = qtCheckLabel->isChecked(); - if(!locked && checkLabel.onToggle) checkLabel.onToggle(); + if(!locked() && checkLabel.onToggle) checkLabel.onToggle(); } } diff --git a/phoenix/qt/widget/combo-button.cpp b/hiro/qt/widget/combo-button.cpp similarity index 67% rename from phoenix/qt/widget/combo-button.cpp rename to hiro/qt/widget/combo-button.cpp index 5b25bc79..4e7250c7 100644 --- a/phoenix/qt/widget/combo-button.cpp +++ b/hiro/qt/widget/combo-button.cpp @@ -1,9 +1,9 @@ namespace phoenix { -void pComboButton::append(string text) { - locked = true; - qtComboButton->addItem(QString::fromUtf8(text)); - locked = false; +void pComboButton::append() { + lock(); + qtComboButton->addItem(""); + unlock(); } Size pComboButton::minimumSize() { @@ -14,23 +14,22 @@ Size pComboButton::minimumSize() { } void pComboButton::remove(unsigned selection) { - locked = true; + lock(); qtComboButton->removeItem(selection); - locked = false; - - if(selection == comboButton.state.selection) comboButton.setSelection(0); + if(selection == comboButton.state.selection) comboButton[0].setSelected(); + unlock(); } void pComboButton::reset() { - locked = true; + lock(); while(qtComboButton->count()) qtComboButton->removeItem(0); - locked = false; + unlock(); } -void pComboButton::setSelection(unsigned selection) { - locked = true; +void pComboButton::setSelected(unsigned selection) { + lock(); qtComboButton->setCurrentIndex(selection); - locked = false; + unlock(); } void pComboButton::setText(unsigned selection, string text) { @@ -43,10 +42,11 @@ void pComboButton::constructor() { pWidget::synchronizeState(); unsigned selection = comboButton.state.selection; - locked = true; - for(auto& text : comboButton.state.text) append(text); - locked = false; - comboButton.setSelection(selection); + for(unsigned n = 0; n < comboButton.count(); n++) { + append(); + setText(n, comboButton.state.text[n]); + } + comboButton[selection].setSelected(); } void pComboButton::destructor() { @@ -61,7 +61,7 @@ void pComboButton::orphan() { void pComboButton::onChange() { comboButton.state.selection = qtComboButton->currentIndex(); - if(!locked && comboButton.onChange) comboButton.onChange(); + if(!locked() && comboButton.onChange) comboButton.onChange(); } } diff --git a/phoenix/qt/widget/console.cpp b/hiro/qt/widget/console.cpp similarity index 67% rename from phoenix/qt/widget/console.cpp rename to hiro/qt/widget/console.cpp index 22a3d813..5173a126 100644 --- a/phoenix/qt/widget/console.cpp +++ b/hiro/qt/widget/console.cpp @@ -7,9 +7,16 @@ void pConsole::reset() { } void pConsole::setBackgroundColor(Color color) { + QPalette palette = qtConsole->palette(); + palette.setColor(QPalette::Base, QColor(color.red, color.green, color.blue)); + qtConsole->setPalette(palette); + qtConsole->setAutoFillBackground(true); } void pConsole::setForegroundColor(Color color) { + QPalette palette = qtConsole->palette(); + palette.setColor(QPalette::Text, QColor(color.red, color.green, color.blue)); + qtConsole->setPalette(palette); } void pConsole::setPrompt(string prompt) { diff --git a/phoenix/qt/widget/frame.cpp b/hiro/qt/widget/frame.cpp similarity index 100% rename from phoenix/qt/widget/frame.cpp rename to hiro/qt/widget/frame.cpp diff --git a/phoenix/qt/widget/hex-edit.cpp b/hiro/qt/widget/hex-edit.cpp similarity index 95% rename from phoenix/qt/widget/hex-edit.cpp rename to hiro/qt/widget/hex-edit.cpp index f0883e36..4a465886 100644 --- a/phoenix/qt/widget/hex-edit.cpp +++ b/hiro/qt/widget/hex-edit.cpp @@ -1,6 +1,10 @@ namespace phoenix { void pHexEdit::setBackgroundColor(Color color) { + QPalette palette = qtHexEdit->palette(); + palette.setColor(QPalette::Base, QColor(color.red, color.green, color.blue)); + qtHexEdit->setPalette(palette); + qtHexEdit->setAutoFillBackground(true); } void pHexEdit::setColumns(unsigned columns) { @@ -8,6 +12,9 @@ void pHexEdit::setColumns(unsigned columns) { } void pHexEdit::setForegroundColor(Color color) { + QPalette palette = qtHexEdit->palette(); + palette.setColor(QPalette::Text, QColor(color.red, color.green, color.blue)); + qtHexEdit->setPalette(palette); } void pHexEdit::setLength(unsigned length) { @@ -18,9 +25,9 @@ void pHexEdit::setLength(unsigned length) { } void pHexEdit::setOffset(unsigned offset) { - locked = true; + lock(); qtScroll->setSliderPosition(hexEdit.state.offset / hexEdit.state.columns); - locked = false; + unlock(); update(); } @@ -254,7 +261,7 @@ void pHexEdit::scrollTo(signed position) { } void pHexEdit::onScroll() { - if(locked) return; + if(locked()) return; unsigned offset = qtScroll->sliderPosition(); hexEdit.state.offset = offset * hexEdit.state.columns; update(); diff --git a/phoenix/qt/widget/horizontal-scroller.cpp b/hiro/qt/widget/horizontal-scroller.cpp similarity index 100% rename from phoenix/qt/widget/horizontal-scroller.cpp rename to hiro/qt/widget/horizontal-scroller.cpp diff --git a/phoenix/qt/widget/horizontal-slider.cpp b/hiro/qt/widget/horizontal-slider.cpp similarity index 100% rename from phoenix/qt/widget/horizontal-slider.cpp rename to hiro/qt/widget/horizontal-slider.cpp diff --git a/hiro/qt/widget/icon-view.cpp b/hiro/qt/widget/icon-view.cpp new file mode 100644 index 00000000..d829cd0d --- /dev/null +++ b/hiro/qt/widget/icon-view.cpp @@ -0,0 +1,148 @@ +namespace phoenix { + +void pIconView::append() { + lock(); + auto item = new QListWidgetItem(qtIconView); + unlock(); +} + +void pIconView::remove(unsigned selection) { + lock(); + if(auto item = qtIconView->item(selection)) { + delete item; + } + unlock(); +} + +void pIconView::reset() { + lock(); + qtIconView->clear(); + unlock(); +} + +void pIconView::setBackgroundColor(Color color) { + QPalette palette = qtIconView->palette(); + palette.setColor(QPalette::Base, QColor(color.red, color.green, color.blue)); + qtIconView->setPalette(palette); + qtIconView->setAutoFillBackground(true); +} + +void pIconView::setFlow(Orientation flow) { + qtIconView->setFlow(flow == Orientation::Horizontal ? QListView::LeftToRight : QListView::TopToBottom); + qtIconView->resize(qtIconView->size()); //adjust visibility of scroll bars +} + +void pIconView::setForegroundColor(Color color) { + QPalette palette = qtIconView->palette(); + palette.setColor(QPalette::Text, QColor(color.red, color.green, color.blue)); + qtIconView->setPalette(palette); +} + +void pIconView::setImage(unsigned selection, const image& image) { + if(auto item = qtIconView->item(selection)) { + item->setIcon(CreateIcon(image)); + } +} + +void pIconView::setOrientation(Orientation orientation) { + qtIconView->setViewMode(orientation == Orientation::Horizontal ? QListView::ListMode : QListView::IconMode); + qtIconView->setWrapping(true); +} + +void pIconView::setSelected(unsigned selection, bool selected) { + lock(); + if(auto item = qtIconView->item(selection)) { + item->setSelected(selected); + } + unlock(); +} + +void pIconView::setSelected(const vector& selections) { + lock(); + qtIconView->clearSelection(); + for(auto& selection : selections) { + if(auto item = qtIconView->item(selection)) { + item->setSelected(true); + } + } + unlock(); +} + +void pIconView::setSelectedAll() { + lock(); + qtIconView->selectAll(); + unlock(); +} + +void pIconView::setSelectedNone() { + lock(); + qtIconView->clearSelection(); + unlock(); +} + +void pIconView::setSingleSelection(bool singleSelection) { + qtIconView->setSelectionMode(singleSelection ? QAbstractItemView::SingleSelection : QAbstractItemView::ExtendedSelection); +} + +void pIconView::setText(unsigned selection, const string& text) { + if(auto item = qtIconView->item(selection)) { + item->setText(QString::fromUtf8(text)); + } +} + +void pIconView::constructor() { + qtWidget = qtIconView = new QtListWidget; + qtIconView->setContextMenuPolicy(Qt::CustomContextMenu); + qtIconView->setMovement(QListView::Static); + qtIconView->setResizeMode(QListView::Adjust); + qtIconView->setSelectionRectVisible(true); + qtIconView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + qtIconView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + + connect(qtIconView, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(onActivate())); + connect(qtIconView, SIGNAL(itemSelectionChanged()), SLOT(onChange())); + connect(qtIconView, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(onContext())); + + setFlow(iconView.state.flow); + setOrientation(iconView.state.orientation); + setSingleSelection(iconView.state.singleSelection); +} + +void pIconView::destructor() { + delete qtIconView; + qtWidget = qtIconView = nullptr; +} + +void pIconView::orphan() { + destructor(); + constructor(); +} + +void pIconView::onActivate() { + if(!locked() && iconView.onActivate) iconView.onActivate(); +} + +void pIconView::onChange() { + for(auto& selected : iconView.state.selected) selected = false; + for(unsigned n = 0; n < qtIconView->count(); n++) { + if(auto item = qtIconView->item(n)) { + if(item->isSelected()) iconView.state.selected[n] = true; + } + } + if(!locked() && iconView.onChange) iconView.onChange(); +} + +void pIconView::onContext() { + if(!locked() && iconView.onContext) iconView.onContext(); +} + +void pIconView::QtListWidget::resizeEvent(QResizeEvent* event) { + //Qt::ScrollBarAsNeeded results in the scroll bar area being reserved from the icon viewport even when scroll bar is hidden + //this creates the appearance of an invisible gap that wastes precious screen space + //below code simulates a Qt::ScrollBarAsNeeded which uses the extra space when the scroll bar is hidden + setHorizontalScrollBarPolicy(horizontalScrollBar()->maximum() > horizontalScrollBar()->minimum() ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(verticalScrollBar()->maximum() > verticalScrollBar()->minimum() ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff); + return QListWidget::resizeEvent(event); +} + +} diff --git a/phoenix/qt/widget/label.cpp b/hiro/qt/widget/label.cpp similarity index 100% rename from phoenix/qt/widget/label.cpp rename to hiro/qt/widget/label.cpp diff --git a/phoenix/qt/widget/line-edit.cpp b/hiro/qt/widget/line-edit.cpp similarity index 76% rename from phoenix/qt/widget/line-edit.cpp rename to hiro/qt/widget/line-edit.cpp index 3142c8ad..ab537608 100644 --- a/phoenix/qt/widget/line-edit.cpp +++ b/hiro/qt/widget/line-edit.cpp @@ -6,6 +6,10 @@ Size pLineEdit::minimumSize() { } void pLineEdit::setBackgroundColor(Color color) { + QPalette palette = qtLineEdit->palette(); + palette.setColor(QPalette::Base, QColor(color.red, color.green, color.blue)); + qtLineEdit->setPalette(palette); + qtLineEdit->setAutoFillBackground(true); } void pLineEdit::setEditable(bool editable) { @@ -13,6 +17,9 @@ void pLineEdit::setEditable(bool editable) { } void pLineEdit::setForegroundColor(Color color) { + QPalette palette = qtLineEdit->palette(); + palette.setColor(QPalette::Text, QColor(color.red, color.green, color.blue)); + qtLineEdit->setPalette(palette); } void pLineEdit::setText(string text) { diff --git a/hiro/qt/widget/list-view.cpp b/hiro/qt/widget/list-view.cpp new file mode 100644 index 00000000..113b6e0b --- /dev/null +++ b/hiro/qt/widget/list-view.cpp @@ -0,0 +1,395 @@ +namespace phoenix { + +void pListView::appendColumn() { + orphan(); +} + +void pListView::appendItem() { + lock(); + auto item = new QTreeWidgetItem(qtListView); + for(unsigned column = 0; column < listView.columns(); column++) { + auto& state = listView.state.columns[column]; + if(state.backgroundColor) { + item->setBackground(column, QColor( + state.backgroundColor->red, state.backgroundColor->green, state.backgroundColor->blue + )); + } + if(state.font) { + item->setFont(column, pFont::create(*state.font)); + } + if(state.foregroundColor) { + item->setForeground(column, QColor( + state.foregroundColor->red, state.foregroundColor->green, state.foregroundColor->blue + )); + } + item->setTextAlignment(column, calculateAlignment( + state.horizontalAlignment, state.verticalAlignment + )); + } + if(listView.state.checkable) item->setCheckState(0, Qt::Unchecked); + unlock(); +} + +void pListView::removeColumn(unsigned position) { + orphan(); +} + +void pListView::removeItem(unsigned position) { + lock(); + if(auto item = qtListView->topLevelItem(position)) { + delete item; + } + unlock(); +} + +void pListView::reset() { + lock(); + qtListView->clear(); + unlock(); +} + +void pListView::resizeColumns() { +} + +//todo: this doesn't work ... +void pListView::setActiveColumn(unsigned column) { + if(column >= listView.columns()) return; + qtListView->header()->setSortIndicator(column, Qt::DescendingOrder); +} + +void pListView::setBackgroundColor(Color color) { + QPalette palette = qtListView->palette(); + palette.setColor(QPalette::Base, QColor(color.red, color.green, color.blue)); + palette.setColor(QPalette::AlternateBase, QColor(max(0, (signed)color.red - 17), max(0, (signed)color.green - 17), max(0, (signed)color.blue - 17))); + qtListView->setPalette(palette); + qtListView->setAutoFillBackground(true); +} + +void pListView::setCheckable(bool checkable) { + lock(); + if(checkable) { + for(unsigned n = 0; n < qtListView->topLevelItemCount(); n++) { + if(auto item = qtListView->topLevelItem(n)) { + item->setCheckState(0, Qt::Unchecked); + } + } + } + unlock(); +} + +void pListView::setChecked(unsigned position, bool checked) { + lock(); + if(auto item = qtListView->topLevelItem(position)) { + item->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked); + } + unlock(); +} + +void pListView::setChecked(const vector& selections) { + lock(); + setCheckedNone(); + for(auto& position : selections) setChecked(position, true); + unlock(); +} + +void pListView::setCheckedAll() { + lock(); + for(unsigned n = 0; n < qtListView->topLevelItemCount(); n++) { + if(auto item = qtListView->topLevelItem(n)) { + item->setCheckState(0, Qt::Checked); + } + } + unlock(); +} + +void pListView::setCheckedNone() { + lock(); + for(unsigned n = 0; n < qtListView->topLevelItemCount(); n++) { + if(auto item = qtListView->topLevelItem(n)) { + item->setCheckState(0, Qt::Unchecked); + } + } + unlock(); +} + +void pListView::setColumnBackgroundColor(unsigned column, maybe color) { + for(unsigned row = 0; row < listView.items(); row++) { + if(auto item = qtListView->topLevelItem(row)) { + item->setBackground(column, color ? QColor(color->red, color->green, color->blue) : QBrush()); + } + } +} + +void pListView::setColumnEditable(unsigned column, bool editable) { +} + +void pListView::setColumnFont(unsigned column, maybe font) { + auto qtFont = pFont::create(font ? *font : widget.state.font); + for(unsigned row = 0; row < listView.items(); row++) { + if(auto item = qtListView->topLevelItem(row)) { + item->setFont(column, qtFont); + } + } +} + +void pListView::setColumnForegroundColor(unsigned column, maybe color) { + for(unsigned row = 0; row < listView.items(); row++) { + if(auto item = qtListView->topLevelItem(row)) { + item->setForeground(column, color ? QColor(color->red, color->green, color->blue) : QBrush()); + } + } +} + +void pListView::setColumnHorizontalAlignment(unsigned column, double alignment) { + qtListView->headerItem()->setTextAlignment(column, calculateAlignment(alignment, 0.5)); + for(unsigned row = 0; row < listView.items(); row++) { + if(auto item = qtListView->topLevelItem(row)) { + auto& state = listView.state.columns[column]; + item->setTextAlignment(column, calculateAlignment(state.horizontalAlignment, state.verticalAlignment)); + } + } +} + +void pListView::setColumnResizable(unsigned column, bool resizable) { + qtListView->header()->setResizeMode(column, resizable ? QHeaderView::Interactive : QHeaderView::Fixed); +} + +void pListView::setColumnSortable(unsigned column, bool sortable) { + bool clickable = false; + for(auto& column : listView.state.columns) clickable |= column.sortable; + qtListView->header()->setClickable(clickable); +} + +void pListView::setColumnText(unsigned column, const string& text) { + qtListView->headerItem()->setText(column, QString::fromUtf8(text)); +} + +void pListView::setColumnVerticalAlignment(unsigned column, double alignment) { + for(unsigned row = 0; row < listView.items(); row++) { + if(auto item = qtListView->topLevelItem(row)) { + auto& state = listView.state.columns[column]; + item->setTextAlignment(column, calculateAlignment(state.horizontalAlignment, state.verticalAlignment)); + } + } +} + +void pListView::setColumnVisible(unsigned column, bool visible) { + if(column >= listView.columns()) return; + qtListView->setColumnHidden(column, !visible); +} + +void pListView::setColumnWidth(unsigned column, signed width) { + if(column >= listView.columns()) return; + resizeColumns(); +} + +void pListView::setForegroundColor(Color color) { + QPalette palette = qtListView->palette(); + palette.setColor(QPalette::Text, QColor(color.red, color.green, color.blue)); + qtListView->setPalette(palette); +} + +void pListView::setGridVisible(bool visible) { + qtListView->repaint(); +} + +void pListView::setHeaderVisible(bool visible) { + qtListView->setHeaderHidden(!visible); + resizeColumns(); +} + +void pListView::setImage(unsigned row, unsigned column, const nall::image& image) { + if(auto item = qtListView->topLevelItem(row)) { + item->setIcon(column, CreateIcon(image)); + } +} + +void pListView::setSelected(unsigned position, bool selected) { + lock(); + if(auto item = qtListView->topLevelItem(position)) { + item->setSelected(selected); + } + unlock(); +} + +void pListView::setSelected(const vector& selections) { + lock(); + setSelectedNone(); + if(selections.size()) { + if(auto item = qtListView->topLevelItem(selections[0])) { + qtListView->setCurrentItem(item); + } + for(auto& position : selections) setSelected(position, true); + } + unlock(); +} + +void pListView::setSelectedAll() { + lock(); + qtListView->selectAll(); + unlock(); +} + +void pListView::setSelectedNone() { + lock(); + qtListView->clearSelection(); + unlock(); +} + +void pListView::setSingleSelection(bool singleSelection) { + lock(); + qtListView->setSelectionMode(singleSelection ? QAbstractItemView::SingleSelection : QAbstractItemView::ExtendedSelection); + unlock(); +} + +void pListView::setText(unsigned row, unsigned column, string text) { + lock(); + if(auto item = qtListView->topLevelItem(row)) { + item->setText(column, QString::fromUtf8(text)); + } + unlock(); +} + +void pListView::constructor() { + qtWidget = qtListView = new QtTreeWidget(*this); + qtListView->setAllColumnsShowFocus(true); + qtListView->setAlternatingRowColors(listView.columns() >= 2); + qtListView->setColumnCount(max(1u, listView.columns())); + qtListView->setContextMenuPolicy(Qt::CustomContextMenu); + qtListView->setRootIsDecorated(false); + qtListView->header()->setMovable(false); + + qtListViewDelegate = new QtTreeWidgetDelegate(*this); + qtListView->setItemDelegate(qtListViewDelegate); + + connect(qtListView, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate())); + connect(qtListView, SIGNAL(itemSelectionChanged()), SLOT(onChange())); + connect(qtListView, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(onContext())); + connect(qtListView->header(), SIGNAL(sectionClicked(int)), SLOT(onSort(int))); + connect(qtListView, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onToggle(QTreeWidgetItem*))); + + pWidget::synchronizeState(); + for(unsigned column = 0; column < listView.columns(); column++) { + auto& state = listView.state.columns[column]; + setColumnBackgroundColor(column, state.backgroundColor); + setColumnEditable(column, state.editable); + setColumnFont(column, state.font); + setColumnForegroundColor(column, state.foregroundColor); + //setColumnHorizontalAlignment(column, state.horizontalAlignment); + setColumnResizable(column, state.resizable); + setColumnSortable(column, state.sortable); + setColumnText(column, state.text); + //setColumnVerticalAlignment(column, state.verticalAlignment); + setColumnVisible(column, state.visible); + //setColumnWidth(column, state.width); + qtListView->headerItem()->setTextAlignment(column, calculateAlignment(state.horizontalAlignment, 0.5)); + } + setActiveColumn(listView.state.activeColumn); + setCheckable(listView.state.checkable); +//setGridVisible(listView.state.gridVisible); + setHeaderVisible(listView.state.headerVisible); + setSingleSelection(listView.state.singleSelection); + for(unsigned row = 0; row < listView.items(); row++) { + appendItem(); + setSelected(row, listView.state.items[row].selected); + if(listView.state.checkable) { + setChecked(row, listView.state.items[row].checked); + } + for(unsigned column = 0; column < listView.columns(); column++) { + setImage(row, column, listView.state.items[row].image(column, {})); + setText(row, column, listView.state.items[row].text(column, "")); + } + } + resizeColumns(); +} + +void pListView::destructor() { + delete qtListViewDelegate; + delete qtListView; + qtWidget = qtListView = nullptr; + qtListViewDelegate = nullptr; +} + +void pListView::orphan() { + destructor(); + constructor(); +} + +void pListView::onActivate() { + if(!locked() && listView.onActivate) listView.onActivate(); +} + +void pListView::onChange() { + for(auto& item : listView.state.items) item.selected = false; + for(unsigned position = 0; position < qtListView->topLevelItemCount(); position++) { + if(auto item = qtListView->topLevelItem(position)) { + if(item->isSelected()) listView.state.items[position].selected = true; + } + } + if(!locked() && listView.onChange) listView.onChange(); +} + +void pListView::onContext() { + if(!locked() && listView.onContext) listView.onContext(); +} + +void pListView::onSort(int column) { + if(column >= listView.columns()) return; + if(listView.state.columns[column].sortable) { + if(!locked() && listView.onSort) listView.onSort(column); + } +} + +void pListView::onToggle(QTreeWidgetItem* item) { + maybe row; + for(unsigned position = 0; position < qtListView->topLevelItemCount(); position++) { + if(auto topLevelItem = qtListView->topLevelItem(position)) { + if(topLevelItem == item) { + row = position; + break; + } + } + } + if(row) { + listView.state.items[*row].checked = (item->checkState(0) == Qt::Checked); + if(!locked() && listView.onToggle) listView.onToggle(*row); + } +} + +int pListView::calculateAlignment(double horizontal, double vertical) { + int alignment = 0; + if(horizontal < 0.333) alignment |= Qt::AlignLeft; + else if(horizontal > 0.666) alignment |= Qt::AlignRight; + else alignment |= Qt::AlignCenter; + if(vertical < 0.333) alignment |= Qt::AlignTop; + else if(vertical > 0.666) alignment |= Qt::AlignBottom; + else alignment |= Qt::AlignVCenter; + return alignment; +} + +void pListView::QtTreeWidget::mousePressEvent(QMouseEvent* event) { + QTreeWidget::mousePressEvent(event); + + if(event->button() == Qt::RightButton) { + self.onContext(); + } +} + +pListView::QtTreeWidget::QtTreeWidget(pListView& self) : self(self) { +} + +void pListView::QtTreeWidgetDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { + QStyledItemDelegate::paint(painter, option, index); + if(self.listView.state.gridVisible) { + QPen pen; + pen.setColor(QColor(192, 192, 192)); + pen.setWidth(1); + painter->setPen(pen); + painter->drawRect(option.rect); + } +} + +pListView::QtTreeWidgetDelegate::QtTreeWidgetDelegate(pListView& self) : QStyledItemDelegate(self.qtListView), self(self) { +} + +} diff --git a/phoenix/qt/widget/progress-bar.cpp b/hiro/qt/widget/progress-bar.cpp similarity index 100% rename from phoenix/qt/widget/progress-bar.cpp rename to hiro/qt/widget/progress-bar.cpp diff --git a/phoenix/qt/widget/radio-button.cpp b/hiro/qt/widget/radio-button.cpp similarity index 94% rename from phoenix/qt/widget/radio-button.cpp rename to hiro/qt/widget/radio-button.cpp index b3554b85..3ba491ab 100644 --- a/phoenix/qt/widget/radio-button.cpp +++ b/hiro/qt/widget/radio-button.cpp @@ -17,20 +17,20 @@ Size pRadioButton::minimumSize() { } void pRadioButton::setChecked() { - parent().locked = true; + parent().lock(); for(auto& item : radioButton.state.group) { bool checked = &item.p == this; item.p.qtRadioButton->setChecked(item.state.checked = checked); } - parent().locked = false; + parent().unlock(); } void pRadioButton::setGroup(const group& group) { - parent().locked = true; + parent().lock(); for(auto& item : radioButton.state.group) { item.p.qtRadioButton->setChecked(item.state.checked); } - parent().locked = false; + parent().unlock(); } void pRadioButton::setImage(const image& image, Orientation orientation) { @@ -74,7 +74,7 @@ void pRadioButton::orphan() { } void pRadioButton::onActivate() { - if(parent().locked) return; + if(parent().locked()) return; bool wasChecked = radioButton.state.checked; setChecked(); if(!wasChecked) { diff --git a/phoenix/qt/widget/radio-label.cpp b/hiro/qt/widget/radio-label.cpp similarity index 91% rename from phoenix/qt/widget/radio-label.cpp rename to hiro/qt/widget/radio-label.cpp index 927591a4..cdbf013f 100644 --- a/phoenix/qt/widget/radio-label.cpp +++ b/hiro/qt/widget/radio-label.cpp @@ -6,20 +6,20 @@ Size pRadioLabel::minimumSize() { } void pRadioLabel::setChecked() { - parent().locked = true; + parent().lock(); for(auto& item : radioLabel.state.group) { bool checked = &item == &radioLabel; item.p.qtRadioLabel->setChecked(item.state.checked = checked); } - parent().locked = false; + parent().unlock(); } void pRadioLabel::setGroup(const group& group) { - parent().locked = true; + parent().lock(); for(auto& item : radioLabel.state.group) { item.p.qtRadioLabel->setChecked(item.state.checked); } - parent().locked = false; + parent().unlock(); } void pRadioLabel::setText(string text) { @@ -52,7 +52,7 @@ void pRadioLabel::orphan() { } void pRadioLabel::onActivate() { - if(parent().locked) return; + if(parent().locked()) return; bool wasChecked = radioLabel.state.checked; setChecked(); if(!wasChecked) { diff --git a/phoenix/qt/widget/tab-frame.cpp b/hiro/qt/widget/tab-frame.cpp similarity index 83% rename from phoenix/qt/widget/tab-frame.cpp rename to hiro/qt/widget/tab-frame.cpp index 6fb9396d..e2b393f0 100644 --- a/phoenix/qt/widget/tab-frame.cpp +++ b/hiro/qt/widget/tab-frame.cpp @@ -1,9 +1,7 @@ namespace phoenix { -void pTabFrame::append(string text, const image& image) { - unsigned selection = tabFrame.state.text.size() - 1; - qtTabFrame->addTab(new QWidget, QString::fromUtf8(text)); - if(!image.empty()) setImage(selection, image); +void pTabFrame::append() { + qtTabFrame->addTab(new QWidget, ""); } QWidget* pTabFrame::container(Widget& widget) { @@ -45,11 +43,11 @@ void pTabFrame::setImage(unsigned selection, const image& image) { qtTabFrame->setTabIcon(selection, CreateIcon(image)); } -void pTabFrame::setSelection(unsigned selection) { - locked = true; +void pTabFrame::setSelected(unsigned selection) { + lock(); qtTabFrame->setCurrentIndex(selection); synchronizeLayout(); - locked = false; + unlock(); } void pTabFrame::setText(unsigned selection, string text) { @@ -67,7 +65,7 @@ void pTabFrame::constructor() { qtWidget = qtTabFrame = new QTabWidget; connect(qtTabFrame, SIGNAL(currentChanged(int)), SLOT(onChange(int))); - setSelection(tabFrame.state.selection); + setSelected(tabFrame.state.selection); } void pTabFrame::destructor() { @@ -91,7 +89,7 @@ void pTabFrame::synchronizeLayout() { void pTabFrame::onChange(int selection) { tabFrame.state.selection = selection; synchronizeLayout(); - if(!locked && tabFrame.onChange) tabFrame.onChange(); + if(!locked() && tabFrame.onChange) tabFrame.onChange(); } } diff --git a/phoenix/qt/widget/text-edit.cpp b/hiro/qt/widget/text-edit.cpp similarity index 81% rename from phoenix/qt/widget/text-edit.cpp rename to hiro/qt/widget/text-edit.cpp index ec705731..8097e2cf 100644 --- a/phoenix/qt/widget/text-edit.cpp +++ b/hiro/qt/widget/text-edit.cpp @@ -1,6 +1,10 @@ namespace phoenix { void pTextEdit::setBackgroundColor(Color color) { + QPalette palette = qtTextEdit->palette(); + palette.setColor(QPalette::Base, QColor(color.red, color.green, color.blue)); + qtTextEdit->setPalette(palette); + qtTextEdit->setAutoFillBackground(true); } void pTextEdit::setCursorPosition(unsigned position) { @@ -15,6 +19,9 @@ void pTextEdit::setEditable(bool editable) { } void pTextEdit::setForegroundColor(Color color) { + QPalette palette = qtTextEdit->palette(); + palette.setColor(QPalette::Text, QColor(color.red, color.green, color.blue)); + qtTextEdit->setPalette(palette); } void pTextEdit::setText(string text) { diff --git a/phoenix/qt/widget/vertical-scroller.cpp b/hiro/qt/widget/vertical-scroller.cpp similarity index 100% rename from phoenix/qt/widget/vertical-scroller.cpp rename to hiro/qt/widget/vertical-scroller.cpp diff --git a/phoenix/qt/widget/vertical-slider.cpp b/hiro/qt/widget/vertical-slider.cpp similarity index 100% rename from phoenix/qt/widget/vertical-slider.cpp rename to hiro/qt/widget/vertical-slider.cpp diff --git a/phoenix/qt/widget/viewport.cpp b/hiro/qt/widget/viewport.cpp similarity index 100% rename from phoenix/qt/widget/viewport.cpp rename to hiro/qt/widget/viewport.cpp diff --git a/phoenix/qt/widget/widget.cpp b/hiro/qt/widget/widget.cpp similarity index 100% rename from phoenix/qt/widget/widget.cpp rename to hiro/qt/widget/widget.cpp diff --git a/phoenix/qt/window.cpp b/hiro/qt/window.cpp similarity index 89% rename from phoenix/qt/window.cpp rename to hiro/qt/window.cpp index 8753f2ef..6c6ae89c 100644 --- a/phoenix/qt/window.cpp +++ b/hiro/qt/window.cpp @@ -41,16 +41,6 @@ bool pWindow::focused() { return qtWindow->isActiveWindow() && !qtWindow->isMinimized(); } -Geometry pWindow::geometry() { - if(window.state.fullScreen) { - unsigned menuHeight = window.state.menuVisible ? qtMenu->height() : 0; - unsigned statusHeight = window.state.statusVisible ? qtStatus->height() : 0; - QRect geometry = qtWindow->geometry(); //frameGeometry() includes frame even though it's not visible in fullscreen mode - return {geometry.x(), geometry.y() + menuHeight, geometry.width(), geometry.height() - menuHeight - statusHeight}; - } - return window.state.geometry; -} - void pWindow::remove(Layout& layout) { } @@ -97,10 +87,9 @@ void pWindow::setFullScreen(bool fullScreen) { } void pWindow::setGeometry(Geometry geometry) { - locked = true; + lock(); Application::processEvents(); QApplication::syncX(); - Geometry margin = frameMargin(); setResizable(window.state.resizable); qtWindow->move(geometry.x - frameMargin().x, geometry.y - frameMargin().y); @@ -116,7 +105,7 @@ void pWindow::setGeometry(Geometry geometry) { geometry.x = geometry.y = 0; layout.setGeometry(geometry); } - locked = false; + unlock(); } void pWindow::setMenuFont(string font) { @@ -137,7 +126,11 @@ void pWindow::setModal(bool modal) { setVisible(true); while(window.state.modal) { Application::processEvents(); - usleep(20 * 1000); + if(Application::main) { + Application::main(); + } else { + usleep(20 * 1000); + } } qtWindow->setWindowModality(Qt::NonModal); } @@ -172,13 +165,13 @@ void pWindow::setTitle(string text) { } void pWindow::setVisible(bool visible) { - locked = true; + lock(); qtWindow->setVisible(visible); if(visible) { updateFrameGeometry(); setGeometry(window.state.geometry); } - locked = false; + unlock(); } void pWindow::setWidgetFont(string font) { @@ -194,6 +187,8 @@ void pWindow::constructor() { qtWindow->setWindowIcon(QIcon(string{"/usr/share/pixmaps/", applicationState.name, ".png"})); } else if(file::exists({"/usr/local/share/pixmaps/", applicationState.name, ".png"})) { qtWindow->setWindowIcon(QIcon(string{"/usr/local/share/pixmaps/", applicationState.name, ".png"})); + } else if(file::exists({userpath(), ".local/share/icons/", applicationState.name, ".png"})) { + qtWindow->setWindowIcon(QIcon(string{userpath(), ".local/share/icons/", applicationState.name, ".png"})); } } @@ -263,14 +258,12 @@ void pWindow::QtWindow::closeEvent(QCloseEvent* event) { } void pWindow::QtWindow::moveEvent(QMoveEvent* event) { - if(self.locked == false && self.window.state.fullScreen == false && self.qtWindow->isVisible() == true) { + if(!self.locked() && self.window.state.fullScreen == false && self.qtWindow->isVisible() == true) { self.window.state.geometry.x += event->pos().x() - event->oldPos().x(); self.window.state.geometry.y += event->pos().y() - event->oldPos().y(); } - if(self.locked == false) { - if(self.window.onMove) self.window.onMove(); - } + if(!self.locked() && self.window.onMove) self.window.onMove(); } void pWindow::QtWindow::dragEnterEvent(QDragEnterEvent* event) { @@ -296,20 +289,18 @@ void pWindow::QtWindow::keyReleaseEvent(QKeyEvent* event) { } void pWindow::QtWindow::resizeEvent(QResizeEvent*) { - if(self.locked == false && self.window.state.fullScreen == false && self.qtWindow->isVisible() == true) { + if(!self.locked() && self.window.state.fullScreen == false && self.qtWindow->isVisible() == true) { self.window.state.geometry.width = self.qtContainer->geometry().width(); self.window.state.geometry.height = self.qtContainer->geometry().height(); } for(auto& layout : self.window.state.layout) { - Geometry geometry = self.geometry(); + Geometry geometry = self.window.state.geometry; geometry.x = geometry.y = 0; layout.setGeometry(geometry); } - if(self.locked == false) { - if(self.window.onSize) self.window.onSize(); - } + if(!self.locked() && self.window.onSize) self.window.onSize(); } QSize pWindow::QtWindow::sizeHint() const { diff --git a/phoenix/reference/action/action.cpp b/hiro/reference/action/action.cpp similarity index 100% rename from phoenix/reference/action/action.cpp rename to hiro/reference/action/action.cpp diff --git a/phoenix/reference/action/action.hpp b/hiro/reference/action/action.hpp similarity index 100% rename from phoenix/reference/action/action.hpp rename to hiro/reference/action/action.hpp diff --git a/phoenix/reference/action/check-item.cpp b/hiro/reference/action/check-item.cpp similarity index 100% rename from phoenix/reference/action/check-item.cpp rename to hiro/reference/action/check-item.cpp diff --git a/phoenix/reference/action/check-item.hpp b/hiro/reference/action/check-item.hpp similarity index 100% rename from phoenix/reference/action/check-item.hpp rename to hiro/reference/action/check-item.hpp diff --git a/phoenix/reference/action/item.cpp b/hiro/reference/action/item.cpp similarity index 100% rename from phoenix/reference/action/item.cpp rename to hiro/reference/action/item.cpp diff --git a/phoenix/reference/action/item.hpp b/hiro/reference/action/item.hpp similarity index 100% rename from phoenix/reference/action/item.hpp rename to hiro/reference/action/item.hpp diff --git a/phoenix/reference/action/menu.cpp b/hiro/reference/action/menu.cpp similarity index 100% rename from phoenix/reference/action/menu.cpp rename to hiro/reference/action/menu.cpp diff --git a/phoenix/reference/action/menu.hpp b/hiro/reference/action/menu.hpp similarity index 100% rename from phoenix/reference/action/menu.hpp rename to hiro/reference/action/menu.hpp diff --git a/phoenix/reference/action/radio-item.cpp b/hiro/reference/action/radio-item.cpp similarity index 100% rename from phoenix/reference/action/radio-item.cpp rename to hiro/reference/action/radio-item.cpp diff --git a/phoenix/reference/action/radio-item.hpp b/hiro/reference/action/radio-item.hpp similarity index 100% rename from phoenix/reference/action/radio-item.hpp rename to hiro/reference/action/radio-item.hpp diff --git a/phoenix/reference/action/separator.cpp b/hiro/reference/action/separator.cpp similarity index 100% rename from phoenix/reference/action/separator.cpp rename to hiro/reference/action/separator.cpp diff --git a/phoenix/reference/action/separator.hpp b/hiro/reference/action/separator.hpp similarity index 100% rename from phoenix/reference/action/separator.hpp rename to hiro/reference/action/separator.hpp diff --git a/phoenix/reference/application.cpp b/hiro/reference/application.cpp similarity index 100% rename from phoenix/reference/application.cpp rename to hiro/reference/application.cpp diff --git a/phoenix/reference/application.hpp b/hiro/reference/application.hpp similarity index 100% rename from phoenix/reference/application.hpp rename to hiro/reference/application.hpp diff --git a/phoenix/reference/browser-window.cpp b/hiro/reference/browser-window.cpp similarity index 100% rename from phoenix/reference/browser-window.cpp rename to hiro/reference/browser-window.cpp diff --git a/phoenix/reference/browser-window.hpp b/hiro/reference/browser-window.hpp similarity index 100% rename from phoenix/reference/browser-window.hpp rename to hiro/reference/browser-window.hpp diff --git a/phoenix/reference/desktop.cpp b/hiro/reference/desktop.cpp similarity index 100% rename from phoenix/reference/desktop.cpp rename to hiro/reference/desktop.cpp diff --git a/phoenix/reference/desktop.hpp b/hiro/reference/desktop.hpp similarity index 100% rename from phoenix/reference/desktop.hpp rename to hiro/reference/desktop.hpp diff --git a/phoenix/reference/font.cpp b/hiro/reference/font.cpp similarity index 100% rename from phoenix/reference/font.cpp rename to hiro/reference/font.cpp diff --git a/phoenix/reference/font.hpp b/hiro/reference/font.hpp similarity index 100% rename from phoenix/reference/font.hpp rename to hiro/reference/font.hpp diff --git a/phoenix/reference/header.hpp b/hiro/reference/header.hpp similarity index 100% rename from phoenix/reference/header.hpp rename to hiro/reference/header.hpp diff --git a/phoenix/reference/keyboard.cpp b/hiro/reference/keyboard.cpp similarity index 100% rename from phoenix/reference/keyboard.cpp rename to hiro/reference/keyboard.cpp diff --git a/phoenix/reference/keyboard.hpp b/hiro/reference/keyboard.hpp similarity index 100% rename from phoenix/reference/keyboard.hpp rename to hiro/reference/keyboard.hpp diff --git a/phoenix/reference/message-window.cpp b/hiro/reference/message-window.cpp similarity index 100% rename from phoenix/reference/message-window.cpp rename to hiro/reference/message-window.cpp diff --git a/phoenix/reference/message-window.hpp b/hiro/reference/message-window.hpp similarity index 100% rename from phoenix/reference/message-window.hpp rename to hiro/reference/message-window.hpp diff --git a/phoenix/reference/monitor.cpp b/hiro/reference/monitor.cpp similarity index 100% rename from phoenix/reference/monitor.cpp rename to hiro/reference/monitor.cpp diff --git a/phoenix/reference/monitor.hpp b/hiro/reference/monitor.hpp similarity index 100% rename from phoenix/reference/monitor.hpp rename to hiro/reference/monitor.hpp diff --git a/phoenix/reference/mouse.cpp b/hiro/reference/mouse.cpp similarity index 100% rename from phoenix/reference/mouse.cpp rename to hiro/reference/mouse.cpp diff --git a/phoenix/reference/mouse.hpp b/hiro/reference/mouse.hpp similarity index 100% rename from phoenix/reference/mouse.hpp rename to hiro/reference/mouse.hpp diff --git a/phoenix/reference/object.cpp b/hiro/reference/object.cpp similarity index 100% rename from phoenix/reference/object.cpp rename to hiro/reference/object.cpp diff --git a/phoenix/reference/object.hpp b/hiro/reference/object.hpp similarity index 100% rename from phoenix/reference/object.hpp rename to hiro/reference/object.hpp diff --git a/phoenix/reference/platform.cpp b/hiro/reference/platform.cpp similarity index 97% rename from phoenix/reference/platform.cpp rename to hiro/reference/platform.cpp index 2a9ff663..883b0b2d 100644 --- a/phoenix/reference/platform.cpp +++ b/hiro/reference/platform.cpp @@ -10,6 +10,7 @@ #include "object.cpp" #include "timer.cpp" #include "window.cpp" +#include "popup-menu.cpp" #include "action/action.cpp" #include "action/menu.cpp" diff --git a/phoenix/reference/platform.hpp b/hiro/reference/platform.hpp similarity index 98% rename from phoenix/reference/platform.hpp rename to hiro/reference/platform.hpp index 059f7799..15cecec4 100644 --- a/phoenix/reference/platform.hpp +++ b/hiro/reference/platform.hpp @@ -16,6 +16,7 @@ namespace phoenix { #include "object.hpp" #include "timer.hpp" #include "window.hpp" +#include "popup-menu.hpp" #include "action/action.hpp" #include "action/menu.hpp" diff --git a/hiro/reference/popup-menu.cpp b/hiro/reference/popup-menu.cpp new file mode 100644 index 00000000..1dea8c2f --- /dev/null +++ b/hiro/reference/popup-menu.cpp @@ -0,0 +1,18 @@ +namespace phoenix { + +void pPopupMenu::append(Action& action) { +} + +void pPopupMenu::remove(Action& action) { +} + +void pPopupMenu::setVisible() { +} + +void pPopupMenu::constructor() { +} + +void pPopupMenu::destructor() { +} + +} diff --git a/hiro/reference/popup-menu.hpp b/hiro/reference/popup-menu.hpp new file mode 100644 index 00000000..c1eb0641 --- /dev/null +++ b/hiro/reference/popup-menu.hpp @@ -0,0 +1,15 @@ +namespace phoenix { + +struct pPopupMenu : public pObject { + PopupMenu& popupMenu; + + void append(Action& action); + void remove(Action& action); + void setVisible(); + + pPopupMenu(PopupMenu& popupMenu) : pObject(popupMenu), popupMenu(popupMenu) {} + void constructor(); + void destructor(); +}; + +} diff --git a/phoenix/reference/timer.cpp b/hiro/reference/timer.cpp similarity index 100% rename from phoenix/reference/timer.cpp rename to hiro/reference/timer.cpp diff --git a/phoenix/reference/timer.hpp b/hiro/reference/timer.hpp similarity index 100% rename from phoenix/reference/timer.hpp rename to hiro/reference/timer.hpp diff --git a/phoenix/reference/widget/button.cpp b/hiro/reference/widget/button.cpp similarity index 81% rename from phoenix/reference/widget/button.cpp rename to hiro/reference/widget/button.cpp index e2a3dfbc..ad7c3362 100644 --- a/phoenix/reference/widget/button.cpp +++ b/hiro/reference/widget/button.cpp @@ -1,5 +1,8 @@ namespace phoenix { +void pButton::setBordered(bool bordered) { +} + void pButton::setImage(const image& image, Orientation orientation) { } diff --git a/phoenix/reference/widget/button.hpp b/hiro/reference/widget/button.hpp similarity index 88% rename from phoenix/reference/widget/button.hpp rename to hiro/reference/widget/button.hpp index be591979..c4e697b1 100644 --- a/phoenix/reference/widget/button.hpp +++ b/hiro/reference/widget/button.hpp @@ -3,6 +3,7 @@ namespace phoenix { struct pButton : public pWidget { Button& button; + void setBordered(bool bordered); void setImage(const image& image, Orientation orientation); void setText(string text); diff --git a/phoenix/reference/widget/canvas.cpp b/hiro/reference/widget/canvas.cpp similarity index 100% rename from phoenix/reference/widget/canvas.cpp rename to hiro/reference/widget/canvas.cpp diff --git a/phoenix/reference/widget/canvas.hpp b/hiro/reference/widget/canvas.hpp similarity index 100% rename from phoenix/reference/widget/canvas.hpp rename to hiro/reference/widget/canvas.hpp diff --git a/phoenix/reference/widget/check-button.cpp b/hiro/reference/widget/check-button.cpp similarity index 100% rename from phoenix/reference/widget/check-button.cpp rename to hiro/reference/widget/check-button.cpp diff --git a/phoenix/reference/widget/check-button.hpp b/hiro/reference/widget/check-button.hpp similarity index 100% rename from phoenix/reference/widget/check-button.hpp rename to hiro/reference/widget/check-button.hpp diff --git a/phoenix/reference/widget/check-label.cpp b/hiro/reference/widget/check-label.cpp similarity index 100% rename from phoenix/reference/widget/check-label.cpp rename to hiro/reference/widget/check-label.cpp diff --git a/phoenix/reference/widget/check-label.hpp b/hiro/reference/widget/check-label.hpp similarity index 100% rename from phoenix/reference/widget/check-label.hpp rename to hiro/reference/widget/check-label.hpp diff --git a/phoenix/reference/widget/combo-button.cpp b/hiro/reference/widget/combo-button.cpp similarity index 72% rename from phoenix/reference/widget/combo-button.cpp rename to hiro/reference/widget/combo-button.cpp index 0eac259b..d9f5d3b1 100644 --- a/phoenix/reference/widget/combo-button.cpp +++ b/hiro/reference/widget/combo-button.cpp @@ -1,6 +1,6 @@ namespace phoenix { -void pComboButton::append(string text) { +void pComboButton::append() { } void pComboButton::remove(unsigned selection) { @@ -9,7 +9,7 @@ void pComboButton::remove(unsigned selection) { void pComboButton::reset() { } -void pComboButton::setSelection(unsigned selection) { +void pComboButton::setSelected(unsigned selection) { } void pComboButton::setText(unsigned selection, string text) { diff --git a/phoenix/reference/widget/combo-button.hpp b/hiro/reference/widget/combo-button.hpp similarity index 82% rename from phoenix/reference/widget/combo-button.hpp rename to hiro/reference/widget/combo-button.hpp index 9c183481..8b2b303f 100644 --- a/phoenix/reference/widget/combo-button.hpp +++ b/hiro/reference/widget/combo-button.hpp @@ -3,10 +3,10 @@ namespace phoenix { struct pComboButton : public pWidget { ComboButton& comboButton; - void append(string text); + void append(); void remove(unsigned selection); void reset(); - void setSelection(unsigned selection); + void setSelected(unsigned selection); void setText(unsigned selection, string text); pComboButton(ComboButton& comboButton) : pWidget(comboButton), comboButton(comboButton) {} diff --git a/phoenix/reference/widget/console.cpp b/hiro/reference/widget/console.cpp similarity index 100% rename from phoenix/reference/widget/console.cpp rename to hiro/reference/widget/console.cpp diff --git a/phoenix/reference/widget/console.hpp b/hiro/reference/widget/console.hpp similarity index 100% rename from phoenix/reference/widget/console.hpp rename to hiro/reference/widget/console.hpp diff --git a/phoenix/reference/widget/frame.cpp b/hiro/reference/widget/frame.cpp similarity index 100% rename from phoenix/reference/widget/frame.cpp rename to hiro/reference/widget/frame.cpp diff --git a/phoenix/reference/widget/frame.hpp b/hiro/reference/widget/frame.hpp similarity index 100% rename from phoenix/reference/widget/frame.hpp rename to hiro/reference/widget/frame.hpp diff --git a/phoenix/reference/widget/hex-edit.cpp b/hiro/reference/widget/hex-edit.cpp similarity index 100% rename from phoenix/reference/widget/hex-edit.cpp rename to hiro/reference/widget/hex-edit.cpp diff --git a/phoenix/reference/widget/hex-edit.hpp b/hiro/reference/widget/hex-edit.hpp similarity index 100% rename from phoenix/reference/widget/hex-edit.hpp rename to hiro/reference/widget/hex-edit.hpp diff --git a/phoenix/reference/widget/horizontal-scroller.cpp b/hiro/reference/widget/horizontal-scroller.cpp similarity index 100% rename from phoenix/reference/widget/horizontal-scroller.cpp rename to hiro/reference/widget/horizontal-scroller.cpp diff --git a/phoenix/reference/widget/horizontal-scroller.hpp b/hiro/reference/widget/horizontal-scroller.hpp similarity index 100% rename from phoenix/reference/widget/horizontal-scroller.hpp rename to hiro/reference/widget/horizontal-scroller.hpp diff --git a/phoenix/reference/widget/horizontal-slider.cpp b/hiro/reference/widget/horizontal-slider.cpp similarity index 100% rename from phoenix/reference/widget/horizontal-slider.cpp rename to hiro/reference/widget/horizontal-slider.cpp diff --git a/phoenix/reference/widget/horizontal-slider.hpp b/hiro/reference/widget/horizontal-slider.hpp similarity index 100% rename from phoenix/reference/widget/horizontal-slider.hpp rename to hiro/reference/widget/horizontal-slider.hpp diff --git a/phoenix/reference/widget/label.cpp b/hiro/reference/widget/label.cpp similarity index 100% rename from phoenix/reference/widget/label.cpp rename to hiro/reference/widget/label.cpp diff --git a/phoenix/reference/widget/label.hpp b/hiro/reference/widget/label.hpp similarity index 100% rename from phoenix/reference/widget/label.hpp rename to hiro/reference/widget/label.hpp diff --git a/phoenix/reference/widget/layout.hpp b/hiro/reference/widget/layout.hpp similarity index 100% rename from phoenix/reference/widget/layout.hpp rename to hiro/reference/widget/layout.hpp diff --git a/phoenix/reference/widget/line-edit.cpp b/hiro/reference/widget/line-edit.cpp similarity index 100% rename from phoenix/reference/widget/line-edit.cpp rename to hiro/reference/widget/line-edit.cpp diff --git a/phoenix/reference/widget/line-edit.hpp b/hiro/reference/widget/line-edit.hpp similarity index 100% rename from phoenix/reference/widget/line-edit.hpp rename to hiro/reference/widget/line-edit.hpp diff --git a/phoenix/reference/widget/list-view.cpp b/hiro/reference/widget/list-view.cpp similarity index 61% rename from phoenix/reference/widget/list-view.cpp rename to hiro/reference/widget/list-view.cpp index e882907c..d774389d 100644 --- a/phoenix/reference/widget/list-view.cpp +++ b/hiro/reference/widget/list-view.cpp @@ -1,6 +1,6 @@ namespace phoenix { -void pListView::append(const lstring& text) { +void pListView::append() { } void pListView::autoSizeColumns() { @@ -21,6 +21,15 @@ void pListView::setCheckable(bool checkable) { void pListView::setChecked(unsigned selection, bool checked) { } +void pListView::setChecked(const vector& selections) { +} + +void pListView::setCheckedAll() { +} + +void pListView::setCheckedNone() { +} + void pListView::setForegroundColor(Color color) { } @@ -33,10 +42,19 @@ void pListView::setHeaderVisible(bool visible) { void pListView::setImage(unsigned selection, unsigned position, const image& image) { } -void pListView::setSelected(bool selected) { +void pListView::setSelected(unsigned selection, bool selected) { } -void pListView::setSelection(unsigned selection) { +void pListView::setSelected(const vector& selections) { +} + +void pListView::setSelectedAll() { +} + +void pListView::setSelectedNone() { +} + +void pListView::setSingleSelection(bool singleSelection) { } void pListView::setText(unsigned selection, unsigned position, string text) { diff --git a/phoenix/reference/widget/list-view.hpp b/hiro/reference/widget/list-view.hpp similarity index 67% rename from phoenix/reference/widget/list-view.hpp rename to hiro/reference/widget/list-view.hpp index 8a97a955..3b2e1528 100644 --- a/phoenix/reference/widget/list-view.hpp +++ b/hiro/reference/widget/list-view.hpp @@ -3,19 +3,25 @@ namespace phoenix { struct pListView : public pWidget { ListView& listView; - void append(const lstring& text); + void append(); void autoSizeColumns(); void remove(unsigned selection); void reset(); void setBackgroundColor(Color color); void setCheckable(bool checkable); void setChecked(unsigned selection, bool checked); + void setChecked(const vector& selections); + void setCheckedAll(); + void setCheckedNone(); void setForegroundColor(Color color); void setHeaderText(const lstring& text); void setHeaderVisible(bool visible); void setImage(unsigned selection, unsigned position, const image& image); - void setSelected(bool selected); - void setSelection(unsigned selection); + void setSelected(unsigned selection, bool selected); + void setSelected(const vector& selections); + void setSelectedAll(); + void setSelectedNone(); + void setSingleSelection(bool singleSelection); void setText(unsigned selection, unsigned position, string text); pListView(ListView& listView) : pWidget(listView), listView(listView) {} diff --git a/phoenix/reference/widget/progress-bar.cpp b/hiro/reference/widget/progress-bar.cpp similarity index 100% rename from phoenix/reference/widget/progress-bar.cpp rename to hiro/reference/widget/progress-bar.cpp diff --git a/phoenix/reference/widget/progress-bar.hpp b/hiro/reference/widget/progress-bar.hpp similarity index 100% rename from phoenix/reference/widget/progress-bar.hpp rename to hiro/reference/widget/progress-bar.hpp diff --git a/phoenix/reference/widget/radio-button.cpp b/hiro/reference/widget/radio-button.cpp similarity index 100% rename from phoenix/reference/widget/radio-button.cpp rename to hiro/reference/widget/radio-button.cpp diff --git a/phoenix/reference/widget/radio-button.hpp b/hiro/reference/widget/radio-button.hpp similarity index 100% rename from phoenix/reference/widget/radio-button.hpp rename to hiro/reference/widget/radio-button.hpp diff --git a/phoenix/reference/widget/radio-label.cpp b/hiro/reference/widget/radio-label.cpp similarity index 100% rename from phoenix/reference/widget/radio-label.cpp rename to hiro/reference/widget/radio-label.cpp diff --git a/phoenix/reference/widget/radio-label.hpp b/hiro/reference/widget/radio-label.hpp similarity index 100% rename from phoenix/reference/widget/radio-label.hpp rename to hiro/reference/widget/radio-label.hpp diff --git a/phoenix/reference/widget/sizable.hpp b/hiro/reference/widget/sizable.hpp similarity index 100% rename from phoenix/reference/widget/sizable.hpp rename to hiro/reference/widget/sizable.hpp diff --git a/phoenix/reference/widget/tab-frame.cpp b/hiro/reference/widget/tab-frame.cpp similarity index 71% rename from phoenix/reference/widget/tab-frame.cpp rename to hiro/reference/widget/tab-frame.cpp index 074a018a..065a89b7 100644 --- a/phoenix/reference/widget/tab-frame.cpp +++ b/hiro/reference/widget/tab-frame.cpp @@ -1,6 +1,6 @@ namespace phoenix { -void pTabFrame::append(string text, const image& image) { +void pTabFrame::append() { } void pTabFrame::remove(unsigned selection) { @@ -9,7 +9,7 @@ void pTabFrame::remove(unsigned selection) { void pTabFrame::setImage(unsigned selection, const image& image) { } -void pTabFrame::setSelection(unsigned selection) { +void pTabFrame::setSelected(unsigned selection) { } void pTabFrame::setText(unsigned selection, string text) { diff --git a/phoenix/reference/widget/tab-frame.hpp b/hiro/reference/widget/tab-frame.hpp similarity index 79% rename from phoenix/reference/widget/tab-frame.hpp rename to hiro/reference/widget/tab-frame.hpp index 3efd9890..9984ef1d 100644 --- a/phoenix/reference/widget/tab-frame.hpp +++ b/hiro/reference/widget/tab-frame.hpp @@ -3,10 +3,10 @@ namespace phoenix { struct pTabFrame : public pWidget { TabFrame& tabFrame; - void append(string text, const image& image); + void append(); void remove(unsigned selection); void setImage(unsigned selection, const image& image); - void setSelection(unsigned selection); + void setSelected(unsigned selection); void setText(unsigned selection, string text); pTabFrame(TabFrame& tabFrame) : pWidget(tabFrame), tabFrame(tabFrame) {} diff --git a/phoenix/reference/widget/text-edit.cpp b/hiro/reference/widget/text-edit.cpp similarity index 100% rename from phoenix/reference/widget/text-edit.cpp rename to hiro/reference/widget/text-edit.cpp diff --git a/phoenix/reference/widget/text-edit.hpp b/hiro/reference/widget/text-edit.hpp similarity index 100% rename from phoenix/reference/widget/text-edit.hpp rename to hiro/reference/widget/text-edit.hpp diff --git a/phoenix/reference/widget/vertical-scroller.cpp b/hiro/reference/widget/vertical-scroller.cpp similarity index 100% rename from phoenix/reference/widget/vertical-scroller.cpp rename to hiro/reference/widget/vertical-scroller.cpp diff --git a/phoenix/reference/widget/vertical-scroller.hpp b/hiro/reference/widget/vertical-scroller.hpp similarity index 100% rename from phoenix/reference/widget/vertical-scroller.hpp rename to hiro/reference/widget/vertical-scroller.hpp diff --git a/phoenix/reference/widget/vertical-slider.cpp b/hiro/reference/widget/vertical-slider.cpp similarity index 100% rename from phoenix/reference/widget/vertical-slider.cpp rename to hiro/reference/widget/vertical-slider.cpp diff --git a/phoenix/reference/widget/vertical-slider.hpp b/hiro/reference/widget/vertical-slider.hpp similarity index 100% rename from phoenix/reference/widget/vertical-slider.hpp rename to hiro/reference/widget/vertical-slider.hpp diff --git a/phoenix/reference/widget/viewport.cpp b/hiro/reference/widget/viewport.cpp similarity index 100% rename from phoenix/reference/widget/viewport.cpp rename to hiro/reference/widget/viewport.cpp diff --git a/phoenix/reference/widget/viewport.hpp b/hiro/reference/widget/viewport.hpp similarity index 100% rename from phoenix/reference/widget/viewport.hpp rename to hiro/reference/widget/viewport.hpp diff --git a/phoenix/reference/widget/widget.cpp b/hiro/reference/widget/widget.cpp similarity index 100% rename from phoenix/reference/widget/widget.cpp rename to hiro/reference/widget/widget.cpp diff --git a/phoenix/reference/widget/widget.hpp b/hiro/reference/widget/widget.hpp similarity index 100% rename from phoenix/reference/widget/widget.hpp rename to hiro/reference/widget/widget.hpp diff --git a/phoenix/reference/window.cpp b/hiro/reference/window.cpp similarity index 95% rename from phoenix/reference/window.cpp rename to hiro/reference/window.cpp index 416f2151..20b63eba 100644 --- a/phoenix/reference/window.cpp +++ b/hiro/reference/window.cpp @@ -23,10 +23,6 @@ Geometry pWindow::frameMargin() { return {0, 0, 0, 0}; } -Geometry pWindow::geometry() { - return {0, 0, 0, 0}; -} - void pWindow::remove(Layout& layout) { } diff --git a/phoenix/reference/window.hpp b/hiro/reference/window.hpp similarity index 97% rename from phoenix/reference/window.hpp rename to hiro/reference/window.hpp index 1039b9e6..b72efc84 100644 --- a/phoenix/reference/window.hpp +++ b/hiro/reference/window.hpp @@ -10,7 +10,6 @@ struct pWindow : public pObject { void append(Widget& widget); bool focused(); Geometry frameMargin(); - Geometry geometry(); void remove(Layout& layout); void remove(Menu& menu); void remove(Widget& widget); diff --git a/hiro/resource/GNUmakefile b/hiro/resource/GNUmakefile new file mode 100644 index 00000000..97e085c2 --- /dev/null +++ b/hiro/resource/GNUmakefile @@ -0,0 +1,13 @@ +all: + sourcery resource.bml resource.cpp resource.hpp + +permissions: + chmod +w icon/action/*.png + chmod +w icon/application/*.png + chmod +w icon/device/*.png + chmod +w icon/edit/*.png + chmod +w icon/emblem/*.png + chmod +w icon/go/*.png + chmod +w icon/media/*.png + chmod +w icon/place/*.png + chmod +w icon/prompt/*.png diff --git a/hiro/resource/icon/action/add.png b/hiro/resource/icon/action/add.png new file mode 100644 index 0000000000000000000000000000000000000000..1aa7f095c6c282262390748ab2e596a3fc15c228 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE7hmi)!cT|6FkAON{jSt(_u!Lq7!B=^4B;IBq%dL`6}O%gpGjO3}J1 z4Y?KfzQ;%l3Rp(0FF*F|EI&io>j^)N99Xu9ZE@HjcqrgTrepSr)S!;v7$d z7#j|r*sm7k|1`qSzwL6X$#3JGkN$s>{Cx9Ec6v|es;&OpMC)hUh7@^ocW)~11Nx1@ M)78&qol`;+0M{XYA^-pY literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/action/attach.png b/hiro/resource/icon/action/attach.png new file mode 100644 index 0000000000000000000000000000000000000000..529bb7f554dfa585a4a8d6b9135956b188be3f37 GIT binary patch literal 649 zcmV;40(Sk0P)s%e4^YA&(d3cVhTCLK&Bw17g6TmTG z1V{n*fT@5#xT4HeH3O0?b^tS7rmoSw{r%V-b~ZOQiN#_pEk6BTsZ=}xe=t$cSGQab zmz{mi(ebe{R#sQJ6}U|#@&J>`gv;$R0T-3Ye*j4q&q%WP893+j`Iw##vHWIvYHO=7 zl>V7MAB{f7>-7Sh`X>Nf@%e^rz^+b1Cz(tJ;8MUJTm){cudQL&u@hi-JD_9GGYEiI z(AHxWNfwU+*8l`T2hh+oL9th9b-HH241~;Pvnr8Dpb>-?Kv{uGC;SGqx_WF6pgJv| z1wdDW+XMBRg})V4l@)2!{{iYJm2wreS`E+xP%4!GD3*%b1NmGYfLE_yGT`11Fln=P z^YPOM0P?w93((NSLZJrC%||(L{3KS3&1kV$2}foCC=?3Y0_)jq)}YtxNhW_}CU0Ih z_SzjhiasQ}k;T#LB>pW95Nr2@*@dMACdQA@(``3uG#cK$e@nSi#bYy1oMBO%h6bQrj!1R8#$B#Q=Wvpxb0Q=5Y{ jFbmuT!U2DDE_ literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/action/bookmark.png b/hiro/resource/icon/action/bookmark.png new file mode 100644 index 0000000000000000000000000000000000000000..6cf6443a296cd908ac3e6dba8861b3955a919e20 GIT binary patch literal 686 zcmV;f0#W^mP)V2b4<9{` z4W?bEH4*2)p%WO^K~|PN4DJbz-B19Xot=HDREk}}AOqQlP{6GeSz2CZeqk8^Ti0+aMGC)N+?tE7I*2kT z7iaJ(DHxl9YPCwWvP!w+P;yo%J1bOH9o(|R*m#MVoKP(e;1%C7JDmov@~r^?5M`mY zg=zUvrVph}#4y<(OAy(27N^#Mm@!61O`tm30Eh_M^kdoqEIWwL--K!V(Wal=Y>rHJ z3QuBS9cON#3ElE?RsY?AVJHkkp|lBrQYMDd#N%<=+S)(_5sl{w01bd;S?l|~ks!6& z#+R`DimlQxLLd;R{~iy%ydP$GUFp4S*lrFdLVSEPgy(tW z^La9v%s)WG2)1nlaP9Ibu3S8cVHotk8s^!H&$PFJA!!NF>5eqt{x0-P6<4y_3RdG};I72S!%7 U#xj@WzW@LL07*qoM6N<$g6$wT&Hw-a literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/action/full-screen.png b/hiro/resource/icon/action/full-screen.png new file mode 100644 index 0000000000000000000000000000000000000000..ffdabd4e97cf7b4d3286ea169c5a71b2f889b052 GIT binary patch literal 650 zcmV;50(Jd~P)Mh53JODVWnpw>WFU8GbZ8({Xk{Qr zNlj3Y*^6%g00GuXL_t(I%bk-uXp>PC$AABu8#NVa(wI$T<{@WGkC&Rq}NCt4}x%j9e{w{GG08_2W z82w8IB#^|@_+o3% z62b*n^?G2CgpncfV1l`YKTLhjGCTK^?5{i{FQ&+~TjD@QIr1YpnEWG%pTp?h$I%#R%DFN>Tzx)VuA;$%;RRC=Co+23>x zBpc7cvJ1JtOWb!3dz~l(Brz86V`L zlg~?3Q5c4wb3NBH){HJ>8WD{a;zqJE7ZpJZA(&N*ah#d0n<-pI`X59s%&oRkw2VYZ z2?P;Zxsyo94AEe0GYfIyz0Npue|#+lXJJTIADq?4`@G)^?@=Pc|BQ9sVlX$@pU>y* ze*$E)slEo(TD4kj_-jBmo9eS0BcDX1`A=d1oynygAfmNCMr6`%j64}09&Vm`Jr!I8 zU@25&Vthi6jgGYljE;J>*j5YF({=j1_0Rl_Ow(&fVhYRoX^V8GM1R`gJ3Qh!`YXHY_>HyF85Nh49eE(%97;OxeF$70P=+;*J z!$SfQ3h>GTa9jt+br2D}s)twgPL0eZW9V63<@)+MvF>heY;Mv$Gec7?qR{}Z>ryV4 z0Vw?3r?aD@eyZu};&OjK${2dKw*hELCeeum6pL6QB8!WQ!OF_YiKVQmrKJz;y z08cd6u?+wK010qNS#tmY3ljhU3ljkVnw%H_000McNliru)dCU@CLGhY87Tk&0cuG^ zK~y-)t&mSkTTu|je{=7RRwR8Tg3!ua7TnbCTxO{o^9{0bS-(ZzvfXzh1jK^hz)d&Z zDuq%?vQkP(T7(e)MPi%YcgKY$#u$@SdNwl*bLN~gQZARbYqeUD5tyC*%iLU>XVGu+ z%b(xnqHiDJ&%R{C8KqK5$Km{VQ!h{7Xy?43mnSQoi^k%vwzBKmGBd8L(rh*fApjsE zJ@t&)W7>Wp4I*kr6}$~JG#W`y z)G#6Xf76e95r#Q(v5I2X42Kx^LBZUY}D`;qn5FxciLM_ej_ug~QY53}!mSE3t?zxwHpXWK} z-YY{xLmWiP&4!4S?k*w%Kv5JTBDA%&eg3uGxLj4$`u_gV)z$UX-EZzMEG>UI@$AWS zilRV7*e4MYCSOdRpPrujfO8S}0T9e=aBy(2)6B>@GdBL1m6a8m%_acuPRe$zP^sC?ptQ@-QuCrdb+y-7#+PUpcUVtdz^5edX(lyb1*!_e$Blc8obQwH#$sup8JB=Bvc!Ow=G z*-60WbcEP)r z=%QrMoYg6I5Q8zI2z{r+`*EJ{?;HUbkH_CZ5WMl6-uwOj7XYs79-o!#x<`QQC33&t z6GagKA`<)Ovxtz%WH3!LjwJw56yf`R;=-jwgnGT6@Uqv9)oL{Wdc9ukbvhkNrBVtA z@N%8O_kC8Y743E#tu`Ffm|-fd_JdAsoVyL2ui8cJ8&F_^?HqA807Q$$M4`YxFn>} zXs}!^?*lG}b}iF1DVNJBKMP>n_RnB2czxz8+P3}4f9Mb3j-%#nF`Fa+0000#yLz&Ndx##4AnMLxFXBZ(g%HuJ zXi&qdfM(p}?71_;z-a>z1OY)1kR%Cdn$l{uaL%E% z20$r|G3H}0Xl>|O*#nSQ0Qr2LFbv7%a)e>nxm#-iK?Fn;rO}H#*uEVR!P*eOn08KU zEzY@4ZV^E#g$TGTkl0Q5yTko z96r1hp-s`2)|%YZ6svCDq_A@*KN&-G|2`-NL;2>{ay<)mpM1>)Xl?vJ194<}C>UEMz1(#)? z2-^S9HcD2kVCu*bayPCMH=C^7umK&0EG{h2Qi}O%6`Yd}!S|+-h9S4NY{31bkNg24I=4Iksz%a>Tzznj;k653ieJ|1K8_%QpT zsQ-%yp65||Q^JNmza1DLpU)yz5Kkbm-p{$%*@Oz8Th_`>gu&CBehx;5n=4n*f;C^bvfq< dg5VDz{U1L){aup)rDXsB002ovPDHLkV1hluXGs76 literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/action/refresh.png b/hiro/resource/icon/action/refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd71d6e5929ba0c40db1960e36e9acba9d7e525 GIT binary patch literal 912 zcmV;B18@9^P)oWowDaEkzU!j%l38$)o7}}cCnx7z zVrKYAWwOsS=-Lqw-t?qu)r6QQ!notg696vQmg&~r9t3cLe1UW(yG7H)Ku^~yeO+g> z(bg0Jm{BNJFfw+(d}sQhCl&9uE%R)8S2n|p?*PPznUTt5*BiPR+1l3~ipPS`iO?Jk zARN#U4H*a;0yD)$9M29{3dM>Y4K?&WE>{g^G!Zl7)jelV^{i|AG#D_%trsJC8h7YDw+>Nu`!(E)&&KfE(t5U!_KF)uRXGsl%@ z#;0eK6ZhtiUhin`+P8I6C=m!d1ufk}o{_gOutKfI-_b^R{JP z`QzJ2^LHMWS&9G(o-t)@yh1Uq9cxfG6X$C)H~ghbOC7?WrZ-yyL0>0QOs`0x)U>uAAQg z>;&LGL0Gpf^PVr@oj>}%1`wDT7wv!4sq=s3q*Oh&WftpMhqGg=O68@F-$%x80Ep=T zKm-sG?*3PXAs8nI|0Dok)RR-0Y?z4d_HJBzCO6*s&6^5?o^0No>h2ra)My_p{u2^&LcltM%9%NL@3OcL;J5G-fbF(raxE|ezZLFV~EA+w-YyVHU|i_?Pt%tbHGab z1&5^a+FUmdNd@kXwZ%tROFFJ>Q*!zI&R_A==FP^f@-i~)|I20A*?&KNrgrv}l!w`~ zS-W;DV_2Rr!zN$cO_)z&Zy0B$7WFVdQ&MBb@09MjczW@LL literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/action/save.png b/hiro/resource/icon/action/save.png new file mode 100644 index 0000000000000000000000000000000000000000..22ff49571020a2b520d34f622673bea031cbbf2d GIT binary patch literal 911 zcmV;A191F_P)UFWod3@ax5SUXmoUNIxjD3X>Dy`V=irVb7^B}VQg$JV|oe-V{&C- zbY)~9cWHEJAarPDAV*0}P%H{)baZe!FE4j@cP?jXZE!Aca%X3X$43AF0)$CKK~y-) zosvyRRACf`pSj)f=Fj9z;I%Q$k+M;2QBgD|6u8J1MHDVVC@g}Csliq)D#}F>R1gMI zv?vN9uqY^MThJnjM2er z*tjzZQ~_IohM*?d(88ZT78%aXyXViH;2#P!cXaKIt*nn#mz#sDYsxyRBZX^i&nNvY z!|UGX>ciJj;*mGYx;yU-{}qrteZJeB8awQX#;6}=+9+dz9;B^hBg-ombNT)Y{GmQ# z1>=94?<9FFC0|AcL_}oZb6R@S1CqM-L=p!tNYAS;()IMMw4S;y?*@nEcUhJtsg9)R zhVHYpJjTSt1mTi$w7?{V;sDV1aTK#e=lghu_XD3;vZxRO075}Q0RXz^f+)dPitQ(E z%-gYda01u!x!CiPi#;y^czkvr$ZTH&P@+)2qU%s20PVYX(wJDs%#2Mmq|uaE&)(MU z0PJaAf$|k1G6xV5B9Sl^Wic)tSjWw~4~WOA&hFy#?;glwrvv%h2{W;VNh9FnHS!gh7CNsvH<|wws9PX>FMctA?pDB z{r$MEo7eC>4_()D?>`lZMDjE6Jdbob&B(|InM?)|K}0YNgQ1}zLZMKuT9$=nS@~B` zN>N-~L@*f4eG&lIbrCfS6E%B2<@@;-!r?HbrKLopQ2?^pEI=;pcwHQ&6!E$`lu|5- lMst<}sgC3s;57fI&R>%|GfdSYVr>8b002ovPDHLkV1jlggmVA@ literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/action/search.png b/hiro/resource/icon/action/search.png new file mode 100644 index 0000000000000000000000000000000000000000..fd7f0b07a558cb6d59af96bebb672bf1abe96c88 GIT binary patch literal 935 zcmV;Y16cftP)&ujZZ2vcpl1 zMZ@GK2apA{PG?ddXEM`!?RHyZ=kcza{{|ocz_G78)~3_xTfzOGVc*@!;z&{~D4M34 z#HCy|oAJK^O5@u;x%xm;z_nWd04$M+pY+%HrNI}599Zr)1O{&1Fr9gQ zRx^nN(=^?Ylb_Xc3crTMTm|}8W6tGCdm-gHU zoivEbfP*V-h@Y#f29hN4c>od3S|m}D80SwWrl%O%n5zs-y=aEVV!4n`6c;!WFs{rR zhNug$8$G1gD4`4AaS<H7=eg9>uBL$90I_nW$UopHtf^aCQMJwQhI406Q(#?y zO-@ZpM5e?TYiVd$*M}u5U8hd09vd6~!{hc8oX&FDU*~sLS6AD5dV3x{dHP7z^Tsz$ zm;I-vElqH5_&#iSZzKKk>qUmIhNJ7$iG2Xj914Xt0)Xc8`7QxKZ+qL(^TA-S6B++< zPs?7gTFc=3v)=)}CSYu?u#}a#&H(^gTU%RH&GN(C?nC&$dI>wJW|L@7q6Gi|002ov JPDHLkV1n1##MS@+ literal 0 HcmV?d00001 diff --git a/target-higan/resource/advanced.png b/hiro/resource/icon/action/settings.png similarity index 100% rename from target-higan/resource/advanced.png rename to hiro/resource/icon/action/settings.png diff --git a/hiro/resource/icon/action/stop.png b/hiro/resource/icon/action/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..ab6808fba55428710250c72b2569ca5288cd6df2 GIT binary patch literal 820 zcmV-41Izr0P)Mc{ zK~y-)ZIioCQ(+i~pL6L2ZH>mr;3bB}Kr47@YPbohHi(*-khrlBSo{xMIye|<92`s> zj0 zfhzpM@ALIWhKAhp&ub29c4n916Y9^A&F#&y1u(Xj-$dR3#d>J@)tT!?^ zxB;)Of@N(J5UR>rI!z!F(O2i@jx3c*X9mOJ=UQhb^X7PCW6$}40e3bY$EvSKkHsLF zL}s%av!6J@-n)0HBoY{3zj8br){Ru^=#NAqsP(AolnVvazCP5J7L<+- z`2HPr|9>&Rx53dc9cF)8t|?gl%I3HXy4zQg`&b zxfypTgs$s291eB|gVcpW$SN$#WyIXvUjZpZ4OUxP@ZP$G)9YnD9%prQ6sO07@7_H; z?d_Pk9LBeA$dwfUbSdSAnqeR;i@LTpTvd2+co^F>(SQT}{nVX0#rlH>plR6EqS^&1 zyDP=w;XqrPR!Sr&y?#yQ=T8=H-lUw#P+nXl_v#gEv$G^`-$v0ie11Rar6v2v@^W5@ zfm4IGCmR~NTZ2JYDjsL8Sgb8;>r)&K8k(9&7YgEII=x^+r#1#60#9C-Mn2yDwjT2}2(B$L*s yY<9+mt|%;SyT+{|0(y3`SA}UC&P8E)GxrC_O;YyPhW8Wz0000Mh53JODVWnpw>WFU8GbZ8({Xk{Qr zNlj3Y*^6%g00QhuL_t(I%dL}LXj^3*hoASH_nc#sG-;dWqm6CW(4s83b+X9Bt0|~3 z6mOI%-9=?M5O0K`ptn*G#rs`|6-PnD>5WW=H?uIcvzCo^E3WHYKeL=HA5C(SbCR6b z3)#f&*5~^FdoKR`eu4)${@&~<;4NLs{R%AQ`wgX7&~)wW+|1M$58jLW!S}zMGrL#P4P+<|J^kR=q!LjUR<=1mzj7BLp1miL0MTgZr{|x^iYGDyl!|!#OL6OV`f;PXlOge)!c#$#{SGXl@)s^XbSCXaYk@OhXc|B#CG* zL-81~z96~mqojuij=b@~*=YbR90{B}oE@c7E^@~W5Fg%$Qs65I} literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/application/calculator.png b/hiro/resource/icon/application/calculator.png new file mode 100644 index 0000000000000000000000000000000000000000..9248971a914ebd40b59fc3e5b0aa98cf24178447 GIT binary patch literal 686 zcmV;f0#W^mP)Mh53JODVWnpw>WFU8GbZ8({Xk{Qr zNlj3Y*^6%g00H_*L_t(I%bkU3zgc4(N=eS6`rHdkVHpB4Gd~^Q)%$TL+ z(nFxk*+$tcEtmAp-P>n6{p{&;+~39K*2_~jwpvG|(*f;v2Wy3)p>r%Q+ypoVG@A#f z0zSOo!&)IaY|(5Uas9?zq9uTtnYmK|Q&TyNF{moW7>qHAW|o#q8a3NIxPR}z{I5QG z!letDeg)lbkMinceswy1RTcdQKtzr$+*(=T)!GZZhl`VweBIy2`nm02#rPq#jrSEB$Z0h?RKfv zD@eQD#>XC2O+o^Q;}|e>Ivu?C0C-ibwdi0@EL@qI;r04D7{f$1%g#;%?_WFU8GbZ8({Xk{QrNlj1+3MgYKATls8GayP~Yjt8ECu(VJ zZDC_4AX9W@X>Mh5Co}I@0004=Nkl*w2IG?`^Ze@_zY&HN0A^r(atJMII0GUjNQmJ&+EQEMA zC#B?kK3@Rkckd|{izJiD$OPf$ry$31NTpIN77OG{H$Ht1!Zb|`!vMhZP8i|l$z(#c zS|y*)~=fa?KX$Q0oQePp>5l`#xRVCBqQuWE|+7yUNaaB7>~#Jz8}#nr9>%(Wm(q~0Q7o2 zmdhoc=h5wUaU2KBvS_th)a!NT^Er)1gIFx~yoBj=sz(fVErejd-|G!XDI*dzAe~NY z(*l>3QYfVmLZFnw_kDeqNF*Ks$K#RVaCr3%y!Kuw6fS^=hd*q$TPl^xi^bsx3=Mpc p+wYqj;OqVU?>GOEKY#tW`3q=*efBLWYwrL6002ovPDHLkV1oAM`$+%* literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/application/chat.png b/hiro/resource/icon/application/chat.png new file mode 100644 index 0000000000000000000000000000000000000000..f6e83254b638a2b939e71f07b182dae793009080 GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE9PK^lLGYXua=0dqb|0 z(0Aed#4mEkrXFFQVIkRU)!iwO@P)-K`H`TB-dCnMEei~^#gkV`ducIu)E`>3<^AjG zztK&BfkHBj6^DMzTFe^of29Ve$ooUjD*2X*ObOZ>y?Y%u!-GJf7{-VfofVRNRrl^& zA4u7ByT`KOXwIvCK3V<4ybKHqr#Hn33O05;u<$d!$H2qsdoZIxGtYU;WIu=L8{Rt1 zcMa9-|9(@J`Qv$g`5*Dqb~CuG?wq}|YY~H>BZuJ)ub;a966xg(BCQv{ZcM%SH|N!2 z9dFH+1n23Q)!EOlecrSASW_MIFQcQU1?I~ieR%rw>)mljBv$9#p2l!3b58*Q7;IDui+ui&r$;~AC~$Nu>2&ag&oQ0@?kEP)R4zO-SE_shK7L#K^bOYL`2|4i#%^^+d&Zo zk&sSy=pcw4>ZZxwY}*bA=G8Pha*v|J@tT}?%W zfngW`WV2bOr`~d}ruX2F47l3KjU|BXjcOQ7B-6|9cn5Kyc>qH_^Pxk?Y5HvP6 z@NQ%F=Lf9UupKV(UBp_bq(9L5mb75XrJ44nVXyC#?3BIa!Q*#eDs))^YbWW z`NsDFJ}oTJ+SbPAhK=hul>Tj?q2ZJq>dv3z`|8@kUyxGLkZ9U&=waVr86b=ZH79G4 oQU(Hs$Hqtd{^O2@kK`J+0Q~)|WKOu)r~m)}07*qoM6N<$g3M6(EC2ui literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/application/monitor.png b/hiro/resource/icon/application/monitor.png new file mode 100644 index 0000000000000000000000000000000000000000..8734e777a1799c9a9d0293d692b3549f2506f418 GIT binary patch literal 611 zcmV-p0-XJcP){lZ-v(r|Lj~5OgyaOZ2LJfeicB?^@C`JZr?Az7B z%cTZg`BR8Uk|Z%vq7ZR}iq)SDP7c%v1Bu8L;M*)gFoKYRtH+LS+(amWlo3J-J~!s*-9O61 z*EP)dJ6L0}#{PPO-3oZ}uA3-Ts8|uj3L!smu=5$dStASro-Xy${E-2R?G0dc-WEsb z9nLu}J?g;u9cXRPR%3Ci1{(odXN(OGaBuF_CfwpYz>BthSnKb xD?=NN)@$d68cm~7Ux!IxdUEo{_J8C5<|lAN08`nh^nm~X002ovPDHLkV1lX$`TPI? literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/application/terminal.png b/hiro/resource/icon/application/terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..c5b797a7dfe82a52fee3df9c7e19d49a4461ac02 GIT binary patch literal 668 zcmV;N0%QG&P)LL=FWNdBW7kS-|1Flt9VjZIBnic?*Db$yx>QG&VIP!QSJs zc<=BfKy0=M*Ov)53jjFhb^=6%sSh*s_1@*#$P<vkh+39&!fBd1N{T!K~miLpN5%0^7 zP?hbT6c8YA-0Z%^@Yn!vCnpHf3aBY5S34BA-9-fWI{S@FS1*DHD0nwMQ@+zW=FIu_ z^4U4Rs|JAcE~$}90nl-_txCE=rBeGS5Gby0{l5*X^50PdrIZG#Z$944!ootiUH7xb zBZrCN2&L5T0Mu|cH-BwxY&6)|C=!MtVYo&VMHp+a)?&9O(ORrEXrozKDQMtnAmZ=j zm%fwD&0jXgWVF_mQ8uOw*&b!BHAb7*SUV&l_x=LcqJkHgP4yiB0000S->P)2^qNERY3;<4ZcwkNNp7Zp5;AjKf{B7T6H z7K$;wTN)8fToCQSV$+QqO#Q&sZ0iseT9M6oFhjF#YAe3W{|(Ih&u?blgZ~U+lHy(Z zfEnP}R(g1dys47_mq#z10cH*!ci4`$5?D>W0r2hlIkux$PfFdaJ1vdV-c&$Y6qM6=z7>zUrb8|$BG>39|jmV1jOTU#EGRpi+xRHO?}@de@`-W?HM1Qj5D_ogg}SY zdLN|}^?H57O9w%Kn@Oz|d&_(+O?3c05d+({v28n2?E5}$CdJ@bk;TUuUX_^(h)oH!))dmc3|x7NH+_f7=kKWb2fXhZ zrnAjAMhLXlWV2a*$wSOL4(~qIS$aJMy=iu>tN_|Hp>9hMh9SE@rg`+GoBO#O-SQ{L5?nn?G7$uQNU|ANHWktGp13@enLu*Z~ zRzquzloG8qLI{Kqt=k(B1Emy><7_&0#$010qNS#tmY4c7nw4c7reD4Tcy000McNliru)e8d_Dk0G8x_1Bo0!&Fn zK~y-)eUo2EQ(+j!f0NC&Q?p3wEXcGA@00}DlvtNub|tbwbkR*|cR|#R42u4kH+AEN zAk_3~9!9&^AJB`ui3p8tNKIYZiJ5GAY#2C?c{uALciL$Bz{mIZdEV!HzxOk7hyhRk zBf!Vem;D15tm(NrP3oGxE)?^U|4bk(qm#UcP($`&Ipo&nsGLg81H{f5Kd=XPJC z^-?RvV$o=dqM)iO3k&nCt*-Lm{zHJ5)d9?vfkV82*Xso!7K;&&#~B+NGY(p^?jSwYh@EEWrbAYe9|Szca7mcQ|1V}n8=&*o-Iw z;x*6M)6;__NdRQCSwvA}a&pojM`KYOqJ!{T3Be{%+ACeJ5h!ft5zjkFr_%tas>pBP80oy+n0GgYdDXo`k3&|hwGk9l+&dyGBU8h_wqw6}Frm^#Dhs@GvQmG`s zp3~{F<<@im1f)>dG<0`x|M|$%Mvli4-~ep@m9nzEHQjQth1_}$DHOhWl)`|gf2!_Z l03uGO>s-a!F^E)8{s80H0eMd}i8cTL002ovPDHLkV1j1}N8kVe literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/device/mouse.png b/hiro/resource/icon/device/mouse.png new file mode 100644 index 0000000000000000000000000000000000000000..eeda4db8643728cfe36c328768cd2c38f2f72984 GIT binary patch literal 720 zcmV;>0x$iEP)Mh53JODVWnpw>WFU8GbZ8({Xk{Qr zNlj3Y*^6%g00JCIL_t(I%Z-rDOH@%9#(($R$*Xhkb)u47DA^y-rd81V1re0C339Sc zLc7pv76l_r5bj&FYcp+PP$Sy42}D;SQTY*pOb#=qIgR7jeBAS%7JfA9NWPoH`<&Ok9&y#xJ*t^l|Tbo<`ilcLBySyFqeD`}S7V|yd z?JNFSyOv6&mQrt0+0n6)8@s+2VK+Q&9e$lmCSSI;`n|>C+9vQZkx2B_rMpn8Ro@%f zYHoJsdb)4jvz{l15=yBdYzw6nmF<9NG)gX?Wnm#hlVhWU012e1l=|@WS)#Z8!%!#` z8oJ;Az}U8Jg~MTnhlkNx<21EkVKMOVF{M(8!s_qH$VmDQZ~&kHD%Gm>b8&HB%;j=a zDwThGK9AQLu^RNnkrLzaIQe{@Y&J_g9_N1(s$W)CR%mN$V{mZrfOcZQYN5btp@8rE zbar$wGdp{-1RJGw&Yd~CFV=z@%fFTnXd9*V;{l%M?nJe~!onCqiy%f2tnAKWiE1Mt?wAScg7bb#;&~(b#^G`Pde43x1 z!}B~^TAHzxLW`jFPJGvOiJXowGxH7LN23nje*N;f&vBe+SJy>6&%*#1!_HyIWENOj z$^pD?1gKT3)w`1u@bl z6ot&>{5&pOIN;*aNY+#^GB7Y!@Jh@sO;S+L%FNA8OjcJ2E=kSIOD)n-;L0c|DX`Ml zhe+t_fg)}5jc2Bb9e$9KAQn7V=g$vj*DJjmd0a}bqGESU z^*CXFp(((nB_hMsQBct3f1}s6n;D*4)K;8MlT^IW!ZK;+@uN%5vbH2cl{+T1Xsr%@;2ek+3;0g9YkE$ z*w?uTumm@7?0YZVrg-~yd}O3$_j~aVf0>s1&t+T?xBl@iy+nymKToU696wkZ%TV-O zf6nCl^>wlLZol6A`7`^z_rX2g3?){wyYA}EdoJiIC~voK`PF-ho_A751b)z47+VEOGtqIty6WcEmt5t{7v*Gm7BUrojO(LT=?cOt4Y04y8`_GsJlM-{pVuswce;{k|aALj$^Gi zYPzV&Z-Q^P+gn>#DwRyW5ujKse$Hr2=2q3+0M0o&oelsZvIbNxm-jR9JP#4U7_%08 z8K^3)R%_W&M5tD)yJbB0&#nN!P$=-@;3v+x4E@#dj4^bdpNQia;CjKpzwj@y){>^_ zUK30v$A}2`4}X1GT~fE(B}o#3AV5_K!;sNv#9%OBI2_XN_v!U|G@DJ{USG01h@y!2 z{hjf6OsP~N3_}3YG+j~$u+}o@hs4P&3m_s)qKF`9GM!EVn9t{kF*s+LTZ>4Jd@je) zadoo_)>;lLzy2|d;+$fwMMReJE|$Cmn9XK*p10L;3l&5JRmC}%0eHNA@P?#{r#7~tvR7-DgH>15x$Lk0q^`xiJYQ8;~4ElcHFfw{^N-dp!3h^jm2+;Geh z_&M{X(gTgRi$Z6%zLh**U1z-Qp=-CMr~fm{!;^oC=m$ zWxMghYF@68lb?Gozx=ZNTxz7-^->0(d5+IzTm%1b>2)>jTGuQ;>&0GvPKN8Rr>|vUM5mRlnNxtZet+01@UlW!AHnN#<_J z^_DrF`1kH78~N`Ga-+ZfwmtrM;;K~vp&?UMJS}ASB$5xknRD3ETwsNk(xIApMsxiR zD>G)yVw*b8$Mx5p-aBP9<&+m^GH8yM#dp00i_>zopr0C4;6C;$Ke literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/edit/clear.png b/hiro/resource/icon/edit/clear.png new file mode 100644 index 0000000000000000000000000000000000000000..e6c8e8b9f341cbf3a1795631ccaafd14b0e0c911 GIT binary patch literal 773 zcmV+g1N!`lP)5 zl1pfmXB38?@0*$EOcI;hNJ5iHyw#`_D<+Ey(t?XhOLl^ng^SURf+GA21zi{y1{{!5 z5QL7#g;8=>?7hOBWP~@Qv%4i?;^z?o7$2sh!G| zts6JQ<4rGsx`hNvL;&d8r%uFIa{QCF&sB3vJ3Xhnz3G3(a_m%-#>gcR&Ll0E*wJ36qI~C2ft2!

!GOpKDtrJ2lSaNQ|Hgjn@93PsJ(gZ`2+IBy96 z0wag|dVeYUtj2Xcip4zE2Iz1NmGK?q-I(0Ec_nX5@MXf0%df=eg{JcD1;K)00000NkvXXu0mjf Dmc(vD literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/edit/copy.png b/hiro/resource/icon/edit/copy.png new file mode 100644 index 0000000000000000000000000000000000000000..8dd48c494924874a088590a749193994d075c22f GIT binary patch literal 498 zcmVl*+}S4tk-SEw(HMMH$UOFgT8OyWIuox(>z|!eNT?Q)#FJN+p=4fyzsz3(&M5 z1Oj8QEH>2c<<$iq9`D@|1fH*+ou9fEhcV03wkV2NSzd)@nNYt}lHgoRaN9}vHG1pg5Cj3DD1s1zdc6*S;N$b%7N-)ik literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/edit/cut.png b/hiro/resource/icon/edit/cut.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9eb9a7ad3e9500991938d0da531c06f90fea85 GIT binary patch literal 807 zcmV+?1K9kDP) z1Hh-$q?nqWnZ{11 z1JXGjGT#nH5JGSEt3`W-F{81UPnb`417>0bwH3tCzhB0pcmY+{X4F+L%h_RSnk|a_^$fF6B>ZO8Zd4#b& zIcbiYQS<4l$&8G?%anG5EK?xFunXWgL9J9WU-R-}CY`QnUJ$&B%*-pvkEGQ$e0RAv z4j($yFl({I2&EV>4gdf!007lmt}-!W5XkX| l!x~>C;!~(p=dGgX{tck>ItSb|!8`x}002ovPDHLkV1ju0W~TrE literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/edit/delete.png b/hiro/resource/icon/edit/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..ea03150a1c15ec650240042fb695e7be84bc3e28 GIT binary patch literal 680 zcmV;Z0$2TsP)&~9SKOY%f0nX^lS0%q#YP1;Cv`C~wifvVWH7q5i>VkBIIeP6 z?s|6)au-91QGBQO`{sE*@B4fS?A7A^!aG@(#_<=$akkoxxl9xQXmcpb()eup8Wcsb zgoa^snGM6hljX9thz?EX=KSV+MNuFK0-`7)n@QnL;d#!A@UhW?AP8tQ8h?ynYKO=6BACOv97OzXrAtf@ z2O)x1X8|H-V>nD%fY=%S{{Wx9i2r094LW{B44uo@Kw#`p>kX`0Uo?09s&V;JTzyn7 zDU*{^%-Y&}CK{d4s?`b^i%n^@T9ulJ#`L$9H{{~N1F9)O#I0o&NqHSeDc6cDqz8 zK1}bwAaOHui(g)OtONMGwY4emZr<;5I_X`d&8)9~I0*nN&z?HdsoA#LQO@rNluJuR z`2EL^Bopb;WFp4+SOttuFuo0rp8m zK~y-)osvy!6Hyq2pF7DUO`2wgN>U06wOwc$MHIn>xD*Oicj6|$z;CJaABeUjK|~aE zS$9RDeGK5zq#vnP18H_P9en3BbiKg914X(U4?fX zv=3%78D?M10+5(X0MN8+cL(3TuaZiqIeKc0ZN-aeE4XBZ)ck8EZr_Z=qW7OQ{wVDZ zG+iT=PIKtw7@rGX1_uI+90*bpKD5zs{F**C6zm9u?EJ zQ5_2JmL<2Flg761XDbP7v)0}Ku5Shi%_G^x}q%2kVgpPOH0wIvBfN{N(qOE7M? z3xuFtwW!u4n_D&9s)POg9;6U0U2p=nX__rgY-58pql(|7qW8J5Es5XbtmWcc6+03YVxryf3dbXat2*wyQorvicCWHaaM z^${Ko^E;cZ_ht1ff`3FT9+eG|{}KR{SUhS0lnsNw28{O8e>3MU00000NkvXXu0mjf D_c;L2 literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/edit/paste.png b/hiro/resource/icon/edit/paste.png new file mode 100644 index 0000000000000000000000000000000000000000..24588a3a4d2356be517b0e066a489284f0326842 GIT binary patch literal 561 zcmV-10?z%3P)FTwJtjVg%6=aCXokI21)~9mK^!mx4G5j`|NYgS(rkOVuvAI4O}*sL@D5 zUT?|aXkli7aX_q`X+NwHimYrk&*ZqAx3 z1|BMmD;{?861m(FJkJ0iqO7cZU|;Pi1_5ZQ>aE8wSu*oyiTIugE}S_S`_jqqF38ff z9j2$JFlHMdtgWq+Ohh@F{LG}k&a>C6R#a0FAm({yEE@57U(d35{}DkDP^nZxtIf?F zB9%&U@9u3bX1*b+F(4Z0|J2@sL?VHzFf(&(FdpLZI9q?fsp)w=fNCfkmfyS$y$ksq zyD7pDoj#T4A6yV|!vVTWVS55qMMcP+JpO+Z6!JMl1Q9`1u+}m$ksb}u-zd^;ZvAMD zK7okqL8@P?G#d3CA%_72HRrm3R?E_;*C`gy58D)P*aX&YQ2Sm(M0)=9`Kw%>S{}Z_ z-Z7;aG)bp3q|+I)*~3`7fvRw0;aacRHyQ$Lis9!@1|a7y6KHYMyRt(@|#< z{cBq{wZeZJJbqvRywOcgMZ;bX8R({V0eC(qv{bfm zby!V}<`4o^j$zq9DScbv%ILiw6A^$HfESPQ`SbEnPO8~uyxOOpbRU~FfUe28J$qL8 z@C5Mk;kD~GW0^Bpm31snBktM&3_1-q+s@zOgv6zhyDTl6DE{o}owMVUv2>RDuXiL` z4H7gMZdG_i0!QlYIz4!@dkqC(K-FfCk4>lJ)_b!1Rd%EVnj)wji8Jm)7Zot;7MWwG z*gs|t5o;aT9wf2Ok6$@g1dX*be!bT##gp?c3Eq+E#Mh2RWxi- zG;9IzHaQf6fo=!vH>>VST}Z(FqG7KdPT<2cMZ+#dZlbEl2Y?p^`wGFq1RKr0vRaV6 z7^XIV*yPVOq9g;1-Im=i2krW;ncR=mZuykZ)veF3J9a;RB)EwqzyeSOHl8Hi?*hE} dMW^#GgWuOnx&>a(HQoRK002ovPDHLkV1oBE0Zsq_ literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/edit/replace.png b/hiro/resource/icon/edit/replace.png new file mode 100644 index 0000000000000000000000000000000000000000..6edbef6145d36c42557ab8ddf6c4d3fe635d04ad GIT binary patch literal 776 zcmV+j1NZ!iP)e`3}G0@e>1bQwMe(jEWv?R(23xniG!fHG;ttONr|sxONv@Sq(l&ciXw5X zL=(g|648T8eY8YKiI1J7MPgf()NXfYKe}DJJFf#fX)jLx$&)T4&ykbYdjUyqZayIe%^>;0FS}?m3e!eJnU;Km-E&p)Ev2?U6I=wMZS2a~h~; zm3BU#p8#mOWwUN+vnYy! zs;Ym>1z=AAD2j6XLd&`BLWl`d6ibqve}~88X$Nxr5B&yt%^M8Py{%aQ0000kSC&LBJ zfVRcM$?V1P3B6PcAX~#mZX7Dr0E-up6>u&Ai1M4+$6px*d6g)50zul{6fOZfD5 zx^(<(+NuITAZTdtF*`7sbB~Mx0Ae$D>fg&k;5u>{h0Ft(%sL2>YF!TkK|`BOGW-0q z$<55rD9F$#2!Mm7ygZedyZydz;2gN<0Fly!zty-=mBaVpcsEVu>hcW{d1#Z{npnGY zBY*fjmK0%?8^t(;YR@+XG=oH^Fxc%lEVS$r0NiT$nf{@pT|4*Ae2zV-96O_3`)`13 k>$j#pJbyuT?P=Bf1qBx3B`dxp6aWAK07*qoM6N<$g68)pi~s-t literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/emblem/archive.png b/hiro/resource/icon/emblem/archive.png new file mode 100644 index 0000000000000000000000000000000000000000..9015426153054c0b529b4d9ebdfa06a221d568ac GIT binary patch literal 540 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 X#=1e{xaN@000000NkvXXu0mjfPHr>| literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/emblem/folder.png b/hiro/resource/icon/emblem/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..65bd0bbdcb9005cb8929f06e25d9cb15a926366a GIT binary patch literal 581 zcmV-L0=oT)P)2|yPkE-3> z-8b(3_?ov1cYiV%432IDm|3sa>)kUm%nWx2;PmwLe!t&8>~uQMm(4k6LI`Cz9Dc0p zx&Tx;XIE7wlL@7i6(oef_V#uMc)NrGOsCVTl=7;s>w_zRjH+U0Ymj!k-P+vTq}6H> zV^0g%)=c>R8-N-3GD0!|F@>GqJ z%4)bdf_Rm4wwyD#6GYg!0ieZcvQf+lK>!v2)x`$$R0x3iqPe(Z=9oKK7jS;E^w*b55oWe`mg~7=)i^mlj0C%nT8s$wuo= zb!&(s!bMVmQn@?FCx!@o{yMsKc&XWJj=)i68(aN%$9JEC^W*#Yp8+C_MZ$~UM;0NT T9Al?300000NkvXXu0mjfM@0T3 literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/emblem/font.png b/hiro/resource/icon/emblem/font.png new file mode 100644 index 0000000000000000000000000000000000000000..bdbc1a80ac4b77f1ed24ff3c6caa77a144bc9c26 GIT binary patch literal 627 zcmV-(0*w8MP)D zlg&$%Q5431Gj|$ibZCUI4}yxUiCnc1+G+-^+iB&#UEqHZZ3c#EArT?8(xOd7R1l~w za#2AgQ;{D@I%7CaNV2IHwbJze{Vh7{VkEa(3LsC%xf zXV%KpjLXrEFdch?XycO3IXeUHP0lxluJw5SKF5VK9f$}A+k3HwI4QL-0IdDOcqB zSPE?{nePsVKHqOC;{4k}t(6bITvXyc-d%VPHD_8EAd@c7LN z0VN#U-}*W8+D$+wD1(hb7ZnxQ)>0#;WVhSMx1M~WOW`<`(y-`~O?lW3>LcLKl zTI-Q&y-_m`fH8&#kDju%^KPiHOVtHdSC#>A0E7_i?tf4s(+R0|vB7qwa4%ryoayflfE%+4_t0F6nNx)`Z6qVHi=FPKTS#CU}=K zz{+W!#C9YIhrSlXiNSHls7#+^Yo;a`d;);QTNPSAe+|gJYq?(Q!^i)DrRoA3o7+RD wat;teu)4CGrROk3N|^!cjmHn~jryI>0JT`*mWx6Xs{jB107*qoM6N<$f&tz34gdfE literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/emblem/markup.png b/hiro/resource/icon/emblem/markup.png new file mode 100644 index 0000000000000000000000000000000000000000..53014ab153f17a68c5b107a7b0f1d153d956afbb GIT binary patch literal 709 zcmV;$0y_PPP)fq#HTtFrvrY!+YtrY0(hb{NEx9zYRiRMGt~$xpLen%X%K|_MvGY{57DC{1x$t_u4wM}O%d&_> zB905S5<)OAFtBSDx%SZC-~V5Ne@U)wtR<-G^IC?buUWE&McJ}(%Mwzloy&KgU43zH z>WPD(udi>%;QQuJ9==*2(55nZ<`@S%n`uxK(s_fG*cOY+vB#HgKfUfSh(@CTBvJ;i z7dALQKFn~hpLE_}HTnhF9L^m6C;rbpTZhG-+so&ddOuo%CZL}L7gPyuCr-SWPA+@0e>rs z;@+LY+r^KZ80{jHPLebm@pp7!+h79-31OM6rz{p%mhjcv&J@DoFbPekyWPipbdzAO zAIpYnF8NG~<0FFzA+T+m`1%IY-vkA-jH0-aJbp6y0$Vu~y;vcqo0$16$6mCxHvb_| zRrU8`$P(G@0*!?qcw~jm?G}=CZpsylLaNM2sYJ18(&TAG*LB3q%*>l)GI_3Q6t@m> z_T(@}dsKo40(^_b`LJSO;>IYJ$!1b0qQZ^IAv8^6*M45R`}}@;K)pFNG0NfYRshnO rEDzqTQNhJ_!Nf33ZcTKO%jNh5gZdd1q4stt00000NkvXXu0mjfZID5< literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/emblem/program.png b/hiro/resource/icon/emblem/program.png new file mode 100644 index 0000000000000000000000000000000000000000..0d49f9dfd9daf9765e8bec7971d631e0a8358062 GIT binary patch literal 609 zcmV-n0-pVeP)5+q8 zV9!bq2F92J!tX8}4cKkbMM_^Wh0ln$4JCqzMk$TezN-$02gZ2)%PZ6+Qx}f3uIn3K zuzW#8fr$Q@ZM~&*@<1J)Yc|UI>LI%Kck(`Z=FT@M%!G8P2e*B2`E6pi{X6`}Q7(OW vTBu~6m7O@IHYb1enfigrdXv{w`CsA(kYu;2BW(0u00000NkvXXu0mjfshAM) literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/emblem/script.png b/hiro/resource/icon/emblem/script.png new file mode 100644 index 0000000000000000000000000000000000000000..c923098eacfdfac51bbc6162656a5b098335f367 GIT binary patch literal 516 zcmV+f0{i`mP)#@I|S_<`|JP!0g*{W zK~y-)m6N}Y+CUJ-e}h({49)`}3JNz!$6G{-s8a9X3|k zq-mPN3xWzrF{aq#tLNQNG56d=B)csTfT{!2H@TQ%1m}PVq6NET3{>6+kRk)k41xs` z2mBEO#OCh)i{;~dmHVPtDHT&t(d>`pw~EyyiFy3_$ZofL2S6Q%0^>~oCNaHUk01!> zbUIwG*S7#tY($@O$P z;rl*O6ah4I0MGOAJdaAHV)aXfYPHH>Fkm{JVvON(xd5?u$zR0000c-+2*wv2(<2J_t+h+ zs5rlI{^p#SO2-|aiODDi-jZP}W|aE1)~BmOR3$EA(Vi@w>U%ZDa$9qM8}c0HKK>=@ z`d4d)YqwsmShMx=n<-}wTJ%-CXPi)?Z+d)E$Kx3$zTq0>%B>G-<`ESK<06 zKLv;!Rde(>`RU=L2g~Ovo%n1M@bQ?*+>S*Vvl$k=|9v$za@qmb9gNTaiaD`NnxMxo zp5*#q&TW}{<`>WDw{ULpSLj^#x@qe3m+d`GEQ*uw+Md|dvtPsTSdE!)vF)Ukp32Aj azp#b`#_#;I)BX+6mkge+elF{r5}E*#afeO- literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/emblem/video.png b/hiro/resource/icon/emblem/video.png new file mode 100644 index 0000000000000000000000000000000000000000..3e4ced5b60ba181f4ae26b11935c57444ffc33a7 GIT binary patch literal 592 zcmV-W0gJlHNNxtsVP?LWIr9x?6w7vAB@=h=0RrJHa=rxwL(NVM|!=UY`0q(4u?`Im9A{pb^nOBS}n0`N3d*14u^xRRx3%T)8e}B zU)jxOQ!LvNmH!m&MLP2~`8i}4~9FCHr5K@{qtRq-ka(iJ?ZP=uTm zA)-=KTXM11RS2~$6nm&uv{cQSuKf$?CbP4jht?XK7~kVJ-#qia^UW|KLbc-EY953z z>WRV7dqi_}NvUZfgl}C)!*&F0M_|b+V97E80CykVr~%gk05Haon|Y41T|%KagO77# zXg_$ht|?xxSRKlv`0H+L2mld?91sx{?rsQB5|>q-9K_b`yI?say^?H5vawt?QN0%L zQr8VKjyDQ9NJT;|(TgXq`xKW7BF8I9f|vxjL{S!?dO5hlaQ@UaF9;B#f^;@jnqQnt zF(N{uTTQn`k0*~rlb-kaSCCvlqKp-L5!3TI5NItHN89$(7@Zg?Pfm^Zz3vh1d@XXv z%dw2{#h9WC`nbQFn~GCVFR$PcMeY21IKx0j@A8ZjM9Y6Ue=LTlryr z>(@2W+wdKbgN~t*f$yfVK)ah_*yWGG{JKoJQ9bX-)!YpMx+aPwk<4VDSzECWL8lc@ z`=3~j{FA#{Y~yeIt$3GuF4Da7HUP}#KVRBt{l5SJIDAFD4*_fWZPlDqB9?#%D^>oA$FjP8SXdVl!5?|TnYO4RbBH?=GA zTUy2|reO<?=@r%h} zW6#cJQfPC~s>mwxzQ}>D!BbZalds_8_h}r7_JCAa@f4F))r6lUrCf(hQ;9=;jU5L& z+1FnmP_XjQREAhnABYqX00}@!0U-tMq%XJx@e~^h8rvWApSa|&uWz9Di?6_?1E%N@ zl4EB68Hfl3f`qGnd$iXb;n;2VsHt)P`R?O`My|Agci-NCF&}hI2Ui3vQGjU{P_$N1 zwo6b*g`Wk{x;wF^0p~U>`wvX#H%c-OZ~=##s0b5Wa!4-09SO%4;Ep?Tu9$V#I5TQr z&Mtkq{`h6ugzb~9dlQg)8A30C1pt3Qg&t7B3bbY+H`>YWThbX9oF#2!=nK7F-=6arTX3U&+XWy2~<%(BYwFX|c pI#R>7P%^)q3wROKeC1m2{15 zl1oTbVI0MO-{a21M#B_R#9l-oXcPp6(?)2~B7y{4Mu9@O$#RS~LMu0okc%jC6BNCq zMPfd15iMrWDWnuP(IPA}ow0!)<9P4f`?UyPGZWN-v-$pq!}*{8hcSkHhP!mEu~WAd zo8?nd1jeIrclCk3aF;a@j#!~$nl%(P0Jzf98$5aR>}dqE;fU4n-v&x*nhu}wwKrd{ z4f;b9;fU2%OeY#6`YVQ=TOJkJo9%;vsn26nmF>ePxAA!V*2;(ZnPFo%AB#FaHw-$p z>A83xDHKX5gpddX0EtgSc(|1Lcd)Cxp7`{*Gd4M}fH9|HQD+7~1Grv}*vDrmsZm0K z5C{Q60m5V1o+G_9&%wGQR!!BO+NWc8C&Ce{BNlb~H9*c=C7oHocC*-S7Ns<$C1sQZ zLijB|M!48sj(1C=)P(9pYjao0(5pv%$FEw)G{Dl2Io>Bnm(2P=eF~WywGEfv2*dEE+1BNH1p0gO_(!va6Ym6#!ZeU0XL$ zmOyFA$XqYlC#eqYr*8WRCf~&E#M}5+`DMhod1o}n6nu_w#4?v#yZPlMNv2Zf#pvLQ?bsc$8%}?|wxEMGI60fdRAO~{ zc52bv6uF?Yza^+BugrY=o*FhT7dA)!rvyS0Urwj)#iE6g^YI%&-U+mBcICDJ0000< KMNUMnLSTZVNH5j^ literal 0 HcmV?d00001 diff --git a/target-higan/resource/up.png b/hiro/resource/icon/go/up.png similarity index 100% rename from target-higan/resource/up.png rename to hiro/resource/icon/go/up.png diff --git a/hiro/resource/icon/media/back.png b/hiro/resource/icon/media/back.png new file mode 100644 index 0000000000000000000000000000000000000000..94381f54fddd07a54b483ff931818cec51d969e7 GIT binary patch literal 770 zcmV+d1O5DoP)eL!nq}o8h%B@qaZ#2x}_K3;az zX7&jHfv)S{wj)2Ca9F$rB07@x#?P=&KDkv;#ZEY(Eg+fGTC2VFJ zob$^a7ca4b!a^dm5|mPCst!#!0)JA!mK1bf>8=TfBAPerBArTsQihh}Eu_A_!S-go zC5+h&MFkc#!8w9C9{^yQCZ?vRq^|48xG8wP55^c=&xPl^$haAJo(skp7^NsK;!vW3 z!!UFJfMMu(_~8DxmxBYpEt4T8)3`Pe2Xg@!r4T|ul=nS5;?K442X#fBr#9xMyg+gnzzxk5f!nB%9@&Et;07*qoM6N<$f`N5b A5&!@I literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/media/eject.png b/hiro/resource/icon/media/eject.png new file mode 100644 index 0000000000000000000000000000000000000000..2084067e94e6473ff10bed0de7d1f8e20100a6af GIT binary patch literal 628 zcmV-)0*n2LP)5 zQ%z_SVGw<@o0xWKEJ5g+-EI@Jr}+p~AqQ-L78e)Z-c5ha<~tOGN1%>zIHJSR>a ze=;`qV(H!cx66a!lj8t<<#B58jT~&)x4-vDAQkHXH!1f(GcW1J5(U;H1?*W)@ z>HvVG>w0f29?j6gz4-l}1q%(eL+fIz1Hrko=S^ z<_mdF%}nv{=}BH#%<{zdiPD)^_(w1p-0JmuZFM8~e7=p{9_7k`P-u&;>q2HO4I%;& zA(vl-swfm5h{(*3ZchH3x(eVIDocq(BAvxz@sRB9x_{^P-8NAW8=jV#abx&;;oFz5 z*Bp-ahlxZYV*>zHRXb+>qy}cw>2;SbU$m%dH(1r1re$wycf?es`x$^00guPCv)k#{vLS6$c^!j64`^iG224w5TYG zSnZ%B2*PqKK16F%{}s!!Tms5h0MH4b3o9{hNdQ0^z${gLXZlY827td5xAz{|3C=bE O0000GuIyyx^)1uEF(>uq-m38vxzu_ zN{@N7>bu}Bz+^ZaVLVD&{Xp7iP_I|1ZT?{6&o{EH#`v*Y1VK3PwB8K_I7hXz$gkyB z)M|AajSLqIvv+u$gN2BF`$yXku^fO2NmMGEWSk=!+GgYcB#{xvB8edh){s2j=K&-Z zz8nQT0=F}}PQ6`*QO9GG@uGB!m#?RAPN+W#b$kMEj$$##15*oPz9VpLtp*?< z)YopkJ}@B@rkyAEgB)Pii!tcwjn(xHk~p9chpmzH#-1dikc6!L-o)F#CJN+@&~0=3 z^5H!1x^?ea6)7hLGh@p_&fd7cE5JX!iRHwoEpMEdnBZgieePdqUDQ!57V#!%|6C`D t)90rjAnpi;*tHAV9B2Y}7fSO_{sK<1@6Q&T)r9~6002ovPDHLkV1o3V0ZIS> literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/media/floppy.png b/hiro/resource/icon/media/floppy.png new file mode 100644 index 0000000000000000000000000000000000000000..f1d7a1985923fbe1f4717bd66985cceddd7f36e4 GIT binary patch literal 561 zcmV-10?z%3P)5 zlfR1-K@`V7GrPHjTF9HM`NVrQkDDElJ zh*(^!7J*!0<8G7eGMko`R|gs-Q{;YB;P_L1kWtz|QptJbUx`b_^gI`2FHBL4;MM*X{!l14cwR z_2@Z-zp4MN%F8SOFM*S{?yhVGkayn~0~8TqI2^8IPLgDaz=$YO6pI7cr1adIE z!Cnt0mkIxCb2uup1VxKFQ zFHx`8snu$;Ypta$OY%HtclSN{+6LaY0I-KRs*1G{?RJ}fzfZ5%quFdCB8Z476IU8FiYblx2x?4(A+YSrS4Zs8Cf4L!4Be*iJVj%d%NOmSsz3 z=Nti0RVweN0oIr=dq01j-|Vb6##tauQ#zdv-h0wCT{1i8Ai#-ZYcm3K@y^S2WB63J ze)C-Xt!_+AATT`#yRon%hQOY`kc+7sk?`XW{qqkxXGvR800000NkvXXu0mjf#Dw-o literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/media/next.png b/hiro/resource/icon/media/next.png new file mode 100644 index 0000000000000000000000000000000000000000..758ec6f1b14f2dbcc92cdb13de57c59ce92175e6 GIT binary patch literal 771 zcmV+e1N{7nP)=MI^)2*h*-#hC`$v=FNQAc%05uTADme$0$B-ud#L7LFp;GJ4>J!^3$Gzw`0}|9~0* z%06cRF#qEJfB>+nX9qwUKoLM~^$`gmUoB_P-CZ=d+e9Q1>0Ve^98RTDX+=?1TrO83 z9B%JkT>Lze&161-z;GOALrRHLr%x{JG$#_10Yz{NhRH4lL(Pe3G;+@C^>SU;1I(c3 zTY^U?LT$k=kH=eYS%F%?w*x$T`Wyhj{Q?TN1XNX3U%hL;!Lqr^zV&tSppjO`=L_}ilXAdK+Lngw&w1>eyu;B%Tp;O`uh57 zve~S+x3}lUp~LlO6%YV`X`0}E4$Tq*g|ZC*$mepP1|<(;k37@UQ@c)cspL-o-2<6y zx~8-9@@@iQ320mhtgI$M2(X@61!D#vCG3I?LV&f*Dj21Zjzlt*l#DR|0Amb-b10m1 z7;XcKq9Py;LU&Qb<4^3F*=f1s4Ccnj%n}GA1U* zieJBf+4TA9x=ho3zg#J^kMr;Cw{x?_>_+}^u%&fic5Z5Edj(Q&mQ(6CH^0tm@$Ia?e6Zr$$L-UA^(Y}>A`C)os$GYqy>EEaqK zC;&%-q#30p0I+S_+8N?5QcACslI(L-N=flQ_zm52>_i|8P1XPa002ovPDHLkV1goq BQIP-u literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/media/optical.png b/hiro/resource/icon/media/optical.png new file mode 100644 index 0000000000000000000000000000000000000000..760de9386f7ccfd2ecaa2680aaa70cd3988e16af GIT binary patch literal 931 zcmV;U16=%xP)f8Te``8a3JK<82zC}l1Ui;A@iO=+SV+Qe-&n%0z3b<-GxwJZMs zjaw+V(}>ulx@_2}MWNWaKqR&-Uc%M{weXh6gVL z9|C4u)YEKu$l7Qz=Cd1n9bsZQDpGfhiuaqv73Aq2kf3qVLY1+Vt8ZO*9GHhlhtgu%-jk+uPg8bUNJ%(4J~%cW;NDo*wb}XJ43rxv{aq&kuhjmpzB; zxYr%ELTU5m3q9v!u~jWHP3d631}}f`Bj#0kABKOeVwJ+#~0gU#Dm8 zj*j01H0`+4#X{-ZXmcbxJ3Et0rP`HgnzE&(10WbcEP)fkXfR0bNN% zK~y-)&5}!Q6hRDzzbd<#?kMWj*ortnatw&zNJwy`D9RZCg*!wL5UgjGNHA&oVHW+! z028qUFG{7aT)%!l;9p1DyPy6&J1w6g;v*0`zpdA6&YwMbzc2ds_4Qc{Lq320^k$!5 zzj=4I*=`dMd4^_&s>bET6_*!RsOsQmtPgN=Ura3y+#M02?|VLd`GAOE?sQ$Z@Y~Nf zBRBg~z|0U4c6Z+?v_MoabGo)gM7V2qh$y0hKP1q!JDR3JR1gu|*FYL}%{SWi2j!|- zoXv6H10NkUZ9^gMh7Gi5vrqV;>BD-9GXJBeDwkV$vM~cQN1dU zzy8jT>#CjwmhIYXH>X4*rDN*a%Jzqz;k7x5ETI&B|H7dZO>0000H0h#)QuLQNI1SZtsXO8U^GGfgrxxh}+}VkxnAb?)YabMHAocX%9NxLrB| zzyY8MfO-Y6yO;d<*y~_0mS+_>8utCg%c)OS>fRtAV|%-`d2TEL zlD|(=Q546&=ia{dwdoJ~#Pku{MHeYy0I>;}NE{r&iB$*x0u8%^ZY(Y`J1cV&;?#7g zO>7B6jVzV`ttCKhO5S_Cw)Y)})|z55CVZ2#+??~tJ>T;sX2x|St~Cw7H}0`O6x4vn z5?D|`5$VDo_YAze$83)U zl!zY1W@odh^>w}Hy682V@LU%%7=+(6;gm|My1DsfzS~{IU~mX15=8^C*!Q~|8#kPT z1E_WzVD6Xa0ZJj5PUAeE@7A}rUd%JU8!=G=Pj0QQM!Tn{=+*0hWdV)@*fwBUV9SDC zE+f9YtZC8ctG`SXzym#*)Gl^+p&AX4-w$aRAfn+9yj~BzRttJ6WfX{vMds$8D-hk0 zN}*FOgB=G#2(Xk8kq9Uf0RjQA>q6CP@W)~*(7#S|xPoFXbWToKo1BCof)E0N2xM76 zqXDm4g?DrWL4=E1P3pk65f2E+xA*os`pgW72sD65Df=)XpqVB}*I_prl{9l_1hByT z>8x1%%tRc@WFVvj1|SeY7zRR1OQ>hF9k}lEt8y@e zqrSb}Ij>Y+&nflh$|RPELL|gnJ&|}8N~JtsI808hCY-~=AFgdbz0aKcXOw^IBayrf nq!~zfz)ptwY+T=!fdADm63+C+aTjYY00000NkvXXu0mjfh3**Q literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/media/rewind.png b/hiro/resource/icon/media/rewind.png new file mode 100644 index 0000000000000000000000000000000000000000..ffcac31132487e90bb4d74c858e0706099250e77 GIT binary patch literal 764 zcmVPA*Jh9cyFkzj@8Rl|wrzVTrBXP&dB3J>#|R-SugBk% zQvirYqqMm>>a}er>^IE=b=zwDw%6CU-;edVC0UXvrQV8)@*NEg^|8w8s-wMk@3{m) z5DdQwv9+buH##=DA+RwJitcPWQ{c-l?dm%3^LRXjXE~V4#HQxP8%)z`E?>IBeEIo= zXE{_=g(%1n4ZqohUDvZSiO<|ww2@9*NaZ+FRT!oTYMSOu zxT31XveKPBcW%Fb*#BVO?P4e~1E5rZtVq1Kx94ql_f1=tlvVC#ZWx9EAr_1ASS)6D zcAgzBG1uK1dpRn-8Xv0^C6N~w8`4nxd8Vd15?NZwyc>M>v}ta3mIi}m;?U6Ga#=8R z{iid=<8cCTmQLG+FGk`QHO5-99GR_^wLuP0Yk5IQC6dQespN^NsgHcm?!BdCtrwh} zoTT79@5A)OrpNvLR}UXLvX2Av1f20K)ag$XX8*vzwYIkQgXDK5a26M30`3KnQ507S u0BqY40B8VL|GG__b7c)iIOqC5SM@u(HR(kN;XjH10000tKSAuPT^ z91PmH7$pWpLv&PdkVkw#OnB5_ppT>Ude`f5Eq@mvQDHNFr(Ztb;M~g+f8*d7hIb$#Dq+*VcBb zw^%G@0cr|@P_pff(qDp5ZOE$zm4}Mr@Amum+q#}xWEiGgmSs|16C6|&e|JTt&utp{ z6;)M>RaI4vrfEAOwlN&`dOYrn&z}v8lQUDzWwLzM!_1}7M_~3zeEbF?!DXNOJmH;6@CaXadC4f>SlB?9~^==XZW-Y5h6a>&s zibOI&-IB2;7=}eqt$|@0h{cAiL^8GH68J;g+_Lf*d;3P8{W`m9 zn)$np4NWluvd*chibU!soT7u#(Gh!LX+H1sRbDyXTK{t9^VEV-tlmdp;PeDuql&y}fd_3LJak)NNw**46p-^b^ z&mj@ZvI1LY9)KZ9VhI3jyWj)BQ;>C05H|LF21==yQc8B=0{%yS0XCc#NPdKXNB{r; M07*qoM6N<$f~CAw@c;k- literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/media/stop.png b/hiro/resource/icon/media/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..ede2815e59858d0b95c02dddc1e0036a23308077 GIT binary patch literal 429 zcmV;e0aE^nP)k2V8nL~zb!m)|pEA$SF2->jn-2hWj=^AH zPL5B%P2Stz^{Pr7#{fi4VAUxi)#JB!S3FMcd3k;2Es0696z@F%)>@ou3v24+*vND076Ixy33;9q2pAv`@ZPsg6f3A(Qi1k* zFkavM@*Aa-5I$9)h)6g*I{0=DB#I*EIzT(hNs`o~9IE3`*}+soD!;iA7_JPj`4{UQ XDQtDP+C_)X00000NkvXXu0mjf5}&Iv literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/place/bookmarks.png b/hiro/resource/icon/place/bookmarks.png new file mode 100644 index 0000000000000000000000000000000000000000..f3b5d9d98cb0ba5a7dfdcc80a0762896f8426b88 GIT binary patch literal 753 zcmVMh53JODVWnpw>WFU8GbZ8({Xk{Qr zNlj3Y*^6%g00KQpL_t(I%axN&Pg6k@hM$?w0X#5SDVBDAx z;=+Z0!K4caEKK|#ggud;VB*4r4GIP@RT1# zz*KQz4w&KJV}9|~^eljwDlW{8NImo7`9nNk zsqExS3z&KQ=s_5UMs|Y^*;I^;@;;5q0Yl|IRI5#>B6y=2TA392kvMfAm7S!vxAfWq za2!V(;NZ|B8grrEBweadyE00Uh++9{Ql$!A6@igBF(>GIu>f3G0fv^}JCI*0)W@g|hZ5PJ#MD5NXz;b-6&lG{J2 zU(WaVBnB;7%3n>6hHch>)Nq*l& zHCl9SMfK*yxf9h>U_dF0bUK0G(d38YB%=;oAM5K%4QTue;5AyjS$>Np4Wa2Rtqnp7 zY!yKWfdIPQkgw%xm~S4*&+F>|Pc48Ct6SW^5$})fc_F2wDbj502XcG-7I%-uSOAA! zgNfV_g~FvXiQ-fN*EV;~t-<{J&FYM9HN%~1AYE6XJ9@zIAB66POy0?urIo5U-8VT^ jT$ugO@66(>X#wyXbGzHwYQAj$00000NkvXXu0mjf74}1O literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/place/desktop.png b/hiro/resource/icon/place/desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..4c9787cc480eff555bcece6acfd9d97893670521 GIT binary patch literal 722 zcmV;@0xkWCP)-{{H`QVRLTI_C4R{IiK_0bIhV;#Z*_7Gw^)~ zfcExwUO%hjZ)?Zyv%GoN13>qOPMYsOz%0yLSMSAQMajm8ck5%%I~oN*RIy>m_OjYT z#+a&PpQ_$7i%|;rE<6ek@V=i$H<0%A;&6 zDW&0ND+6D90Y)1Dqe2*`a$hlD`npnX_x%y9jo7($F*WDUF+F>J;>`PnLl~!G@0yfC z6~WpFV?1K9G{&W;vupbj`aV2Ocw#fN=gj@w)0uOid=timztKfd6;wf0u+AdRAx_Ag zFwDzWy@;zD>+ef3n!ySaSjo|+0k9Z;ly$6#(Q>@meKt9W9l4qb;p^vpnx;AcUZk* z7JfJkD3P^{#Y0QmAe*<8aN*MJLNQX=FBuF+_0RIAnJqhRkn z#+dxz;NWwbra3_3z1I)|olb{5&&LpB43$cy3cMRZ0eZb&lIQuWG)>np0X!iDVvG}z za=BbA6bclJMXa?LV`#NnwA<~)@dzP=7(&j*N5^S)Q3(V9r4RJSUR49Etg*1NX07>| zc<NoK67f`+S&qLCK?1nobZA&RhV<6IEsRC?Wz| zKU(A9?Y+ZE35V^BzV+#8AA!vzPL&$(cW0l1vj3}nh3Z$E2yGGb;xF#2Hvb@(uulL0 N002ovPDHLkV1g4YGGqV% literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/place/server.png b/hiro/resource/icon/place/server.png new file mode 100644 index 0000000000000000000000000000000000000000..068ffebee274d5b48b36a68670e191a7ed4cbf06 GIT binary patch literal 642 zcmV-|0)737P)WFU8GbZ8({Xk{QrNlj1+3MgYKATls8GayP~Yjt8ECu(VJ zZDC_4AX9W@X>Mh5Co}I@0005SNkl)(8U!C>$i_{ANvESF31eP4Xv7tiy=bzN~?SBx=YjFItpELv*;zFx7l)^a|d zugLcVPN$RX_xn%;>rzB1#b`A8$N{ZZD~hf6kEhd#a=HAFJe^K4#{3h|T7Ln)hZo6Y z5@QS^f`||V0V0C$`+o_RMGyp`?Vnb++XbN4>j7{)9+}VQ0EkGGDU3rQfKI0~vqEBs zMxzmZ3M)`bAtD%Kh{xk7r2y#n`%l(jFn9%Cwbo);7Q^9?)oMjPpQltRvE6R*eLt!| zM95~d;XZtey>F7^I24OTX0sVeDdO=sg+d`ZmlkfOAR-hB1tyaT?RFd6wsBpT#bOav zVB0o_!{PB5>-9R-YBlP7E|~=c< zHk%EJM1u8tO)M6RHa6V5D+`CiflMX?K&4V4l}gcUHc6#Y)M_=->GVyaOM&N?mzN*> cKb`^p0DMpp{`zwTlK=n!07*qoM6N<$f&;Gw9smFU literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/place/share.png b/hiro/resource/icon/place/share.png new file mode 100644 index 0000000000000000000000000000000000000000..5234eab449c95983aee2239151f159dffbd9a1e9 GIT binary patch literal 697 zcmV;q0!ICbP)`( z(kX%tL7hdsb&wD`Ro5;BCFCCa8I zb1tr|tjteNPDX$%gkY*lwOS>{*oHXg=?;+##w7GZ4hG5JCzefEiANj{g8O8hJ>>WcX%^O@L}MgGLdNR>>NT zXhup#G9zeH17u!k6xs%uYD6TX`YWgMqd~6eza?Z|sIKKrfU2gVD8M|QD(if&=j{n- zV}08=vd(Tm@J{%))+#|nQj8J7Xyk#;j%E**Up`>Hve)%=D zwaXV77#KiW3t?s~E-rC%;toB%`|)11r?cag3=R$+PAOdi4sHdQ*%>oCxz*;J`zRvQ f*8E-Sy?^uvyGK{t-)XRw00000NkvXXu0mjfoG~vv literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/prompt/error.png b/hiro/resource/icon/prompt/error.png new file mode 100644 index 0000000000000000000000000000000000000000..3bbbb4a0d3dc2f6bfb653bd25e80169e96c6c833 GIT binary patch literal 653 zcmV;80&@L{P)&6kU&^O z2QZQrnrLJAuq31{O{kZd49Zz&wx!#=YkfunsI` zVC#CnxgmZ#911N=CX)oiVSEDvs4AVaGtSFpiiHBzW;2_C#oquqcsHF)z8smE;c|N$ z=kydD2USH3SVMR5Pfb$Y-Q`oUxSD}i0KTsCbTaw+UMxm?a}#YeKm=7mML`5$&hffQ81ak$9mc{~;YnD+zeVE8^iK72$)87qJ1PqlB~L8>(Z z4<7-f{lK`@KZuGO*xyP-QSD%Q0s!L{aFzDI0Py-$1pq%#>eSCB6oab6myr>-LBzdL zH#|30MBN~@*#an8!20>g3C13}BL5=pI*KP&!5SQ-U8@1CTfox(-X4K?+$GC(kvBT+ zPD4;*@JAw)4i5pAtPE_`TCHrQkf&$rsSCO0ig&9h7(-7qM&sasdb^#?z?KhS8CITG zDzmoF7ad3>a2gHdqJ8xf6)<*)-uMKKa+$*M@oEO%+`3G5U*E!$(NO}njp^-0MR1x; nI`ukVkB+*|i??p$|E%**!bfHvxmb3000000NkvXXu0mjfWCIe6 literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/prompt/information.png b/hiro/resource/icon/prompt/information.png new file mode 100644 index 0000000000000000000000000000000000000000..8851b99ba1060109ab8387fd9254870480e9284c GIT binary patch literal 863 zcmV-l1EBngP)Mh53JODVWnpw>WFU8GbZ8({Xk{Qr zNlj3Y*^6%g00OH?L_t(I%axK#NK|nY#=rmEJLA1N*GDEB)OrZasDZh+oSvYeh-b)!X&wkCqi5%=xUSx|_F{6#zu1AgWFc?@DNvi{=o` zb31h=C3AB8Z6^Sj!X$=0S8gvrAf%45EJH13#vp`HP#BtSD3rqJ8l3DdD$D`Ha;MgE zVZf?F;{_`ZSZ+ivaM`C+Z(3 zy#C(dnS~`$HdpLVs~B>P!OCIcuN!O=LdQG1`sJDF`RueL>!EAy12@kc&bs9OG9O}C zlIXN&Rr?p0a@>O>s=)e6!>h0VgJY)~t7IxXFDosw6duS%G|xfRb@-M=47tYf&NZUN zanj`{?Kd7o1OPy7T|;7sZgB-3|fr;X0czA^&R5dAdz!r1Ht08mwZ p@_LOR#2;B$Sa_Y67yBrZ={HtPHeP&+9RvUX002ovPDHLkV1i2wZan}1 literal 0 HcmV?d00001 diff --git a/hiro/resource/icon/prompt/question.png b/hiro/resource/icon/prompt/question.png new file mode 100644 index 0000000000000000000000000000000000000000..f25fc3fbf106af60de59581bf2e6fba58d489bf8 GIT binary patch literal 932 zcmV;V16%xwP)n<^0M7t*KyZHC1w??>xEt=fabLR*P`s^00F8@s%vX0ly3W2Q;1iYQ`2d{1 zn56SU!aH>A*UV&krU`gE?uNYufcfLL`>KjUEiXOnoQe)`qCG}W|1bb+O7eK1#?QvJ zs|dgU_0&(D106tZ+zosBJd?&v>qnWFmUKydqeslSKE)YIWlRZ)Gjda>n*%4R*)(?6s}$J0tF zrB0rXshXW1sfM?{P>GRo72Li*T~yy3kh%V?FTe2QhE1d6Y3FzU6LKF3;uj?|T^;O;NgH2_-9*%2UxlCj?MeRpHZ4w8sFjOr1-Y$4FjHVOs`O z6+Qs2{*%TqbaEVv&fkX!tu7E!h&mkz2FsQcy_m!>B&KO#Sq7GA5DFBqd&fqUQXD+m zfn!?;p^>;U$?D=fJf(uyMMMYXO4>Md`aVN{(Y9gut;(G&D3o z09{?N%Y*_27>1l9_a8%EHtR(M(E9O_Gnox*SF!%CmFQBU zOF`};huu%zOT%N;EOv}x2@;w%)hg>aX0MU5~e$Dv-j=Valc(v;nT_sm!fGJ@x&;<^^bV( zeDYmpd~&)e>v=ba>Hp#^rKnR%1p%a#U9+>J2V5SdEtMnl9PhCxc2Fa&}~V}o=Tx)35=bmuS|@d;cT zbY;Loz(q+`1+A}82tI&NTm%Y*7F^UoNilyn))L6H_Q1W1%i%j`bA(=?F!-5EVN!MFB_9*XAp~_l%n771CUH65fQk#;c9J-59jBDOQ<*CorDm33|CLV znm<0~VYP}<3Z)daS`C19yN!q-BK$Z#V4_~XOaDE<2tY)*Zne1F+TuNYlS3Fj19`yz=_l|J pl>P}02k>Sh;xD3f4Z|KZe*u@?eFz-1;S&G=002ovPDHLkV1mMw_G175 literal 0 HcmV?d00001 diff --git a/hiro/resource/resource.bml b/hiro/resource/resource.bml new file mode 100644 index 00000000..3c3effbd --- /dev/null +++ b/hiro/resource/resource.bml @@ -0,0 +1,92 @@ +namespace name=Icon + namespace name=Action + binary name=Add file=icon/action/add.png + binary name=Attach file=icon/action/attach.png + binary name=Bookmark file=icon/action/bookmark.png + binary name=FullScreen file=icon/action/full-screen.png + binary name=Mute file=icon/action/mute.png + binary name=New file=icon/action/new.png + binary name=Open file=icon/action/open.png + binary name=Properties file=icon/action/properties.png + binary name=Quit file=icon/action/quit.png + binary name=Refresh file=icon/action/refresh.png + binary name=Remove file=icon/action/remove.png + binary name=Save file=icon/action/save.png + binary name=Search file=icon/action/search.png + binary name=Settings file=icon/action/settings.png + binary name=Stop file=icon/action/stop.png + namespace name=Application + binary name=Browser file=icon/application/browser.png + binary name=Calculator file=icon/application/calculator.png + binary name=Calendar file=icon/application/calendar.png + binary name=Chat file=icon/application/chat.png + binary name=FileManager file=icon/application/file-manager.png + binary name=Mail file=icon/application/mail.png + binary name=Monitor file=icon/application/monitor.png + binary name=Terminal file=icon/application/terminal.png + binary name=TextEditor file=icon/application/text-editor.png + namespace name=Device + binary name=Clock file=icon/device/clock.png + binary name=Display file=icon/device/display.png + binary name=Joypad file=icon/device/joypad.png + binary name=Keyboard file=icon/device/keyboard.png + binary name=Microphone file=icon/device/microphone.png + binary name=Mouse file=icon/device/mouse.png + binary name=Network file=icon/device/network.png + binary name=Optical file=icon/device/optical.png + binary name=Printer file=icon/device/printer.png + binary name=Speaker file=icon/device/speaker.png + binary name=Storage file=icon/device/storage.png + namespace name=Edit + binary name=Clear file=icon/edit/clear.png + binary name=Copy file=icon/edit/copy.png + binary name=Cut file=icon/edit/cut.png + binary name=Delete file=icon/edit/delete.png + binary name=Find file=icon/edit/find.png + binary name=Paste file=icon/edit/paste.png + binary name=Redo file=icon/edit/redo.png + binary name=Replace file=icon/edit/replace.png + binary name=Undo file=icon/edit/undo.png + namespace name=Emblem + binary name=Archive file=icon/emblem/archive.png + binary name=Audio file=icon/emblem/audio.png + binary name=Binary file=icon/emblem/binary.png + binary name=File file=icon/emblem/file.png + binary name=Folder file=icon/emblem/folder.png + binary name=Font file=icon/emblem/font.png + binary name=Image file=icon/emblem/image.png + binary name=Markup file=icon/emblem/markup.png + binary name=Program file=icon/emblem/program.png + binary name=Script file=icon/emblem/script.png + binary name=Text file=icon/emblem/text.png + binary name=Video file=icon/emblem/video.png + namespace name=Go + binary name=Down file=icon/go/down.png + binary name=Home file=icon/go/home.png + binary name=Left file=icon/go/left.png + binary name=Right file=icon/go/right.png + binary name=Up file=icon/go/up.png + namespace name=Media + binary name=Back file=icon/media/back.png + binary name=Eject file=icon/media/eject.png + binary name=Flash file=icon/media/flash.png + binary name=Floppy file=icon/media/floppy.png + binary name=Next file=icon/media/next.png + binary name=Optical file=icon/media/optical.png + binary name=Pause file=icon/media/pause.png + binary name=Play file=icon/media/play.png + binary name=Record file=icon/media/record.png + binary name=Rewind file=icon/media/rewind.png + binary name=Skip file=icon/media/skip.png + binary name=Stop file=icon/media/stop.png + namespace name=Place + binary name=Bookmarks file=icon/place/bookmarks.png + binary name=Desktop file=icon/place/desktop.png + binary name=Home file=icon/place/home.png + binary name=Server file=icon/place/server.png + binary name=Share file=icon/place/share.png + namespace name=Prompt + binary name=Error file=icon/prompt/error.png + binary name=Information file=icon/prompt/information.png + binary name=Question file=icon/prompt/question.png + binary name=Warning file=icon/prompt/warning.png diff --git a/hiro/resource/resource.cpp b/hiro/resource/resource.cpp new file mode 100644 index 00000000..19096fbd --- /dev/null +++ b/hiro/resource/resource.cpp @@ -0,0 +1,1891 @@ +namespace Icon { +namespace Action { +const nall::vector Add = { //size: 323 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,214,1,11,16,0,17,148,68,120,161,0,0,0,208,73, + 68,65,84,56,203,205,145,189,14,193,96,20,134,31,210,197,96,183,114,7,210,186,129,198,96,54,91,59,116,113,7,68, + 210,196,100,23,177,90,13,38,131,132,27,232,103,55,90,44,86,105,226,167,223,49,16,138,250,139,4,239,118,242,157,188, + 249,158,231,192,175,147,184,247,96,57,61,31,48,143,163,242,187,21,43,110,47,249,160,220,244,92,27,207,181,137,20,189, + 85,240,82,62,46,48,238,48,199,57,145,200,120,114,98,68,153,91,213,34,91,45,36,128,109,120,222,247,92,27,17,16, + 57,88,175,119,198,230,205,15,0,86,235,144,249,50,64,4,180,22,180,64,176,17,194,80,216,105,65,107,200,101,82,241, + 8,128,106,116,38,23,8,229,82,1,128,193,200,191,38,82,79,229,88,78,79,134,211,133,52,251,51,185,226,255,242,25, + 243,217,244,107,103,140,137,170,181,79,182,21,127,155,61,84,114,75,11,139,178,119,142,0,0,0,0,73,69,78,68,174, + 66,96,130, +}; +const nall::vector Attach = { //size: 649 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,27,73,68,65,84,56,141, + 133,211,223,107,146,81,24,192,241,175,250,170,140,114,25,221,76,47,212,205,233,88,233,162,112,51,2,7,131,193,198,168, + 219,32,168,151,94,120,137,186,136,8,130,160,191,160,174,130,26,196,64,144,12,162,187,230,72,27,68,174,117,185,173,232, + 231,42,236,23,25,182,145,166,108,110,234,252,213,133,89,175,154,235,92,29,158,243,240,57,207,121,120,142,170,90,173,210, + 188,36,89,84,3,19,192,49,96,4,72,1,247,128,169,128,63,184,162,204,85,53,3,146,44,118,0,51,93,166,174,209, + 189,253,253,216,29,118,54,55,54,137,197,98,44,45,62,253,94,169,84,60,1,127,48,81,207,87,183,92,15,151,157,125, + 206,209,241,177,49,86,86,87,185,21,184,77,36,242,0,147,201,132,203,237,50,1,23,149,201,127,0,73,22,207,72,178, + 248,25,56,231,243,249,152,158,14,177,252,102,121,106,107,171,48,148,254,153,62,31,141,62,198,235,245,2,156,250,39,0, + 92,241,249,134,109,192,174,78,67,39,153,76,6,224,82,192,31,92,4,110,172,175,173,97,216,177,19,96,119,59,160,99, + 208,51,8,128,86,208,214,99,21,73,22,143,2,215,0,4,65,7,208,208,52,65,177,87,105,117,186,102,192,12,132,204, + 102,179,42,145,72,160,17,132,22,64,89,129,74,39,252,6,180,186,122,108,15,160,58,45,159,5,64,87,131,219,3,245, + 155,133,191,21,84,149,21,105,212,255,1,234,39,149,114,21,181,90,13,208,3,80,42,149,0,40,150,138,219,3,249,92, + 30,128,87,175,95,50,224,222,15,48,105,179,118,243,241,211,7,0,242,185,92,11,208,208,196,66,161,6,204,205,71,57, + 113,252,36,86,139,205,104,177,88,9,71,102,0,40,20,10,219,2,235,217,108,214,160,215,235,73,38,127,100,38,111,94, + 55,246,218,29,60,138,62,36,187,145,197,209,235,36,254,45,14,16,107,247,132,217,133,165,5,38,198,143,208,211,109,55, + 106,52,26,222,189,127,75,185,82,198,181,207,205,161,161,195,204,63,153,3,184,218,174,130,11,207,95,60,27,72,165,146, + 125,86,139,149,131,7,60,8,130,64,169,88,226,107,252,11,247,35,33,210,153,116,24,184,163,4,26,126,163,36,139,6, + 106,179,62,2,12,83,155,131,52,48,11,220,5,194,1,127,176,172,4,126,1,41,32,186,81,242,76,218,213,0,0,0, + 0,73,69,78,68,174,66,96,130, +}; +const nall::vector Bookmark = { //size: 686 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,10,17,21,6,52,65,49,61,207,0,0,2,59,73, + 68,65,84,56,203,149,210,65,72,147,97,28,199,241,239,255,125,158,247,221,187,185,114,91,35,107,172,21,45,17,44,47, + 129,66,69,247,194,168,32,130,14,65,135,162,123,208,161,162,118,176,67,167,162,171,116,173,131,224,37,40,138,40,43,208, + 166,65,33,120,113,83,9,209,201,212,68,90,178,215,109,239,246,118,152,168,43,19,252,93,158,231,240,252,63,252,255,207, + 243,8,107,233,58,115,231,22,240,24,240,216,136,7,32,34,243,247,174,231,146,221,167,127,181,129,238,130,218,34,212,210, + 192,162,6,232,237,237,237,207,231,243,151,38,38,167,200,46,198,228,193,221,171,245,114,169,19,15,31,61,143,13,166,93, + 167,53,17,231,192,161,19,24,214,65,86,150,62,12,238,9,142,221,80,0,157,157,157,125,169,84,138,93,193,32,3,233, + 31,132,91,162,124,207,228,152,156,249,137,83,170,48,49,62,205,237,155,199,232,56,122,4,171,249,2,166,125,8,67,251, + 19,218,253,58,167,55,181,75,161,80,192,173,20,89,90,94,102,126,97,25,0,91,215,112,43,69,10,191,93,220,154,139, + 174,58,136,50,40,23,103,240,41,41,24,155,129,106,181,74,181,178,74,185,228,80,114,86,40,59,43,84,86,29,220,178, + 195,216,120,137,153,156,80,45,14,224,21,223,49,59,157,6,175,242,173,1,0,16,101,161,181,133,105,249,80,166,15,165, + 77,196,48,217,31,75,16,217,119,22,167,214,129,152,49,70,70,77,160,58,218,0,136,8,218,244,99,218,1,44,59,136, + 207,223,132,105,251,209,166,159,220,108,142,76,118,10,79,98,96,29,103,110,161,9,221,242,114,85,255,221,129,97,40,12, + 67,161,180,9,128,82,38,134,210,196,227,113,218,218,218,64,4,17,141,231,9,0,13,128,101,89,235,251,189,145,32,181, + 218,198,151,176,253,138,173,210,48,66,32,16,168,255,30,15,190,188,31,102,120,96,4,207,171,35,77,129,102,68,100,123, + 192,231,243,1,240,233,237,16,137,216,110,14,39,66,124,124,51,132,231,121,228,243,121,50,153,204,63,64,195,8,182,109, + 3,112,237,242,41,174,92,60,137,97,24,244,191,26,230,217,139,207,180,183,183,147,76,38,183,7,162,209,40,79,238,159, + 67,41,69,54,155,69,68,232,104,13,243,52,117,158,112,56,188,254,82,255,5,66,161,16,161,80,8,17,89,63,184,121, + 221,234,14,26,128,72,36,194,78,163,215,90,127,221,211,211,211,189,147,194,104,52,218,7,240,7,70,86,184,198,50,151, + 228,191,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector FullScreen = { //size: 650 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,214,3,16,19,13,53,226,119,223,154,0,0,0,53,116, + 69,88,116,67,111,109,109,101,110,116,0,40,99,41,32,50,48,48,52,32,74,97,107,117,98,32,83,116,101,105,110,101, + 114,10,10,67,114,101,97,116,101,100,32,119,105,116,104,32,84,104,101,32,71,73,77,80,144,217,139,111,0,0,1,214, + 73,68,65,84,56,203,157,147,59,104,147,81,20,199,127,255,155,27,53,21,105,211,37,72,241,5,113,8,8,130,32,148, + 42,118,42,20,95,80,197,201,199,224,208,193,42,213,197,65,112,112,72,249,154,224,168,96,6,193,65,80,2,237,224,179, + 86,81,116,80,113,13,45,138,37,45,22,69,106,77,83,21,77,76,251,117,248,146,216,188,28,114,224,192,133,115,207,239, + 254,207,185,231,200,137,69,111,0,253,52,103,9,156,88,212,109,214,156,88,212,181,37,212,238,254,219,21,232,39,195,189, + 0,72,6,112,233,185,248,168,34,254,46,113,28,0,83,173,201,24,253,75,6,36,144,196,211,248,126,140,81,77,13,166, + 58,121,67,192,207,133,235,111,188,151,101,80,209,79,57,47,104,89,107,177,62,213,7,72,48,230,244,178,177,61,64,184, + 163,149,123,175,103,144,60,25,119,158,127,100,199,214,118,66,193,0,227,241,131,248,86,41,41,247,96,60,118,0,128,107, + 131,123,25,125,53,77,40,24,224,253,167,69,172,53,132,59,218,88,99,125,92,58,177,11,23,241,236,234,161,90,128,228, + 85,45,160,111,223,54,38,166,51,68,182,180,97,100,248,48,187,64,103,36,92,190,231,174,170,188,12,176,182,116,244,32, + 126,191,197,250,252,200,136,245,45,235,240,89,11,18,194,5,87,245,122,96,144,132,145,33,241,96,130,185,133,63,76,125, + 206,50,59,247,147,236,175,60,35,47,167,138,191,98,74,114,43,1,221,231,71,145,12,199,174,60,102,114,38,67,42,253, + 157,237,155,130,108,14,181,146,74,207,243,118,242,43,71,46,63,4,96,207,217,100,45,192,117,161,123,112,132,204,143,28, + 233,47,139,156,59,186,19,73,72,226,100,79,132,84,122,158,111,217,223,116,13,36,27,207,193,178,11,185,191,75,220,119, + 14,123,157,40,2,36,49,22,239,99,105,217,253,255,32,149,172,107,32,137,49,194,200,115,100,232,60,115,183,238,54,217, + 234,217,110,100,141,226,182,80,40,220,28,142,15,157,110,102,151,243,185,252,173,21,142,211,185,159,81,219,35,189,0,0, + 0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Mute = { //size: 632 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,10,73,68,65,84,56,141, + 165,147,207,75,84,81,24,134,159,115,61,215,51,214,140,46,100,26,17,141,22,226,70,178,50,23,21,65,11,33,152,85, + 139,113,156,153,173,155,41,92,70,250,31,68,45,204,173,182,82,180,140,68,72,9,4,17,90,185,147,72,200,12,209,96, + 108,51,11,113,225,189,206,56,115,127,124,45,6,103,97,72,86,31,156,213,199,251,188,223,11,239,81,34,194,255,140,117, + 222,98,48,55,216,159,207,231,237,127,2,100,179,169,190,6,212,90,181,90,109,248,107,64,54,155,234,179,27,35,159,68, + 164,249,79,98,0,157,201,165,29,32,162,181,62,70,100,210,110,140,60,25,30,30,110,158,122,61,21,92,4,96,41,84, + 100,98,124,66,143,141,142,181,8,140,142,140,140,52,223,189,115,15,173,245,69,244,104,65,136,199,175,16,143,39,16,17, + 117,235,230,109,140,49,40,165,46,6,0,216,250,246,181,238,184,179,243,29,219,182,241,60,143,135,11,239,243,243,211,211, + 207,4,34,103,133,10,78,4,158,107,0,199,113,234,0,207,247,16,106,221,176,124,255,101,39,24,109,12,150,49,4,71, + 71,232,214,86,252,195,67,2,17,10,240,202,2,112,92,7,199,117,16,17,188,170,135,87,245,78,141,204,37,99,232,89, + 93,229,250,250,58,177,238,110,110,108,110,210,61,51,67,83,45,162,209,0,174,235,82,46,151,1,40,252,220,167,179,163, + 163,126,170,233,234,226,114,127,63,202,24,122,182,183,1,104,73,38,209,137,4,20,139,88,34,34,139,139,139,193,202,202, + 202,137,165,172,169,165,165,15,238,126,97,191,14,56,217,218,226,71,38,83,203,109,213,106,179,51,48,128,95,44,214,98, + 2,49,17,137,134,97,24,125,251,230,221,99,175,18,36,151,63,46,187,97,24,90,0,118,123,59,87,39,39,65,41,36, + 8,64,132,107,179,179,88,177,88,205,65,68,126,123,233,116,250,126,58,147,58,158,3,249,210,214,38,149,66,65,188,131, + 3,217,203,229,36,40,149,196,221,216,144,207,209,168,204,129,168,243,126,227,208,208,208,131,71,11,11,107,93,160,35,137, + 4,13,209,40,149,189,61,154,122,123,169,236,238,82,45,149,216,5,255,92,0,192,188,82,47,66,120,122,218,151,51,227, + 91,48,254,11,41,211,229,38,66,238,34,57,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector New = { //size: 477 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,252,0,233,0,79,52,215,177,13,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,2,18,14,38,28,211,182,25,41,0,0,1,106,73, + 68,65,84,56,203,173,144,79,75,91,81,16,197,127,115,239,141,86,36,125,37,130,208,202,91,22,220,212,238,92,102,169, + 27,243,13,178,113,89,191,69,222,178,221,119,35,4,196,130,223,192,77,55,221,42,133,82,74,178,82,74,73,90,132,16, + 255,69,98,155,222,119,199,133,38,198,24,147,84,122,54,51,12,115,230,156,51,82,46,151,183,107,181,90,145,17,152,157, + 253,203,220,92,155,103,209,111,242,203,159,223,229,162,111,31,225,207,190,100,195,25,165,82,73,199,225,252,120,83,47,79, + 223,104,231,188,160,151,39,43,157,139,198,226,174,182,178,235,218,50,51,174,171,210,108,54,9,33,0,32,34,61,245,140, + 217,99,218,126,33,227,190,34,102,9,235,76,38,216,246,106,199,183,91,83,206,87,123,7,6,201,221,106,228,8,107,234, + 136,121,133,184,2,96,49,42,70,211,95,139,224,94,186,254,172,131,228,235,94,111,58,11,76,129,56,16,11,130,0,23, + 110,52,89,8,58,79,208,231,216,80,69,211,105,64,208,180,162,222,155,122,198,166,21,247,208,231,187,135,2,175,241,225, + 39,224,177,90,1,20,239,95,232,233,89,235,211,204,252,247,131,145,17,68,4,229,41,29,93,67,117,129,52,253,1,60, + 97,107,231,208,108,108,108,191,5,112,163,200,183,53,139,215,60,34,66,20,69,52,26,73,79,212,48,33,250,127,211,143, + 123,17,134,57,120,136,124,199,193,176,165,193,217,176,29,51,169,221,177,17,114,185,28,143,129,139,227,248,67,146,36,197, + 127,33,197,113,252,158,255,133,43,204,61,153,96,123,172,20,201,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Open = { //size: 672 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,2,29,73,68,65,84,56,141,141,147,191,75,151,81,20,198,63,231,125, + 175,111,73,160,107,4,225,210,82,208,24,168,75,63,164,37,13,114,106,208,165,197,193,160,230,134,254,130,134,16,55,135, + 138,6,251,15,4,35,133,8,77,43,104,104,138,16,33,181,69,66,45,205,239,247,222,115,207,105,248,234,155,150,96,207, + 112,238,185,151,123,159,231,57,231,222,43,67,67,67,28,68,202,205,134,136,148,238,46,34,2,64,81,20,34,34,180,181, + 181,125,254,181,221,184,92,85,213,250,254,254,208,213,213,245,212,221,111,238,47,44,45,127,57,241,236,201,115,138,162,64, + 68,216,39,17,17,38,95,76,158,159,158,158,250,128,115,17,248,1,16,204,108,112,112,112,176,211,204,200,57,51,54,254, + 152,149,149,21,154,205,38,0,238,78,206,25,51,99,120,104,152,173,205,205,179,11,239,23,230,227,110,186,84,85,213,110, + 72,41,185,170,178,190,190,142,170,238,91,102,241,221,226,161,210,122,186,187,1,24,29,189,43,229,68,184,48,55,255,102, + 12,99,100,143,32,161,170,152,25,34,66,85,85,244,93,235,195,221,107,23,101,89,214,34,189,61,189,242,118,97,238,182, + 25,35,65,85,77,53,147,115,174,29,132,16,152,153,125,69,206,185,118,112,245,202,53,98,140,173,137,128,153,21,80,16, + 82,74,30,99,172,9,246,186,77,255,141,129,90,253,239,177,253,100,59,56,6,16,98,140,166,170,76,204,59,13,13,208, + 121,139,129,135,47,113,107,137,249,129,216,34,216,75,218,251,59,202,162,88,13,170,74,74,137,157,8,143,238,95,231,40, + 72,29,254,32,170,241,96,124,230,76,72,41,89,74,9,112,74,129,143,203,91,71,146,28,68,89,10,231,78,159,2,113, + 15,41,37,83,77,8,80,136,80,133,226,88,130,108,142,27,8,98,123,215,152,17,9,196,100,148,114,176,226,195,208,236, + 52,147,161,102,52,83,6,240,160,170,22,99,68,36,240,109,163,193,207,134,162,217,73,217,49,115,204,157,108,78,210,86, + 14,16,74,97,245,251,46,136,88,16,17,51,51,4,216,216,142,108,55,148,164,255,122,8,165,212,157,44,10,216,220,137, + 136,187,7,119,103,109,163,245,96,94,127,90,173,63,207,113,216,217,217,5,145,175,33,23,237,179,83,75,29,119,192,89, + 94,90,251,175,195,180,188,108,100,228,222,111,248,2,75,29,117,50,217,195,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Properties = { //size: 464 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,11,4,10,21,27,198,210,43,84,0,0,1,93,73, + 68,65,84,56,203,173,147,189,106,194,80,24,134,159,175,186,25,13,145,108,14,14,130,34,222,130,102,117,232,216,161,215, + 224,45,56,40,113,200,37,136,46,93,116,105,233,218,193,81,112,245,2,78,68,232,162,100,208,156,213,41,118,16,131,49, + 162,8,125,167,195,251,113,158,239,239,28,1,24,143,199,223,65,16,188,241,156,222,251,253,254,23,0,174,235,30,159,149, + 235,186,71,128,236,37,114,191,223,19,69,17,0,34,18,251,231,179,136,144,201,100,48,77,51,142,37,0,81,20,225,251, + 126,226,194,165,68,132,122,189,158,240,178,215,141,213,106,53,0,122,189,94,236,117,58,29,74,165,82,10,8,240,114,157, + 193,247,125,86,171,21,237,118,27,173,53,90,107,60,207,67,41,133,82,234,62,0,96,58,157,98,24,6,205,102,147,110, + 183,139,101,89,88,86,129,106,181,26,87,119,23,112,206,184,88,44,240,60,15,17,65,36,203,118,251,123,115,151,169,22, + 78,25,45,102,179,25,197,98,49,142,141,70,31,4,65,240,184,130,203,222,195,48,36,12,67,180,214,28,14,7,134,195, + 33,187,221,238,254,22,90,173,22,142,227,196,21,109,54,27,38,147,9,133,66,129,92,46,199,124,62,167,82,169,220,6, + 136,8,74,169,212,59,112,28,135,245,122,141,97,24,228,243,249,199,239,224,52,184,36,164,209,104,176,92,46,239,3,46, + 135,118,45,211,52,41,151,203,41,63,11,96,219,246,207,96,48,120,125,230,43,218,182,253,201,127,232,15,224,142,163,230, + 109,49,155,36,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Quit = { //size: 799 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,2,156,73,68,65,84,56,141,117,147,79,104,20,73,20,198,127,175,170, + 186,187,122,178,131,123,136,30,140,32,234,206,97,47,226,69,65,133,16,209,171,104,80,195,170,228,40,30,12,44,26,15, + 146,187,46,30,246,224,31,140,160,87,69,80,47,158,68,80,20,36,106,4,133,21,28,221,29,119,66,38,108,64,103,162, + 201,244,100,58,157,238,169,61,196,25,255,63,248,168,122,151,175,126,95,61,158,28,28,220,127,50,73,146,17,126,80,34, + 130,239,251,216,192,98,140,1,17,178,44,197,6,246,207,179,103,206,159,48,73,146,140,244,239,218,67,185,92,38,138,34, + 26,141,6,205,102,147,56,142,73,211,148,11,23,206,163,148,66,107,131,82,10,128,102,220,228,236,185,51,195,192,105,3, + 16,4,1,65,16,144,36,9,105,154,210,106,181,112,206,161,181,6,64,41,141,49,230,99,47,104,109,232,89,217,3,144, + 87,0,249,124,158,48,12,201,229,114,132,97,216,185,91,107,1,65,4,68,20,165,209,139,60,216,190,29,17,193,218,16, + 192,152,118,78,107,45,206,185,78,110,17,65,41,133,8,184,44,227,217,209,33,178,106,149,15,197,34,245,191,95,195,127, + 211,252,51,58,218,109,150,16,21,90,107,180,214,248,190,79,150,101,29,179,180,94,231,201,254,131,116,23,10,172,30,24, + 32,46,151,25,223,187,143,101,201,2,79,203,19,247,58,4,109,19,165,84,71,54,138,120,216,219,199,218,29,59,88,190, + 110,29,233,244,52,235,15,29,2,17,196,24,238,28,62,188,20,161,77,209,150,214,154,220,212,20,171,110,222,164,176,115, + 39,63,25,67,116,255,62,40,181,36,17,242,125,125,136,82,116,12,218,175,183,207,238,91,183,88,93,40,96,227,152,232, + 249,115,90,113,76,171,209,160,53,63,143,238,234,34,88,179,6,68,80,159,19,124,30,225,237,224,32,111,94,189,98,186, + 88,68,133,33,139,149,10,217,220,28,46,77,201,234,117,146,74,5,151,101,159,8,218,255,208,54,74,86,172,96,234,200, + 17,114,55,174,19,55,155,172,220,176,1,29,134,44,46,44,208,82,138,249,106,21,156,147,14,193,247,166,145,134,33,183, + 183,108,193,21,126,161,92,169,144,68,17,127,141,143,243,239,228,36,47,138,47,241,186,186,158,126,97,96,140,233,104,98, + 98,130,192,250,12,13,31,227,215,203,151,88,214,191,155,215,165,18,218,90,54,62,30,99,242,248,48,251,162,168,255,139, + 8,158,231,81,122,83,194,134,62,191,29,24,32,159,207,163,181,38,106,212,89,254,251,16,178,170,135,217,187,119,153,157, + 251,64,181,246,14,96,222,0,120,158,71,173,86,37,89,92,96,243,214,77,120,158,143,115,45,230,234,179,128,124,218,204, + 109,189,252,188,173,151,247,239,107,204,204,204,44,25,248,190,127,234,234,181,43,35,181,90,21,17,97,236,209,216,55,235, + 252,117,57,231,8,130,224,15,32,253,31,63,61,253,93,147,0,165,101,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Refresh = { //size: 912 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,3,34,73,68,65,84,56,141, + 109,82,77,108,84,101,20,61,247,123,239,149,249,173,51,109,7,91,168,182,10,134,18,166,161,162,51,141,127,209,152,70, + 55,196,96,88,168,188,68,140,144,129,240,179,97,7,27,12,77,12,17,116,97,162,224,3,163,49,76,37,152,52,1,55, + 252,4,33,146,212,194,171,113,209,208,146,212,210,198,1,70,59,180,29,232,204,180,243,222,251,190,235,162,243,146,89,112, + 146,155,220,197,61,39,39,231,92,98,102,248,72,101,178,207,52,232,218,17,16,222,244,164,106,213,132,152,39,194,184,227, + 202,19,0,46,216,150,233,214,221,30,4,112,130,124,129,116,38,187,69,211,196,64,79,215,42,125,93,103,179,209,214,20, + 1,152,81,40,86,48,50,118,191,124,103,250,161,39,21,239,182,45,243,108,122,87,54,195,140,239,0,196,136,153,145,202, + 100,215,27,186,24,217,218,215,29,138,199,130,208,137,208,28,13,32,28,208,17,13,25,8,26,2,51,197,69,28,207,14, + 87,10,197,138,29,13,53,244,62,46,87,13,102,52,17,51,227,213,61,103,79,245,172,107,251,52,24,48,196,173,209,28, + 170,174,7,67,215,228,154,213,177,197,190,244,243,225,222,245,173,164,9,130,16,132,95,174,77,168,183,94,108,23,7,190, + 190,234,56,174,108,209,1,128,153,63,188,51,93,16,174,167,88,49,47,50,227,51,199,149,103,198,167,103,147,19,247,230, + 143,94,239,104,238,218,183,117,83,40,17,11,225,227,119,187,68,45,6,2,160,4,0,72,169,194,85,199,243,146,47,60, + 251,131,148,234,17,128,65,219,50,243,182,101,94,249,227,219,143,94,26,157,44,236,221,125,236,18,238,63,44,97,122,166, + 12,169,24,0,3,0,11,44,175,170,233,169,72,127,99,36,240,85,103,251,202,110,0,83,117,105,235,186,38,118,110,123, + 39,233,118,62,29,69,162,113,5,52,65,190,3,214,107,119,241,95,63,223,188,128,39,227,180,39,213,107,23,135,39,171, + 87,237,169,37,223,188,227,170,0,0,246,91,168,2,48,106,4,174,155,223,0,236,4,224,62,65,88,183,45,243,158,47, + 224,157,63,250,190,6,16,152,25,23,237,127,212,169,243,127,229,164,84,61,182,101,22,235,89,135,179,99,171,74,229,165, + 142,223,71,198,111,0,136,233,0,64,4,16,17,238,254,87,134,33,24,39,7,255,36,0,95,212,147,83,153,108,152,136, + 238,246,110,92,123,38,63,51,151,2,160,1,168,10,0,16,68,4,0,29,137,16,86,183,132,241,229,254,183,169,173,37, + 114,236,149,61,63,223,74,101,178,233,154,198,246,21,134,174,231,242,179,7,242,133,226,235,154,70,174,109,153,174,88,118, + 64,120,92,113,113,97,104,138,61,143,209,190,50,138,195,59,222,8,125,208,151,124,185,181,57,114,45,189,107,192,53,116, + 241,141,84,50,62,247,104,1,77,141,65,210,132,24,4,0,255,145,168,255,199,161,165,137,220,220,228,165,225,201,206,204, + 150,77,225,68,44,136,238,181,9,122,174,61,30,42,150,93,252,59,91,130,227,120,20,9,26,56,119,121,180,226,73,117, + 4,0,150,31,73,49,77,228,230,78,223,60,185,45,249,160,176,240,73,255,247,55,230,143,15,220,44,13,223,206,35,63, + 91,70,213,149,16,68,40,204,151,228,185,203,163,139,82,169,140,109,153,99,0,224,183,240,19,128,237,182,101,114,45,48, + 3,192,123,13,134,182,87,49,111,144,82,197,13,93,155,33,194,80,213,145,135,108,203,252,219,15,247,127,46,85,118,106, + 19,101,204,198,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Remove = { //size: 247 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,214,1,11,15,59,34,0,92,18,194,0,0,0,132,73, + 68,65,84,56,203,237,145,177,9,131,80,16,134,191,7,105,220,192,58,43,232,8,25,35,173,109,70,8,25,32,11,136, + 173,115,196,5,116,136,212,182,34,68,243,238,79,33,202,179,179,51,133,31,28,28,7,255,119,28,7,7,251,227,230,38, + 205,202,26,72,54,230,154,186,184,166,0,167,96,152,60,111,23,70,19,14,24,189,86,9,105,42,7,220,243,215,178,40, + 20,208,125,60,239,182,71,2,51,97,130,126,16,222,139,175,9,51,56,199,209,74,28,10,154,71,94,109,62,225,248,254, + 63,241,3,172,83,45,219,70,228,128,216,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Save = { //size: 911 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,11,10,13,55,15,158,42,216,191,0,0,0,140,116, + 69,88,116,67,111,109,109,101,110,116,0,77,101,110,117,45,115,105,122,101,100,32,105,99,111,110,10,61,61,61,61,61, + 61,61,61,61,61,10,10,40,99,41,32,50,48,48,51,32,74,97,107,117,98,32,39,106,105,109,109,97,99,39,32,83, + 116,101,105,110,101,114,44,32,10,104,116,116,112,58,47,47,106,105,109,109,97,99,46,109,117,115,105,99,104,97,108,108, + 46,99,122,10,10,99,114,101,97,116,101,100,32,119,105,116,104,32,116,104,101,32,71,73,77,80,44,10,104,116,116,112, + 58,47,47,119,119,119,46,103,105,109,112,46,111,114,103,103,138,199,71,0,0,2,132,73,68,65,84,56,203,157,146,77, + 72,84,97,20,134,159,185,221,241,230,207,228,76,224,181,49,205,145,178,81,108,81,81,52,38,20,184,200,22,69,20,46, + 66,40,44,130,138,169,193,86,45,42,202,69,17,84,16,6,82,180,40,10,34,176,40,40,106,91,208,34,137,68,138,166, + 69,153,84,106,134,164,232,220,155,206,253,249,78,11,97,108,178,54,189,155,243,193,225,60,156,247,61,95,224,200,217,227, + 39,63,91,21,218,216,184,51,9,84,1,91,129,134,160,38,217,208,194,159,63,22,25,206,205,187,231,207,157,224,31,10, + 52,119,116,237,141,173,172,143,85,151,155,131,171,107,202,58,170,35,133,107,109,207,39,253,45,195,235,222,231,234,195,215, + 81,226,145,55,203,186,59,239,12,255,21,144,60,125,190,219,157,26,59,236,137,198,168,31,102,218,40,99,129,30,164,173, + 101,35,203,43,22,115,249,254,11,252,161,62,98,5,227,127,155,239,36,121,44,37,95,70,6,68,68,100,224,115,90,122, + 211,3,146,186,246,68,18,7,47,72,207,171,47,210,245,244,173,180,158,186,46,239,6,135,229,119,89,150,37,169,142,164, + 232,134,238,179,180,60,198,196,196,4,225,146,114,180,192,36,133,226,0,208,247,113,20,179,68,231,251,120,134,247,3,159, + 88,178,168,16,2,0,66,65,65,1,0,186,231,130,40,193,87,138,237,39,110,204,219,177,119,112,2,215,243,185,216,243, + 146,139,61,47,1,120,124,118,31,200,108,95,3,80,162,80,190,162,235,80,35,0,237,187,119,210,152,88,199,204,140,77, + 52,164,209,148,88,207,222,214,237,0,236,105,94,129,242,21,34,50,7,16,17,34,145,48,21,101,49,46,29,88,199,205, + 187,15,136,199,170,208,8,160,17,32,81,95,205,173,123,143,104,219,92,195,142,166,245,20,21,23,229,3,0,44,203,194, + 52,77,170,163,181,57,72,227,170,229,212,198,42,185,124,251,33,109,155,107,216,181,41,129,105,154,56,142,147,179,168,3, + 40,165,176,109,27,0,211,52,49,77,147,238,163,133,28,187,218,67,214,245,217,223,82,79,251,182,45,104,154,198,212,212, + 20,182,109,19,10,133,230,0,134,97,80,89,89,153,23,222,154,134,13,60,187,178,1,0,219,182,113,28,135,233,233,233, + 121,33,235,0,253,253,253,184,174,155,215,240,60,15,93,215,115,239,63,21,137,68,242,51,240,60,143,116,58,205,200,200, + 8,153,76,6,17,65,68,48,12,131,161,161,33,66,161,80,174,90,150,133,101,89,249,87,80,74,81,92,92,68,48,24, + 204,125,18,0,215,117,17,53,11,19,53,123,62,229,251,249,22,194,225,48,165,165,165,68,163,81,0,178,217,44,64,46, + 237,120,93,28,165,20,241,186,58,148,82,44,137,70,115,150,3,169,142,228,25,224,52,255,167,206,95,147,59,51,76,213, + 34,98,109,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Search = { //size: 935 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,6,29,17,18,8,200,223,108,120,0,0,3,52,73, + 68,65,84,56,203,165,147,91,104,84,119,16,198,103,254,231,178,231,156,205,222,226,110,54,169,27,52,136,26,139,151,54, + 27,91,179,84,173,164,62,24,124,80,52,20,20,162,146,66,169,171,173,15,53,77,53,84,90,52,68,193,18,164,84,104, + 107,21,164,133,38,47,125,170,180,198,16,47,72,172,104,64,163,193,91,196,100,147,205,222,183,155,205,238,158,61,57,243, + 247,37,27,90,241,173,31,12,51,204,195,143,111,24,62,132,87,212,214,126,248,55,189,144,223,138,136,42,113,66,206,249, + 140,205,102,191,216,121,188,235,19,120,141,196,210,240,69,251,225,13,185,124,254,175,230,157,205,178,195,81,142,69,195,228, + 38,7,144,5,180,78,103,82,31,103,50,211,123,237,118,91,99,231,241,174,155,255,6,32,0,192,177,175,59,214,166,211, + 233,91,193,253,159,97,223,221,201,226,72,82,44,40,154,166,154,196,165,92,54,155,241,191,1,74,227,219,62,185,251,204, + 105,170,240,84,212,119,28,61,54,244,31,7,137,68,114,224,211,3,135,240,247,219,81,99,74,183,75,187,54,249,178,11, + 23,104,255,152,68,174,161,231,233,196,141,145,216,162,233,191,195,197,131,193,67,114,247,153,111,175,1,128,173,4,16,58, + 190,58,210,230,175,171,223,60,154,20,205,209,25,77,250,168,113,73,164,202,165,162,34,51,137,8,100,213,34,166,114,250, + 236,195,231,73,170,177,80,206,240,186,20,92,189,102,85,246,234,192,181,91,0,0,44,145,136,159,244,215,249,165,193,23, + 134,28,88,238,54,4,6,110,221,48,157,121,125,86,51,137,4,211,52,221,145,148,238,65,192,240,112,4,228,119,214,190, + 171,68,163,145,238,249,19,36,73,226,4,12,173,118,7,40,178,120,47,147,55,152,98,114,93,20,176,72,196,151,246,220, + 8,157,52,136,202,128,131,43,109,136,159,171,170,6,146,36,241,121,0,17,205,90,36,81,146,24,231,79,38,166,167,24, + 218,152,171,12,76,189,104,134,199,98,185,144,78,20,23,56,18,48,174,204,26,134,169,235,186,64,68,198,60,192,235,245, + 222,153,152,152,168,119,200,50,62,30,143,151,143,199,115,55,57,131,40,34,139,32,113,183,0,48,3,200,173,201,88,116, + 125,237,162,114,76,38,19,122,101,101,213,96,9,192,68,81,252,177,127,224,74,120,171,223,43,168,86,53,96,114,178,1, + 71,6,156,139,28,200,65,8,114,161,80,168,112,121,60,239,111,121,203,195,126,190,112,46,147,78,167,250,231,191,112,165, + 175,127,104,197,155,181,109,86,139,168,175,92,86,163,141,198,139,245,177,112,200,163,170,234,51,226,84,27,25,127,177,221, + 229,118,239,222,177,74,132,193,235,127,114,85,209,48,22,139,53,212,44,89,124,225,225,131,145,172,0,0,176,99,231,246, + 203,195,15,238,239,231,185,212,212,174,166,128,221,0,177,114,166,200,63,224,40,172,169,91,90,81,181,205,239,134,115,103, + 79,83,96,93,128,77,78,77,74,68,166,196,24,107,105,104,88,215,135,37,43,93,167,78,172,30,27,27,255,195,227,246, + 20,156,206,114,217,95,231,119,86,87,87,219,122,122,123,30,61,121,250,72,213,243,198,55,78,151,253,167,166,45,77,112, + 111,248,62,108,120,111,35,253,242,235,69,134,175,134,163,235,212,137,125,0,208,28,10,133,54,2,128,230,243,249,46,1, + 64,111,123,219,209,243,193,96,176,19,25,255,114,79,203,94,176,90,203,224,251,179,223,1,190,38,96,108,174,176,148,149, + 185,206,1,0,90,91,91,91,84,205,242,195,220,238,67,248,191,122,9,59,169,102,147,104,79,162,5,0,0,0,0,73, + 69,78,68,174,66,96,130, +}; +const nall::vector Settings = { //size: 611 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,9,26,12,19,57,139,99,194,72,0,0,1,240,73, + 68,65,84,56,203,165,146,75,104,19,97,20,133,191,153,248,76,138,77,20,10,130,74,176,204,198,133,182,221,69,172,46, + 52,20,98,102,235,66,112,33,84,164,168,181,45,18,82,2,21,3,67,66,160,107,65,116,101,64,138,226,194,137,141,208, + 98,87,130,210,54,137,73,23,21,130,85,105,211,151,134,32,68,68,58,51,110,102,134,49,29,235,194,179,251,185,231,156, + 123,239,185,63,252,39,4,231,35,157,81,162,128,10,200,241,88,34,247,23,77,52,157,81,108,142,216,82,84,251,175,246, + 3,168,166,153,171,248,250,181,1,205,108,180,29,233,140,98,52,26,117,35,157,81,12,247,90,195,170,69,1,196,116,70, + 137,90,100,171,171,215,219,230,102,28,5,120,240,240,62,241,88,66,6,114,0,34,160,14,222,28,50,158,62,155,48,0, + 245,246,173,17,54,215,215,144,58,37,234,245,175,247,90,179,137,221,25,21,44,49,128,96,21,111,12,12,26,154,182,37, + 232,186,110,232,186,70,97,126,78,40,188,47,2,200,59,5,43,180,116,176,17,233,187,72,185,82,97,185,246,5,32,25, + 143,37,238,254,243,140,78,188,202,191,52,74,149,18,221,39,123,40,150,11,152,19,76,2,186,171,65,48,146,58,12,212, + 172,247,149,144,78,215,9,137,163,71,142,209,108,54,121,55,247,22,183,53,60,78,241,248,112,152,190,80,39,29,1,47, + 217,153,77,142,183,127,75,46,125,94,58,215,125,170,135,128,63,192,74,109,249,242,133,240,249,249,233,169,215,85,192,0, + 16,131,145,84,23,80,123,52,38,51,91,94,100,182,188,72,199,65,31,0,230,222,114,46,255,2,73,146,56,123,186,215, + 250,100,118,30,34,80,28,31,14,51,245,166,196,150,166,35,238,243,179,81,111,218,35,154,35,203,217,39,143,57,208,238, + 231,76,168,23,96,204,105,0,192,238,93,30,246,248,14,241,243,199,47,178,249,5,128,112,171,73,46,175,82,253,88,253, + 35,108,17,96,101,227,59,251,125,1,218,246,122,120,62,243,1,32,252,105,114,116,218,73,52,77,146,107,235,171,11,64, + 210,190,66,48,146,186,4,76,56,184,219,196,59,225,55,55,226,213,246,234,188,84,188,0,0,0,0,73,69,78,68,174, + 66,96,130, +}; +const nall::vector Stop = { //size: 820 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,10,17,23,45,13,107,192,156,192,0,0,2,193,73, + 68,65,84,56,203,109,147,187,79,83,97,24,135,159,115,233,5,109,141,198,200,224,37,134,198,64,43,120,105,106,184,9, + 169,54,136,154,152,144,184,177,16,88,252,15,92,58,56,24,105,28,28,76,28,140,11,113,208,193,187,49,184,152,80,36, + 154,176,136,193,196,14,14,40,181,212,22,74,105,161,7,225,180,231,59,159,3,165,130,242,38,95,190,228,77,158,223,123, + 249,229,85,216,18,143,194,97,61,61,49,241,68,192,85,118,8,13,198,4,92,142,66,101,51,167,252,3,63,107,244,249, + 46,93,188,118,205,173,104,26,0,82,74,16,2,105,89,124,120,248,208,252,50,51,243,94,192,149,40,88,53,129,42,252, + 194,239,243,245,70,134,134,220,243,227,227,152,249,252,182,234,78,175,151,250,142,14,62,60,125,106,38,146,201,49,1,125, + 81,176,180,145,80,200,145,157,156,124,25,56,118,172,55,50,56,184,1,175,174,130,101,109,19,16,170,202,90,58,77,32, + 18,209,87,231,230,142,44,149,74,103,6,195,225,231,90,103,38,243,230,120,99,99,207,249,129,1,119,54,30,199,170,175, + 71,143,197,32,153,68,102,179,27,179,159,56,193,222,187,119,169,36,18,24,95,191,114,60,28,214,141,84,234,232,143,68, + 34,168,245,168,234,227,254,235,215,245,204,187,119,148,11,5,212,190,62,212,150,22,148,142,14,248,254,29,117,255,126,246, + 12,15,227,218,183,15,69,74,74,227,227,252,46,20,104,14,135,245,169,207,159,3,186,162,40,32,37,229,66,97,163,213, + 145,17,112,185,112,245,246,226,190,113,3,93,81,112,122,60,152,241,56,249,59,119,176,129,117,195,64,10,129,2,168,255, + 121,37,37,226,254,125,228,212,20,206,93,187,112,122,189,88,211,211,228,98,49,132,109,99,3,54,32,171,59,82,119,244, + 187,185,25,119,40,132,174,235,56,28,14,118,7,131,212,133,66,200,42,44,202,101,196,220,220,95,1,41,68,13,86,91, + 90,240,222,186,133,211,235,101,61,30,103,117,116,20,167,199,131,239,222,61,60,237,237,152,185,28,198,183,111,200,149,21, + 0,116,41,229,134,154,97,32,44,139,186,182,54,92,85,120,113,120,24,219,52,209,128,3,253,253,212,157,58,197,250,131, + 7,160,105,216,213,162,218,5,41,187,43,197,226,225,64,91,155,86,74,36,40,189,126,77,229,231,79,22,110,222,164,156, + 201,80,94,92,36,247,234,21,107,179,179,36,111,223,70,209,52,124,126,63,233,165,37,251,199,242,114,94,137,129,83,131, + 183,39,27,26,186,91,131,65,87,42,30,103,173,88,172,45,107,235,83,28,14,26,154,154,72,23,10,226,99,58,189,96, + 67,167,54,6,34,2,79,114,197,98,151,105,24,135,2,173,173,122,105,126,158,138,105,110,131,85,135,131,6,191,159,217, + 124,94,76,254,250,149,178,161,61,10,169,218,49,109,118,226,63,120,176,251,236,233,211,46,69,8,108,203,66,90,86,237, + 79,36,147,214,167,108,118,198,134,174,40,44,110,187,198,173,34,2,122,118,178,87,133,105,27,206,69,97,121,51,247,7, + 199,77,82,246,215,134,247,20,0,0,0,0,73,69,78,68,174,66,96,130, +}; +} +namespace Application { +const nall::vector Browser = { //size: 928 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,4,26,7,44,7,230,25,222,143,0,0,0,53,116, + 69,88,116,67,111,109,109,101,110,116,0,40,99,41,32,50,48,48,52,32,74,97,107,117,98,32,83,116,101,105,110,101, + 114,10,10,67,114,101,97,116,101,100,32,119,105,116,104,32,84,104,101,32,71,73,77,80,144,217,139,111,0,0,2,236, + 73,68,65,84,56,203,173,147,93,104,91,101,28,135,159,247,156,247,156,99,147,52,105,155,230,163,141,109,214,208,162,44, + 184,117,178,200,196,171,41,168,48,20,111,148,41,221,69,101,56,16,111,132,161,160,183,82,16,197,251,93,136,21,71,65, + 196,233,141,76,134,55,179,48,181,179,150,141,118,43,174,235,92,63,179,156,44,31,77,114,146,115,146,156,215,11,217,196, + 237,214,231,250,255,123,46,254,252,126,130,7,56,254,222,236,41,224,45,93,202,253,10,44,229,251,13,165,88,208,116,237, + 236,220,204,212,23,15,222,139,251,193,247,191,156,52,117,237,199,137,177,100,226,200,129,52,99,169,40,1,203,162,92,111, + 178,182,105,179,184,178,201,141,141,194,101,33,196,201,185,153,169,171,255,17,188,246,238,231,185,96,184,231,183,87,142,30, + 20,7,39,226,148,235,77,236,157,13,100,40,14,61,253,224,216,164,18,81,22,86,182,57,63,191,114,23,33,158,189,39, + 145,0,209,104,232,167,231,159,201,138,39,50,3,148,138,121,6,71,179,68,6,135,112,90,109,242,155,235,72,223,67,235, + 54,121,46,151,161,235,171,232,133,75,215,207,0,79,3,104,111,126,248,213,71,201,120,127,248,104,110,28,67,243,233,200, + 16,104,2,67,74,76,67,18,176,36,137,104,47,67,241,24,177,190,32,185,236,163,164,135,7,142,188,241,193,217,105,0, + 45,28,9,156,60,156,29,165,82,46,114,199,13,16,31,222,135,82,224,43,64,104,8,223,99,183,212,224,251,139,203,92, + 152,95,36,98,41,246,143,15,3,188,10,32,107,78,59,150,78,246,179,112,163,64,102,34,142,175,254,253,108,189,82,226, + 169,201,44,66,8,148,82,108,239,222,161,213,108,50,20,139,0,28,6,208,90,94,71,179,44,19,45,20,167,82,111,97, + 215,60,28,183,75,205,241,240,234,54,66,252,163,19,66,144,136,69,185,186,122,19,203,144,0,3,0,82,215,53,191,218, + 104,105,193,214,14,33,105,81,104,12,82,52,76,58,93,159,86,169,195,100,187,141,235,122,244,134,130,56,142,195,190,84, + 140,66,211,3,40,1,72,67,211,242,183,182,138,195,135,198,147,100,70,134,184,189,185,205,252,218,30,30,38,77,47,200, + 167,223,94,193,18,93,222,126,249,0,181,90,141,165,107,55,161,55,13,240,59,128,166,186,221,115,75,171,91,120,190,4, + 32,61,146,226,216,161,24,187,133,18,119,171,13,170,174,224,118,217,199,182,109,170,213,42,143,244,167,88,93,207,3,124, + 3,160,47,253,124,238,252,120,238,165,211,66,215,205,72,208,160,199,212,249,101,113,153,229,188,162,214,112,217,107,184,236, + 57,46,185,17,157,194,158,199,86,217,231,218,218,206,175,115,51,83,239,220,47,82,165,80,60,113,241,178,255,157,239,195, + 147,143,37,248,225,74,149,178,103,226,117,186,184,94,7,203,16,108,84,20,127,21,218,92,250,99,173,44,132,56,245,208, + 22,142,77,127,252,250,104,102,100,54,28,233,51,31,207,36,73,14,134,177,44,3,167,213,102,215,174,240,231,173,60,91, + 59,197,235,66,151,199,31,218,194,61,250,6,198,204,23,78,156,158,213,173,192,139,232,178,15,132,80,202,239,168,78,123, + 93,9,237,179,175,63,153,62,195,255,205,223,112,108,55,247,49,218,29,149,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Calculator = { //size: 686 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,6,6,13,47,29,93,206,74,167,0,0,0,53,116, + 69,88,116,67,111,109,109,101,110,116,0,40,99,41,32,50,48,48,52,32,74,97,107,117,98,32,83,116,101,105,110,101, + 114,10,10,67,114,101,97,116,101,100,32,119,105,116,104,32,84,104,101,32,71,73,77,80,144,217,139,111,0,0,1,250, + 73,68,65,84,56,203,157,147,193,106,83,65,20,134,191,57,51,193,94,210,214,146,54,8,90,109,11,117,97,82,72,218, + 110,196,165,175,16,74,23,69,16,116,227,86,220,27,10,238,196,39,80,240,61,164,186,44,90,219,36,205,109,192,130,138, + 74,139,168,237,197,132,18,99,114,231,184,72,188,165,139,34,118,54,195,240,207,124,115,254,255,204,152,165,229,210,67,160, + 204,217,70,217,44,45,151,244,206,221,219,103,58,253,236,233,115,220,223,197,230,214,203,83,55,182,90,71,164,211,1,237, + 118,7,107,133,161,161,115,44,46,220,4,56,6,52,155,7,167,2,62,188,223,195,90,33,58,108,209,108,30,113,253,198, + 92,162,37,128,153,153,185,83,1,83,83,57,140,49,168,42,198,24,140,49,137,102,150,150,75,26,53,219,60,184,127,239, + 191,252,175,62,122,194,165,11,153,126,5,221,110,143,242,234,99,126,117,58,125,85,21,253,7,64,68,142,45,220,90,89, + 225,213,218,11,188,135,139,147,147,124,221,223,199,251,152,145,243,99,180,126,70,168,247,4,233,17,140,8,209,225,1,34, + 134,254,13,30,23,4,1,149,173,55,92,157,157,69,85,9,195,144,124,62,143,181,150,48,12,201,229,114,136,8,141,70, + 3,197,176,56,95,36,149,74,209,237,118,169,213,43,72,187,221,198,199,30,85,77,66,2,136,227,24,48,116,58,29,188, + 247,0,120,85,172,181,232,96,78,44,92,153,154,225,245,250,58,24,195,68,54,203,206,78,3,239,99,198,50,227,188,219, + 221,5,85,198,50,19,40,80,171,213,18,72,2,248,252,233,35,197,98,161,111,161,209,32,151,187,134,115,142,122,189,206, + 124,177,136,136,80,173,214,112,206,81,40,20,146,42,55,43,27,200,32,118,156,115,120,239,241,189,30,214,90,156,115,136, + 72,210,119,17,3,244,75,79,165,82,39,187,48,121,121,154,202,230,91,192,48,158,205,178,93,175,227,172,37,61,60,204, + 118,24,98,84,25,10,2,126,15,218,60,58,58,74,20,69,39,95,226,252,194,2,0,214,90,226,233,105,12,96,68,208, + 65,128,70,132,189,189,47,124,255,241,141,195,232,96,16,114,31,80,174,86,55,206,252,157,255,0,132,92,203,16,0,89, + 204,210,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Calendar = { //size: 603 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,251,0,251,0,251,85,89,109,150,0,0,0,9,112,72,89,115,0,0,11,18,0, + 0,11,18,1,210,221,126,252,0,0,0,7,116,73,77,69,7,213,6,3,15,29,43,75,94,175,19,0,0,0,62,116, + 69,88,116,67,111,109,109,101,110,116,0,67,114,101,97,116,101,100,32,119,105,116,104,32,84,104,101,32,71,73,77,80, + 10,10,40,99,41,32,50,48,48,51,32,74,97,107,117,98,32,39,106,105,109,109,97,99,39,32,83,116,101,105,110,101, + 114,39,51,239,88,0,0,1,158,73,68,65,84,56,203,157,147,177,138,26,81,20,134,191,59,115,103,28,80,80,176,16, + 123,11,5,17,130,1,21,124,5,43,9,193,98,11,193,224,110,49,181,181,189,196,128,32,90,167,77,47,250,2,98,37, + 34,193,38,33,149,133,173,144,197,217,48,222,20,50,119,103,214,221,37,155,83,205,156,123,206,119,207,255,159,25,241,225, + 99,243,27,208,228,255,98,34,129,102,247,211,221,155,59,227,241,56,159,191,12,110,101,144,216,108,54,0,8,33,254,9, + 80,171,213,0,144,0,153,76,134,82,169,116,213,44,132,120,54,39,165,228,124,62,95,0,229,119,239,41,22,139,36,147, + 201,200,4,225,230,167,32,199,113,72,165,82,44,22,11,228,75,55,62,125,14,194,52,77,12,195,0,192,243,78,24,225, + 230,201,100,66,181,90,37,159,207,227,186,174,206,151,203,101,178,217,44,167,211,9,33,4,190,239,107,96,4,208,233,116, + 88,173,86,244,251,125,102,179,153,214,57,26,141,46,122,165,196,182,109,76,211,212,0,25,6,236,118,59,218,237,54,135, + 195,1,215,117,117,161,109,219,186,198,48,140,136,36,35,236,65,46,151,99,189,94,51,24,12,24,143,199,248,190,31,209, + 44,165,68,41,133,101,89,215,19,0,244,122,61,150,203,37,158,231,209,237,118,113,28,7,203,178,104,181,90,212,235,117, + 230,243,57,141,70,131,88,44,246,188,132,233,116,170,71,12,118,45,132,96,191,223,235,13,72,41,35,18,52,32,157,78, + 107,211,2,151,149,82,40,165,16,66,160,148,194,247,125,125,150,72,36,30,1,199,227,145,225,112,120,245,13,188,246,94, + 40,20,46,128,135,135,63,108,183,91,42,149,202,139,197,225,8,12,13,124,144,219,239,155,27,224,235,253,253,239,55,255, + 145,63,127,253,184,249,11,104,130,125,246,45,41,107,239,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Chat = { //size: 422 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,6,6,13,5,59,224,168,3,114,0,0,1,51,73, + 68,65,84,56,203,149,147,65,78,132,48,24,133,223,79,155,176,109,34,18,247,19,111,97,244,30,198,149,196,3,152,56, + 25,131,58,139,137,16,96,244,4,70,99,226,17,52,46,245,2,156,132,160,48,43,23,99,169,27,74,42,3,136,127,194, + 162,180,239,235,123,253,91,130,81,81,18,28,1,120,194,248,154,163,5,80,255,169,40,9,20,239,194,230,121,14,165,20, + 148,82,189,91,187,174,11,0,224,81,18,92,1,88,232,137,120,25,14,122,222,223,59,192,100,178,219,140,57,128,197,108, + 234,143,14,29,47,195,13,0,0,32,203,178,94,17,17,129,136,224,56,78,51,222,0,12,9,77,193,104,128,41,110,67, + 180,147,78,64,151,176,237,64,159,69,85,41,143,247,217,29,3,241,207,47,31,248,95,150,187,0,70,171,137,155,185,138, + 162,0,17,65,8,49,216,74,249,45,79,24,103,119,0,20,133,209,245,177,101,209,253,108,234,163,44,75,41,132,96,67, + 151,105,123,107,231,214,243,188,179,198,130,126,3,250,50,197,203,16,159,31,197,225,203,243,235,187,94,196,24,171,108,219, + 150,0,214,105,154,126,1,88,155,93,32,51,215,170,92,157,38,241,205,91,61,103,1,144,0,170,250,83,245,255,95,0, + 165,115,93,248,243,71,0,172,22,178,122,77,213,130,72,51,210,15,141,12,145,160,100,148,198,107,0,0,0,0,73,69, + 78,68,174,66,96,130, +}; +const nall::vector FileManager = { //size: 378 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,6,16,18,41,48,44,67,93,90,0,0,1,7,73, + 68,65,84,56,203,189,146,189,74,3,65,28,196,127,251,145,69,177,176,73,44,124,128,128,207,225,19,8,130,136,31,129, + 136,104,37,34,104,173,32,10,130,181,165,112,6,242,20,190,78,138,120,8,90,104,178,183,123,107,17,15,205,37,94,238, + 82,56,229,252,255,59,179,179,179,226,168,221,4,216,19,130,136,10,8,129,125,224,73,103,135,175,78,46,73,146,1,225, + 123,90,4,33,36,215,15,183,81,8,32,142,15,154,225,188,125,138,148,211,151,245,48,198,153,250,4,175,134,49,55,157, + 14,58,35,30,163,59,250,214,148,186,254,138,177,180,118,47,70,6,25,217,183,134,237,213,151,82,2,221,94,131,193,231, + 59,90,215,144,204,9,169,70,222,114,150,83,183,215,40,20,210,191,115,253,181,156,231,151,148,35,245,14,231,146,31,129, + 245,250,219,92,81,52,128,181,31,60,199,203,149,90,216,202,71,168,218,130,79,253,236,71,44,213,6,64,234,221,255,182, + 48,33,96,236,43,155,27,135,99,131,212,123,164,82,164,222,231,62,208,56,39,90,59,107,247,139,11,254,76,235,218,84, + 7,231,146,194,8,95,134,90,101,183,231,143,210,134,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Mail = { //size: 550 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,18,0, + 0,11,18,1,210,221,126,252,0,0,0,7,116,73,77,69,7,213,6,6,12,23,54,231,47,101,43,0,0,1,179,73, + 68,65,84,56,203,197,147,65,72,20,97,24,134,159,89,70,247,119,112,23,215,177,173,131,167,234,88,104,23,221,240,212, + 146,134,134,129,6,65,25,102,97,68,68,224,69,139,60,111,108,219,65,17,4,145,144,78,118,232,32,136,29,234,166,201, + 222,108,219,14,9,230,213,52,88,171,63,98,254,29,115,103,60,168,131,131,163,16,8,126,199,247,251,222,231,127,127,62, + 62,56,238,210,130,196,116,38,85,15,228,2,90,23,158,14,12,126,62,148,152,206,164,234,211,153,148,27,84,233,76,202, + 221,129,7,39,216,125,249,73,255,51,150,22,243,252,150,146,98,209,230,231,250,47,254,252,149,116,223,185,207,139,151,207, + 125,73,180,131,204,185,124,158,120,252,20,85,85,49,52,45,132,82,54,170,88,36,153,76,250,32,250,158,0,185,219,183, + 186,249,240,126,134,229,229,111,180,180,92,37,86,93,77,69,133,129,97,24,0,100,179,89,166,167,222,114,175,167,151,137, + 215,175,114,128,182,23,128,105,214,96,89,54,61,119,31,120,166,221,42,20,10,152,166,137,8,235,68,34,81,79,247,1, + 132,16,52,54,54,240,110,102,154,75,201,203,0,88,150,133,82,10,165,20,139,95,191,208,126,173,3,33,68,48,0,224, + 68,60,78,226,98,130,55,147,147,156,61,115,26,128,242,176,206,202,202,15,58,175,119,162,135,252,155,215,131,86,25,141, + 68,49,99,149,52,95,105,246,180,209,145,33,202,117,13,219,182,17,84,122,122,104,159,219,117,153,155,155,229,198,205,46, + 79,114,74,155,60,124,244,152,143,243,243,40,101,249,198,247,1,62,45,44,208,218,214,198,230,134,141,235,56,148,254,109, + 160,161,225,148,28,234,206,159,227,251,234,218,193,95,144,82,210,144,104,218,110,232,97,223,96,25,32,140,8,53,39,107, + 145,82,6,2,134,199,198,71,251,254,227,142,134,143,228,26,183,0,252,253,172,100,78,184,216,168,0,0,0,0,73,69, + 78,68,174,66,96,130, +}; +const nall::vector Monitor = { //size: 611 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,10,19,17,58,52,159,194,36,103,0,0,1,240,73, + 68,65,84,56,203,165,147,61,104,20,65,24,134,159,221,153,157,221,189,194,20,34,18,209,75,97,12,66,208,72,2,1, + 33,96,97,115,96,17,36,106,180,17,82,88,137,193,70,17,15,46,133,164,176,178,49,130,149,86,134,147,72,136,88,156, + 66,42,27,65,68,61,73,180,9,130,7,241,206,52,10,130,119,59,127,22,49,49,33,39,74,124,225,101,186,103,158,225, + 251,38,40,149,138,15,128,115,108,35,222,251,105,74,165,162,111,181,154,190,217,106,250,191,197,57,231,51,157,173,183,84, + 42,122,185,70,155,184,59,79,185,82,253,167,155,71,11,135,185,112,162,7,0,9,16,69,138,114,165,138,234,0,37,99, + 136,20,103,142,46,67,16,50,251,166,11,156,7,60,24,139,54,134,114,165,202,248,233,62,0,194,141,100,21,167,68,105, + 202,217,161,58,23,135,7,17,74,146,38,9,105,46,69,37,41,34,151,144,36,9,0,214,152,223,6,107,17,42,70,36, + 49,253,61,123,8,115,5,250,187,27,168,232,19,143,23,14,32,188,3,35,201,66,13,128,177,118,171,65,148,40,70,6, + 107,236,219,213,193,203,165,6,93,249,83,136,72,146,36,49,81,162,16,113,132,138,213,159,13,78,14,212,8,3,137,200, + 21,224,219,44,65,48,130,144,130,171,199,159,179,80,223,141,179,14,235,44,83,111,3,140,109,3,184,60,122,157,128,128, + 143,181,25,222,47,127,37,191,23,14,229,119,114,164,211,48,216,55,142,247,0,158,169,251,183,218,3,110,207,220,68,40, + 129,148,17,66,10,62,55,230,232,221,63,202,195,215,53,204,247,59,88,99,177,198,254,122,130,221,10,120,242,174,155,40, + 85,168,88,17,197,10,33,63,112,176,243,25,190,89,35,12,2,158,46,245,210,252,145,1,139,237,13,96,117,222,22,71, + 232,29,206,57,46,61,234,192,249,29,104,109,208,86,99,113,171,6,27,1,90,103,140,13,15,112,111,238,213,38,220,226, + 60,192,139,182,155,184,242,101,101,179,193,149,243,67,92,27,59,134,214,25,89,43,67,27,141,214,107,231,134,26,77,163, + 81,95,135,73,96,122,114,242,198,246,127,227,255,230,39,112,67,0,83,217,168,244,129,0,0,0,0,73,69,78,68,174, + 66,96,130, +}; +const nall::vector Terminal = { //size: 668 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,10,18,21,37,27,70,252,216,25,0,0,2,41,73, + 68,65,84,56,203,125,147,207,75,84,81,20,199,63,119,124,51,42,100,65,134,209,194,192,18,10,87,174,92,181,168,69, + 203,54,237,130,210,106,145,186,8,23,65,96,173,130,54,181,14,74,176,69,98,130,254,1,181,45,37,8,194,162,52,80, + 35,157,177,24,43,29,125,142,153,239,221,95,167,197,27,103,70,45,15,28,238,189,220,115,63,247,123,14,231,168,161,231, + 131,7,141,177,253,214,218,238,56,142,27,140,49,84,220,98,108,245,57,113,103,221,122,20,199,143,181,214,15,2,165,212, + 253,163,77,199,122,78,182,180,166,51,181,117,128,128,240,79,243,222,177,94,44,146,95,202,55,142,79,188,190,157,91,204, + 166,3,224,250,137,150,214,244,149,174,78,166,63,77,179,159,137,36,228,211,109,167,232,237,233,205,228,22,179,61,129,136, + 212,41,149,226,203,220,28,163,47,31,225,197,33,34,120,113,120,239,17,73,220,121,65,196,225,189,163,243,66,63,169,148, + 66,68,14,5,21,121,194,212,199,89,192,225,189,148,64,201,227,109,144,23,193,121,11,128,117,201,90,5,240,52,54,53, + 36,193,222,227,177,120,239,240,37,64,108,182,8,215,151,9,55,11,0,56,231,118,2,68,132,169,15,51,244,245,222,229, + 217,200,19,150,11,121,4,193,57,75,33,252,73,20,109,38,129,74,37,31,238,1,120,161,190,33,195,171,55,47,184,209, + 213,71,97,109,153,193,145,135,172,21,126,65,141,165,254,64,109,9,64,41,133,93,0,47,158,217,233,121,86,127,252,161, + 163,253,28,153,160,150,247,147,159,17,239,203,143,80,149,237,158,20,16,32,112,220,236,190,197,240,216,0,111,39,39,8, + 210,10,168,41,41,87,59,20,184,221,69,4,248,58,251,141,75,87,47,130,8,40,120,55,62,83,190,211,58,230,204,249, + 246,242,217,57,191,171,6,128,243,46,169,145,74,1,208,113,182,173,74,186,66,165,82,251,40,16,40,174,110,253,191,13, + 171,242,223,81,3,165,148,6,169,111,62,222,204,194,194,66,185,93,247,179,198,35,135,137,226,8,165,212,239,0,212,112, + 54,55,127,109,108,108,52,216,216,40,18,134,33,97,184,70,20,69,24,107,176,214,98,183,39,209,90,172,53,104,163,89, + 89,41,104,224,105,32,226,239,228,151,190,147,205,205,95,54,198,100,180,214,149,81,54,166,12,217,30,101,173,53,70,155, + 216,88,59,36,34,247,254,2,215,162,130,23,152,77,245,29,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector TextEditor = { //size: 574 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,9,22,18,55,41,59,82,2,72,0,0,1,203,73, + 68,65,84,56,203,165,147,77,104,19,65,20,199,127,51,221,163,72,22,34,45,226,177,224,41,160,88,43,1,15,130,21, + 132,120,236,69,208,182,39,175,165,23,21,60,138,32,197,32,245,34,126,128,154,22,138,49,189,91,26,17,77,92,16,237, + 193,98,211,141,27,76,253,192,213,108,235,16,21,90,145,205,120,48,67,179,109,106,43,190,203,255,13,204,251,207,111,102, + 222,131,255,12,97,146,226,93,250,128,25,224,216,86,122,120,136,188,169,147,0,151,71,47,157,1,102,14,30,119,216,142, + 182,18,88,77,189,1,240,237,249,57,182,163,87,79,74,221,172,59,45,141,211,222,84,64,89,21,88,221,147,167,172,10, + 252,232,122,216,86,95,76,75,6,199,138,28,233,31,6,24,55,4,196,227,113,196,137,165,63,139,125,77,101,77,125,223, + 39,127,79,50,116,237,25,31,158,140,51,183,16,132,64,135,213,122,31,165,20,245,122,125,195,75,7,65,128,155,73,173, + 21,123,203,124,45,77,117,0,61,17,3,219,182,177,109,59,82,236,251,62,110,38,197,224,88,145,197,199,25,94,149,151, + 81,165,28,64,207,200,100,99,246,175,4,230,228,129,116,129,197,124,134,185,183,10,85,202,241,115,255,69,206,159,189,48, + 11,136,77,9,180,214,20,210,189,12,92,121,138,55,125,135,202,231,239,168,249,7,188,239,26,166,179,205,55,70,8,180, + 214,100,179,89,126,201,67,204,59,14,239,62,213,89,122,61,5,189,105,118,173,172,0,218,52,161,110,75,16,134,33,187, + 63,166,121,244,165,155,251,185,28,221,242,37,59,251,110,145,76,38,113,93,151,55,149,5,140,139,92,79,80,173,86,241, + 60,143,145,201,6,71,59,43,172,238,72,16,30,24,37,145,72,96,89,22,150,101,69,186,120,3,65,44,22,67,107,77, + 173,86,67,107,141,148,18,173,53,66,8,132,16,173,219,27,17,3,165,20,142,227,108,58,117,198,100,125,24,131,137,155, + 183,175,159,250,135,41,158,48,201,111,90,157,232,152,121,9,252,18,0,0,0,0,73,69,78,68,174,66,96,130, +}; +} +namespace Device { +const nall::vector Clock = { //size: 897 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,9,15,8,58,5,128,132,46,85,0,0,3,14,73, + 68,65,84,56,203,101,146,75,76,92,101,28,197,127,223,119,239,188,152,185,119,96,34,8,210,202,35,88,29,108,48,150, + 190,226,162,177,59,220,152,138,193,186,32,26,54,38,68,87,181,53,38,44,77,99,26,31,137,198,68,77,172,53,177,139, + 62,240,17,77,76,163,46,176,5,77,85,40,5,58,88,43,218,17,233,76,167,204,12,195,204,189,195,12,119,190,207,141, + 109,40,158,228,236,206,57,255,71,142,96,19,142,28,24,25,210,146,23,5,226,97,148,14,8,67,122,90,138,27,85,181, + 126,230,157,207,94,127,101,179,94,108,48,246,104,248,116,247,190,71,123,182,247,198,9,71,194,8,1,90,67,113,181,196, + 204,84,130,75,151,230,211,131,195,231,142,245,60,146,10,34,117,146,80,242,180,185,193,124,97,112,120,192,46,27,138,85, + 159,131,40,190,118,103,138,221,113,140,120,224,65,26,59,83,205,141,205,149,55,61,189,115,213,208,191,172,8,183,93,73, + 0,141,62,62,56,60,96,223,88,43,208,254,80,136,104,245,237,187,214,180,235,45,182,110,107,161,119,111,142,104,195,46, + 131,192,187,13,200,167,163,192,14,121,228,192,200,208,238,125,59,118,150,180,71,91,87,35,45,91,226,155,207,68,74,137, + 16,2,51,16,67,178,68,165,116,2,167,52,19,4,253,131,4,6,182,247,198,89,46,103,105,109,109,166,144,255,135,248, + 227,167,72,103,125,119,63,75,8,42,94,31,158,232,39,149,172,114,242,195,7,170,120,242,156,169,209,123,194,145,48,150, + 23,66,41,133,207,103,81,118,139,132,234,44,70,94,218,134,223,222,203,115,109,57,108,219,66,200,24,210,127,16,195,187, + 201,194,212,199,209,161,23,250,131,18,168,23,2,154,154,26,200,23,242,40,165,168,41,141,227,20,57,250,222,239,68,98, + 221,76,76,76,160,148,66,107,133,97,26,152,134,4,165,5,208,101,2,43,90,19,43,187,85,58,58,218,169,84,214,80, + 74,81,44,22,233,238,238,230,229,195,175,114,237,218,85,106,181,26,82,74,180,82,104,13,72,52,176,32,5,226,162,83, + 114,88,252,59,141,82,10,207,243,240,60,143,67,135,14,147,72,36,200,100,210,88,150,69,173,86,195,178,108,202,110,25, + 167,228,128,207,112,63,57,253,150,35,129,179,115,147,243,216,134,133,83,114,241,249,252,140,141,141,49,58,58,74,42,181, + 116,39,48,28,142,160,53,44,95,207,50,55,57,79,133,218,12,128,124,227,203,163,39,126,62,63,53,217,24,182,25,255, + 254,87,180,214,244,245,61,65,58,157,98,173,82,65,107,77,32,16,192,52,77,242,153,28,238,178,203,197,31,167,171,95, + 77,156,121,6,192,0,232,188,183,107,110,97,54,249,236,254,253,143,249,255,252,99,145,92,33,207,253,109,91,8,6,130, + 4,131,33,252,190,0,55,255,202,144,191,190,194,201,15,206,234,217,165,217,247,167,230,127,154,3,178,6,192,76,114,58, + 239,55,253,87,150,174,102,246,52,53,196,162,109,45,173,120,69,143,74,126,141,114,182,204,173,228,45,46,143,207,242,245, + 231,223,174,143,255,118,225,248,249,233,239,190,1,210,64,78,108,232,74,61,208,249,228,174,254,231,239,187,103,235,83,117, + 254,186,22,41,164,169,209,202,93,119,139,233,66,58,241,197,248,169,143,128,20,112,5,88,4,180,224,255,136,252,23,118, + 155,26,40,3,171,64,22,40,0,234,182,248,95,201,36,100,6,22,194,54,223,0,0,0,0,73,69,78,68,174,66,96, + 130, +}; +const nall::vector Display = { //size: 662 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,2,19,73,68,65,84,56,141,165,147,203,106,20,65,20,134,191,83,85, + 115,109,72,50,32,6,98,18,35,38,11,183,222,54,186,112,99,6,29,240,25,124,4,55,130,184,81,80,4,241,49,124, + 131,108,92,8,9,17,34,226,222,96,188,129,38,16,131,97,72,156,233,234,233,158,238,58,46,58,17,19,3,65,60,155, + 42,170,234,255,207,119,206,161,164,221,110,243,63,225,58,157,206,29,17,121,168,170,181,127,17,138,136,87,213,187,78,85, + 31,183,111,92,143,154,141,38,121,174,199,103,116,130,181,134,110,183,91,95,90,124,245,196,169,106,109,116,116,132,249,155, + 207,73,233,3,160,122,132,209,222,81,77,34,94,190,184,205,200,232,40,64,195,237,223,167,161,207,133,171,99,136,200,30, + 34,128,148,171,0,90,238,223,44,111,179,250,238,61,83,83,147,37,81,154,166,128,160,226,136,211,80,10,20,68,228,128, + 73,54,204,217,238,254,4,28,103,103,103,49,18,74,3,239,61,33,20,24,99,24,228,82,102,43,155,4,148,194,205,31, + 59,196,62,5,160,97,90,124,88,91,99,122,122,146,36,73,112,73,146,80,20,1,140,35,201,203,108,138,32,64,156,164, + 236,244,18,84,29,149,250,94,181,137,101,122,230,52,21,103,240,222,227,226,56,70,131,98,76,133,65,112,251,0,36,233, + 144,108,104,112,181,232,224,248,172,229,243,199,79,204,205,205,210,239,247,75,2,69,17,107,73,131,3,5,69,81,107,169, + 216,35,134,97,135,76,156,154,192,24,202,18,188,247,0,24,227,176,213,232,111,197,161,24,154,62,69,81,160,8,113,28, + 227,66,40,187,217,106,56,178,205,193,177,6,81,213,33,70,49,34,37,129,115,174,183,254,109,163,245,236,209,249,99,197, + 191,41,210,156,245,245,13,128,29,233,116,58,183,106,181,218,3,17,141,64,12,48,83,169,56,87,169,86,197,26,3,64, + 17,2,89,150,105,62,204,135,192,87,208,160,202,174,247,201,125,151,231,249,66,158,231,11,0,170,26,181,78,140,189,157, + 111,183,207,93,186,120,153,241,147,227,168,42,91,91,223,89,121,189,162,75,203,75,171,73,111,112,37,203,50,191,79,35, + 135,191,179,49,102,164,222,172,63,109,70,205,107,214,154,51,128,22,161,248,50,240,131,197,222,110,255,158,136,196,127,190, + 255,5,119,143,242,70,185,147,13,30,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Joypad = { //size: 812 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,172,0,77,0,0,52,214,215,123,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,4,7,15,10,39,178,201,163,153,0,0,0,140,116, + 69,88,116,67,111,109,109,101,110,116,0,77,101,110,117,45,115,105,122,101,100,32,105,99,111,110,10,61,61,61,61,61, + 61,61,61,61,61,10,10,40,99,41,32,50,48,48,51,32,74,97,107,117,98,32,39,106,105,109,109,97,99,39,32,83, + 116,101,105,110,101,114,44,32,10,104,116,116,112,58,47,47,106,105,109,109,97,99,46,109,117,115,105,99,104,97,108,108, + 46,99,122,10,10,99,114,101,97,116,101,100,32,119,105,116,104,32,116,104,101,32,71,73,77,80,44,10,104,116,116,112, + 58,47,47,119,119,119,46,103,105,109,112,46,111,114,103,103,138,199,71,0,0,2,33,73,68,65,84,56,203,149,146,203, + 107,83,65,20,198,127,147,220,228,38,214,210,164,177,54,245,209,135,160,184,73,176,20,255,130,130,123,17,138,136,130,168, + 32,88,8,193,133,173,15,180,221,136,46,68,10,10,130,72,22,93,213,186,19,68,208,133,187,34,84,179,19,68,20,42, + 21,53,53,183,105,244,230,117,111,230,184,184,105,154,66,178,232,129,3,195,240,205,55,191,249,230,40,58,212,199,179,132, + 255,170,221,51,97,41,95,2,124,235,42,178,96,80,191,58,62,95,40,181,234,84,167,195,117,124,223,250,14,237,141,27, + 225,16,162,53,142,93,102,237,251,186,181,161,122,6,79,204,231,237,77,173,175,157,129,70,165,99,67,177,184,175,43,140, + 235,247,99,21,107,216,174,143,129,35,253,189,192,253,86,173,175,195,11,82,129,93,97,252,166,137,17,12,16,12,26,252, + 94,181,136,14,198,137,200,198,153,86,161,145,74,79,206,0,119,90,55,203,86,6,167,84,193,202,217,116,71,187,40,230, + 255,225,214,28,220,170,67,69,153,209,84,250,178,52,164,179,42,149,158,148,185,135,143,182,93,255,235,229,61,170,203,115, + 88,185,34,249,181,18,162,96,223,240,30,162,177,46,234,135,47,112,240,212,109,108,219,230,198,173,41,12,0,173,53,133, + 66,97,11,235,248,57,114,111,30,211,63,212,199,200,104,15,134,25,160,248,243,15,185,85,135,3,231,47,98,89,22,65, + 51,184,149,129,104,241,90,188,86,129,16,3,215,151,88,212,167,249,186,244,133,207,239,62,241,170,52,206,254,155,239,81, + 129,16,34,2,141,71,120,4,162,209,34,32,226,125,172,0,134,137,27,234,101,228,193,42,43,43,43,228,223,190,134,128, + 137,214,26,192,51,105,18,136,96,189,184,198,143,233,97,214,23,167,26,68,26,183,238,182,36,35,72,93,35,186,209,13, + 3,163,153,252,242,2,82,43,81,90,94,160,251,228,93,0,142,37,71,121,250,236,73,115,93,23,221,68,111,230,181,25, + 98,104,108,130,202,135,231,132,198,38,208,90,163,68,72,36,146,36,18,73,68,20,74,137,135,223,48,216,70,96,154,38, + 71,175,100,128,76,219,169,178,109,111,114,203,229,50,0,149,74,101,59,65,54,155,197,117,93,118,82,74,169,45,131,72, + 36,210,68,2,168,86,171,0,212,106,181,142,6,142,227,120,70,237,70,121,7,53,251,31,168,192,0,159,97,230,172,204, + 0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Keyboard = { //size: 587 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,1,200,73,68,65,84,56,141,181,146,177,107,83,81,20,198,127,247,222, + 115,95,95,8,73,159,136,180,209,38,177,21,7,165,21,26,16,204,228,34,102,8,8,34,212,168,127,72,193,191,160,131, + 45,174,29,178,184,180,116,17,212,12,25,4,23,137,32,168,56,85,227,146,162,85,112,145,212,190,151,52,125,185,14,109, + 53,29,164,193,226,7,151,115,46,231,124,223,189,231,240,169,82,169,196,113,160,15,146,122,189,174,142,37,48,191,48,159, + 30,134,80,169,84,252,193,187,58,24,161,88,156,157,242,60,223,3,239,187,136,216,100,210,88,99,196,199,152,139,190,245, + 175,2,87,28,76,3,30,74,189,72,38,82,229,106,181,26,203,31,45,127,195,57,123,201,250,186,108,69,143,59,103,50, + 32,99,86,108,216,239,179,174,148,187,15,242,174,213,106,253,204,159,157,104,110,111,255,40,0,175,127,11,52,26,141,93, + 224,205,254,249,219,247,131,252,228,196,50,142,157,173,173,206,251,67,59,56,10,115,119,230,174,163,226,183,202,169,200,104, + 175,80,171,213,186,0,114,20,113,239,229,91,151,193,61,82,112,111,101,101,237,249,96,77,45,173,45,37,78,118,131,166, + 159,24,57,163,181,70,27,141,86,123,209,104,131,214,10,173,13,206,57,0,246,123,94,61,88,120,88,4,144,157,86,120, + 45,83,184,112,106,102,122,6,107,61,68,4,43,22,99,4,173,13,56,71,223,245,137,162,136,48,10,49,90,211,104,188, + 156,173,84,110,158,95,93,125,220,20,17,239,118,144,62,225,133,97,135,205,175,159,72,37,211,160,0,20,74,41,218,237, + 54,249,92,142,56,142,249,178,249,153,108,54,79,106,52,144,245,15,31,111,0,139,98,180,46,7,65,0,206,145,61,157, + 99,183,31,31,154,127,52,157,166,215,235,1,138,169,201,115,116,186,93,50,99,227,102,196,179,119,129,69,137,227,120,227, + 233,179,39,90,169,225,157,236,156,3,199,55,24,112,226,191,98,104,31,252,55,129,95,252,113,137,228,164,151,154,151,0, + 0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Microphone = { //size: 703 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,234,0,234,0,234,127,141,58,17,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,11,3,22,42,33,208,235,186,119,0,0,2,76,73, + 68,65,84,56,203,125,147,95,72,83,97,24,198,127,147,205,182,83,179,72,234,44,200,180,11,239,148,4,217,148,88,151, + 94,118,37,178,65,116,209,77,105,119,65,212,141,12,138,254,152,55,117,227,134,32,212,244,106,30,70,187,216,31,208,139, + 188,137,8,141,109,72,77,93,218,137,153,108,122,108,24,56,143,121,56,235,34,119,218,104,250,192,199,247,247,121,222,231, + 123,191,247,51,113,136,1,79,255,35,192,199,209,152,3,178,82,40,124,187,122,209,84,33,187,156,46,95,111,239,85,186, + 174,116,213,176,138,197,34,0,91,202,22,35,47,158,1,220,147,66,225,87,149,253,134,195,222,231,118,95,163,245,82,43, + 197,98,209,104,138,162,160,170,42,11,11,243,172,173,174,242,224,254,67,128,151,213,1,204,149,129,67,188,128,215,235,5, + 32,22,139,17,143,199,25,27,27,51,14,90,173,39,176,9,86,132,147,2,245,4,30,139,162,232,243,251,253,104,154,134, + 162,40,184,221,110,186,187,187,255,94,126,238,29,0,171,107,95,145,191,203,117,5,124,51,51,51,140,142,142,26,14,162, + 209,40,129,64,160,198,129,165,209,66,211,105,59,117,147,24,124,61,229,91,89,89,65,211,52,44,22,11,130,32,96,54, + 155,89,94,94,70,150,191,241,99,99,131,66,33,207,230,102,129,125,245,55,246,38,251,155,233,144,116,235,72,7,137,68, + 130,137,137,137,154,104,103,206,158,198,227,241,146,74,37,153,159,255,116,3,48,4,158,244,245,245,13,183,183,183,163,235, + 58,249,124,158,142,142,14,130,193,32,187,187,187,200,178,76,38,147,225,195,199,247,164,82,73,50,95,150,48,97,106,168, + 206,193,240,236,236,172,225,32,18,137,144,72,36,24,31,31,199,106,181,26,14,218,46,183,145,74,166,41,151,203,216,237, + 167,226,53,207,216,211,211,131,36,73,0,100,179,89,68,81,100,114,114,210,32,71,99,81,28,162,131,240,91,9,193,38, + 80,218,43,93,175,17,40,108,230,17,207,59,72,167,211,0,168,170,202,226,226,34,154,166,161,235,58,7,218,1,219,63, + 21,0,154,155,155,41,173,151,106,11,201,31,240,51,120,103,136,206,206,78,116,93,167,92,46,163,235,58,154,166,177,243, + 107,135,204,210,103,82,169,36,192,158,211,233,178,229,214,115,255,4,164,80,216,52,116,119,112,255,249,200,211,70,142,199, + 18,224,0,108,255,149,178,178,189,53,221,114,177,133,220,122,14,41,20,190,121,148,194,128,167,127,170,238,95,0,34,78, + 167,235,92,197,218,49,136,84,79,254,0,227,216,1,121,79,52,137,54,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Mouse = { //size: 720 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,4,8,13,24,4,51,189,102,0,0,0,0,53,116, + 69,88,116,67,111,109,109,101,110,116,0,40,99,41,32,50,48,48,52,32,74,97,107,117,98,32,83,116,101,105,110,101, + 114,10,10,67,114,101,97,116,101,100,32,119,105,116,104,32,84,104,101,32,71,73,77,80,144,217,139,111,0,0,2,28, + 73,68,65,84,56,203,141,144,205,75,84,81,24,198,127,247,220,201,171,115,239,117,162,146,92,40,217,31,208,166,85,208, + 252,5,17,148,182,9,114,178,77,66,187,208,106,22,5,35,76,16,238,91,180,107,51,109,98,80,35,218,181,9,68,87, + 34,81,249,17,129,76,14,51,166,57,141,227,215,124,220,243,158,22,126,52,234,72,190,155,195,251,156,231,252,206,195,99, + 113,104,210,233,116,39,48,80,46,151,111,27,99,60,192,120,190,251,170,251,102,207,147,122,223,216,187,209,235,91,155,91, + 253,138,163,115,105,187,188,29,243,124,247,123,44,22,243,61,223,237,43,254,89,187,150,74,165,150,82,111,82,217,209,177, + 145,27,187,190,23,97,55,60,109,29,126,157,76,38,95,182,182,250,189,197,226,218,38,240,49,145,72,244,213,165,187,80, + 171,85,223,27,216,106,110,118,230,122,186,111,221,179,158,39,135,18,74,169,33,108,11,165,20,149,237,128,104,52,74,46, + 159,101,97,33,67,147,99,163,131,0,9,164,168,148,250,240,244,89,162,183,254,195,80,40,20,26,186,223,255,192,216,182, + 109,133,195,97,134,135,135,209,90,227,52,181,96,97,49,240,240,49,165,82,137,194,234,239,200,200,72,250,14,112,0,160, + 0,42,213,170,245,115,113,113,95,204,229,114,84,42,149,127,123,62,143,215,26,177,26,244,197,145,18,227,241,56,249,124, + 158,108,54,75,60,30,231,127,19,170,95,86,86,86,104,107,107,99,112,112,240,128,118,98,192,106,161,192,106,161,128,239, + 251,116,118,116,48,51,59,123,178,4,27,165,117,206,157,57,187,47,214,130,26,203,191,150,15,104,27,165,245,227,1,158, + 231,238,68,181,192,194,194,24,65,139,32,70,16,173,209,34,180,159,111,231,184,18,167,196,24,180,209,136,104,180,14,208, + 162,17,17,68,11,34,6,35,178,231,159,106,4,152,213,90,99,43,155,32,16,180,214,232,96,23,38,130,136,208,116,202, + 217,243,79,55,2,124,154,159,159,195,243,60,90,90,154,177,148,66,139,160,245,78,124,215,117,137,156,142,48,51,243,13, + 224,71,163,14,222,126,253,242,185,207,113,156,104,87,215,69,60,207,195,0,24,195,206,97,200,100,22,88,90,202,1,188, + 110,4,168,85,171,213,187,147,19,227,143,38,39,198,47,3,87,26,116,149,1,174,2,107,135,47,254,2,161,171,0,195, + 167,31,206,166,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Network = { //size: 408 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,18,0, + 0,11,18,1,210,221,126,252,0,0,0,7,116,73,77,69,7,214,2,16,22,3,20,11,54,9,17,0,0,1,37,73, + 68,65,84,56,203,157,146,61,75,195,80,20,134,159,155,92,242,63,164,46,221,2,226,238,32,226,38,82,255,131,17,10, + 34,56,74,196,42,232,228,80,63,210,95,32,4,99,5,255,134,131,110,46,130,56,152,22,170,129,214,170,225,82,18,7, + 13,26,242,97,240,29,207,121,207,203,121,206,189,130,2,181,246,182,61,160,65,185,58,178,164,217,88,152,95,164,86,55, + 115,155,131,167,7,188,174,107,149,5,80,171,155,44,55,47,48,140,180,77,169,9,87,206,10,0,165,1,66,8,12,67, + 98,206,78,3,49,32,0,184,189,190,39,138,190,60,178,140,245,180,189,207,220,20,168,151,30,143,98,134,247,15,197,235, + 56,76,121,100,69,86,122,207,111,223,21,29,128,56,142,127,16,170,176,70,163,97,170,254,123,131,74,172,238,225,82,102, + 179,204,17,117,93,163,63,24,231,178,58,71,7,121,132,118,42,224,230,174,15,177,200,101,93,91,109,166,38,53,77,227, + 196,105,183,100,98,82,106,130,49,28,101,110,144,40,8,130,220,35,203,132,231,242,184,81,248,10,0,238,249,89,97,64, + 199,235,186,214,31,127,222,182,183,118,118,139,2,172,141,245,77,194,48,204,157,76,88,129,194,0,124,223,231,191,146,101, + 124,85,244,9,241,192,132,130,214,14,135,66,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Optical = { //size: 720 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,4,5,17,7,21,115,1,202,165,0,0,0,140,116, + 69,88,116,67,111,109,109,101,110,116,0,77,101,110,117,45,115,105,122,101,100,32,105,99,111,110,10,61,61,61,61,61, + 61,61,61,61,61,10,10,40,99,41,32,50,48,48,51,32,74,97,107,117,98,32,39,106,105,109,109,97,99,39,32,83, + 116,101,105,110,101,114,44,32,10,104,116,116,112,58,47,47,106,105,109,109,97,99,46,109,117,115,105,99,104,97,108,108, + 46,99,122,10,10,99,114,101,97,116,101,100,32,119,105,116,104,32,116,104,101,32,71,73,77,80,44,10,104,116,116,112, + 58,47,47,119,119,119,46,103,105,109,112,46,111,114,103,103,138,199,71,0,0,1,197,73,68,65,84,56,203,157,146,77, + 107,19,81,20,134,159,51,153,102,22,195,224,100,96,22,83,157,44,252,248,3,69,212,141,40,110,10,34,234,90,93,184, + 149,72,200,63,208,130,80,68,132,88,104,69,65,17,17,68,255,129,74,214,217,104,73,180,38,168,203,102,25,33,208,132, + 4,146,185,199,197,164,205,4,233,34,61,171,195,185,231,62,239,123,238,61,82,174,148,30,2,15,56,90,172,81,174,148, + 244,40,209,239,247,181,92,41,169,13,96,140,161,215,235,45,36,157,119,242,0,216,0,106,20,53,10,178,0,65,153,1, + 140,26,140,42,232,20,50,61,76,211,255,10,233,125,213,140,3,85,140,73,0,65,208,131,78,157,245,131,128,152,140,129, + 44,96,223,133,0,70,1,145,153,160,234,1,216,72,150,152,29,193,24,52,209,84,83,4,85,69,84,81,217,87,19,68, + 20,213,67,70,112,28,135,229,227,203,135,190,215,96,48,0,96,56,28,2,48,26,141,230,29,52,26,13,198,227,241,66, + 223,232,121,94,10,48,137,33,159,207,243,230,237,171,133,0,151,46,94,73,1,98,9,237,118,11,128,167,79,170,76,38, + 19,70,163,33,221,191,93,154,205,6,182,189,196,141,235,55,169,213,106,4,65,64,20,69,172,63,126,68,16,4,83,128, + 8,190,239,19,134,33,219,219,95,89,89,57,139,239,23,240,253,2,167,79,157,1,160,94,175,227,186,46,97,24,242,249, + 203,39,28,199,193,117,93,0,114,231,47,156,147,223,127,126,93,222,219,235,179,243,243,7,190,239,83,140,139,0,116,58, + 29,186,221,46,158,231,17,69,17,31,62,190,167,213,222,33,73,18,154,223,27,136,200,218,220,242,150,238,223,187,150,179, + 173,103,241,137,248,228,234,234,85,138,113,140,101,229,216,237,236,154,23,47,183,44,160,5,172,111,84,55,223,101,246,139, + 108,110,221,190,115,107,169,16,28,123,110,89,214,221,185,213,87,125,45,34,91,27,213,205,111,217,250,63,189,144,236,196, + 0,156,143,39,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Printer = { //size: 481 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,17,0, + 0,11,17,1,127,100,95,145,0,0,0,7,116,73,77,69,7,213,8,18,15,53,11,122,248,175,234,0,0,1,110,73, + 68,65,84,56,203,165,147,205,78,34,81,16,133,191,91,176,224,33,122,235,204,138,16,34,179,49,242,24,227,248,48,218, + 254,60,129,154,209,103,16,120,2,122,199,154,37,59,113,167,38,36,205,95,104,18,187,105,238,45,87,32,61,252,77,244, + 38,149,155,186,73,157,58,85,231,92,248,230,49,171,73,189,81,187,2,252,255,168,187,62,249,253,231,98,237,181,222,168, + 105,146,36,59,35,142,99,173,55,106,186,168,201,111,130,111,183,219,91,91,87,42,149,76,190,17,160,88,44,126,206,104, + 76,230,86,213,221,0,206,57,58,157,14,0,34,178,6,84,46,151,247,51,240,60,15,17,193,24,179,22,123,25,168,42, + 173,86,107,217,81,68,168,86,171,187,101,60,247,207,174,0,191,80,40,240,227,224,39,206,185,12,253,213,241,140,49,116, + 159,159,136,227,24,224,122,193,192,191,240,47,177,214,146,166,233,94,19,76,38,199,136,8,247,15,127,125,89,93,82,183, + 219,37,73,18,130,32,64,85,9,195,144,209,104,196,96,48,96,56,28,210,239,247,233,245,122,52,155,77,222,94,95,178, + 59,136,162,136,248,253,157,241,120,76,169,84,34,12,67,0,210,52,93,82,7,176,214,50,232,135,196,201,44,11,32,34, + 76,162,136,32,104,50,157,78,1,152,207,231,136,49,56,103,153,91,139,72,142,124,46,199,209,113,117,179,10,214,90,14, + 43,191,254,49,140,226,156,98,173,69,68,150,242,46,150,188,4,152,205,102,120,158,183,213,113,11,21,68,4,85,197,57, + 151,1,120,188,189,187,57,253,194,111,126,252,0,186,104,203,229,25,65,188,29,0,0,0,0,73,69,78,68,174,66,96, + 130, +}; +const nall::vector Speaker = { //size: 592 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,1,226,73,68,65,84,56,141, + 165,147,191,79,83,81,20,199,63,231,246,245,165,68,168,3,193,201,63,64,99,66,4,139,128,113,100,241,71,88,40,88, + 162,46,36,242,106,58,233,0,127,132,49,93,173,12,13,137,160,169,105,2,196,133,196,168,131,131,137,16,23,69,172,147, + 58,176,184,152,247,76,244,93,222,61,14,198,218,22,140,65,191,227,57,159,156,123,190,223,123,175,168,42,255,35,243,167, + 70,126,58,159,11,130,32,253,79,3,10,133,137,193,20,242,56,142,227,212,129,7,20,10,19,131,105,63,243,84,85,179, + 173,245,161,224,94,112,122,118,121,172,147,247,46,77,79,134,64,198,243,188,175,168,222,73,251,153,235,51,51,51,217,202, + 221,74,210,10,58,167,239,141,104,53,23,60,236,223,168,76,126,105,110,32,72,166,124,187,236,205,207,205,31,86,152,43, + 149,74,217,209,145,51,120,158,7,64,110,118,169,56,114,109,233,232,230,194,213,39,10,235,104,124,179,205,130,162,244,245, + 29,225,248,177,19,168,170,12,156,60,69,38,211,133,136,0,32,66,111,34,148,1,68,101,69,144,209,61,25,188,217,122, + 205,187,198,91,0,26,141,109,182,183,183,176,214,2,144,114,44,2,99,34,136,26,247,10,116,72,4,105,102,0,16,134, + 97,115,101,187,107,81,126,191,141,93,163,137,168,164,0,172,209,196,79,164,45,120,3,16,70,33,97,20,162,170,216,216, + 98,99,219,4,4,83,64,244,153,42,234,37,169,1,96,83,91,78,48,0,81,20,177,179,179,3,192,135,79,31,137,109, + 220,26,191,167,164,111,252,132,245,130,194,139,182,107,84,85,173,215,235,137,136,88,35,102,113,117,117,229,242,248,197,241, + 238,95,192,203,133,43,183,0,134,139,247,71,129,60,98,250,59,45,244,168,106,183,115,174,123,121,233,65,209,126,79,206, + 173,61,90,139,156,115,109,94,93,226,134,65,139,27,149,233,207,173,117,217,239,51,77,77,77,157,197,184,245,67,93,61, + 189,213,106,245,219,30,160,51,196,78,213,106,181,231,56,115,222,247,253,100,191,254,95,55,56,136,126,0,228,148,200,42, + 201,231,90,24,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Storage = { //size: 603 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,4,5,15,53,8,235,207,124,119,0,0,0,140,116, + 69,88,116,67,111,109,109,101,110,116,0,77,101,110,117,45,115,105,122,101,100,32,105,99,111,110,10,61,61,61,61,61, + 61,61,61,61,61,10,10,40,99,41,32,50,48,48,51,32,74,97,107,117,98,32,39,106,105,109,109,97,99,39,32,83, + 116,101,105,110,101,114,44,32,10,104,116,116,112,58,47,47,106,105,109,109,97,99,46,109,117,115,105,99,104,97,108,108, + 46,99,122,10,10,99,114,101,97,116,101,100,32,119,105,116,104,32,116,104,101,32,71,73,77,80,44,10,104,116,116,112, + 58,47,47,119,119,119,46,103,105,109,112,46,111,114,103,103,138,199,71,0,0,1,80,73,68,65,84,56,203,165,147,77, + 110,194,48,16,133,191,160,64,164,32,203,201,38,106,36,246,112,55,36,196,13,218,222,144,21,39,64,44,216,65,108,16, + 249,153,233,34,224,40,237,162,85,153,133,237,25,207,123,126,51,182,225,69,139,54,219,245,7,240,254,79,252,39,155,237, + 90,255,99,206,57,221,108,215,26,3,136,8,231,243,25,85,133,40,2,213,177,76,64,159,67,4,160,204,102,51,0,98, + 0,21,165,19,233,179,69,6,0,16,17,33,170,125,140,168,199,247,206,64,32,42,72,39,68,15,144,2,168,62,0,202, + 83,24,170,61,177,208,171,13,10,84,201,243,140,211,233,244,167,206,101,89,70,215,117,0,76,158,65,231,28,69,81,252, + 10,46,138,130,186,174,131,31,154,232,189,15,9,0,215,235,149,170,170,0,48,198,144,166,41,147,201,132,203,229,130,247, + 30,99,204,64,144,36,9,139,197,98,116,146,181,22,107,45,0,222,123,234,186,230,118,187,253,80,20,3,236,118,59,154, + 166,25,109,180,109,75,28,199,97,253,221,242,60,31,247,160,109,91,246,251,61,199,227,145,170,170,80,85,84,149,36,73, + 56,28,14,24,99,194,236,156,195,57,55,16,168,42,34,194,124,158,50,157,78,195,35,1,104,154,6,149,158,76,69,250, + 220,199,13,132,18,178,44,195,90,75,89,150,0,220,239,119,128,208,237,229,106,137,136,176,92,173,16,17,222,202,50,148, + 252,250,103,122,213,190,0,151,85,237,38,182,108,181,11,0,0,0,0,73,69,78,68,174,66,96,130, +}; +} +namespace Edit { +const nall::vector Clear = { //size: 773 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,151,73,68,65,84,56,141, + 149,146,75,104,148,103,20,134,159,239,155,153,232,76,18,155,219,72,66,147,72,188,213,168,20,43,38,139,10,210,130,139, + 74,75,118,130,151,133,139,209,141,130,34,252,11,5,93,24,23,6,28,144,82,16,132,142,198,133,96,75,117,161,11,233, + 141,22,49,45,180,105,52,49,138,49,141,154,113,70,73,147,201,101,204,63,243,79,254,255,251,142,43,69,99,33,248,172, + 207,251,112,206,203,81,71,190,96,115,56,196,5,17,162,198,178,247,212,13,249,145,247,64,135,52,223,175,109,142,173,218, + 176,162,188,49,164,185,122,116,155,218,250,94,2,96,113,69,84,179,180,42,194,199,45,177,88,72,115,246,244,126,165,83, + 73,213,153,74,170,218,5,5,86,232,28,124,82,116,125,35,212,215,148,17,93,172,234,171,26,233,5,142,3,75,23,20, + 136,240,141,235,153,139,183,6,243,238,76,201,167,169,157,202,149,173,27,55,196,227,77,47,128,186,133,4,74,68,0,232, + 218,167,78,196,87,114,252,147,182,207,85,115,75,59,61,167,187,189,233,127,198,114,236,84,147,198,200,37,17,206,39,28, + 25,255,95,65,42,169,118,105,173,190,253,116,115,71,180,174,174,129,127,191,254,155,167,87,31,178,254,236,118,106,215,85, + 145,30,237,247,238,223,253,67,140,245,190,51,70,142,37,28,201,206,23,236,209,154,100,83,125,107,57,151,36,106,38,93, + 182,116,111,101,81,141,6,21,133,80,53,126,80,206,189,193,95,253,129,254,223,13,226,255,96,12,41,224,230,235,19,82, + 73,181,40,114,142,59,21,205,181,171,58,46,31,14,105,253,28,66,13,96,198,192,100,177,65,30,207,182,224,205,213,144, + 201,12,200,227,145,1,119,106,50,91,212,175,86,73,56,82,242,119,211,85,123,176,177,164,35,101,96,103,33,24,1,147, + 5,243,31,94,225,25,179,185,235,204,140,157,35,94,141,218,212,254,85,133,86,74,194,111,53,82,193,207,217,76,90,91, + 171,80,254,8,34,62,254,156,135,87,154,165,88,152,161,80,152,70,68,208,225,74,210,79,122,3,148,252,166,223,204,39, + 28,121,230,207,77,143,164,211,119,153,113,99,76,76,140,146,203,165,153,204,101,112,221,41,68,132,88,245,54,10,69,205, + 208,131,254,146,49,56,111,9,0,2,35,135,250,122,127,41,250,172,198,117,61,138,197,60,214,6,232,112,13,149,241,29, + 228,221,152,220,186,121,37,111,76,240,101,194,145,204,235,18,223,164,251,140,234,89,253,81,123,219,242,21,173,17,47,255, + 39,101,177,53,232,200,50,30,13,247,4,67,67,125,227,214,242,89,194,145,135,0,225,119,210,128,49,116,12,61,248,235, + 118,229,146,134,15,63,168,106,211,163,163,247,252,225,225,159,2,107,188,235,214,114,32,225,200,196,59,159,56,159,84,82, + 45,83,138,62,165,16,224,154,181,156,76,56,242,120,254,220,75,126,7,67,8,40,132,18,218,0,0,0,0,73,69,78, + 68,174,66,96,130, +}; +const nall::vector Copy = { //size: 498 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,10,26,20,8,47,131,20,52,155,0,0,1,127,73, + 68,65,84,56,203,149,147,75,75,2,81,24,134,223,35,51,99,218,128,253,10,207,8,221,22,253,143,8,90,182,136,160, + 117,23,240,66,182,176,69,145,118,219,68,68,68,27,177,54,5,254,4,49,179,54,129,101,48,163,191,160,154,48,5,55, + 205,237,180,105,116,70,71,177,111,245,157,195,121,31,222,247,227,59,228,232,36,51,175,235,250,44,70,40,193,207,189,109, + 174,197,239,156,119,156,97,24,211,241,232,214,40,122,164,15,246,38,1,184,1,118,211,106,53,193,24,235,19,17,66,0, + 0,161,208,132,39,148,115,30,106,181,26,94,171,149,133,198,119,99,102,144,139,253,204,110,202,238,121,158,191,117,1,36, + 73,66,177,84,152,250,71,164,69,23,64,81,148,78,140,86,171,57,84,108,71,114,1,40,165,40,150,10,157,179,44,203, + 158,226,72,36,210,63,3,198,24,100,89,118,13,210,249,112,80,185,0,148,82,148,202,197,161,14,122,161,156,45,182,44, + 6,69,25,205,65,48,56,142,118,187,221,5,232,186,14,198,24,194,97,138,242,83,105,168,3,74,37,152,166,129,202,75, + 165,11,208,180,31,4,2,99,176,44,54,212,238,229,213,5,30,30,239,221,17,4,158,175,158,157,159,186,22,135,49,203, + 211,182,40,138,88,89,94,133,101,153,80,191,84,228,174,179,224,54,214,163,121,0,121,199,114,108,27,134,225,235,21,59, + 75,85,85,228,110,178,0,240,236,243,26,146,166,233,240,251,253,16,4,1,162,40,130,16,130,122,189,14,128,224,227,243, + 221,22,167,18,177,228,28,233,21,31,30,167,179,166,105,46,121,125,172,191,42,0,40,36,98,201,29,0,248,5,66,89, + 166,3,21,136,247,216,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Cut = { //size: 807 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,10,28,22,29,49,104,65,100,94,0,0,2,180,73, + 68,65,84,56,203,133,147,93,72,147,81,24,199,159,115,222,119,175,175,219,212,125,165,219,108,248,21,104,120,209,85,16, + 116,97,148,73,87,69,222,100,34,17,104,105,150,88,168,105,129,144,4,149,165,125,129,136,16,148,24,232,16,244,74,144, + 36,186,12,2,181,48,109,51,54,242,99,239,54,117,155,238,117,95,239,118,206,219,77,206,97,90,231,238,252,255,15,63, + 254,207,243,156,131,32,229,60,235,125,114,14,0,222,243,60,239,109,186,121,187,116,143,215,207,178,236,165,59,205,173,186, + 84,29,167,94,24,134,25,187,213,216,172,141,70,163,203,125,253,175,59,83,61,5,171,184,112,230,116,185,230,197,171,158, + 79,7,2,8,33,252,79,135,29,215,213,214,87,16,66,142,237,232,79,123,30,151,153,115,205,166,237,144,136,40,165,39, + 14,4,96,140,67,75,75,191,128,79,75,67,177,88,172,116,39,5,203,178,83,133,133,133,224,113,123,40,165,212,241,175, + 4,21,54,155,13,86,93,43,168,174,182,190,56,145,72,156,234,121,222,61,80,82,82,162,64,128,193,225,116,0,0,88, + 15,4,220,109,189,247,25,99,188,188,184,104,7,62,141,71,146,36,29,215,235,244,215,100,10,176,190,177,70,1,96,162, + 173,165,227,225,129,0,0,0,74,105,229,194,143,5,121,109,205,3,141,55,154,84,241,68,28,137,98,16,230,230,230,36, + 0,232,218,91,255,23,160,173,165,99,26,99,60,100,95,180,209,96,112,11,107,52,26,16,220,130,44,203,242,187,182,150, + 142,233,255,2,254,164,152,154,157,153,198,78,167,3,210,57,30,50,223,14,70,16,66,111,246,171,69,123,133,49,163,177, + 151,80,122,61,190,185,169,38,229,101,50,51,249,17,21,24,115,64,32,116,11,33,52,80,233,241,180,239,11,24,51,153, + 58,227,126,255,131,163,38,19,36,40,69,222,173,77,217,23,222,30,102,101,84,85,144,157,195,240,28,71,37,89,6,231, + 250,58,40,178,178,174,86,186,221,67,201,22,198,205,230,26,201,231,235,42,54,26,233,194,202,202,84,48,18,150,2,65, + 17,215,196,105,77,148,35,58,150,193,52,16,18,19,142,213,213,15,71,244,122,18,243,249,6,199,205,230,221,151,58,106, + 48,8,243,69,69,100,132,97,238,3,0,204,88,44,33,171,82,153,216,241,71,24,134,124,201,53,7,1,0,134,49,110, + 255,150,159,79,70,13,6,97,119,136,177,152,94,146,36,82,69,200,163,9,149,234,165,130,101,121,132,177,61,57,105,142, + 155,81,243,233,170,201,140,140,190,203,148,118,131,44,83,32,196,176,11,224,56,65,173,84,50,95,243,242,98,38,157,174, + 105,94,16,188,138,204,204,43,201,143,164,213,54,124,119,185,54,14,31,58,212,48,107,177,196,8,165,24,48,14,0,0, + 48,0,0,213,90,173,207,229,247,159,244,75,18,27,0,144,57,181,250,236,69,65,72,238,220,42,138,238,234,236,108,143, + 55,16,200,241,135,195,26,95,36,226,83,168,84,231,173,162,232,254,13,160,243,58,7,220,52,193,60,0,0,0,0,73, + 69,78,68,174,66,96,130, +}; +const nall::vector Delete = { //size: 680 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,141,0,142,0,139,33,244,163,126,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,214,6,19,15,29,9,72,179,203,198,0,0,0,15,116, + 69,88,116,67,111,109,109,101,110,116,0,105,100,32,108,111,103,111,134,198,119,185,0,0,2,26,73,68,65,84,56,203, + 165,144,191,79,19,113,24,198,159,251,165,119,45,180,165,215,214,90,42,20,162,12,180,14,110,110,80,40,131,236,154,56, + 105,106,127,128,17,77,77,220,26,233,96,82,7,147,66,212,52,197,70,5,55,39,117,49,49,182,22,249,3,100,48,186, + 181,139,169,24,19,56,174,114,87,238,122,119,14,114,23,67,137,81,124,167,247,251,230,121,62,239,251,124,9,236,213,226, + 253,194,59,89,150,198,241,23,197,113,182,218,141,185,76,20,0,104,115,40,203,210,248,108,250,26,20,69,177,132,134,97, + 116,153,13,195,192,147,229,178,181,136,14,77,231,231,1,228,0,29,146,36,65,16,132,46,163,249,102,24,6,36,73,2, + 0,66,211,121,3,64,142,6,144,203,102,46,160,190,186,4,81,20,209,108,54,15,52,3,0,69,81,32,8,2,162,40, + 34,155,73,225,78,225,121,206,138,240,177,209,130,32,8,104,52,26,127,140,96,106,135,199,246,34,152,195,186,28,68,252, + 110,165,75,76,16,7,33,130,86,103,1,34,103,99,56,76,89,128,216,25,254,255,0,159,190,136,255,100,28,13,58,126, + 69,12,157,203,215,64,96,236,80,235,13,172,90,95,52,119,253,170,113,249,82,92,125,84,46,41,147,147,83,204,218,218, + 123,38,26,157,208,170,213,10,25,139,77,105,181,90,149,154,136,198,244,183,149,55,228,226,194,3,170,43,2,203,178,170, + 218,81,183,121,175,71,107,181,126,16,67,161,225,94,93,55,228,193,193,33,90,211,116,201,225,112,248,105,134,217,228,56, + 155,237,247,35,72,179,225,121,126,135,36,201,215,54,155,13,35,167,70,32,237,238,40,3,3,39,116,151,203,41,187,251, + 220,109,0,136,132,195,71,189,94,175,218,5,40,44,220,43,1,208,34,225,211,23,125,30,223,177,141,111,95,125,0,100, + 158,247,144,36,73,212,123,29,61,157,254,254,32,88,150,211,237,118,187,84,44,62,76,239,191,32,113,51,115,139,95,94, + 121,172,3,248,188,181,181,41,240,110,222,239,114,58,233,93,165,205,172,175,127,56,9,0,43,207,158,58,211,169,217,182, + 218,81,206,239,7,148,75,75,69,248,253,199,143,36,19,233,209,100,34,221,167,40,10,94,190,122,209,67,81,116,224,74, + 60,73,164,146,51,68,32,16,152,185,61,159,253,206,178,220,134,9,248,9,228,204,195,8,165,247,44,101,0,0,0,0, + 73,69,78,68,174,66,96,130, +}; +const nall::vector Find = { //size: 617 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,240,0,240,0,239,52,6,103,27,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,11,5,16,15,5,37,253,173,47,0,0,1,246,73, + 68,65,84,56,203,157,146,77,107,19,81,24,133,159,59,201,36,77,154,102,134,74,82,10,10,181,93,104,26,69,20,193, + 133,184,20,10,85,119,226,38,191,192,111,169,244,31,136,182,36,65,68,20,116,89,119,85,16,197,77,168,59,65,236,162, + 84,40,164,137,86,171,150,80,53,141,205,71,39,77,50,51,215,69,72,73,66,82,170,103,119,15,239,61,239,225,188,71, + 60,121,250,120,49,247,39,119,140,61,64,85,213,231,19,183,38,47,182,144,211,209,187,150,220,35,238,77,223,145,237,162, + 78,41,235,92,62,191,185,235,118,77,211,59,242,78,33,196,206,35,153,76,118,28,10,133,66,93,133,119,28,180,15,102, + 50,25,102,95,204,2,144,152,75,0,208,180,107,119,7,223,190,175,146,74,167,57,122,106,140,109,197,139,105,43,184,100, + 133,212,252,107,38,110,223,140,196,162,247,159,53,254,40,237,14,52,93,35,149,78,115,232,228,24,159,11,94,6,7,2, + 140,28,8,82,18,62,180,209,113,252,154,62,115,237,198,149,227,93,29,36,230,18,12,135,79,179,82,112,115,233,204,16, + 190,30,21,211,182,81,29,10,239,150,37,193,35,227,54,75,111,22,0,1,160,116,10,75,122,3,12,13,232,88,182,100, + 219,52,169,212,44,202,85,139,126,159,155,95,101,181,37,9,69,74,137,148,118,75,48,110,183,11,132,160,92,181,168,214, + 36,155,91,53,220,170,131,253,253,30,164,16,45,93,112,2,182,105,154,45,78,108,99,131,53,163,138,223,163,162,247,185, + 176,45,137,223,227,228,211,70,129,125,61,150,157,107,114,174,212,43,234,66,211,116,52,77,231,194,185,243,164,23,222,18, + 236,19,124,249,153,39,155,43,145,55,42,124,92,89,167,84,174,144,91,122,229,44,21,139,63,26,2,34,26,159,154,177, + 44,43,210,124,13,195,48,112,56,84,78,156,141,176,188,86,100,203,84,24,236,149,172,47,190,100,248,224,8,0,31,230, + 223,167,30,62,120,116,88,116,107,216,213,235,151,167,2,129,224,100,51,231,235,245,17,30,13,243,59,155,173,247,101,245, + 43,130,127,68,44,30,149,13,145,255,18,0,148,88,60,106,1,148,13,131,191,6,140,246,211,127,51,231,46,0,0,0, + 0,73,69,78,68,174,66,96,130, +}; +const nall::vector Paste = { //size: 561 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,9,112,72,89,115,0,0,11,19,0,0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213, + 10,14,0,28,21,175,226,241,24,0,0,1,208,73,68,65,84,56,203,149,147,177,107,83,81,20,198,127,247,189,52,130, + 36,49,141,212,148,12,133,34,6,92,92,180,106,98,4,209,18,112,118,208,33,56,20,69,109,29,196,197,65,151,130,56, + 8,142,250,15,52,131,187,155,168,75,213,46,186,56,41,145,82,168,209,72,66,94,111,108,208,70,239,57,14,161,49,47, + 109,32,126,219,253,206,61,63,206,249,224,24,6,84,42,149,140,239,123,207,157,147,217,126,223,247,189,23,206,73,177,92, + 46,107,191,111,0,110,206,154,43,6,30,42,140,43,30,118,242,18,185,220,17,60,207,0,32,162,172,172,124,96,95,237, + 41,6,1,104,170,234,173,199,47,89,50,243,103,137,248,158,9,46,156,57,24,251,210,201,240,46,200,210,180,29,166,167, + 167,48,102,27,32,172,173,173,147,76,68,57,154,252,204,164,191,206,179,215,171,86,84,83,17,32,230,121,102,44,26,241, + 121,95,207,178,120,255,17,65,16,80,169,84,66,171,205,205,29,34,149,74,113,239,238,109,46,102,190,33,170,49,32,26, + 233,255,212,222,130,68,34,129,170,48,51,115,108,48,30,226,241,56,91,127,192,169,233,121,61,128,106,40,27,150,223,188, + 13,189,11,249,28,187,41,194,16,157,62,149,231,31,92,16,113,195,1,186,75,97,123,2,85,69,69,200,157,60,254,127, + 19,20,242,57,68,4,17,65,85,176,214,50,49,145,30,13,208,223,40,210,109,110,253,104,141,62,129,136,235,65,170,95, + 171,52,26,245,29,33,135,1,3,53,231,186,128,86,203,210,168,215,41,22,207,15,219,20,111,216,4,214,110,80,251,94, + 67,68,122,254,245,249,171,92,158,90,30,190,194,222,49,165,25,52,73,167,51,164,211,25,178,217,195,88,187,129,170,112, + 99,225,90,175,217,55,26,2,108,138,232,239,246,47,183,231,68,242,35,15,22,239,240,211,237,140,166,176,255,19,171,237, + 3,0,36,181,138,49,102,83,85,59,6,96,225,92,247,26,49,140,51,130,84,187,215,248,228,21,75,127,1,79,230,225, + 152,120,105,196,218,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Redo = { //size: 591 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,214,7,26,10,39,21,63,184,237,33,0,0,1,220,73, + 68,65,84,56,203,157,147,77,107,19,81,24,133,159,59,95,77,140,164,66,76,99,131,31,109,54,213,118,211,210,42,126, + 84,99,13,66,169,56,110,68,43,130,184,26,112,173,59,193,191,224,126,86,221,117,41,68,10,133,138,197,82,186,106,164, + 168,27,193,77,117,33,41,98,76,38,77,154,201,100,198,205,24,39,157,65,130,103,249,94,158,195,185,231,190,23,250,144, + 110,106,158,110,106,211,81,103,18,253,107,91,55,181,194,127,27,60,126,96,0,188,209,77,109,46,56,23,17,113,7,128, + 60,176,8,76,1,147,1,3,150,150,77,128,27,69,195,94,15,25,232,166,118,1,120,62,39,180,84,182,112,117,88,77, + 141,230,16,2,85,142,97,217,63,41,125,91,225,202,232,189,30,19,17,128,23,128,23,143,242,249,243,242,80,78,170,217, + 101,188,218,167,158,116,31,155,53,128,174,201,185,61,123,86,248,240,4,240,242,225,181,235,55,99,153,51,88,149,117,44, + 79,35,238,218,0,12,58,13,54,219,206,223,226,132,196,165,145,187,44,45,155,40,254,236,233,157,179,227,147,177,116,150, + 250,175,119,36,90,13,18,52,24,110,85,120,69,2,71,234,237,58,61,120,178,123,13,5,96,64,213,102,143,143,77,167, + 227,214,123,178,251,85,118,164,4,154,34,168,29,137,51,238,67,23,21,48,235,22,153,99,167,217,92,253,208,237,64,1, + 232,184,110,70,200,130,84,195,98,171,84,247,214,90,149,208,235,76,92,62,17,130,187,123,224,116,156,228,209,198,87,182, + 119,118,89,107,181,45,224,25,48,85,52,108,81,52,108,1,240,54,57,20,130,129,110,7,236,55,171,238,74,93,72,192, + 253,162,97,175,30,78,224,195,51,69,195,46,69,110,162,170,200,7,128,23,5,251,10,193,193,4,27,205,189,178,90,144, + 189,24,166,54,127,216,228,207,53,162,36,3,140,221,150,221,47,7,237,250,173,153,220,143,212,110,249,148,208,213,173,207, + 175,59,118,63,127,36,184,137,35,192,2,80,5,54,158,36,221,239,2,188,249,69,167,243,47,131,223,215,75,186,5,94, + 207,53,222,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Replace = { //size: 776 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,214,1,6,22,4,3,245,118,104,130,0,0,2,149,73, + 68,65,84,56,203,173,147,77,108,12,97,24,199,127,51,179,179,181,72,183,204,44,193,129,86,208,137,224,160,137,131,160, + 184,52,113,32,82,73,137,175,99,75,138,90,65,164,68,16,130,138,34,113,173,68,19,196,54,18,209,131,75,125,180,68, + 72,137,143,157,165,69,98,91,149,212,110,119,103,63,186,93,187,59,175,3,59,105,47,78,254,201,147,60,239,155,252,127, + 121,158,55,255,87,98,156,246,29,104,212,52,77,139,20,207,209,104,84,191,218,122,45,202,63,36,21,27,255,161,3,107, + 75,189,101,93,75,86,212,136,20,83,37,85,140,137,190,151,15,164,132,21,95,119,169,165,245,209,63,1,141,251,247,106, + 186,238,139,44,172,170,97,32,237,97,229,226,89,152,225,24,233,100,2,43,212,137,203,165,160,40,178,99,82,85,53,224, + 111,58,188,5,192,5,160,235,190,72,249,226,149,124,177,74,168,91,93,206,36,183,130,170,200,116,135,4,51,150,108,96, + 248,125,39,199,142,54,59,128,243,23,207,214,22,123,151,115,59,217,199,188,233,165,20,108,65,54,87,32,155,179,241,149, + 150,240,117,104,12,9,176,172,56,0,94,111,25,37,111,142,115,121,171,44,128,29,206,92,106,33,193,224,112,130,112,36, + 67,60,157,103,142,230,193,45,23,208,167,216,0,132,66,33,0,90,183,41,236,186,210,67,117,237,126,128,155,50,64,194, + 138,175,235,123,221,197,204,82,9,115,96,132,145,212,24,47,204,239,196,82,25,162,239,239,179,105,227,38,12,195,160,173, + 65,99,247,213,103,12,62,109,231,157,57,88,0,144,1,166,149,77,239,170,40,159,79,248,213,61,42,124,37,244,132,126, + 146,28,205,50,252,186,3,93,211,24,77,143,58,230,129,39,55,121,215,31,101,196,236,80,128,42,233,204,153,83,98,238, + 188,114,124,186,78,208,12,146,74,167,156,103,89,182,116,25,213,107,170,105,107,208,216,121,169,155,112,79,59,111,63,69, + 137,153,1,128,170,166,91,118,175,11,112,204,7,155,252,88,86,220,217,23,248,99,110,121,74,255,195,54,62,126,79,18, + 51,3,252,90,84,207,145,147,215,123,1,73,110,110,62,33,5,205,32,249,194,47,187,104,50,12,3,195,48,168,172,172, + 228,155,188,130,224,243,231,244,15,89,196,130,119,169,59,253,2,219,51,219,201,144,12,224,63,120,72,2,16,194,97,32, + 132,224,198,30,157,207,63,162,220,9,4,136,124,232,96,85,125,7,147,180,5,228,114,185,98,4,132,60,46,149,118,62, + 159,159,0,104,186,101,179,126,230,103,106,54,239,102,121,195,99,196,228,57,36,147,73,114,185,60,128,50,49,72,128,170, + 186,241,122,221,14,32,147,201,144,72,36,200,102,179,40,138,130,170,170,127,203,5,96,79,0,40,138,114,251,66,203,185, + 237,66,136,9,83,20,75,146,156,127,135,199,227,105,7,114,252,15,253,6,121,205,27,12,206,189,173,89,0,0,0,0, + 73,69,78,68,174,66,96,130, +}; +const nall::vector Undo = { //size: 650 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,214,7,26,10,14,0,22,35,150,33,0,0,2,23,73, + 68,65,84,56,203,149,147,79,104,146,97,28,199,191,207,243,190,207,212,229,254,232,198,26,210,136,214,193,242,16,20,132, + 65,131,21,4,66,176,67,120,8,130,98,68,80,93,59,140,60,120,40,199,140,29,34,186,116,169,88,65,16,52,233,80, + 44,22,193,82,140,90,118,138,148,180,104,13,114,19,92,190,58,231,134,239,235,243,60,29,194,165,155,150,125,111,207,23, + 190,159,231,121,126,207,247,1,154,40,58,5,137,22,164,110,53,230,238,161,151,41,200,162,69,209,218,133,223,199,108,76, + 65,214,237,13,181,154,255,115,2,191,143,217,60,78,35,231,246,134,128,194,213,205,107,232,164,39,195,5,205,128,182,197, + 195,201,236,197,241,9,189,84,11,32,91,195,70,110,28,42,213,0,139,23,144,21,112,46,1,136,242,155,217,199,95,25, + 5,121,149,40,120,2,65,227,71,21,160,248,125,172,221,227,52,86,221,222,16,140,159,215,65,40,69,185,12,128,47,66, + 95,79,65,91,137,65,202,146,58,232,58,209,103,182,40,189,54,228,79,15,236,171,188,142,68,197,50,0,40,19,23,132, + 94,13,83,170,252,166,170,12,82,74,8,193,33,132,128,224,107,40,175,167,96,178,152,200,142,174,93,157,157,98,237,208, + 238,253,250,163,72,84,24,244,101,146,217,231,67,94,176,142,147,0,0,206,117,44,124,251,136,197,239,113,164,211,95,234, + 6,86,212,226,176,247,187,96,110,103,7,134,157,221,225,237,51,24,25,195,66,226,38,246,184,174,64,240,98,93,88,20, + 239,34,147,101,40,235,28,61,142,75,248,244,118,186,116,252,108,218,170,2,64,32,104,104,240,49,59,48,153,115,143,140, + 1,0,98,51,119,234,223,203,66,224,58,114,25,133,204,3,152,204,58,8,145,106,93,15,2,65,67,155,77,50,251,252, + 179,201,205,204,208,40,200,208,40,8,128,131,165,188,60,149,152,187,253,190,111,224,28,184,232,0,145,210,132,191,213,184, + 81,149,195,247,225,120,55,77,229,234,242,13,17,121,104,147,219,154,88,187,115,35,127,248,60,150,20,97,149,27,197,56, + 132,106,207,55,5,52,131,68,167,48,216,237,56,44,180,236,18,0,220,106,248,153,254,161,163,93,59,247,206,124,142,61, + 169,28,59,163,93,251,111,128,108,235,183,166,62,60,127,65,117,237,105,213,251,5,5,22,226,37,43,190,36,20,0,0, + 0,0,73,69,78,68,174,66,96,130, +}; +} +namespace Emblem { +const nall::vector Archive = { //size: 540 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,6,16,18,24,9,181,27,210,224,0,0,1,169,73, + 68,65,84,56,203,173,146,49,104,84,65,16,134,191,217,219,221,119,119,201,61,98,12,65,174,16,17,4,145,32,73,35, + 138,77,196,198,82,9,40,135,141,88,40,150,17,11,59,175,72,41,30,164,17,148,20,177,9,104,21,44,4,69,15,181, + 20,244,154,136,98,108,140,152,34,42,81,162,225,93,222,219,177,120,57,21,35,120,81,167,153,217,129,255,155,217,153,129, + 127,52,1,104,212,204,48,240,108,147,218,145,241,153,208,146,70,205,52,129,209,179,87,23,244,253,252,99,21,91,54,160, + 0,24,35,185,23,72,62,47,98,74,3,25,105,34,47,158,222,51,115,15,167,1,234,22,224,244,229,86,150,44,191,49, + 179,147,167,196,59,7,192,218,90,27,31,69,8,130,115,14,83,112,248,184,90,56,118,241,14,75,111,159,179,251,192,24, + 175,91,247,71,45,176,67,140,152,144,165,98,10,158,52,228,253,69,189,3,0,84,250,171,32,6,128,234,174,125,180,87, + 222,17,40,80,217,178,13,13,217,176,5,250,146,149,15,188,124,114,155,147,23,166,64,179,13,159,85,5,80,8,109,210, + 143,175,72,86,63,225,138,49,0,22,40,62,186,57,33,135,143,158,131,244,11,100,171,160,1,213,12,66,138,106,200,125, + 88,7,107,96,207,222,253,60,152,189,14,104,209,2,126,112,251,144,98,140,224,43,64,229,199,122,80,36,175,189,254,166, + 51,95,134,70,14,178,48,215,140,164,81,51,151,128,250,95,158,65,189,115,7,122,228,196,121,150,231,155,93,169,226,157, + 135,184,123,235,10,227,51,65,108,39,233,163,50,61,241,214,174,0,206,71,223,227,159,0,37,136,251,187,2,152,168,184, + 17,224,74,61,216,46,1,169,251,93,7,113,149,224,123,255,32,205,247,17,130,252,2,176,229,107,211,19,199,207,108,102, + 252,95,19,189,193,255,176,111,224,210,135,204,19,41,165,180,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Audio = { //size: 688 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,2,45,73,68,65,84,56,141,165,146,63,104,83,113,16,199,63,247,123, + 239,165,125,201,139,173,182,52,181,162,130,72,139,184,57,84,193,81,232,32,69,28,44,22,43,213,65,176,168,139,131,139, + 130,116,18,156,156,85,4,7,55,209,81,23,5,65,28,28,212,69,7,161,96,165,54,109,109,211,166,77,94,146,247,239, + 119,14,117,146,196,165,55,222,113,31,190,119,124,68,85,217,73,153,29,109,3,110,187,230,165,27,123,159,138,232,49,85, + 12,136,3,8,162,70,21,71,20,163,130,128,56,40,171,109,1,89,166,231,199,199,79,117,15,244,13,179,43,216,71,193, + 239,195,243,2,140,113,200,178,136,86,84,165,222,92,230,209,147,7,253,109,1,0,131,3,251,201,251,62,65,16,80,44, + 148,8,252,33,114,94,145,86,84,161,22,46,144,247,3,16,180,35,160,90,155,39,177,91,196,73,141,122,163,76,87,174, + 7,193,33,73,67,162,100,147,40,222,0,171,210,17,144,164,13,94,188,124,95,111,54,50,81,139,108,255,3,81,85,227, + 229,76,58,49,49,230,91,181,157,1,160,108,85,211,32,197,61,136,155,196,110,230,165,41,205,164,133,159,20,163,116,83, + 85,81,254,147,64,213,34,34,60,127,88,94,208,127,100,153,154,41,97,53,67,173,74,71,15,172,166,128,232,236,44,210, + 118,110,83,64,59,139,100,109,138,8,188,235,32,155,181,9,86,255,158,48,53,51,112,218,245,204,109,207,20,142,231,186, + 242,226,122,110,166,196,136,160,195,101,100,242,106,105,172,203,53,247,242,249,222,67,34,226,56,174,177,86,99,80,196,189, + 120,109,240,130,231,57,143,207,158,57,151,31,57,124,146,176,185,196,74,229,147,179,81,155,67,21,66,51,120,179,191,183, + 231,238,244,228,173,194,158,221,67,132,205,21,150,42,31,217,10,231,0,196,117,140,92,25,57,90,200,71,250,149,239,63, + 23,105,69,235,52,163,53,204,118,56,5,123,103,244,196,129,194,239,173,183,44,87,83,154,113,133,36,9,49,198,67,21, + 227,42,250,225,199,92,99,180,216,83,46,248,254,10,105,170,132,245,140,122,173,129,181,214,184,142,172,46,150,127,21,115, + 221,137,136,24,162,86,68,101,189,65,101,173,145,0,70,84,149,233,235,165,251,32,151,179,76,251,68,36,113,92,153,71, + 245,115,26,235,43,208,111,142,103,158,101,153,30,49,70,98,133,204,49,242,37,77,236,27,140,121,253,7,117,49,14,53, + 175,233,38,194,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Binary = { //size: 560 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,4,22,20,7,56,114,185,172,74,0,0,1,189,73, + 68,65,84,56,203,181,147,205,78,19,97,20,134,159,239,155,111,102,164,77,72,40,130,164,96,59,13,144,9,198,40,104, + 32,97,163,27,72,240,6,184,0,55,77,220,176,96,227,206,112,1,46,154,184,97,195,5,52,222,128,209,149,113,229,66, + 170,9,218,81,204,12,161,105,11,180,252,101,250,135,40,46,148,102,20,102,118,188,201,89,62,79,78,242,158,3,33,89, + 92,90,157,156,89,120,122,182,184,180,58,73,68,100,24,236,57,238,250,243,103,143,241,28,119,61,74,34,163,224,98,105, + 135,137,123,118,164,68,134,193,155,149,26,186,210,184,51,62,76,98,100,40,84,34,47,93,123,119,31,93,73,116,77,131, + 51,232,49,12,44,59,115,169,68,252,15,151,234,135,8,4,66,128,16,130,79,197,18,166,161,56,61,253,201,23,183,138, + 231,184,88,118,102,42,159,203,22,0,100,16,174,30,28,163,107,26,186,250,51,237,246,15,248,5,137,222,56,183,70,147, + 12,247,247,5,55,153,3,80,231,112,237,184,129,174,52,132,16,8,4,141,86,135,218,190,207,221,137,155,92,51,21,239, + 222,111,34,17,164,7,250,1,240,28,247,53,32,164,101,103,230,151,87,214,184,222,27,167,213,58,193,111,180,249,238,237, + 178,181,93,167,92,57,164,217,232,80,174,28,161,164,36,102,26,108,237,213,241,28,151,212,88,234,62,128,204,231,178,111, + 44,59,51,181,188,178,198,200,96,31,27,197,50,123,53,31,223,239,48,150,30,36,149,76,208,106,158,16,51,13,156,114, + 181,11,191,124,241,228,67,183,133,124,46,91,56,151,60,122,120,155,184,105,16,55,13,142,14,154,72,33,80,66,242,209, + 43,93,128,255,169,49,40,121,48,59,78,204,52,24,77,15,96,234,138,183,27,223,240,28,151,164,117,99,58,8,119,107, + 12,59,166,175,197,29,94,21,62,95,168,46,82,16,148,252,173,44,20,142,76,224,27,231,184,202,252,6,31,155,240,68, + 82,120,70,77,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector File = { //size: 741 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,0,18,116,69,88,116,84,105,116,108,101,0,80,97,112,101,114,32,83, + 104,101,101,116,115,185,175,145,249,0,0,0,23,116,69,88,116,65,117,116,104,111,114,0,76,97,112,111,32,67,97,108, + 97,109,97,110,100,114,101,105,223,145,26,42,0,0,0,39,116,69,88,116,68,101,115,99,114,105,112,116,105,111,110,0, + 119,105,116,104,32,97,32,72,85,71,69,32,104,101,108,112,32,102,114,111,109,32,74,97,107,117,98,134,84,7,179,0, + 0,1,238,73,68,65,84,56,141,133,147,77,107,83,65,20,134,159,51,247,166,26,80,209,104,177,181,136,27,107,55,138, + 127,64,68,220,248,1,42,184,240,71,40,226,170,11,23,130,63,65,20,44,85,132,46,42,22,63,176,208,160,155,254,27, + 181,177,109,154,144,80,53,201,153,153,227,226,222,155,220,166,130,7,14,51,12,243,62,231,61,51,28,49,51,234,95,87, + 111,136,200,98,8,241,52,24,102,134,25,128,1,252,1,89,143,49,60,191,123,231,222,58,227,97,102,172,174,125,252,190, + 211,106,90,140,113,95,14,6,125,219,104,252,176,181,47,171,191,87,62,188,125,156,193,71,233,0,250,253,254,204,177,163, + 53,118,127,237,210,233,182,217,105,111,179,213,108,176,241,243,27,155,219,13,186,157,14,55,175,221,170,78,158,152,124,178, + 252,110,105,190,108,192,1,168,122,0,66,80,124,240,132,16,178,140,17,245,202,86,115,19,231,28,87,46,95,173,30,152, + 56,248,244,205,210,171,75,99,0,5,216,39,142,49,16,99,36,196,192,251,79,43,212,235,117,46,156,191,88,197,108,126, + 15,192,171,2,150,139,125,46,204,196,209,34,83,211,83,204,205,205,50,115,230,20,206,57,233,245,122,215,95,188,124,150, + 236,113,96,249,131,154,25,6,8,130,147,81,86,171,85,142,28,62,196,236,217,115,168,250,68,85,43,0,105,249,13,138, + 16,192,4,16,65,196,145,166,46,59,23,161,40,24,45,50,2,120,45,62,53,147,11,8,142,196,9,137,75,70,224,2, + 224,21,139,86,2,104,1,112,56,103,24,130,12,189,148,151,108,227,189,39,134,184,23,32,128,115,110,120,187,168,38,185, + 163,50,64,213,19,67,40,3,60,32,164,105,2,150,139,165,228,162,0,152,32,34,120,85,66,25,224,243,22,146,36,29, + 86,23,100,228,34,95,45,27,16,84,149,48,222,2,64,226,146,76,92,206,146,131,108,182,254,1,16,145,70,187,221,154, + 174,213,142,243,191,232,118,59,128,180,212,107,63,107,203,140,135,143,30,220,78,43,233,130,14,6,39,205,192,48,200,71, + 186,188,7,163,82,153,216,86,213,251,139,11,175,63,3,252,5,198,186,65,227,184,230,144,207,0,0,0,0,73,69,78, + 68,174,66,96,130, +}; +const nall::vector Folder = { //size: 581 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,1,194,73,68,65,84,56,141,165,144,49,107,147,81,20,134,159,115,239, + 87,44,41,226,224,16,186,20,28,156,50,118,235,46,153,28,130,208,213,95,160,187,208,63,224,226,86,87,255,135,40,196, + 185,96,196,89,41,138,36,146,80,105,191,38,37,223,189,231,158,227,144,38,54,88,90,193,119,57,220,123,207,121,238,121, + 95,233,118,187,252,143,170,221,221,221,55,238,254,248,154,183,11,119,127,50,24,12,142,110,4,152,89,175,215,235,221,51, + 51,204,12,119,7,224,244,244,244,126,191,223,63,236,116,58,207,151,205,57,103,66,8,101,56,28,126,172,235,186,0,84, + 57,103,87,85,38,147,9,165,148,21,36,132,192,246,246,118,7,120,187,132,2,76,167,211,170,148,242,170,174,235,131,43, + 128,140,170,98,102,107,144,118,187,221,218,220,220,164,213,106,17,99,36,132,192,104,52,98,60,30,63,92,89,80,85,83, + 45,28,126,72,204,154,63,63,129,0,224,204,129,249,234,214,61,0,123,251,236,236,237,199,24,190,85,57,103,79,41,49, + 109,156,151,207,30,33,114,217,120,53,41,95,59,1,144,212,57,120,253,126,167,74,41,153,170,2,78,12,240,233,248,236, + 234,2,203,178,158,124,20,30,180,183,64,220,43,85,37,231,140,136,16,131,16,227,117,35,235,202,106,184,57,130,120,149, + 115,182,156,51,184,19,68,216,184,1,160,197,105,178,81,204,9,65,0,22,0,213,197,6,243,84,8,128,249,162,185,184, + 99,230,152,59,89,23,117,105,161,73,182,2,184,106,65,164,98,82,55,12,127,205,105,212,110,180,80,69,97,114,54,95, + 0,84,213,82,74,224,145,47,163,115,78,166,13,127,103,190,174,24,132,159,103,151,22,68,196,204,12,17,161,201,70,235, + 78,117,107,136,34,194,69,82,128,82,185,59,199,39,134,8,124,254,58,186,117,120,169,217,108,142,192,81,101,27,91,253, + 119,199,119,159,130,243,227,251,248,159,1,34,140,69,194,139,223,71,22,33,158,28,99,167,49,0,0,0,0,73,69,78, + 68,174,66,96,130, +}; +const nall::vector Font = { //size: 627 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,5,73,68,65,84,56,141, + 157,147,205,75,148,81,20,198,127,51,119,26,103,116,104,132,176,15,130,138,172,137,92,181,16,218,106,6,173,219,105,229, + 190,93,224,127,16,109,6,134,105,33,17,33,180,210,162,77,68,84,16,168,45,114,81,65,37,83,145,31,73,58,99,56, + 78,227,152,54,239,124,221,251,222,247,180,136,25,169,209,192,14,28,184,220,115,249,61,231,121,224,250,18,201,248,85,32, + 97,173,141,176,139,82,74,57,192,16,137,100,188,88,169,148,197,243,188,93,181,83,114,36,145,140,23,253,214,218,72,40, + 20,102,108,98,14,128,177,137,57,68,132,209,241,89,60,207,50,58,62,67,177,92,101,248,233,60,90,107,180,174,81,171, + 85,105,107,109,195,90,27,241,215,87,186,114,254,20,0,151,251,98,136,8,151,206,157,68,68,24,232,61,193,147,183,171, + 164,243,37,106,198,34,34,136,72,195,74,3,80,87,254,187,231,87,138,188,251,186,129,118,45,217,245,202,206,128,186,242, + 214,3,161,102,44,83,51,5,180,54,24,237,178,178,94,218,221,6,227,169,60,61,93,251,136,134,20,218,184,44,231,255, + 1,168,123,174,171,103,214,202,212,140,203,209,142,48,29,123,131,104,227,146,206,57,59,3,238,77,206,55,134,174,245,120, + 254,62,199,133,51,29,136,8,7,219,131,104,237,178,148,43,54,1,2,245,195,64,111,103,99,56,249,33,207,199,244,6, + 67,119,215,208,198,160,181,139,49,46,217,82,133,82,85,19,14,6,154,1,247,95,44,208,223,211,73,110,179,74,106,241, + 7,55,6,78,227,67,240,60,97,41,87,228,250,88,10,109,44,153,239,14,177,195,209,102,11,253,61,199,241,196,227,193, + 203,12,23,207,30,162,173,69,17,14,42,90,91,20,7,218,67,104,227,162,141,203,98,246,231,246,25,120,158,240,248,205, + 10,1,37,28,219,223,250,71,160,126,31,191,1,218,101,250,75,1,216,6,240,240,213,55,166,62,231,89,93,175,242,122, + 54,223,0,204,45,111,50,252,232,19,65,191,16,218,227,99,122,161,192,200,179,217,173,12,148,82,78,185,92,138,12,246, + 197,24,236,163,169,186,187,162,116,119,29,105,186,119,28,7,165,148,19,0,134,110,223,185,117,243,63,191,243,181,95,46, + 181,156,109,120,254,28,88,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Image = { //size: 558 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,11,10,16,7,18,54,148,178,182,0,0,1,187,73, + 68,65,84,56,203,157,211,77,107,19,65,24,192,241,255,236,219,52,221,152,212,5,161,165,5,161,224,165,133,92,196,162, + 23,83,232,201,131,159,64,232,103,40,158,235,49,24,131,245,11,8,222,122,245,32,210,64,181,216,30,10,213,158,84,68, + 15,42,210,67,34,5,149,38,155,110,183,217,153,233,97,233,234,98,10,33,3,3,243,250,123,102,134,103,68,189,81,91, + 3,238,51,90,121,66,189,81,51,90,235,145,106,189,81,51,14,128,49,134,7,143,158,178,181,243,110,168,176,75,213,5, + 86,87,150,1,112,0,132,16,236,238,127,102,238,230,29,44,203,194,181,21,133,130,226,247,145,77,162,52,137,210,40,165, + 1,72,148,97,107,231,77,30,48,198,224,216,130,160,236,51,51,25,115,183,90,36,40,5,108,236,126,231,237,123,63,67, + 82,64,211,254,231,52,206,121,195,178,44,46,249,146,27,243,49,179,83,139,8,225,114,251,122,151,111,7,167,68,39,2, + 165,83,64,41,147,187,206,95,64,8,74,227,146,78,104,19,39,45,92,187,204,159,163,46,190,156,64,58,160,207,1,125, + 1,32,128,98,193,163,125,120,133,215,123,95,8,202,167,124,61,8,40,142,123,104,109,104,255,248,196,228,213,57,244,133, + 128,5,37,95,130,16,244,142,125,122,61,131,231,128,235,167,111,244,106,239,37,133,49,143,153,217,249,193,64,210,239,19, + 117,14,115,147,6,3,6,180,73,163,238,111,63,167,31,71,131,129,78,55,228,217,250,139,244,46,233,110,180,214,132,199, + 17,97,24,81,153,78,135,155,205,38,120,151,51,192,202,105,158,196,118,36,8,135,190,22,196,137,193,113,199,168,76,159, + 100,107,166,38,24,124,2,128,197,91,21,90,63,127,13,200,189,107,185,94,235,195,199,255,129,165,234,2,27,155,219,67, + 167,114,14,16,66,176,186,178,156,165,231,48,69,74,153,1,235,141,199,15,239,141,250,157,207,0,181,88,225,150,139,66, + 18,171,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Markup = { //size: 709 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,4,22,20,19,51,203,197,162,151,0,0,2,82,73, + 68,65,84,56,203,149,146,189,79,83,81,24,198,127,231,246,210,43,80,108,122,129,66,33,66,172,124,72,136,128,24,28, + 28,140,68,93,48,33,38,14,70,101,209,77,227,232,162,49,33,93,252,7,12,38,24,163,131,31,3,49,46,234,224,228, + 96,92,64,38,33,166,45,1,77,173,20,232,237,135,45,247,182,183,237,189,14,166,216,43,198,132,103,122,79,242,158,231, + 252,222,243,188,98,118,118,246,101,34,145,184,192,222,116,113,122,122,122,14,128,80,40,100,239,85,161,80,200,174,58,201, + 213,66,211,52,44,203,2,64,8,177,243,84,181,22,66,224,114,185,240,122,189,14,148,29,3,203,178,136,68,34,142,11, + 181,18,66,48,48,48,176,107,22,185,246,208,223,223,255,95,130,127,73,174,109,172,37,168,234,243,90,134,165,175,89,178, + 134,69,217,178,113,203,18,82,169,157,203,119,158,93,125,113,111,234,137,131,160,175,175,111,199,224,251,230,79,30,190,90, + 32,208,166,50,121,230,24,7,59,155,105,80,20,210,121,131,149,216,22,139,203,177,199,151,110,63,189,238,48,136,70,163, + 0,36,82,6,175,23,54,56,63,62,204,112,175,159,116,222,96,53,250,5,217,227,135,122,31,77,251,224,202,196,8,243, + 203,241,49,199,8,85,130,185,71,239,153,60,53,196,145,160,74,42,153,160,165,107,16,111,75,0,189,80,34,17,91,69, + 182,76,164,138,193,233,177,160,243,19,35,145,8,159,194,26,62,223,126,198,199,122,200,101,52,202,178,7,36,65,157,36, + 227,174,179,105,80,100,124,13,10,1,127,43,138,226,222,157,194,219,197,143,156,24,237,34,147,78,146,52,27,241,119,116, + 96,219,96,3,8,9,97,153,172,167,44,22,87,150,240,213,219,206,20,194,225,48,9,77,167,187,221,199,124,116,147,96, + 175,31,203,134,106,46,249,76,138,227,35,131,8,33,176,109,155,248,250,6,210,223,4,5,179,140,162,184,145,60,126,50, + 249,2,91,57,19,189,88,33,167,155,152,249,45,199,94,180,181,54,255,33,80,85,245,247,98,200,18,217,237,2,141,133, + 31,120,100,133,205,237,22,146,117,110,202,21,139,66,170,204,72,169,68,177,104,210,228,105,68,215,117,196,204,204,204,155, + 100,50,121,174,106,20,183,14,113,246,228,48,71,123,84,130,7,2,124,139,197,249,176,98,96,226,198,40,150,201,102,82, + 40,162,194,141,201,33,52,77,99,215,126,94,187,251,252,126,123,64,189,57,53,49,202,225,238,86,0,210,153,44,15,222, + 173,81,193,197,118,193,196,48,76,110,77,116,146,203,229,248,5,131,250,25,20,161,246,118,40,0,0,0,0,73,69,78, + 68,174,66,96,130, +}; +const nall::vector Program = { //size: 609 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,214,1,5,14,9,17,179,225,58,161,0,0,1,238,73, + 68,65,84,56,203,165,147,61,104,83,81,20,128,191,123,238,123,105,140,177,105,82,7,155,162,173,70,170,77,148,214,90, + 39,7,21,7,103,135,110,65,156,93,172,17,7,137,173,58,184,137,139,160,131,63,136,118,214,69,212,69,196,216,165,40, + 175,138,105,165,224,79,138,144,34,181,146,180,9,36,105,124,215,193,164,160,77,176,234,129,51,221,251,125,231,222,115,207, + 133,255,12,213,108,193,137,211,1,100,1,180,176,175,239,46,175,214,108,117,226,116,56,113,76,241,83,202,93,154,121,104, + 156,56,38,125,156,45,141,246,74,179,202,59,206,63,49,75,233,123,106,254,241,9,182,158,188,70,165,202,108,35,137,52, + 130,35,137,91,110,110,226,178,18,81,40,183,76,46,53,74,100,248,122,67,137,172,134,111,186,185,231,103,197,242,172,199, + 246,111,194,227,11,98,89,54,249,241,139,68,78,173,150,72,13,238,7,178,219,19,55,220,252,139,17,209,150,141,29,236, + 166,58,55,129,50,101,188,225,189,248,163,67,84,191,56,244,156,187,79,165,202,236,155,99,12,2,88,53,209,100,228,244, + 109,55,159,74,138,214,22,118,107,39,246,134,48,170,180,128,39,180,13,29,236,1,37,24,99,112,23,51,196,174,76,49, + 149,136,189,4,212,202,21,90,2,93,69,221,226,199,14,108,198,183,115,136,106,118,28,17,176,55,198,16,109,163,68,106, + 169,49,197,249,82,157,171,159,32,60,61,122,56,219,155,124,144,255,94,204,4,150,63,62,66,219,62,172,64,23,162,53, + 198,24,20,6,227,130,132,98,165,233,145,131,94,96,207,74,15,6,198,152,3,194,239,46,29,13,216,109,209,69,74,95, + 49,133,207,136,183,13,37,130,136,70,41,141,213,190,171,14,135,7,198,120,253,203,43,212,37,83,23,142,180,174,235,27, + 94,176,124,65,68,129,136,254,153,109,189,165,116,242,64,29,158,107,54,202,250,234,33,186,247,119,242,62,122,230,206,55, + 41,204,132,116,168,7,183,125,112,249,109,98,183,253,59,252,199,81,46,125,120,90,168,100,158,149,157,56,166,54,39,127, + 245,153,250,129,201,122,147,215,84,249,95,226,7,144,100,183,170,35,108,244,94,0,0,0,0,73,69,78,68,174,66,96, + 130, +}; +const nall::vector Script = { //size: 516 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,236,0,236,0,236,29,35,22,54,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,9,15,10,59,4,237,28,251,236,0,0,1,145,73, + 68,65,84,56,203,149,147,191,142,218,64,16,198,127,131,86,162,12,206,3,32,10,10,55,72,199,91,68,138,168,82,240, + 8,185,154,198,13,7,114,7,244,20,52,244,156,174,35,77,36,222,129,148,84,200,72,8,176,131,43,26,104,152,43,214, + 235,24,78,119,209,141,52,187,171,209,206,55,223,252,147,201,100,242,114,56,28,126,240,57,105,247,251,253,103,0,194,48, + 212,207,74,24,134,234,144,140,123,164,105,154,195,11,130,10,72,49,166,216,227,171,231,221,80,49,247,220,68,36,187,45, + 16,128,170,3,211,55,185,152,98,4,231,128,8,162,5,187,100,12,84,222,7,144,34,3,205,12,130,5,18,7,252,17, + 3,196,230,238,254,139,229,227,124,149,251,162,88,41,21,83,80,209,236,143,228,183,138,213,36,137,121,252,249,200,110,183, + 123,7,64,29,135,2,227,76,255,38,49,189,94,143,32,8,232,116,58,92,175,215,183,0,82,228,231,10,42,16,39,49, + 79,79,214,121,179,217,224,251,62,171,213,138,32,8,30,110,106,160,242,175,255,37,4,69,73,226,36,143,188,221,110,49, + 198,80,175,215,73,211,148,40,138,150,65,16,52,239,230,64,17,205,134,72,36,119,222,239,247,24,99,242,25,41,151,203, + 212,106,53,162,40,90,150,238,219,104,251,173,40,202,104,52,98,56,28,98,140,201,245,116,58,225,251,62,81,20,1,52, + 115,0,207,243,240,60,143,74,165,98,245,75,133,106,181,202,96,48,96,58,157,98,140,225,114,185,0,176,88,44,0,154, + 179,217,236,143,140,199,227,95,199,227,241,251,71,171,119,62,159,89,175,215,180,90,45,230,243,57,141,70,227,119,183,219, + 253,118,195,252,191,251,219,110,63,0,75,23,217,217,95,1,152,44,191,17,163,238,139,75,0,0,0,0,73,69,78,68, + 174,66,96,130, +}; +const nall::vector Text = { //size: 333 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,4,22,20,15,56,186,96,38,66,0,0,0,218,73, + 68,65,84,56,203,173,146,61,110,132,48,16,133,191,7,72,187,91,33,33,159,129,159,179,108,153,34,199,65,230,22,28, + 33,81,218,28,6,115,1,26,250,173,76,138,136,21,36,94,88,162,188,106,44,123,222,124,51,30,181,109,251,49,12,195, + 11,199,244,90,215,245,59,0,214,218,233,168,172,181,211,236,148,204,193,56,142,120,239,1,144,116,47,53,199,146,136,227, + 152,52,77,87,40,119,3,239,61,206,185,85,194,82,146,168,170,234,87,47,201,242,80,20,197,38,65,72,201,242,225,146, + 224,167,158,34,200,243,60,80,241,198,52,157,136,162,104,155,0,160,239,251,213,101,89,150,192,5,184,1,231,253,22,66, + 4,146,144,46,15,23,98,69,224,156,219,28,222,55,209,206,47,132,9,180,79,32,137,174,235,130,149,231,233,135,140,130, + 4,33,147,221,61,200,178,140,191,40,49,198,124,54,77,115,61,146,100,140,121,227,191,244,5,84,81,95,185,252,185,63, + 236,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Video = { //size: 592 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,4,28,9,32,30,1,50,75,149,0,0,1,221,73, + 68,65,84,56,203,165,147,191,170,26,81,16,198,127,251,71,55,55,70,238,53,32,65,13,168,205,54,194,86,203,130,205, + 54,10,130,104,231,59,228,33,146,34,16,244,17,52,15,96,17,172,197,70,43,27,219,72,34,9,11,130,141,165,138,112, + 37,146,213,157,20,234,230,154,164,72,110,6,206,97,102,190,153,57,243,13,103,20,203,118,94,37,19,119,239,1,2,225, + 44,114,190,5,4,68,4,80,78,30,57,97,135,195,33,248,238,251,175,177,108,71,122,189,158,108,183,91,25,14,135,82, + 42,149,174,108,215,117,255,136,183,90,45,177,108,71,176,108,71,14,135,131,172,86,43,73,167,211,226,186,238,95,217,205, + 102,83,44,219,17,149,255,20,237,69,58,243,54,249,60,129,105,154,56,142,195,100,50,33,22,139,133,246,120,60,38,30, + 143,255,134,111,54,27,62,127,249,138,98,217,142,36,19,119,60,102,136,247,223,246,170,14,144,121,153,225,126,187,253,167, + 214,159,221,222,6,31,63,205,84,21,224,137,97,0,208,237,118,169,86,171,24,134,65,52,26,37,18,137,80,175,215,209, + 52,13,85,85,169,215,235,40,138,194,57,71,7,80,1,162,209,40,34,66,16,4,100,179,89,114,185,220,245,160,52,45, + 76,20,57,209,208,117,29,128,83,149,51,56,157,78,201,231,243,152,166,73,173,86,3,192,243,60,42,149,10,166,105,226, + 121,30,134,97,176,223,239,209,53,141,176,131,167,55,55,136,8,237,118,155,217,108,198,104,52,162,211,233,176,88,44,240, + 125,159,76,38,67,54,155,101,50,153,224,251,62,34,18,210,86,1,34,145,8,0,229,114,153,245,122,77,185,92,166,84, + 42,145,203,229,40,20,10,44,151,75,82,169,20,197,98,145,227,241,200,133,118,72,225,120,60,34,34,12,6,131,144,39, + 64,191,223,7,32,159,207,211,104,52,174,102,16,4,193,207,2,23,231,229,132,191,225,172,207,231,243,80,255,53,78,191, + 4,219,182,29,82,121,152,12,132,175,61,212,119,187,29,0,138,101,59,239,128,55,143,92,133,15,63,0,208,50,35,119, + 229,61,168,67,0,0,0,0,73,69,78,68,174,66,96,130, +}; +} +namespace Go { +const nall::vector Down = { //size: 683 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,61,73,68,65,84,56,141, + 133,147,77,104,19,65,24,134,223,153,236,230,15,107,192,96,210,67,252,193,170,245,34,26,143,73,180,224,193,139,241,34, + 20,47,30,42,226,65,20,234,161,85,241,42,8,210,21,60,169,80,132,156,20,33,162,82,83,91,114,177,214,85,8,181, + 45,20,123,168,85,180,84,205,154,174,253,11,233,38,179,179,159,135,214,26,155,24,223,227,55,223,60,243,190,243,205,48, + 34,66,181,226,221,106,30,132,48,234,137,193,208,123,68,115,117,73,169,105,34,132,111,93,72,195,118,4,108,71,96,201, + 42,96,201,50,1,0,119,31,221,168,1,215,2,0,48,198,144,155,121,142,178,93,66,161,56,131,143,115,99,104,63,120, + 181,174,41,94,175,88,29,202,163,248,235,110,108,8,0,17,136,28,16,17,20,238,110,8,80,18,151,85,157,28,196,214, + 237,187,96,57,36,189,146,108,72,178,177,92,54,81,189,22,239,82,215,13,50,142,55,10,57,72,69,66,45,209,139,39, + 175,251,20,151,10,34,199,43,73,130,152,4,184,68,81,22,160,122,57,184,194,112,254,212,53,47,8,16,162,130,116,54, + 85,154,95,156,75,49,34,66,162,91,77,183,69,143,39,143,68,147,158,247,249,87,144,92,64,162,140,21,123,17,211,243, + 57,16,104,45,22,71,219,246,211,24,157,24,41,79,78,141,247,189,238,17,237,124,45,114,199,203,177,140,241,197,152,162, + 72,112,47,136,87,0,151,141,66,101,26,170,143,193,237,227,80,125,46,68,35,71,97,46,152,52,249,97,220,32,194,153, + 245,75,212,53,81,4,33,249,112,240,158,229,229,77,8,248,131,40,209,79,148,93,139,112,123,57,220,62,23,182,109,217, + 131,144,175,5,217,161,140,69,14,146,186,38,138,127,77,65,215,196,68,69,172,116,62,24,188,83,218,17,56,0,155,149, + 160,122,86,79,222,188,41,128,253,161,99,232,203,62,46,9,81,233,212,53,49,81,119,140,186,38,122,103,141,79,47,134, + 199,6,68,107,48,1,174,48,40,110,142,67,225,19,200,189,123,91,249,97,126,235,215,53,209,219,240,29,144,131,142,161, + 145,129,239,166,177,64,187,155,98,216,229,143,193,252,186,76,185,81,61,239,200,213,220,13,1,186,38,138,36,145,204,100, + 159,89,91,177,15,65,167,21,79,251,159,88,142,252,147,187,90,108,227,111,252,173,120,151,122,46,210,188,243,54,0,204, + 230,63,95,218,104,253,191,0,0,56,124,69,189,15,0,195,55,197,217,127,245,252,2,115,74,18,42,134,104,28,203,0, + 0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Home = { //size: 606 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,10,14,20,37,19,83,42,210,59,0,0,1,235,73, + 68,65,84,56,203,149,147,191,107,83,81,20,128,191,123,251,222,75,211,64,242,36,160,85,135,100,81,123,19,104,85,172, + 17,92,28,140,66,19,167,135,212,74,39,145,162,163,24,92,58,180,110,193,169,254,24,234,212,37,139,245,199,96,19,240, + 15,240,63,16,121,91,92,196,90,219,240,98,81,137,33,121,215,33,246,217,151,80,33,103,186,92,206,247,221,115,14,231, + 194,1,225,41,85,172,128,174,128,246,148,122,200,48,177,7,123,74,105,79,169,61,73,113,104,120,177,56,163,203,55,111, + 252,87,34,250,225,154,235,110,20,148,98,253,220,89,182,39,78,113,228,240,56,39,188,38,83,107,107,212,92,151,130,82, + 215,14,185,110,117,64,176,31,126,83,156,97,247,248,49,148,202,50,22,141,210,106,181,24,219,252,74,182,92,30,144,136, + 126,184,122,251,22,157,100,146,116,42,77,42,149,2,64,107,104,183,219,236,214,235,156,44,149,66,18,177,31,126,247,160, + 68,199,48,201,229,46,96,219,118,208,154,214,26,0,223,247,249,185,181,69,114,110,46,144,136,10,232,130,82,188,127,84, + 198,107,54,57,63,157,35,30,143,35,132,8,9,124,223,15,206,134,16,140,230,243,212,92,23,3,184,3,172,78,157,62, + 195,253,210,61,54,170,111,3,240,201,202,51,86,30,63,69,139,17,116,167,133,48,70,209,221,223,44,47,45,209,238,165, + 204,202,121,120,190,48,153,33,17,79,0,160,212,4,153,140,34,155,205,244,94,20,146,145,244,149,222,196,83,121,144,22, + 90,107,22,38,51,204,195,186,236,239,211,178,44,76,211,196,48,140,224,254,75,227,7,0,31,234,59,116,187,126,144,11, + 48,32,144,82,34,165,196,146,159,1,232,96,241,241,83,3,128,111,222,47,58,34,18,90,36,99,96,179,254,14,207,231, + 40,0,151,46,78,115,53,26,67,234,113,46,75,147,237,77,66,21,24,253,21,252,155,126,239,165,239,222,14,162,217,56, + 112,245,3,65,36,18,193,182,109,18,137,4,2,137,16,16,139,197,112,28,103,0,178,44,43,252,23,174,207,58,175,0, + 135,225,98,245,229,139,215,119,255,0,86,248,213,163,133,187,128,26,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Left = { //size: 655 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,33,73,68,65,84,56,141, + 133,147,79,72,20,113,20,199,191,111,102,126,179,59,187,82,98,108,173,27,181,66,8,17,9,130,149,110,91,135,220,34, + 86,211,76,68,34,136,14,37,116,178,162,45,186,122,137,16,3,59,196,30,36,240,208,37,10,130,176,110,29,36,87,138, + 142,21,30,34,75,247,80,185,108,146,187,237,204,238,204,239,247,235,48,153,174,140,238,131,119,122,127,248,188,239,123,15, + 82,74,212,242,163,55,181,43,241,91,90,198,43,166,97,11,139,167,88,29,17,38,163,225,230,174,133,31,159,13,175,28, + 101,139,226,22,16,62,157,60,220,223,115,109,224,158,103,49,0,111,130,120,138,13,25,190,186,241,139,201,97,99,207,206, + 102,82,104,115,208,170,200,42,242,190,200,129,174,193,83,87,13,147,175,224,227,247,105,28,137,246,128,84,88,241,20,147, + 85,213,132,159,36,165,92,135,76,83,137,67,125,141,29,7,59,217,215,95,31,80,176,242,208,84,134,88,83,31,136,20, + 16,0,9,64,74,1,33,5,238,164,47,184,4,241,20,27,10,26,219,31,244,159,184,228,175,175,111,160,247,139,175,192, + 165,3,166,232,16,146,99,102,254,25,136,8,4,130,132,171,126,123,180,215,29,225,216,109,246,168,169,113,255,249,238,227, + 131,70,174,180,128,119,223,222,128,49,31,116,77,7,87,4,44,81,128,105,22,80,180,86,80,182,75,80,72,133,159,5, + 209,186,59,177,166,1,231,54,44,251,15,76,231,55,74,50,15,112,1,135,155,168,8,19,92,114,72,46,193,29,9,199, + 22,224,142,59,114,174,152,117,215,56,51,106,95,206,46,125,185,254,248,101,218,132,237,147,173,123,19,144,122,25,66,47, + 129,5,0,127,64,133,30,80,193,12,5,204,175,64,213,168,90,199,245,34,146,130,169,182,150,88,184,189,45,166,207,21, + 94,35,95,153,135,144,192,233,200,13,136,127,20,220,118,29,0,210,79,238,174,53,248,191,70,21,147,187,118,68,146,231, + 206,12,4,138,108,17,115,203,211,232,12,13,227,254,196,136,197,43,240,111,186,198,141,135,196,116,125,188,183,251,172,17, + 14,135,40,168,132,48,250,112,4,153,49,155,54,230,122,158,114,102,204,158,176,43,149,142,231,47,158,102,103,103,223,150, + 203,229,138,87,90,181,6,94,182,58,82,195,182,80,50,191,156,11,120,17,212,124,229,90,239,252,23,109,243,52,116,236, + 202,203,9,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Right = { //size: 676 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,54,73,68,65,84,56,141, + 149,146,75,72,84,97,28,197,127,223,227,206,195,70,195,20,82,196,94,68,32,104,20,4,133,211,70,104,209,34,130,4, + 91,70,129,66,184,201,114,140,54,66,43,55,141,144,139,40,114,19,20,189,164,69,98,62,112,17,45,102,208,41,164,20, + 55,209,34,44,51,157,177,129,30,227,120,239,220,251,181,8,95,51,19,212,129,179,249,254,135,195,249,159,255,135,49,134, + 124,134,187,116,172,177,83,183,21,155,229,83,82,4,198,163,113,119,245,129,190,112,151,53,16,142,88,161,98,154,53,20, + 53,0,184,210,210,27,60,121,244,236,105,4,179,225,136,213,240,223,6,74,106,154,14,159,241,181,55,95,175,13,250,67, + 19,225,136,213,86,76,39,26,35,250,43,134,157,91,30,21,217,155,237,131,129,169,207,99,84,149,237,195,39,183,241,120, + 252,214,202,135,249,153,97,99,56,31,139,58,63,55,12,58,181,233,185,120,31,41,20,74,40,132,144,8,4,0,137,79, + 67,120,184,148,249,119,176,171,188,158,248,244,184,51,54,57,176,128,49,167,98,81,103,6,64,3,184,94,142,216,199,103, + 40,169,81,66,129,16,8,1,66,1,194,99,217,158,35,189,52,207,193,186,35,86,77,213,158,218,167,99,119,39,194,17, + 171,35,22,117,250,53,64,206,91,37,157,89,192,118,179,216,110,22,165,52,165,37,101,148,4,66,248,45,63,70,184,216, + 94,142,119,75,163,212,132,234,68,107,115,87,201,208,171,71,125,199,175,90,199,52,192,210,143,57,222,39,95,175,119,160, + 125,130,148,35,209,89,137,214,10,191,47,136,79,6,80,248,41,205,149,163,76,144,172,157,49,235,43,108,41,80,130,212, + 2,101,201,63,244,129,167,178,160,44,26,42,154,72,47,102,204,131,151,119,86,178,171,153,141,21,0,90,14,93,91,55, + 80,150,64,105,201,200,92,47,218,39,169,14,237,167,110,251,9,38,223,196,237,196,219,248,87,227,178,169,68,193,226,237, + 39,61,91,206,40,45,178,151,206,117,7,148,82,212,87,54,81,161,247,50,240,252,97,102,49,249,101,196,184,121,103,52, + 198,20,124,142,112,196,50,151,91,187,249,229,37,73,166,82,230,197,232,224,138,237,216,29,177,27,78,127,190,182,160,131, + 53,56,57,155,196,84,98,117,122,118,106,209,219,20,185,160,179,191,37,168,40,175,204,124,251,158,26,54,46,23,54,71, + 254,167,4,66,18,95,78,167,238,197,162,133,145,243,241,27,65,222,9,180,110,118,229,182,0,0,0,0,73,69,78,68, + 174,66,96,130, +}; +const nall::vector Up = { //size: 652 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,30,73,68,65,84,56,141, + 149,147,79,104,19,65,20,198,191,55,187,51,217,141,133,122,104,76,255,209,130,4,237,193,64,42,168,208,213,138,104,68, + 98,69,45,20,114,107,74,201,73,144,98,22,193,171,199,82,145,160,23,15,69,79,30,165,66,241,226,77,42,94,68,80, + 208,67,41,180,42,149,148,52,137,166,154,38,217,217,25,15,81,172,33,169,246,29,223,251,230,199,124,223,155,33,173,53, + 218,213,201,155,124,30,0,150,102,189,233,118,26,214,110,224,184,60,221,223,21,73,246,117,29,76,58,46,79,239,9,224, + 184,60,26,16,251,178,87,206,76,6,199,70,147,193,128,8,102,29,151,71,255,11,224,184,188,3,132,197,137,115,211,214, + 150,151,199,150,183,137,248,200,37,11,132,69,199,229,29,255,4,16,225,209,232,112,162,167,55,52,72,159,75,31,240,177, + 244,30,157,157,157,20,27,58,209,13,194,195,93,1,142,203,211,253,7,34,137,179,71,199,249,74,254,13,12,198,97,50, + 142,87,107,11,136,13,29,23,161,253,61,137,230,60,216,142,195,81,193,237,108,42,225,218,235,229,101,104,242,32,132,137, + 58,125,199,54,21,241,46,255,28,23,78,95,13,154,166,248,43,15,182,211,247,212,88,198,82,228,161,34,75,16,1,1, + 30,224,40,203,117,8,219,64,65,174,162,168,86,113,254,212,69,139,216,159,60,216,111,223,241,99,227,221,135,250,98,148, + 175,172,193,228,6,56,55,80,81,5,84,141,175,16,54,131,176,25,150,191,189,64,184,55,68,71,14,15,135,137,53,242, + 160,145,140,153,30,232,142,100,111,76,220,177,5,15,64,65,194,135,135,215,185,5,188,45,60,131,100,21,16,35,36,6, + 50,208,90,67,41,160,94,175,225,241,211,249,74,177,180,57,99,18,67,234,83,110,197,158,185,119,185,225,137,163,122,247, + 250,19,171,44,115,240,141,109,112,193,192,76,130,193,9,115,15,110,87,101,77,91,191,236,7,137,33,101,46,205,122,78, + 211,38,180,214,10,165,250,23,48,131,96,112,6,30,104,64,100,77,91,47,231,60,218,245,29,0,128,210,62,126,212,139, + 141,43,251,26,178,174,160,85,235,63,99,182,106,250,74,162,90,219,134,50,53,160,21,124,73,240,189,61,0,164,47,17, + 31,188,6,98,0,49,2,17,246,0,32,108,220,186,63,25,110,37,38,194,70,115,239,39,48,247,197,219,182,208,154,34, + 0,0,0,0,73,69,78,68,174,66,96,130, +}; +} +namespace Media { +const nall::vector Back = { //size: 770 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,12,6,17,45,2,189,124,103,101,0,0,2,143,73, + 68,65,84,56,203,165,83,75,72,84,81,24,254,206,189,215,251,56,231,58,51,62,152,115,238,216,66,169,241,65,153,20, + 101,66,104,17,33,210,178,168,36,104,17,73,45,42,90,181,13,83,194,32,13,119,17,101,49,52,139,138,158,154,101,229, + 34,136,44,180,32,113,81,173,194,69,138,66,216,99,102,238,189,94,157,211,194,81,52,90,8,254,240,111,190,255,255,126, + 190,255,5,172,209,200,42,114,20,0,38,0,9,192,253,7,183,53,0,206,127,72,147,185,4,150,115,146,35,187,0,12, + 0,145,92,28,26,179,25,154,154,26,39,22,153,3,207,95,196,8,33,150,162,40,249,144,80,67,225,112,69,60,190,97, + 255,200,200,135,11,65,16,148,100,179,217,226,104,52,26,41,47,143,31,24,30,30,238,208,120,84,0,0,238,222,185,135, + 195,205,135,32,184,3,69,85,34,233,116,58,182,62,94,118,212,102,246,9,0,129,174,235,215,77,211,204,171,170,170,56, + 98,231,219,167,8,33,243,130,59,29,138,227,136,21,218,253,89,63,42,132,104,222,182,125,107,255,142,218,218,99,125,189, + 253,150,150,167,233,149,149,241,157,117,117,181,189,155,106,170,79,62,126,244,196,84,85,85,229,142,128,198,163,28,148,90, + 0,0,74,41,118,237,105,232,41,42,40,44,107,109,109,43,8,133,66,68,102,37,108,102,27,156,243,203,29,23,47,177, + 130,194,66,34,179,18,148,82,104,170,14,77,56,2,127,82,191,150,20,116,95,233,174,9,135,34,154,55,235,34,157,74, + 129,82,134,150,227,45,164,190,190,193,246,102,189,37,140,217,12,69,5,22,52,193,57,130,57,31,0,96,154,38,166,166, + 167,164,174,235,200,184,41,120,190,15,198,24,92,207,133,231,187,200,184,25,120,158,11,198,24,24,165,40,46,226,80,162, + 130,195,48,116,0,128,97,232,120,248,224,254,183,151,131,3,191,45,147,33,38,214,65,81,84,188,29,122,35,147,201,132, + 171,231,25,75,152,197,44,112,206,161,56,92,44,155,129,133,205,213,91,118,127,249,252,245,106,34,209,243,243,211,232,71, + 55,152,11,64,41,243,77,202,206,222,74,220,152,233,127,214,231,7,115,1,24,165,16,66,64,227,130,195,52,141,92,11, + 6,4,231,136,149,236,235,118,51,153,107,239,222,15,181,143,141,141,30,228,130,207,111,172,172,126,154,158,75,189,154,153, + 254,113,250,118,242,230,153,108,86,18,193,57,52,46,22,214,216,214,126,30,0,192,29,1,85,81,167,33,101,184,180,180, + 244,220,248,196,120,215,235,193,193,206,198,189,194,39,144,105,25,91,223,57,49,57,158,156,248,62,217,197,29,1,34,165, + 92,113,202,158,231,193,178,172,73,0,240,124,95,39,144,139,103,235,27,134,57,227,186,158,10,192,6,36,93,237,51,65, + 74,105,0,0,33,196,95,134,145,133,66,107,180,191,249,146,220,194,180,154,76,242,0,0,0,0,73,69,78,68,174,66, + 96,130, +}; +const nall::vector Eject = { //size: 628 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,6,73,68,65,84,56,141, + 149,83,77,104,19,97,16,125,179,155,152,118,105,44,65,232,154,221,110,18,130,43,98,2,66,65,5,181,90,35,136,138, + 20,255,218,24,155,24,5,65,17,4,79,94,148,30,60,121,82,207,158,12,90,170,130,224,201,131,182,122,240,162,222,60, + 24,17,84,234,15,173,105,77,211,109,218,36,187,109,50,30,154,72,210,36,37,14,124,48,135,247,30,111,102,222,71,204, + 140,102,69,68,118,0,196,204,86,51,140,109,13,242,122,77,211,54,51,179,64,68,159,153,217,104,89,128,136,236,46,151, + 75,219,179,119,215,83,129,32,189,126,245,230,32,17,37,153,217,172,3,51,115,205,3,64,0,60,39,78,29,127,50,54, + 246,98,233,221,251,183,203,131,225,147,227,0,124,229,113,106,240,141,28,108,216,183,191,247,72,32,24,232,239,235,11,217, + 64,192,246,29,59,119,103,178,115,209,151,207,199,239,1,152,110,234,0,128,164,235,122,111,44,30,205,230,242,57,206,46, + 204,243,124,214,96,211,50,249,252,133,120,174,167,103,219,97,81,20,59,106,56,149,70,81,20,209,239,247,111,58,61,20, + 254,144,252,148,44,230,11,121,78,205,76,241,239,233,73,94,88,204,242,196,247,137,210,153,88,248,71,48,24,220,234,245, + 122,109,117,35,248,124,190,141,221,30,229,202,129,80,104,139,174,235,66,102,46,13,34,2,17,33,151,95,132,170,40,20, + 30,136,200,204,143,110,78,254,156,186,10,224,23,42,75,137,68,34,157,197,98,241,144,236,238,186,127,231,246,221,54,81, + 16,27,158,150,153,113,99,248,122,225,219,151,175,215,28,142,246,135,137,68,34,99,3,0,85,85,59,102,254,164,6,102, + 211,233,117,151,46,95,180,168,106,55,88,213,155,166,101,111,107,119,196,84,165,251,25,128,21,1,143,199,179,228,118,187, + 135,13,195,184,69,68,171,51,81,215,75,146,84,112,58,157,22,80,14,146,166,105,210,232,227,145,143,13,125,55,169,254, + 163,199,2,0,82,21,7,34,0,140,60,24,109,137,124,246,92,180,168,40,138,88,237,160,36,8,194,114,44,62,68,107, + 83,255,21,203,178,92,2,202,87,0,208,9,160,11,43,49,110,73,0,64,26,192,44,85,125,103,250,79,1,6,128,191, + 20,183,247,30,217,9,206,54,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Flash = { //size: 607 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,1,220,73,68,65,84,56,141,133,147,59,107,148,65,24,133,159,249,110, + 43,209,40,134,40,152,8,171,177,49,177,241,2,134,32,66,44,20,4,11,11,27,11,123,241,31,216,139,32,22,234,191, + 208,50,8,130,133,63,32,44,22,65,188,173,96,52,70,99,130,65,55,155,221,253,246,75,230,61,22,123,55,31,241,133, + 153,102,230,60,51,115,206,59,78,18,103,166,103,230,128,171,128,241,255,10,128,183,102,54,187,80,154,175,68,0,146,174, + 92,186,56,19,7,1,4,8,156,90,91,165,1,165,112,136,128,242,167,197,169,229,149,213,57,96,54,234,95,62,57,242, + 156,201,177,175,56,6,133,173,213,214,92,254,121,28,239,175,37,75,223,87,46,0,116,1,50,99,114,236,51,51,215,31, + 18,186,117,0,178,44,35,77,155,164,105,147,102,179,137,56,132,74,143,121,179,234,187,224,46,192,100,56,28,97,60,74, + 90,253,64,218,104,80,175,87,169,109,254,96,227,207,55,178,172,198,248,177,91,4,65,56,240,180,222,13,4,56,71,181, + 178,200,175,229,87,212,106,117,26,141,12,23,12,179,119,120,156,131,133,136,125,251,71,219,15,177,28,128,9,73,84,42, + 155,100,156,35,26,218,102,228,0,36,145,17,199,34,137,33,9,214,144,60,222,231,1,36,22,190,28,5,61,2,183,51, + 187,78,189,91,58,130,247,189,13,81,199,99,147,241,162,116,138,151,175,167,112,78,168,63,9,117,124,2,111,142,98,49, + 199,3,83,11,98,190,35,112,109,173,6,32,32,212,215,110,189,62,48,33,19,166,157,39,247,131,28,96,214,139,49,232, + 233,141,213,245,13,146,56,160,16,135,173,145,244,198,158,36,162,144,132,172,253,222,196,219,191,38,10,228,141,208,109,115, + 251,242,225,60,239,186,117,239,89,21,41,39,5,51,99,203,66,206,222,184,191,43,192,63,189,137,229,196,168,45,111,156, + 152,152,224,99,249,125,238,95,104,93,212,81,44,22,241,38,104,255,92,39,137,211,231,167,31,32,238,8,134,216,181,11, + 218,28,104,2,119,23,74,243,79,254,2,78,177,239,207,22,156,213,133,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Floppy = { //size: 561 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,1,195,73,68,65,84,56,141, + 149,147,191,139,19,65,20,199,63,51,187,185,132,228,20,148,52,70,136,44,28,92,35,40,34,28,136,86,138,165,133,181, + 216,28,162,127,131,98,103,165,157,40,254,3,162,133,216,88,164,201,157,88,168,136,88,92,171,22,129,92,97,227,110,147, + 236,50,155,157,247,198,34,119,249,33,39,196,47,51,195,131,225,251,229,243,30,60,179,117,239,245,91,17,185,201,84,129, + 185,22,235,35,255,172,181,175,98,17,185,241,112,251,42,91,31,158,130,170,9,170,160,74,8,106,56,172,85,65,101,94, + 135,192,206,245,7,60,123,243,249,118,12,32,26,248,253,226,49,65,132,85,165,215,238,3,16,3,70,68,56,245,232,57, + 132,191,169,255,173,202,203,44,0,47,129,147,183,238,174,108,6,144,119,223,23,3,20,17,97,56,28,174,100,78,146,100, + 137,192,136,40,81,20,145,36,201,234,4,94,231,4,114,48,188,193,96,176,146,185,219,237,46,207,160,58,72,251,31,130, + 229,22,188,178,253,228,35,141,236,43,81,177,127,180,195,76,159,73,227,12,121,235,44,27,167,143,207,9,188,8,76,10, + 162,98,159,43,151,47,81,175,215,169,213,106,179,107,173,165,44,75,242,60,103,119,247,61,249,218,6,222,183,0,176,135, + 56,170,138,181,17,237,118,155,126,191,79,175,215,163,217,108,34,34,140,199,99,70,163,17,69,81,128,177,168,42,126,177, + 5,149,128,170,98,12,180,90,173,25,117,154,166,148,101,137,115,14,231,28,101,89,18,66,32,168,80,85,11,67,156,84, + 158,216,78,55,36,203,178,89,64,150,101,75,102,231,28,1,80,85,42,239,167,1,214,152,47,123,63,127,157,223,236,172, + 55,198,89,32,77,83,58,157,14,222,123,210,52,93,50,59,231,32,192,137,99,107,51,2,115,241,206,203,117,99,248,84, + 183,126,243,92,252,173,110,76,76,32,48,61,7,187,177,176,35,134,192,158,191,144,139,169,27,145,240,227,15,253,243,15, + 58,103,73,91,81,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Next = { //size: 771 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,12,6,17,45,27,217,23,207,165,0,0,2,144,73, + 68,65,84,56,203,189,146,205,75,84,81,24,135,127,231,222,59,247,156,123,103,70,156,132,57,231,14,153,180,8,196,116, + 6,197,153,6,218,180,16,170,255,32,136,136,218,180,206,2,147,74,164,54,130,81,88,67,209,70,8,103,81,145,86,138, + 50,72,43,69,173,69,148,203,180,175,77,230,76,126,204,140,51,222,249,242,158,22,142,34,214,50,122,224,133,195,195,121, + 15,191,243,242,2,255,128,26,0,202,62,103,0,48,255,226,255,128,0,176,170,103,7,64,26,64,17,64,109,245,17,9, + 32,95,45,103,207,221,93,52,183,219,68,36,18,233,94,88,88,28,78,165,82,105,69,81,86,92,46,87,33,28,110,239, + 94,92,252,60,146,205,100,62,129,192,112,28,103,67,74,137,83,167,79,46,237,52,39,18,147,1,69,112,11,134,201,46, + 6,67,205,137,104,52,114,206,235,245,114,93,215,3,204,160,231,91,130,71,39,66,109,193,46,143,199,91,111,89,129,90, + 193,183,3,60,123,250,28,0,192,253,2,10,183,4,84,85,85,95,189,124,205,154,67,45,151,162,209,200,104,99,227,145, + 227,154,75,211,199,70,199,141,99,145,200,133,246,112,219,184,16,226,76,177,84,244,239,141,111,89,2,26,247,251,161,83, + 13,138,162,226,193,64,204,179,190,182,230,238,190,126,173,63,159,203,83,41,37,250,250,250,107,178,217,172,183,183,183,231, + 198,161,195,245,103,21,16,0,128,105,154,224,126,14,205,18,2,133,178,13,0,200,231,114,160,6,37,15,99,143,60,211, + 211,83,187,78,115,169,228,78,255,221,3,153,108,186,166,179,243,242,110,2,97,9,104,92,8,172,172,38,65,8,176,158, + 89,5,99,6,32,37,236,130,13,66,128,181,204,42,24,165,144,142,68,50,149,148,140,49,0,0,99,12,130,115,40,156, + 115,24,110,3,138,162,34,32,14,66,119,81,196,227,79,236,153,217,105,185,227,12,230,198,228,155,68,118,100,248,197,55, + 74,117,0,0,165,58,252,130,67,19,66,32,249,235,7,202,149,50,38,38,198,138,95,191,127,217,244,249,234,186,76,211, + 125,191,92,41,179,143,243,239,237,183,115,179,197,236,70,254,113,176,165,117,96,118,110,106,105,123,6,6,44,46,160,9, + 206,241,97,94,146,161,248,96,201,231,171,139,181,134,219,99,110,205,83,172,84,202,247,134,226,131,165,92,62,63,210,26, + 10,223,52,76,211,118,42,21,194,24,173,126,129,130,11,14,141,91,2,170,162,204,52,53,54,93,9,88,13,203,68,193, + 166,4,209,150,39,127,190,59,209,209,113,181,33,208,176,76,128,2,8,201,108,57,91,28,0,110,221,238,217,222,3,33, + 64,108,219,174,174,39,217,4,144,51,12,182,85,44,22,124,0,40,0,71,130,164,25,165,37,0,176,109,219,218,25,226, + 46,82,74,175,148,146,236,115,84,74,73,241,63,248,13,221,115,236,68,32,12,77,214,0,0,0,0,73,69,78,68,174, + 66,96,130, +}; +const nall::vector Optical = { //size: 931 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,13,215,0, + 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,4,1,17,53,53,42,125,41,75,0,0,3,48,73, + 68,65,84,56,203,109,147,203,79,92,101,24,198,127,223,119,206,249,56,103,206,64,231,82,24,40,101,46,13,139,138,181, + 11,77,105,162,27,218,196,109,53,154,214,148,82,117,211,24,132,181,43,255,0,141,91,40,184,211,136,216,164,186,108,216, + 168,69,161,216,185,64,36,182,44,96,8,129,4,40,48,131,23,152,14,115,174,110,74,98,136,239,242,201,251,203,179,120, + 158,71,112,226,134,134,7,47,3,31,2,125,64,238,133,188,6,76,3,95,141,142,140,229,255,251,47,78,192,99,201,68, + 242,245,219,183,63,216,239,232,232,120,213,178,172,102,128,122,189,94,219,218,218,124,50,49,241,77,164,186,95,157,27,29, + 25,27,228,127,156,167,30,205,205,126,231,121,94,176,180,180,20,46,44,44,132,165,82,41,92,92,92,12,203,229,114,88, + 173,86,67,223,247,131,217,217,153,169,161,225,193,169,99,78,59,118,238,239,31,16,47,157,239,185,145,207,231,229,193,193, + 1,190,239,35,132,64,8,129,97,24,72,41,105,52,26,34,155,205,117,39,18,137,253,136,109,190,86,44,148,30,104,67, + 195,131,151,147,137,228,199,183,250,7,174,46,47,47,75,223,247,169,213,14,57,172,29,80,171,29,80,175,63,71,211,53, + 154,148,66,211,116,194,48,164,187,187,187,51,159,127,28,121,229,226,133,121,173,183,247,210,167,119,238,124,148,118,29,55, + 85,175,215,113,93,7,93,55,104,110,110,33,213,214,78,107,107,27,137,68,146,74,117,151,38,213,132,227,184,248,190,79, + 170,45,229,46,46,254,110,233,64,223,217,206,179,185,74,165,130,82,10,215,115,137,218,205,172,174,174,146,47,252,6,16, + 222,184,254,158,200,229,206,177,82,94,38,17,79,226,121,30,103,206,116,158,6,250,36,144,51,77,83,41,165,48,77,19, + 33,32,30,143,147,47,60,14,35,150,125,209,247,253,214,239,127,184,31,196,98,49,170,213,10,158,231,225,56,14,134,97, + 24,64,78,63,142,83,41,69,16,4,232,186,142,109,219,72,41,130,63,255,218,223,0,208,52,205,1,76,199,113,240,60, + 15,33,4,190,239,11,64,72,96,173,209,104,120,74,41,148,82,156,58,21,163,209,104,240,238,59,215,165,82,234,153,174, + 235,171,111,93,123,91,173,175,175,163,84,19,174,235,226,121,30,135,135,135,62,176,166,3,211,219,219,219,201,116,58,221, + 10,208,158,106,103,119,111,135,158,158,30,241,249,103,95,152,128,185,177,177,193,207,15,127,36,151,61,135,235,186,68,34, + 17,118,118,119,234,192,67,173,183,247,82,165,188,186,114,237,74,223,213,184,166,105,232,186,142,101,90,236,85,246,152,159, + 47,242,228,201,31,84,170,21,218,90,83,8,33,145,82,210,213,213,197,189,123,147,255,212,143,234,159,104,197,66,105,243, + 229,11,61,231,99,177,88,71,186,43,221,34,132,64,74,13,93,55,136,70,155,137,199,19,216,118,20,41,37,71,71,71, + 100,179,89,138,197,194,223,79,151,158,222,191,59,58,254,165,6,80,44,148,30,88,17,243,77,219,142,158,206,100,50,166, + 148,18,199,113,8,130,128,48,12,1,176,44,139,76,38,195,220,220,35,231,151,95,167,103,238,142,142,223,4,52,237,184, + 211,197,66,233,219,104,115,36,59,59,59,147,75,165,218,149,105,154,178,165,165,5,203,178,0,216,220,218,244,39,39,39, + 158,175,148,87,190,30,29,25,187,249,2,11,197,137,101,234,183,6,250,223,176,237,200,251,186,166,95,17,82,116,9,33, + 68,16,4,155,158,231,253,100,24,198,248,201,57,255,11,186,149,81,110,74,152,180,58,0,0,0,0,73,69,78,68,174, + 66,96,130, +}; +const nall::vector Pause = { //size: 464 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,12,6,17,32,43,74,96,129,68,0,0,1,93,73, + 68,65,84,56,203,205,146,75,110,20,65,12,134,191,42,187,153,238,40,234,213,216,138,56,64,114,12,136,224,72,72,112, + 164,40,202,25,0,133,59,68,16,16,172,103,150,72,48,105,250,97,22,253,200,0,19,177,4,47,74,165,175,92,191,126, + 63,224,95,71,218,187,159,254,61,59,45,159,34,226,35,16,58,191,173,215,107,206,159,61,121,191,47,250,246,245,245,89, + 12,67,62,127,254,244,102,159,95,191,121,119,182,217,110,19,16,121,134,102,134,170,198,229,197,21,151,23,87,168,234,224, + 102,172,15,112,115,95,76,45,14,220,29,17,161,239,123,62,125,249,128,136,96,238,116,93,183,240,219,207,55,35,55,251, + 83,192,204,16,17,118,119,223,41,180,64,84,48,115,186,182,69,68,184,107,118,136,40,162,130,63,36,208,180,59,154,166, + 65,84,16,17,220,215,64,26,118,205,55,218,246,7,229,170,90,156,205,113,223,3,31,29,52,109,67,34,33,121,116,48, + 246,70,136,8,202,85,137,228,95,29,44,2,110,62,38,14,3,67,12,168,42,102,134,79,165,229,44,148,101,133,170,96, + 110,15,59,32,160,239,187,169,4,95,184,100,229,81,177,154,154,120,104,10,54,78,225,228,228,49,146,5,45,70,7,36, + 16,17,170,163,106,226,197,92,66,28,154,66,188,124,245,2,0,201,57,215,245,81,189,42,143,191,254,206,143,235,170,158, + 5,150,237,218,108,55,167,68,34,165,105,99,35,17,41,72,115,74,26,143,116,191,185,183,252,23,241,19,86,58,109,31, + 74,23,56,251,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Play = { //size: 660 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,12,6,17,36,33,206,217,173,94,0,0,2,33,73, + 68,65,84,56,203,157,147,75,107,19,1,20,133,207,60,50,201,36,77,38,49,153,105,98,19,19,90,73,48,35,186,74, + 209,212,72,82,108,138,5,193,103,116,39,88,16,193,66,182,221,249,7,92,244,23,72,151,130,47,186,114,163,136,32,46, + 12,66,77,21,177,88,108,160,17,74,250,208,164,51,77,50,51,185,46,196,166,98,41,177,119,117,238,230,131,115,239,57, + 64,119,120,28,96,184,93,58,2,192,1,160,9,128,122,5,176,187,151,252,248,216,235,96,48,152,6,224,235,21,192,252, + 17,138,44,31,25,62,149,250,198,48,76,199,178,204,47,229,15,159,110,182,90,173,207,181,90,77,239,201,66,52,22,147, + 188,62,169,248,236,233,28,239,145,60,254,106,117,101,178,191,95,25,233,48,244,102,32,52,80,175,213,106,180,47,32,169, + 170,146,40,58,138,215,11,55,216,72,100,128,157,56,63,193,245,185,221,225,141,245,245,219,162,83,76,58,69,215,187,100, + 242,88,99,121,185,178,55,96,56,149,146,56,142,41,94,189,114,141,5,1,174,62,55,212,164,202,165,79,167,5,151,83, + 76,252,168,255,156,52,45,107,117,104,112,168,178,180,180,212,252,7,144,203,102,165,182,217,46,94,186,120,153,221,210,235, + 48,140,54,12,163,13,187,195,142,120,34,193,229,243,227,14,34,186,64,48,83,137,120,252,125,230,76,166,81,42,149,204, + 157,223,7,100,5,13,173,14,0,208,116,13,32,2,1,176,241,54,120,61,62,232,164,131,200,98,252,135,252,134,215,19, + 144,120,142,117,3,104,238,0,20,69,70,245,251,111,127,186,190,5,155,205,142,195,193,48,44,211,196,236,236,3,107,241, + 235,226,102,44,22,189,163,4,66,111,1,90,187,59,53,101,252,149,62,89,150,201,38,8,0,8,209,240,32,120,158,199, + 227,39,143,172,133,143,11,70,60,113,244,94,102,36,251,176,211,233,172,22,10,133,22,246,138,175,44,43,16,4,27,117, + 136,240,242,213,11,42,151,231,45,183,199,243,60,123,118,116,90,16,236,149,92,46,171,237,245,198,46,64,9,64,20,237, + 52,51,115,223,210,116,109,101,52,59,122,43,32,135,230,143,171,234,198,126,65,234,222,32,32,99,123,187,181,121,110,44, + 53,125,66,61,57,7,48,155,138,162,80,207,81,38,162,48,0,3,192,26,195,48,214,127,215,146,136,216,131,212,249,23, + 48,70,193,31,65,224,78,98,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Record = { //size: 653 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,31,73,68,65,84,56,141, + 165,146,191,79,83,81,20,199,191,231,222,190,246,181,233,15,250,196,244,17,219,69,23,41,97,0,177,9,152,72,28,28, + 193,137,85,7,255,2,13,187,131,110,44,46,50,59,43,115,19,226,212,116,168,77,108,9,67,141,44,150,0,173,37,64, + 109,74,222,123,188,182,247,29,135,214,154,98,49,38,124,147,179,220,156,243,201,61,223,243,37,102,198,117,36,174,53,13, + 192,55,238,177,64,20,212,128,199,18,88,80,64,18,64,81,2,249,57,230,175,151,123,233,242,10,59,68,15,69,52,250, + 97,106,109,205,8,77,79,251,68,56,76,238,254,190,247,51,151,235,182,10,133,247,12,188,188,199,108,143,5,148,136,30, + 197,102,103,179,169,245,117,189,231,186,232,53,155,240,92,23,50,24,132,223,52,225,148,74,170,186,185,249,101,190,219,93, + 196,96,112,8,40,18,69,3,177,216,247,187,27,27,55,156,131,3,168,118,27,96,238,151,231,1,74,33,152,78,227,60, + 159,239,214,183,182,94,204,51,191,27,49,81,2,79,110,173,174,70,187,167,167,232,213,235,128,101,1,142,3,216,54,96, + 89,96,203,130,93,46,35,190,188,172,105,209,232,171,191,76,20,192,3,61,153,212,46,118,119,161,26,13,144,223,15,105, + 24,32,162,225,15,188,94,15,189,86,11,122,42,101,20,136,140,69,230,230,159,43,16,221,145,74,161,83,46,131,29,7, + 66,8,176,148,16,145,8,40,18,1,2,1,176,235,66,213,106,240,199,98,42,208,191,78,115,184,130,98,46,116,78,78, + 88,155,156,132,32,130,16,2,130,8,100,89,64,163,1,175,90,133,119,116,4,65,132,139,90,77,234,192,183,17,15,8, + 200,183,247,246,58,250,204,12,136,8,52,128,72,41,251,48,33,160,153,38,72,215,97,55,26,149,52,115,103,4,176,192, + 252,233,172,88,252,204,68,28,202,100,32,164,4,6,32,16,65,24,6,66,75,75,168,103,179,29,184,238,243,171,114,48, + 165,133,195,229,228,202,202,77,221,52,165,58,62,6,92,23,52,49,1,17,143,163,190,189,221,57,175,84,94,207,41,245, + 230,202,36,150,136,66,36,196,91,61,145,120,22,74,165,60,95,56,76,78,173,38,156,195,195,31,174,109,63,189,207,156, + 251,103,148,127,235,35,145,188,13,164,25,72,120,192,78,134,249,108,92,223,149,128,255,213,47,18,206,244,197,113,23,107, + 46,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Rewind = { //size: 764 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,12,6,17,39,32,146,243,206,11,0,0,2,137,73, + 68,65,84,56,203,189,147,203,75,84,97,24,198,159,239,59,183,153,243,157,51,206,120,59,103,108,186,200,232,228,128,102, + 58,102,74,58,16,65,16,109,211,69,101,33,129,45,170,93,23,108,17,210,133,90,212,34,250,11,2,105,85,102,19,66, + 132,82,139,194,114,22,225,37,44,138,74,37,203,209,105,200,60,115,142,142,206,215,102,144,2,187,64,208,11,239,230,247, + 240,91,189,239,3,252,135,161,0,220,191,224,30,241,15,34,203,173,3,192,206,113,5,128,55,151,67,88,67,36,30,143, + 238,82,20,197,87,84,84,92,29,137,212,118,204,37,147,143,100,89,6,33,196,160,148,110,240,251,253,129,186,186,72,199, + 236,108,226,9,249,209,12,133,66,50,231,220,107,89,214,250,96,121,105,155,198,180,14,0,153,145,225,177,45,182,109,123, + 40,165,82,56,188,121,191,166,107,199,8,33,43,175,199,223,148,83,0,136,70,163,180,185,57,234,181,109,39,236,55,205, + 3,117,219,106,251,182,215,215,183,223,143,245,185,37,89,146,40,165,222,138,138,242,29,13,13,245,177,202,234,170,163,189, + 119,239,185,4,65,16,12,191,9,177,181,165,213,55,58,54,186,33,176,49,16,138,238,108,58,83,224,203,47,237,234,58, + 239,243,120,60,132,103,57,152,202,196,166,230,198,27,76,211,106,46,95,186,194,124,249,249,132,103,57,84,85,133,40,200, + 16,13,191,225,42,44,246,157,211,116,125,215,169,147,167,89,158,199,43,58,75,54,172,133,5,168,42,131,174,107,66,87, + 215,133,198,194,130,2,209,89,114,86,57,211,24,10,124,110,80,211,48,225,86,93,94,213,237,146,102,18,51,220,118,210, + 176,172,111,248,242,53,9,66,0,93,215,179,51,137,207,220,89,180,145,78,91,72,229,56,83,85,24,166,9,106,154,230, + 76,184,162,170,197,178,210,157,61,119,110,191,127,216,255,96,222,237,98,40,49,3,160,84,128,172,72,188,183,183,231,109, + 119,247,77,91,150,148,85,238,102,110,24,134,1,33,22,139,241,88,44,102,119,118,158,29,46,49,215,221,26,123,57,42, + 189,26,31,171,20,37,145,23,23,27,210,80,252,121,166,166,58,18,89,90,201,188,27,124,246,180,105,110,118,150,6,131, + 101,226,208,208,224,114,89,48,116,253,167,51,198,227,113,2,112,150,78,219,133,47,70,226,23,53,198,90,178,28,153,173, + 149,181,65,14,80,107,121,65,73,37,146,199,83,169,228,137,169,169,143,124,207,238,189,165,100,173,23,156,156,156,164,224, + 60,239,195,244,196,166,199,253,253,87,15,31,58,178,143,3,243,4,156,241,44,212,233,79,19,102,255,192,192,181,182,182, + 246,131,228,119,37,112,22,23,101,2,238,5,144,81,20,87,10,0,108,219,17,0,104,0,87,255,186,77,156,115,101,13, + 70,56,231,250,63,87,245,59,186,53,233,69,8,225,63,138,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Skip = { //size: 782 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,12,6,17,39,8,167,70,102,241,0,0,2,155,73, + 68,65,84,56,203,189,147,59,76,19,113,28,199,191,255,123,244,238,218,43,82,192,222,181,64,33,62,18,104,4,68,211, + 68,133,193,129,81,6,28,28,25,157,92,140,38,74,84,210,85,33,44,190,66,28,12,218,184,24,37,6,69,67,116,84, + 112,144,71,124,64,76,120,212,96,160,143,163,244,122,215,235,113,45,127,23,32,81,97,51,126,167,95,62,223,228,51,125, + 127,192,63,72,25,0,102,23,46,237,193,127,11,11,160,2,128,12,192,3,160,8,160,180,213,201,0,246,1,32,91,156, + 238,42,240,120,220,222,246,246,182,30,199,113,82,133,66,65,230,121,158,147,36,201,113,9,2,215,214,118,170,183,88,44, + 102,1,106,10,130,80,178,237,141,210,95,130,80,109,200,171,6,149,135,138,226,239,246,251,247,219,186,158,91,100,24,166, + 92,150,101,82,93,19,28,84,20,127,119,69,165,207,109,26,249,21,85,85,139,85,85,85,142,166,105,59,34,182,49,28, + 246,122,60,238,139,207,159,13,139,147,51,83,205,101,178,124,214,227,145,150,114,57,35,93,93,27,60,255,98,120,68,154, + 155,251,22,22,68,225,28,207,242,122,42,173,25,45,45,45,118,125,125,221,70,60,30,167,164,171,171,43,224,18,184,133, + 216,227,39,34,97,8,50,107,107,180,231,218,85,211,52,140,41,128,156,120,52,20,227,9,67,160,235,58,141,70,123,51, + 90,102,109,49,153,76,221,92,142,47,127,111,58,210,244,131,11,168,42,10,142,5,0,48,13,3,130,36,144,123,119,238, + 203,105,77,59,25,141,222,96,182,57,199,179,164,191,111,160,34,171,175,151,245,245,223,122,112,248,224,129,119,44,235,186, + 192,41,170,138,180,150,0,33,64,38,171,65,20,37,128,82,36,146,171,212,235,245,110,18,2,102,45,171,65,20,4,208, + 77,138,68,50,65,221,146,200,151,74,78,121,69,185,31,156,162,40,48,11,58,24,134,69,80,173,129,97,26,136,197,134, + 172,68,50,181,228,18,248,67,219,220,178,242,24,123,251,70,159,253,58,187,106,154,249,187,141,13,77,49,2,178,206,169, + 170,138,68,234,39,156,162,131,209,209,17,123,97,105,62,239,243,85,94,57,222,90,255,114,230,243,212,130,83,116,248,233, + 153,79,214,196,248,7,91,207,153,131,199,142,70,6,40,161,122,231,153,206,2,0,144,137,241,241,192,235,177,87,139,181, + 181,213,196,231,171,188,237,243,87,222,241,112,178,77,128,205,233,47,147,243,12,1,111,152,230,211,214,230,200,117,183,91, + 74,3,196,140,68,34,59,163,226,148,128,10,150,97,222,135,27,194,151,130,129,186,85,194,32,79,65,76,2,148,173,142, + 173,124,60,221,209,113,185,62,88,183,4,66,178,161,80,104,243,207,33,17,203,178,2,91,103,30,128,33,73,98,9,0, + 108,187,224,3,192,83,144,117,81,16,54,246,124,6,74,169,151,82,74,118,225,2,254,71,126,1,54,156,22,72,126,132, + 128,72,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Stop = { //size: 429 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,12,6,17,40,46,242,211,255,195,0,0,1,58,73, + 68,65,84,56,203,205,146,95,74,3,49,16,135,191,236,164,175,22,10,102,60,128,88,240,20,34,30,66,196,75,8,226, + 137,68,188,130,136,215,16,84,4,69,41,138,62,172,44,180,187,221,221,196,135,253,171,173,138,79,26,8,204,100,50,95, + 230,55,25,248,235,101,122,246,198,47,115,111,128,96,27,111,52,26,177,189,179,117,105,140,145,159,50,207,207,46,198,113, + 28,155,15,0,117,142,193,96,96,78,142,79,191,77,222,219,223,245,170,74,28,199,0,68,77,96,213,41,34,213,227,183, + 119,87,60,78,238,121,121,125,230,45,137,73,179,20,239,61,0,214,90,156,106,11,108,1,170,29,64,196,214,91,144,72, + 48,192,60,207,234,152,160,206,45,2,156,186,22,16,69,2,6,124,8,20,101,65,154,165,204,102,211,10,96,5,183,12, + 176,214,171,32,4,79,89,150,20,197,156,44,75,153,165,83,166,105,5,176,34,104,79,130,237,122,224,152,60,61,0,80, + 150,37,222,123,202,162,226,251,26,216,200,115,234,22,1,234,58,9,121,158,19,8,24,32,16,240,222,183,77,20,43,168, + 91,82,129,246,122,48,94,223,252,242,27,165,147,16,62,85,160,136,72,56,60,58,248,118,14,36,138,34,231,58,64,59, + 202,73,146,212,163,28,170,227,80,217,193,84,66,42,191,185,17,24,174,12,175,249,23,235,29,41,108,117,184,218,69,135, + 206,0,0,0,0,73,69,78,68,174,66,96,130, +}; +} +namespace Place { +const nall::vector Bookmarks = { //size: 753 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,10,6,3,42,40,185,100,186,202,0,0,0,53,116, + 69,88,116,67,111,109,109,101,110,116,0,40,99,41,32,50,48,48,52,32,74,97,107,117,98,32,83,116,101,105,110,101, + 114,10,10,67,114,101,97,116,101,100,32,119,105,116,104,32,84,104,101,32,71,73,77,80,144,217,139,111,0,0,2,61, + 73,68,65,84,56,203,149,147,77,79,83,65,20,134,159,153,222,185,247,246,131,182,96,63,80,106,20,98,76,140,49,38, + 198,104,252,13,154,96,220,152,16,226,194,133,127,193,164,11,8,44,76,252,31,132,61,145,159,96,226,194,132,13,10,6, + 48,86,180,84,161,32,45,183,237,237,237,244,142,139,98,161,194,66,79,50,155,153,57,207,188,239,57,103,4,192,84,113, + 97,14,152,225,223,99,126,241,213,244,44,128,152,42,46,204,141,72,61,243,226,249,67,60,95,227,181,58,4,90,83,243, + 218,0,72,41,0,16,199,153,13,63,160,94,89,230,217,189,34,169,236,228,75,11,152,121,252,232,65,24,134,70,118,131, + 14,217,84,140,141,242,62,141,202,1,67,229,61,84,171,77,168,34,120,163,25,90,153,20,249,145,56,117,32,149,157,164, + 182,183,244,218,2,112,28,71,26,224,224,208,35,26,115,161,222,36,93,170,80,187,50,74,144,136,97,249,109,82,165,10, + 93,21,129,145,56,49,39,232,123,177,0,92,87,1,134,150,223,59,144,95,42,212,199,178,68,130,14,185,213,45,140,16, + 252,186,86,32,249,109,23,198,243,68,237,206,32,192,118,108,194,110,216,223,20,135,30,237,66,142,204,90,137,122,33,71, + 226,199,62,218,181,81,77,31,128,119,159,124,58,106,131,143,43,49,36,128,173,20,230,84,161,8,13,70,8,164,238,98, + 34,17,16,2,231,168,137,142,218,103,218,33,1,132,16,128,57,33,196,93,84,195,199,31,30,234,189,110,43,146,219,63, + 169,95,206,247,248,36,6,45,156,68,143,16,142,143,146,220,44,83,187,122,17,29,117,64,136,129,91,110,73,241,100,17, + 110,175,55,123,0,131,1,3,185,11,41,0,76,54,77,189,173,73,126,223,69,53,90,116,109,69,245,230,196,185,19,213, + 83,96,64,41,139,116,58,129,223,209,228,135,227,36,163,14,92,31,235,235,74,13,104,252,11,224,53,90,188,89,126,139, + 37,13,161,233,45,173,13,66,10,108,21,65,8,129,0,186,221,144,175,229,106,152,111,30,201,207,235,235,0,79,45,128, + 15,171,91,220,191,17,239,143,237,121,33,165,164,41,210,108,236,7,114,123,252,22,119,143,197,88,0,135,94,131,137,220, + 16,133,194,165,51,137,226,84,1,215,54,119,206,173,193,252,251,205,234,140,110,53,195,157,106,32,93,87,161,59,122,192, + 240,31,132,238,134,76,222,201,152,165,149,170,56,221,55,57,85,92,152,253,207,239,204,226,171,105,1,240,27,115,187,219, + 217,106,190,108,255,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Desktop = { //size: 722 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,2,23,0,42,10,182,151,62,76,0,0,2,95,73, + 68,65,84,56,203,165,147,93,76,207,81,24,199,63,231,247,79,180,48,179,24,27,235,154,102,46,136,205,172,197,52,46, + 112,161,194,13,174,72,102,140,214,100,105,11,115,229,109,35,204,186,112,41,11,139,27,47,155,41,169,141,44,111,49,47, + 75,72,249,139,213,164,214,239,229,156,231,113,81,254,254,255,113,97,115,110,206,246,61,223,231,57,159,243,221,115,204,162, + 101,197,84,87,149,51,240,125,8,128,246,246,118,94,63,171,227,111,107,199,238,179,188,121,215,3,64,247,135,78,154,239, + 63,192,44,204,91,87,239,197,98,69,201,198,135,119,235,99,207,59,26,5,64,84,177,97,200,246,178,218,67,198,152,170, + 100,159,170,222,51,139,150,21,235,191,16,244,13,206,166,186,106,255,31,4,105,0,111,222,245,208,210,246,130,129,175,189, + 184,225,247,156,58,126,44,81,248,139,64,129,178,202,163,108,43,41,165,225,102,43,3,95,123,1,70,27,0,163,66,24, + 167,114,95,49,95,250,186,82,110,247,253,17,172,141,216,185,117,49,53,231,207,49,61,123,126,226,204,251,133,67,24,167, + 98,239,154,148,66,21,193,218,8,99,60,98,177,52,198,165,167,179,107,251,18,250,62,60,77,120,98,51,179,231,204,253, + 220,211,153,115,160,124,19,198,132,191,209,69,80,21,84,65,85,176,206,34,206,33,78,200,156,48,204,203,87,189,136,198, + 14,123,143,154,174,108,152,58,49,78,86,214,20,0,156,115,88,107,113,206,34,162,168,42,65,24,160,162,88,107,241,131, + 17,188,152,146,53,169,151,182,198,203,7,19,25,8,58,214,192,162,40,6,16,129,48,244,113,206,33,170,132,81,136,136, + 36,191,210,75,203,205,47,186,248,237,71,72,198,248,76,6,198,8,140,49,40,6,107,35,48,6,85,37,138,2,212,9, + 34,14,128,254,161,25,228,230,23,174,242,140,49,27,243,150,175,165,116,207,73,84,21,17,71,24,133,248,254,8,65,224, + 19,4,62,97,20,224,156,224,156,195,57,199,195,39,131,108,44,94,143,49,222,117,15,160,171,59,206,226,165,43,57,81, + 115,11,39,163,70,113,14,17,193,217,209,93,196,225,196,113,237,198,123,118,148,150,209,252,248,99,234,28,116,117,199,153, + 183,160,128,51,181,119,88,189,98,22,126,56,12,40,145,181,140,197,67,75,219,32,155,183,148,112,225,210,237,68,8,105, + 201,137,116,117,199,153,144,145,73,221,181,183,76,155,252,41,101,38,134,252,41,172,40,40,162,225,102,107,138,110,114,243, + 11,59,140,241,114,146,69,17,119,228,81,211,213,211,64,255,152,52,46,55,191,168,226,111,159,137,255,93,63,1,185,254, + 98,48,219,255,91,223,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Home = { //size: 679 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,2,36,73,68,65,84,56,141,165,146,77,107,83,65,20,134,159,51,115, + 107,211,196,170,88,48,196,66,193,69,237,34,27,161,226,162,123,201,170,139,32,116,235,47,208,189,208,63,224,198,93,221, + 250,55,68,20,226,78,40,24,237,198,34,149,86,41,77,73,168,54,183,105,155,59,51,119,142,139,124,180,129,226,198,179, + 25,230,204,57,207,249,120,71,106,181,26,255,99,201,242,242,242,27,85,93,189,226,237,76,85,159,52,155,205,205,127,2, + 98,140,245,122,189,126,51,198,72,140,17,85,5,224,248,248,120,174,209,104,108,84,171,213,231,163,96,239,61,198,152,252, + 224,224,224,115,154,166,57,64,226,189,215,16,2,157,78,135,60,207,199,16,99,12,149,74,165,10,188,27,65,1,122,189, + 94,146,231,249,171,52,77,215,47,1,60,33,4,98,140,19,144,114,185,92,44,20,10,20,139,69,172,181,24,99,104,181, + 90,180,219,237,197,241,8,33,132,24,66,206,198,71,199,105,118,81,9,4,0,165,15,244,199,94,85,3,172,172,177,176, + 178,102,173,249,153,120,239,213,57,71,47,83,94,62,123,140,200,48,240,242,166,116,226,6,128,11,202,250,235,15,11,137, + 115,46,134,16,0,197,26,248,178,219,189,220,192,232,152,220,188,21,238,149,75,32,170,73,8,1,239,61,34,130,53,130, + 181,23,41,215,11,9,143,22,111,147,24,225,211,247,223,164,231,126,160,70,136,104,84,4,209,196,123,31,189,247,160,138, + 17,97,202,10,198,8,247,43,215,89,186,59,139,53,3,96,237,65,153,111,251,41,95,247,186,184,160,152,129,127,0,8, + 97,208,65,223,229,220,185,49,205,210,252,44,51,215,44,103,46,31,143,175,170,204,207,205,112,171,52,197,214,94,151,204, + 197,49,64,67,200,17,73,232,164,25,219,251,39,108,238,252,97,245,97,101,84,101,176,11,129,204,71,222,54,15,177,70, + 88,152,155,25,0,66,8,209,57,7,106,217,105,157,112,212,203,80,224,168,231,198,138,140,150,233,66,36,61,247,88,35, + 28,118,135,35,136,72,140,49,34,34,100,62,82,156,78,0,232,251,124,152,120,65,201,163,82,154,78,16,17,206,92,0, + 200,19,85,101,247,40,34,2,91,63,90,227,224,237,189,195,73,9,135,237,140,190,245,233,105,31,129,205,36,78,149,26, + 239,119,103,159,130,178,255,171,125,133,234,87,155,8,109,17,243,226,47,238,171,54,255,32,151,176,79,0,0,0,0,73, + 69,78,68,174,66,96,130, +}; +const nall::vector Server = { //size: 642 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,96,0,96,0,96,101,20,102,74,0,0,0,9,112,72,89,115,0,0,11,18,0, + 0,11,18,1,210,221,126,252,0,0,0,7,116,73,77,69,7,213,5,24,13,41,13,225,69,167,57,0,0,0,62,116, + 69,88,116,67,111,109,109,101,110,116,0,67,114,101,97,116,101,100,32,119,105,116,104,32,84,104,101,32,71,73,77,80, + 10,10,40,99,41,32,50,48,48,51,32,74,97,107,117,98,32,39,106,105,109,109,97,99,39,32,83,116,101,105,110,101, + 114,39,51,239,88,0,0,1,197,73,68,65,84,56,203,141,146,189,138,34,81,16,133,191,235,54,218,6,6,98,172,160, + 145,8,3,254,177,6,194,226,62,192,198,70,3,247,5,140,134,13,124,2,31,192,23,16,246,17,54,22,100,2,3,55, + 145,53,53,145,246,47,16,49,209,139,77,119,215,6,59,221,171,163,50,123,224,66,113,239,61,167,234,84,149,226,26,79, + 90,235,223,124,128,193,96,240,25,248,197,29,178,44,151,75,241,125,95,124,223,23,207,243,196,117,93,113,93,87,140,49, + 98,140,145,241,120,44,90,107,1,190,94,177,181,214,114,62,159,175,200,247,4,78,167,147,236,247,251,80,4,235,82,68, + 41,197,104,52,250,200,1,173,86,43,138,173,247,143,167,211,137,114,185,252,144,60,157,78,49,198,252,19,208,90,127,1, + 190,135,23,201,100,18,99,12,34,130,136,16,4,1,34,130,239,251,127,9,150,69,16,4,161,237,159,86,183,219,5,160, + 215,235,1,112,60,30,153,207,231,0,136,72,148,41,140,67,33,128,78,167,51,179,66,98,136,70,163,17,125,10,43,80, + 74,33,34,24,99,136,199,227,40,165,0,232,247,251,79,214,96,48,120,5,94,181,214,98,89,22,195,225,144,213,106,69, + 62,159,167,84,42,177,221,110,241,125,63,170,64,68,200,102,179,225,62,124,139,189,111,146,227,56,20,139,69,102,179,25, + 74,41,226,241,56,133,66,33,58,151,22,110,166,32,34,20,10,5,38,147,9,237,118,27,219,182,113,93,151,197,98,17, + 85,96,219,54,135,195,225,241,24,235,245,58,213,106,53,234,124,46,151,187,219,204,55,124,186,177,224,121,30,65,16,68, + 222,29,199,193,243,60,28,199,1,136,70,248,134,68,236,209,194,236,118,59,0,54,155,13,137,68,130,245,122,77,44,22, + 139,54,54,220,187,43,11,135,195,129,76,38,3,64,165,82,33,149,74,209,108,54,73,165,82,212,106,53,210,233,244,77, + 162,75,129,231,151,151,151,31,252,63,158,1,254,0,124,80,17,254,250,115,5,147,0,0,0,0,73,69,78,68,174,66, + 96,130, +}; +const nall::vector Share = { //size: 697 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, + 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, + 97,112,101,46,111,114,103,155,238,60,26,0,0,2,54,73,68,65,84,56,141,125,147,207,75,212,65,20,192,63,111,230, + 107,172,38,90,80,45,66,132,68,157,194,91,93,130,46,65,7,15,29,36,242,210,41,130,14,65,157,69,188,117,144,16, + 58,85,215,46,5,37,228,31,32,84,22,221,52,163,31,134,66,96,65,184,225,82,173,185,201,126,191,243,102,94,135,93, + 55,53,233,93,30,243,230,205,231,253,28,25,29,29,189,111,102,231,249,87,54,204,236,194,248,248,248,236,46,119,109,145, + 145,145,145,218,208,208,80,111,74,137,148,18,102,6,64,173,86,99,102,102,102,54,165,116,99,211,57,132,128,115,46,174, + 172,172,204,79,78,78,70,128,44,132,96,170,74,181,90,37,198,216,134,56,231,232,235,235,59,1,76,111,66,1,234,245, + 122,22,99,188,13,140,109,1,4,84,149,148,210,54,72,185,92,238,42,149,74,116,117,117,225,189,199,57,71,165,82,97, + 117,117,245,248,38,48,83,213,164,26,185,251,162,224,119,254,55,18,8,0,70,3,104,180,173,102,14,56,61,124,234,234, + 195,97,239,221,151,44,132,96,69,81,80,207,141,91,215,207,33,210,114,220,218,41,219,118,2,160,80,99,236,222,211,35, + 89,81,20,73,85,1,35,115,240,102,121,173,25,95,118,233,120,75,59,47,28,45,239,5,49,203,84,149,16,2,34,130, + 115,130,247,187,188,220,33,170,9,51,16,196,178,16,66,10,33,128,25,78,132,142,255,0,52,26,121,72,196,100,248,102, + 138,77,128,106,51,131,70,17,145,86,201,26,141,104,70,74,70,50,35,104,83,3,100,94,104,20,218,6,152,106,68,36, + 163,250,43,167,242,163,65,174,233,191,37,100,94,168,174,229,77,128,170,166,162,40,192,60,159,42,235,124,175,231,237,9, + 104,99,125,219,56,178,206,110,64,240,78,248,182,214,42,65,68,82,140,17,193,104,228,129,206,142,102,15,150,95,62,96, + 189,178,216,126,159,98,162,251,80,63,199,206,94,193,249,140,141,70,142,64,204,82,74,242,122,225,51,165,159,57,243,207, + 22,219,209,194,215,247,76,76,76,48,55,55,215,222,204,39,83,83,124,120,254,24,201,246,16,130,146,113,96,73,222,190, + 91,88,46,237,235,235,223,89,231,181,203,23,25,24,24,64,90,11,97,102,44,46,46,113,115,226,14,61,189,251,241,94, + 180,167,179,227,149,12,14,14,30,78,41,93,2,14,110,5,152,217,25,51,59,185,213,230,156,251,40,34,211,214,252,93, + 234,189,127,244,7,187,71,87,220,223,105,176,149,0,0,0,0,73,69,78,68,174,66,96,130, +}; +} +namespace Prompt { +const nall::vector Error = { //size: 653 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,11,10,9,50,14,147,83,180,176,0,0,2,26,73, + 68,65,84,56,203,157,147,189,79,147,81,20,198,127,247,109,11,229,163,190,160,196,26,77,160,104,155,2,182,11,196,148, + 68,135,142,186,50,105,210,129,17,254,34,59,50,116,102,35,178,144,64,88,68,7,48,146,22,154,104,99,248,176,36,164, + 45,77,91,40,246,61,199,225,125,75,16,137,26,79,114,115,147,155,243,252,158,228,57,247,24,110,84,14,82,192,60,144, + 6,198,189,231,18,176,14,44,101,96,235,122,191,185,33,126,59,28,10,45,76,38,147,4,195,97,124,3,3,168,42,157, + 179,51,206,203,101,138,133,2,213,102,51,155,129,197,223,0,57,120,55,157,76,190,28,153,153,225,114,123,27,231,244,20, + 28,7,85,69,12,88,67,119,241,79,77,82,221,221,229,83,177,184,154,129,87,0,190,174,243,116,50,249,250,94,44,70, + 123,115,19,109,52,64,4,85,65,69,65,4,105,182,232,28,124,163,63,22,195,182,172,232,139,106,245,193,50,172,152,28, + 164,134,67,161,247,207,230,230,184,88,91,67,157,14,170,138,42,168,122,98,5,197,133,169,49,4,83,41,62,111,108,80, + 107,181,102,45,96,126,50,145,224,114,103,7,117,28,16,80,1,21,113,15,234,129,20,84,193,113,184,200,231,121,60,22, + 1,152,247,3,233,96,248,62,63,62,124,68,69,25,43,127,231,79,181,111,223,65,170,53,2,15,31,1,164,253,192,184, + 213,63,136,138,27,216,223,74,68,81,237,96,122,2,0,227,22,112,149,246,191,0,240,250,84,5,0,63,80,234,212,207, + 38,20,131,170,195,151,145,17,183,65,196,189,81,55,60,55,85,68,221,32,181,217,2,40,89,192,250,249,201,9,198,30, + 186,34,255,34,238,58,138,39,86,193,26,28,164,93,171,1,172,91,192,210,254,222,30,129,120,220,37,203,117,145,55,58, + 237,78,67,80,99,240,71,34,148,14,15,1,150,172,12,108,213,90,173,108,165,144,167,103,234,169,11,185,230,138,119,171, + 40,24,67,79,52,70,227,224,128,122,187,157,205,192,150,15,96,25,86,158,87,42,179,182,207,23,29,72,36,112,26,13, + 228,162,125,245,19,21,48,118,136,222,248,4,141,114,153,194,241,241,106,6,222,220,186,76,118,95,223,194,147,209,81,2, + 182,141,233,237,69,69,112,154,77,58,245,58,95,143,142,186,206,139,183,110,227,255,172,243,79,194,71,102,30,185,88,118, + 119,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Information = { //size: 863 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,3,2,6,32,50,58,80,156,247,0,0,0,53,116, + 69,88,116,67,111,109,109,101,110,116,0,40,99,41,32,50,48,48,52,32,74,97,107,117,98,32,83,116,101,105,110,101, + 114,10,10,67,114,101,97,116,101,100,32,119,105,116,104,32,84,104,101,32,71,73,77,80,144,217,139,111,0,0,2,171, + 73,68,65,84,56,203,149,146,75,72,84,113,20,198,191,255,220,59,227,189,58,215,71,38,89,106,102,82,62,8,69,34, + 19,196,161,6,37,212,164,162,144,108,98,202,112,97,180,8,19,178,69,203,16,49,170,69,143,77,162,139,136,160,2,3, + 3,37,200,16,73,116,38,74,74,205,138,52,149,76,157,113,116,156,185,119,174,247,245,111,229,160,53,17,126,171,115,224, + 251,126,156,115,56,4,17,84,92,217,212,76,41,28,6,37,41,32,132,152,136,49,203,16,250,180,255,101,107,227,159,94, + 118,125,83,84,222,148,193,48,164,239,98,109,101,90,185,189,0,113,2,15,85,55,224,241,5,83,123,122,63,92,33,38, + 230,44,165,122,73,127,87,235,215,136,0,150,37,111,239,181,212,111,223,147,185,99,44,16,82,70,103,125,146,18,90,85, + 89,69,211,163,109,37,249,89,233,233,201,123,91,110,61,118,1,136,95,203,48,107,69,73,213,213,219,245,231,143,150,21, + 31,204,249,172,168,186,155,183,152,21,0,68,167,32,170,78,13,239,74,104,150,139,230,16,205,115,59,117,38,37,115,114, + 252,109,39,0,152,194,36,134,61,87,110,47,64,32,164,142,177,44,67,45,102,198,32,132,80,80,24,154,110,40,148,194, + 232,26,156,236,46,42,204,1,195,114,167,214,114,97,192,170,66,227,5,43,15,89,209,87,85,205,72,52,51,166,11,137, + 177,156,115,87,178,224,200,223,189,213,1,37,144,58,229,17,253,60,207,33,32,169,92,109,93,131,105,195,13,8,33,68, + 209,116,72,178,106,50,12,42,38,88,163,224,245,75,46,81,10,49,43,65,73,27,158,150,134,21,69,55,169,170,177,22, + 225,1,136,97,64,12,207,74,94,95,32,70,148,85,203,138,164,250,51,146,99,49,250,195,247,94,84,116,58,183,36,41, + 238,111,139,30,193,106,73,240,250,131,136,19,120,181,163,173,89,220,176,130,153,209,6,122,222,12,131,143,98,115,39,126, + 45,139,0,240,211,39,234,31,39,188,254,222,225,153,133,37,81,54,87,236,79,171,24,114,141,193,202,97,226,175,27,108, + 19,66,199,59,187,250,229,153,233,249,236,180,36,235,161,107,237,3,55,207,28,206,186,228,254,50,31,98,88,146,232,180, + 103,85,251,23,151,114,220,131,35,170,192,250,74,195,171,175,255,131,99,167,27,171,100,42,60,47,43,45,178,20,30,200, + 70,52,207,65,213,117,248,150,69,12,185,198,241,206,53,162,197,113,210,229,39,237,55,30,68,4,0,64,109,93,67,98, + 136,110,113,5,100,164,59,78,36,49,132,0,44,11,116,117,207,5,25,205,191,175,163,237,206,20,254,167,154,26,187,213, + 233,180,81,207,98,31,21,101,23,253,62,249,140,58,157,54,26,201,203,254,131,161,2,192,253,187,15,145,157,155,141,233, + 169,105,108,90,78,167,141,206,204,190,50,2,210,16,253,52,250,194,216,236,4,0,80,85,125,242,122,141,32,196,31,89, + 88,88,120,157,151,23,251,40,146,233,55,86,76,54,94,124,138,29,4,0,0,0,0,73,69,78,68,174,66,96,130, +}; +const nall::vector Question = { //size: 932 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, + 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,3,54,73,68,65,84,56,141, + 109,147,91,108,84,101,20,133,191,243,255,231,90,81,26,192,134,78,161,244,54,237,128,78,169,83,130,5,77,83,46,70, + 45,250,162,162,134,196,132,152,24,19,43,6,73,76,39,65,140,105,162,173,23,36,241,65,13,137,17,210,248,224,131,9, + 160,71,35,130,142,213,160,5,105,25,90,219,130,99,167,98,157,161,45,80,123,153,105,167,118,206,239,67,75,3,193,157, + 236,151,157,189,87,214,94,89,75,83,74,113,99,21,111,107,9,0,207,0,117,64,112,126,220,5,68,128,214,184,27,238, + 187,113,95,187,14,80,188,173,69,0,141,139,114,204,87,119,62,186,206,190,39,224,19,149,229,249,0,156,191,152,164,243, + 66,194,59,116,236,215,204,100,122,166,9,120,59,238,134,189,5,128,249,227,182,251,170,138,66,45,47,61,236,156,138,14, + 112,162,61,70,79,255,48,0,107,74,242,120,160,198,207,198,181,171,8,191,255,245,212,79,157,3,29,64,109,220,13,123, + 250,60,147,198,77,235,74,67,111,238,122,200,217,179,255,75,174,141,165,217,251,220,102,42,253,249,164,167,102,248,161,35, + 78,171,219,201,241,95,98,188,187,231,17,231,149,3,110,245,143,29,241,70,160,153,162,250,230,64,112,251,123,169,191,135, + 199,212,211,225,79,85,81,125,179,122,177,229,136,202,102,61,213,211,63,164,70,199,211,74,41,165,78,158,142,169,154,157, + 31,169,134,183,190,80,137,145,113,21,220,190,63,93,84,223,28,144,185,254,173,47,191,240,228,134,77,163,227,105,237,208, + 177,179,0,24,134,206,103,199,207,115,216,61,71,123,247,95,60,190,229,110,86,46,207,229,243,239,123,25,25,77,81,186, + 98,9,37,43,150,202,83,209,63,39,4,80,87,85,225,211,78,180,199,0,176,76,157,75,151,199,72,94,77,97,91,6, + 85,21,62,0,174,254,147,198,48,116,114,28,139,206,223,135,8,173,46,16,82,136,58,29,8,6,203,150,19,189,152,196, + 48,36,166,105,96,89,6,150,105,16,10,20,176,123,199,70,148,82,28,60,218,129,99,91,8,161,145,184,50,201,234,226, + 60,60,165,130,215,69,68,8,13,67,215,49,141,185,182,76,131,189,207,214,98,234,146,195,95,69,233,187,52,74,142,99, + 34,132,192,177,76,52,52,52,64,0,93,93,177,203,132,2,5,24,134,156,99,97,232,44,190,221,102,32,57,198,153,222, + 4,109,209,65,28,219,196,177,45,114,28,147,242,194,101,196,6,175,33,164,232,18,64,228,220,133,132,183,101,125,25,186, + 46,209,117,137,97,232,104,66,240,115,247,32,167,123,147,72,41,177,109,99,1,164,210,159,71,247,31,67,94,54,235,69, + 4,208,250,241,145,51,153,13,107,87,177,254,174,149,232,82,162,75,65,238,34,135,221,79,221,75,195,99,213,228,56,38, + 150,101,98,219,38,107,138,239,164,204,151,203,129,214,72,70,41,213,42,226,110,184,111,34,149,105,218,247,193,55,83,175, + 63,191,153,80,192,135,148,2,41,181,5,191,27,243,186,4,10,151,240,68,109,41,175,125,248,237,244,68,42,211,20,119, + 195,125,55,89,121,107,141,191,250,141,134,7,237,104,108,152,104,108,152,196,149,73,108,123,238,231,202,210,101,148,228,47, + 166,233,224,201,105,183,173,231,236,204,191,179,181,113,55,236,221,18,166,59,110,179,247,237,218,113,191,93,85,225,211,202, + 11,151,162,105,26,241,196,40,191,245,143,120,239,124,242,93,102,124,114,186,41,235,121,55,135,233,255,226,44,165,168,83, + 74,5,1,164,148,93,179,179,217,136,82,234,150,56,255,7,102,247,76,148,162,219,138,97,0,0,0,0,73,69,78,68, + 174,66,96,130, +}; +const nall::vector Warning = { //size: 603 + 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, + 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, + 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,214,2,16,14,39,45,183,238,146,119,0,0,1,232,73, + 68,65,84,56,203,149,147,193,74,27,97,20,133,191,59,153,206,52,137,51,131,16,153,74,237,70,67,196,32,134,65,74, + 154,48,4,130,72,99,131,116,23,186,16,34,93,116,231,48,27,241,9,92,27,116,101,192,66,192,69,73,86,5,173,175, + 80,8,62,128,80,92,4,10,133,22,92,212,64,73,49,127,55,214,18,200,180,246,192,189,139,203,225,59,103,115,133,8, + 133,240,200,128,183,0,3,120,221,128,47,227,124,122,20,192,132,163,121,120,14,112,1,71,64,117,156,79,139,72,247,82, + 176,90,88,88,208,158,164,82,90,10,86,67,240,238,13,48,97,47,13,122,98,119,151,76,179,73,26,116,19,246,238,5, + 8,161,56,5,197,108,185,44,122,62,143,158,207,147,45,151,101,10,138,33,20,249,151,118,160,123,2,195,94,167,163,60, + 207,83,158,231,169,94,167,163,78,96,184,3,221,191,54,8,97,197,133,165,140,239,139,225,251,56,142,131,227,56,24,190, + 79,198,247,197,133,165,16,86,34,1,38,236,103,193,72,4,1,162,105,88,150,133,101,89,136,166,145,8,2,178,96,152, + 176,63,22,16,194,250,52,164,231,10,5,140,82,9,17,193,182,109,108,219,70,68,48,74,37,230,10,5,166,33,29,194, + 250,8,32,4,49,160,177,120,155,174,233,58,34,242,167,129,8,154,174,147,8,2,22,193,48,160,17,130,192,237,10,225, + 213,44,180,94,44,47,27,147,103,103,16,139,161,148,162,223,239,3,144,76,38,17,17,184,185,225,106,109,141,15,231,231, + 131,75,168,55,224,157,132,16,123,12,87,79,193,154,63,62,230,97,181,138,82,10,165,20,181,90,13,128,118,187,141,136, + 32,34,252,56,61,229,98,99,131,46,124,255,12,147,154,192,102,28,204,153,92,142,120,165,114,103,20,17,92,215,197,117, + 221,145,91,188,82,97,38,151,35,14,166,192,166,108,195,215,151,144,154,61,56,96,162,94,191,75,255,61,192,8,64,68, + 184,110,181,184,220,218,226,61,124,147,67,24,62,3,121,192,255,233,39,240,17,148,254,9,14,7,240,102,34,226,47,162, + 116,13,195,30,52,127,1,151,222,125,8,28,180,225,19,0,0,0,0,73,69,78,68,174,66,96,130, +}; +} +} diff --git a/hiro/resource/resource.hpp b/hiro/resource/resource.hpp new file mode 100644 index 00000000..5597d3dd --- /dev/null +++ b/hiro/resource/resource.hpp @@ -0,0 +1,102 @@ +namespace Icon { +namespace Action { +extern const nall::vector Add; +extern const nall::vector Attach; +extern const nall::vector Bookmark; +extern const nall::vector FullScreen; +extern const nall::vector Mute; +extern const nall::vector New; +extern const nall::vector Open; +extern const nall::vector Properties; +extern const nall::vector Quit; +extern const nall::vector Refresh; +extern const nall::vector Remove; +extern const nall::vector Save; +extern const nall::vector Search; +extern const nall::vector Settings; +extern const nall::vector Stop; +} +namespace Application { +extern const nall::vector Browser; +extern const nall::vector Calculator; +extern const nall::vector Calendar; +extern const nall::vector Chat; +extern const nall::vector FileManager; +extern const nall::vector Mail; +extern const nall::vector Monitor; +extern const nall::vector Terminal; +extern const nall::vector TextEditor; +} +namespace Device { +extern const nall::vector Clock; +extern const nall::vector Display; +extern const nall::vector Joypad; +extern const nall::vector Keyboard; +extern const nall::vector Microphone; +extern const nall::vector Mouse; +extern const nall::vector Network; +extern const nall::vector Optical; +extern const nall::vector Printer; +extern const nall::vector Speaker; +extern const nall::vector Storage; +} +namespace Edit { +extern const nall::vector Clear; +extern const nall::vector Copy; +extern const nall::vector Cut; +extern const nall::vector Delete; +extern const nall::vector Find; +extern const nall::vector Paste; +extern const nall::vector Redo; +extern const nall::vector Replace; +extern const nall::vector Undo; +} +namespace Emblem { +extern const nall::vector Archive; +extern const nall::vector Audio; +extern const nall::vector Binary; +extern const nall::vector File; +extern const nall::vector Folder; +extern const nall::vector Font; +extern const nall::vector Image; +extern const nall::vector Markup; +extern const nall::vector Program; +extern const nall::vector Script; +extern const nall::vector Text; +extern const nall::vector Video; +} +namespace Go { +extern const nall::vector Down; +extern const nall::vector Home; +extern const nall::vector Left; +extern const nall::vector Right; +extern const nall::vector Up; +} +namespace Media { +extern const nall::vector Back; +extern const nall::vector Eject; +extern const nall::vector Flash; +extern const nall::vector Floppy; +extern const nall::vector Next; +extern const nall::vector Optical; +extern const nall::vector Pause; +extern const nall::vector Play; +extern const nall::vector Record; +extern const nall::vector Rewind; +extern const nall::vector Skip; +extern const nall::vector Stop; +} +namespace Place { +extern const nall::vector Bookmarks; +extern const nall::vector Desktop; +extern const nall::vector Home; +extern const nall::vector Server; +extern const nall::vector Share; +} +namespace Prompt { +extern const nall::vector Error; +extern const nall::vector Information; +extern const nall::vector Question; +extern const nall::vector Warning; +} +} diff --git a/phoenix/windows/action/action.cpp b/hiro/windows/action/action.cpp similarity index 100% rename from phoenix/windows/action/action.cpp rename to hiro/windows/action/action.cpp diff --git a/phoenix/windows/action/check-item.cpp b/hiro/windows/action/check-item.cpp similarity index 100% rename from phoenix/windows/action/check-item.cpp rename to hiro/windows/action/check-item.cpp diff --git a/phoenix/windows/action/item.cpp b/hiro/windows/action/item.cpp similarity index 100% rename from phoenix/windows/action/item.cpp rename to hiro/windows/action/item.cpp diff --git a/phoenix/windows/action/menu.cpp b/hiro/windows/action/menu.cpp similarity index 100% rename from phoenix/windows/action/menu.cpp rename to hiro/windows/action/menu.cpp diff --git a/phoenix/windows/action/radio-item.cpp b/hiro/windows/action/radio-item.cpp similarity index 100% rename from phoenix/windows/action/radio-item.cpp rename to hiro/windows/action/radio-item.cpp diff --git a/phoenix/windows/action/separator.cpp b/hiro/windows/action/separator.cpp similarity index 100% rename from phoenix/windows/action/separator.cpp rename to hiro/windows/action/separator.cpp diff --git a/phoenix/windows/application.cpp b/hiro/windows/application.cpp similarity index 100% rename from phoenix/windows/application.cpp rename to hiro/windows/application.cpp diff --git a/phoenix/windows/browser-window.cpp b/hiro/windows/browser-window.cpp similarity index 96% rename from phoenix/windows/browser-window.cpp rename to hiro/windows/browser-window.cpp index 146c4c8e..93b2ba6b 100644 --- a/phoenix/windows/browser-window.cpp +++ b/hiro/windows/browser-window.cpp @@ -19,7 +19,7 @@ static string BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) { for(auto& filter : state.filters) { lstring part = filter.split("("); if(part.size() != 2) continue; - part[1].rtrim<1>(")"); + part[1].rtrim(")"); part[1].replace(" ", ""); part[1].transform(",", ";"); filters.append(filter, "\t", part[1], "\t"); diff --git a/phoenix/windows/desktop.cpp b/hiro/windows/desktop.cpp similarity index 100% rename from phoenix/windows/desktop.cpp rename to hiro/windows/desktop.cpp diff --git a/phoenix/windows/font.cpp b/hiro/windows/font.cpp similarity index 94% rename from phoenix/windows/font.cpp rename to hiro/windows/font.cpp index 94db0ecf..6cfadfb2 100644 --- a/phoenix/windows/font.cpp +++ b/hiro/windows/font.cpp @@ -26,9 +26,7 @@ Size pFont::size(string font, string text) { } HFONT pFont::create(string description) { - lstring part; - part.split(",", description); - for(auto& item : part) item.trim(" "); + lstring part = description.split<2>(",").strip(); string family = "Sans"; unsigned size = 8u; diff --git a/phoenix/windows/header.hpp b/hiro/windows/header.hpp similarity index 100% rename from phoenix/windows/header.hpp rename to hiro/windows/header.hpp diff --git a/phoenix/windows/keyboard.cpp b/hiro/windows/keyboard.cpp similarity index 100% rename from phoenix/windows/keyboard.cpp rename to hiro/windows/keyboard.cpp diff --git a/phoenix/windows/message-window.cpp b/hiro/windows/message-window.cpp similarity index 100% rename from phoenix/windows/message-window.cpp rename to hiro/windows/message-window.cpp diff --git a/phoenix/windows/monitor.cpp b/hiro/windows/monitor.cpp similarity index 100% rename from phoenix/windows/monitor.cpp rename to hiro/windows/monitor.cpp diff --git a/phoenix/windows/mouse.cpp b/hiro/windows/mouse.cpp similarity index 100% rename from phoenix/windows/mouse.cpp rename to hiro/windows/mouse.cpp diff --git a/phoenix/windows/object.cpp b/hiro/windows/object.cpp similarity index 100% rename from phoenix/windows/object.cpp rename to hiro/windows/object.cpp diff --git a/phoenix/windows/phoenix.Manifest b/hiro/windows/phoenix.Manifest similarity index 100% rename from phoenix/windows/phoenix.Manifest rename to hiro/windows/phoenix.Manifest diff --git a/phoenix/windows/phoenix.rc b/hiro/windows/phoenix.rc similarity index 100% rename from phoenix/windows/phoenix.rc rename to hiro/windows/phoenix.rc diff --git a/phoenix/windows/platform.cpp b/hiro/windows/platform.cpp similarity index 100% rename from phoenix/windows/platform.cpp rename to hiro/windows/platform.cpp diff --git a/phoenix/windows/platform.hpp b/hiro/windows/platform.hpp similarity index 98% rename from phoenix/windows/platform.hpp rename to hiro/windows/platform.hpp index 06378f53..36366c6b 100644 --- a/phoenix/windows/platform.hpp +++ b/hiro/windows/platform.hpp @@ -273,6 +273,7 @@ struct pButton : public pWidget { HIMAGELIST himagelist; Size minimumSize(); + void setBordered(bool bordered); void setImage(const image& image, Orientation orientation); void setText(string text); @@ -360,6 +361,7 @@ struct pComboButton : public pWidget { struct pConsole : public pWidget { Console& console; LRESULT CALLBACK (*windowProc)(HWND, UINT, LPARAM, WPARAM); + HBRUSH backgroundBrush = nullptr; void print(string text); void reset(); @@ -392,6 +394,7 @@ struct pHexEdit : public pWidget { HexEdit& hexEdit; WindowProc windowProc = nullptr; HWND scrollBar = nullptr; + HBRUSH backgroundBrush = nullptr; void setBackgroundColor(Color color); void setColumns(unsigned columns); @@ -456,6 +459,7 @@ struct pLabel : public pWidget { struct pLineEdit : public pWidget { LineEdit& lineEdit; + HBRUSH backgroundBrush = nullptr; Size minimumSize(); void setBackgroundColor(Color color); @@ -580,6 +584,7 @@ struct pTabFrame : public pWidget { struct pTextEdit : public pWidget { TextEdit& textEdit; + HBRUSH backgroundBrush = nullptr; void setBackgroundColor(Color color); void setCursorPosition(unsigned position); diff --git a/phoenix/windows/settings.cpp b/hiro/windows/settings.cpp similarity index 100% rename from phoenix/windows/settings.cpp rename to hiro/windows/settings.cpp diff --git a/phoenix/windows/timer.cpp b/hiro/windows/timer.cpp similarity index 100% rename from phoenix/windows/timer.cpp rename to hiro/windows/timer.cpp diff --git a/phoenix/windows/utility.cpp b/hiro/windows/utility.cpp similarity index 86% rename from phoenix/windows/utility.cpp rename to hiro/windows/utility.cpp index 5902f0d5..ce692b59 100644 --- a/phoenix/windows/utility.cpp +++ b/hiro/windows/utility.cpp @@ -245,13 +245,41 @@ static LRESULT CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT switch(msg) { case WM_CTLCOLORBTN: + case WM_CTLCOLOREDIT: case WM_CTLCOLORSTATIC: { Object* object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA); if(object == nullptr) break; - if(dynamic_cast(object) || dynamic_cast(object) || dynamic_cast(object)) { - //text edit controls, when disabled, use CTLCOLORSTATIC instead of CTLCOLOREDIT - //override this behavior: we do not want read-only edit controls to use the parent window background color - return windowProc(hwnd, WM_CTLCOLOREDIT, wparam, lparam); + //allow custom colors for various widgets + //note that this happens always: default colors are black text on a white background, unless overridden + //this intentionally overrides the default behavior of Windows to paint disabled controls with the window background color + if(dynamic_cast(object)) { + Console& console = *(Console*)object; + Color& background = console.state.backgroundColor; + Color& foreground = console.state.foregroundColor; + SetTextColor((HDC)wparam, RGB(foreground.red, foreground.green, foreground.blue)); + SetBkColor((HDC)wparam, RGB(background.red, background.green, background.blue)); + return (LRESULT)console.p.backgroundBrush; + } else if(dynamic_cast(object)) { + HexEdit& hexEdit = *(HexEdit*)object; + Color& background = hexEdit.state.backgroundColor; + Color& foreground = hexEdit.state.foregroundColor; + SetTextColor((HDC)wparam, RGB(foreground.red, foreground.green, foreground.blue)); + SetBkColor((HDC)wparam, RGB(background.red, background.green, background.blue)); + return (LRESULT)hexEdit.p.backgroundBrush; + } else if(dynamic_cast(object)) { + LineEdit& lineEdit = *(LineEdit*)object; + Color& background = lineEdit.state.backgroundColor; + Color& foreground = lineEdit.state.foregroundColor; + SetTextColor((HDC)wparam, RGB(foreground.red, foreground.green, foreground.blue)); + SetBkColor((HDC)wparam, RGB(background.red, background.green, background.blue)); + return (LRESULT)lineEdit.p.backgroundBrush; + } else if(dynamic_cast(object)) { + TextEdit& textEdit = *(TextEdit*)object; + Color& background = textEdit.state.backgroundColor; + Color& foreground = textEdit.state.foregroundColor; + SetTextColor((HDC)wparam, RGB(foreground.red, foreground.green, foreground.blue)); + SetBkColor((HDC)wparam, RGB(background.red, background.green, background.blue)); + return (LRESULT)textEdit.p.backgroundBrush; } else if(!GetParentWidget((Sizable*)object) && window.p.brush) { SetBkColor((HDC)wparam, window.p.brushColor); return (INT_PTR)window.p.brush; diff --git a/phoenix/windows/widget/button.cpp b/hiro/windows/widget/button.cpp similarity index 95% rename from phoenix/windows/widget/button.cpp rename to hiro/windows/widget/button.cpp index 0598c620..26a938f1 100644 --- a/phoenix/windows/widget/button.cpp +++ b/hiro/windows/widget/button.cpp @@ -32,7 +32,10 @@ Size pButton::minimumSize() { size.height += button.state.image.height; } - return {size.width + 20, size.height + 10}; + return {size.width + (button.state.text ? 20 : 10), size.height + 10}; +} + +void pButton::setBordered(bool bordered) { } void pButton::setImage(const image& image, Orientation orientation) { @@ -75,6 +78,7 @@ void pButton::constructor() { hwnd = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_TABSTOP, 0, 0, 0, 0, parentHwnd, (HMENU)id, GetModuleHandle(0), 0); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&button); setDefaultFont(); + setBordered(button.state.bordered); setImage(button.state.image, button.state.orientation); //setText(button.state.text); //called by setImage(); synchronize(); diff --git a/phoenix/windows/widget/canvas.cpp b/hiro/windows/widget/canvas.cpp similarity index 100% rename from phoenix/windows/widget/canvas.cpp rename to hiro/windows/widget/canvas.cpp diff --git a/phoenix/windows/widget/check-button.cpp b/hiro/windows/widget/check-button.cpp similarity index 100% rename from phoenix/windows/widget/check-button.cpp rename to hiro/windows/widget/check-button.cpp diff --git a/phoenix/windows/widget/check-label.cpp b/hiro/windows/widget/check-label.cpp similarity index 100% rename from phoenix/windows/widget/check-label.cpp rename to hiro/windows/widget/check-label.cpp diff --git a/phoenix/windows/widget/combo-button.cpp b/hiro/windows/widget/combo-button.cpp similarity index 100% rename from phoenix/windows/widget/combo-button.cpp rename to hiro/windows/widget/combo-button.cpp diff --git a/phoenix/windows/widget/console.cpp b/hiro/windows/widget/console.cpp similarity index 86% rename from phoenix/windows/widget/console.cpp rename to hiro/windows/widget/console.cpp index 812fdfa3..64abd98b 100644 --- a/phoenix/windows/widget/console.cpp +++ b/hiro/windows/widget/console.cpp @@ -15,6 +15,8 @@ void pConsole::reset() { } void pConsole::setBackgroundColor(Color color) { + if(backgroundBrush) DeleteObject(backgroundBrush); + backgroundBrush = CreateSolidBrush(RGB(color.red, color.green, color.blue)); } void pConsole::setForegroundColor(Color color) { @@ -31,6 +33,7 @@ void pConsole::constructor() { ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&console); setDefaultFont(); + setBackgroundColor(console.state.backgroundColor); windowProc = (LRESULT CALLBACK (*)(HWND, UINT, LPARAM, WPARAM))GetWindowLongPtr(hwnd, GWLP_WNDPROC); SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)Console_windowProc); diff --git a/phoenix/windows/widget/frame.cpp b/hiro/windows/widget/frame.cpp similarity index 100% rename from phoenix/windows/widget/frame.cpp rename to hiro/windows/widget/frame.cpp diff --git a/phoenix/windows/widget/hex-edit.cpp b/hiro/windows/widget/hex-edit.cpp similarity index 97% rename from phoenix/windows/widget/hex-edit.cpp rename to hiro/windows/widget/hex-edit.cpp index 3dace06c..b29f81b4 100644 --- a/phoenix/windows/widget/hex-edit.cpp +++ b/hiro/windows/widget/hex-edit.cpp @@ -50,6 +50,8 @@ static LRESULT CALLBACK HexEdit_windowProc(HWND hwnd, UINT msg, WPARAM wparam, L } void pHexEdit::setBackgroundColor(Color color) { + if(backgroundBrush) DeleteObject(backgroundBrush); + backgroundBrush = CreateSolidBrush(RGB(color.red, color.green, color.blue)); } void pHexEdit::setColumns(unsigned columns) { @@ -131,6 +133,7 @@ void pHexEdit::constructor() { SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)HexEdit_windowProc); setDefaultFont(); + setBackgroundColor(hexEdit.state.backgroundColor); setLength(hexEdit.state.length); setOffset(hexEdit.state.offset); update(); diff --git a/phoenix/windows/widget/horizontal-scroller.cpp b/hiro/windows/widget/horizontal-scroller.cpp similarity index 100% rename from phoenix/windows/widget/horizontal-scroller.cpp rename to hiro/windows/widget/horizontal-scroller.cpp diff --git a/phoenix/windows/widget/horizontal-slider.cpp b/hiro/windows/widget/horizontal-slider.cpp similarity index 100% rename from phoenix/windows/widget/horizontal-slider.cpp rename to hiro/windows/widget/horizontal-slider.cpp diff --git a/phoenix/windows/widget/label.cpp b/hiro/windows/widget/label.cpp similarity index 100% rename from phoenix/windows/widget/label.cpp rename to hiro/windows/widget/label.cpp diff --git a/phoenix/windows/widget/line-edit.cpp b/hiro/windows/widget/line-edit.cpp similarity index 87% rename from phoenix/windows/widget/line-edit.cpp rename to hiro/windows/widget/line-edit.cpp index 0b383132..c1e0be14 100644 --- a/phoenix/windows/widget/line-edit.cpp +++ b/hiro/windows/widget/line-edit.cpp @@ -6,6 +6,8 @@ Size pLineEdit::minimumSize() { } void pLineEdit::setBackgroundColor(Color color) { + if(backgroundBrush) DeleteObject(backgroundBrush); + backgroundBrush = CreateSolidBrush(RGB(color.red, color.green, color.blue)); } void pLineEdit::setEditable(bool editable) { @@ -37,6 +39,7 @@ void pLineEdit::constructor() { ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&lineEdit); setDefaultFont(); + setBackgroundColor(lineEdit.state.backgroundColor); setEditable(lineEdit.state.editable); setText(lineEdit.state.text); synchronize(); diff --git a/phoenix/windows/widget/list-view.cpp b/hiro/windows/widget/list-view.cpp similarity index 91% rename from phoenix/windows/widget/list-view.cpp rename to hiro/windows/widget/list-view.cpp index 465a9fe0..7813614b 100644 --- a/phoenix/windows/widget/list-view.cpp +++ b/hiro/windows/widget/list-view.cpp @@ -57,6 +57,7 @@ void pListView::reset() { } void pListView::setBackgroundColor(Color color) { + ListView_SetBkColor(hwnd, RGB(color.red, color.green, color.blue)); } void pListView::setCheckable(bool checkable) { @@ -152,6 +153,7 @@ void pListView::constructor() { SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&listView); setDefaultFont(); setHeaderText(listView.state.headerText); + setBackgroundColor(listView.state.backgroundColor); setHeaderVisible(listView.state.headerVisible); setCheckable(listView.state.checkable); for(auto& text : listView.state.text) append(text); @@ -259,17 +261,28 @@ LRESULT pListView::onCustomDraw(LPARAM lparam) { LPNMLVCUSTOMDRAW lvcd = (LPNMLVCUSTOMDRAW)lparam; switch(lvcd->nmcd.dwDrawStage) { - case CDDS_PREPAINT: + + case CDDS_PREPAINT: { return CDRF_NOTIFYITEMDRAW; - case CDDS_ITEMPREPAINT: - if(listView.state.headerText.size() >= 2) { - //draw alternating row colors of there are two or more columns - if(lvcd->nmcd.dwItemSpec % 2) lvcd->clrTextBk = GetSysColor(COLOR_WINDOW) ^ 0x070707; + } + + case CDDS_ITEMPREPAINT: { + Color& background = listView.state.backgroundColor; + Color& foreground = listView.state.foregroundColor; + lvcd->clrText = RGB(foreground.red, foreground.green, foreground.blue); + lvcd->clrTextBk = RGB(background.red, background.green, background.blue); + if(listView.state.headerText.size() >= 2 && lvcd->nmcd.dwItemSpec % 2) { + //draw alternating row colors if there are two or more columns + lvcd->clrTextBk = RGB(max(0, (signed)background.red - 17), max(0, (signed)background.green - 17), max(0, (signed)background.blue - 17)); } return CDRF_DODEFAULT; - default: + } + + default: { return CDRF_DODEFAULT; } + + } } } diff --git a/phoenix/windows/widget/progress-bar.cpp b/hiro/windows/widget/progress-bar.cpp similarity index 100% rename from phoenix/windows/widget/progress-bar.cpp rename to hiro/windows/widget/progress-bar.cpp diff --git a/phoenix/windows/widget/radio-button.cpp b/hiro/windows/widget/radio-button.cpp similarity index 100% rename from phoenix/windows/widget/radio-button.cpp rename to hiro/windows/widget/radio-button.cpp diff --git a/phoenix/windows/widget/radio-label.cpp b/hiro/windows/widget/radio-label.cpp similarity index 100% rename from phoenix/windows/widget/radio-label.cpp rename to hiro/windows/widget/radio-label.cpp diff --git a/phoenix/windows/widget/tab-frame.cpp b/hiro/windows/widget/tab-frame.cpp similarity index 100% rename from phoenix/windows/widget/tab-frame.cpp rename to hiro/windows/widget/tab-frame.cpp diff --git a/phoenix/windows/widget/text-edit.cpp b/hiro/windows/widget/text-edit.cpp similarity index 91% rename from phoenix/windows/widget/text-edit.cpp rename to hiro/windows/widget/text-edit.cpp index 509897fc..7ce02d7a 100644 --- a/phoenix/windows/widget/text-edit.cpp +++ b/hiro/windows/widget/text-edit.cpp @@ -1,6 +1,8 @@ namespace phoenix { void pTextEdit::setBackgroundColor(Color color) { + if(backgroundBrush) DeleteObject(backgroundBrush); + backgroundBrush = CreateSolidBrush(RGB(color.red, color.green, color.blue)); } void pTextEdit::setCursorPosition(unsigned position) { @@ -49,6 +51,7 @@ void pTextEdit::constructor() { ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&textEdit); setDefaultFont(); + setBackgroundColor(textEdit.state.backgroundColor); setCursorPosition(textEdit.state.cursorPosition); setEditable(textEdit.state.editable); setText(textEdit.state.text); diff --git a/phoenix/windows/widget/vertical-scroller.cpp b/hiro/windows/widget/vertical-scroller.cpp similarity index 100% rename from phoenix/windows/widget/vertical-scroller.cpp rename to hiro/windows/widget/vertical-scroller.cpp diff --git a/phoenix/windows/widget/vertical-slider.cpp b/hiro/windows/widget/vertical-slider.cpp similarity index 100% rename from phoenix/windows/widget/vertical-slider.cpp rename to hiro/windows/widget/vertical-slider.cpp diff --git a/phoenix/windows/widget/viewport.cpp b/hiro/windows/widget/viewport.cpp similarity index 100% rename from phoenix/windows/widget/viewport.cpp rename to hiro/windows/widget/viewport.cpp diff --git a/phoenix/windows/widget/widget.cpp b/hiro/windows/widget/widget.cpp similarity index 100% rename from phoenix/windows/widget/widget.cpp rename to hiro/windows/widget/widget.cpp diff --git a/phoenix/windows/window.cpp b/hiro/windows/window.cpp similarity index 98% rename from phoenix/windows/window.cpp rename to hiro/windows/window.cpp index fff305f0..79b64c4e 100644 --- a/phoenix/windows/window.cpp +++ b/hiro/windows/window.cpp @@ -192,7 +192,11 @@ void pWindow::setModal(bool modality) { updateModality(); while(window.state.modal) { Application::processEvents(); - usleep(20 * 1000); + if(Application::main) { + Application::main(); + } else { + usleep(20 * 1000); + } } if(auto position = modal.find(this)) modal.remove(position()); updateModality(); diff --git a/nall/Makefile b/nall/GNUmakefile similarity index 90% rename from nall/Makefile rename to nall/GNUmakefile index 9697bcd6..e51a20a8 100644 --- a/nall/Makefile +++ b/nall/GNUmakefile @@ -1,7 +1,3 @@ -# Makefile -# author: byuu -# license: public domain - [A-Z] = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [a-z] = a b c d e f g h i j k l m n o p q r s t u v w x y z [0-9] = 0 1 2 3 4 5 6 7 8 9 @@ -36,8 +32,8 @@ endif cflags := -x c -std=c99 objcflags := -x objective-c -std=c99 -cppflags := -x c++ -std=c++11 -objcppflags := -x objective-c++ -std=c++11 +cppflags := -x c++ -std=c++14 +objcppflags := -x objective-c++ -std=c++14 flags := link := @@ -48,20 +44,23 @@ ifeq ($(compiler),) else ifeq ($(platform),macosx) compiler := clang++ else ifeq ($(platform),bsd) - compiler := g++47 + compiler := g++49 else compiler := g++ endif endif +# clang settings +ifeq ($(findstring clang++,$(compiler)),clang++) + flags += -fwrapv # gcc settings -ifeq ($(findstring g++,$(compiler)),g++) +else ifeq ($(findstring g++,$(compiler)),g++) flags += -fwrapv endif -# clang settings -ifeq ($(findstring clang++,$(compiler)),clang++) - flags += -fwrapv -w +# windows settings +ifeq ($(platform),windows) + link := $(link) -lws2_32 -lole32 endif # macosx settings @@ -81,9 +80,8 @@ ifeq ($(arch),x86) link := -m32 $(link) endif -ifeq ($(prefix),) - prefix := /usr/local -endif +# paths +prefix := $(HOME)/.local # function rwildcard(directory, pattern) rwildcard = \ diff --git a/nall/algorithm.hpp b/nall/algorithm.hpp index 5867c1cd..89fec57d 100644 --- a/nall/algorithm.hpp +++ b/nall/algorithm.hpp @@ -1,19 +1,29 @@ #ifndef NALL_ALGORITHM_HPP #define NALL_ALGORITHM_HPP +#include + #undef min #undef max -namespace nall { +namespace nall { namespace { -template T min(const T& t, const U& u) { +template auto min(const T& t, const U& u) -> T { return t < u ? t : u; } -template T max(const T& t, const U& u) { +template auto min(const T& t, const U& u, P&&... p) -> T { + return t < u ? min(t, forward

(p)...) : min(u, forward

(p)...); +} + +template auto max(const T& t, const U& u) -> T { return t > u ? t : u; } +template auto max(const T& t, const U& u, P&&... p) -> T { + return t > u ? max(t, forward

(p)...) : max(u, forward

(p)...); } +}} + #endif diff --git a/nall/any.hpp b/nall/any.hpp index 27a07ef2..8d6b638a 100644 --- a/nall/any.hpp +++ b/nall/any.hpp @@ -15,11 +15,7 @@ struct any { } template any& operator=(const T& value) { - typedef typename type_if< - std::is_array::value, - typename std::remove_extent::type>::type*, - T - >::type auto_t; + using auto_t = type_if, typename std::remove_extent::type>::type*, T>; if(type() == typeid(auto_t)) { static_cast*>(container)->value = (auto_t)value; @@ -46,7 +42,7 @@ struct any { any() = default; any(const any& source) { operator=(source); } - any(any&& source) { operator=(std::move(source)); } + any(any&& source) { operator=(move(source)); } template any(const T& value) { operator=(value); } ~any() { reset(); } diff --git a/nall/beat/archive.hpp b/nall/beat/archive.hpp index f8c6b6cf..f3fce618 100644 --- a/nall/beat/archive.hpp +++ b/nall/beat/archive.hpp @@ -10,7 +10,7 @@ struct beatArchive : beatBase { if(fp.open(beatname, file::mode::write) == false) return false; if(pathname.endsWith("/") == false) pathname.append("/"); - checksum = ~0; + checksum.reset(); writeString("BPA1"); writeNumber(metadata.length()); writeString(metadata); @@ -19,7 +19,7 @@ struct beatArchive : beatBase { ls(list, pathname, pathname); for(auto &name : list) { if(name.endsWith("/")) { - name.rtrim<1>("/"); + name.rtrim("/"); writeNumber(0 | ((name.length() - 1) << 1)); writeString(name); } else { @@ -29,17 +29,17 @@ struct beatArchive : beatBase { writeString(name); unsigned size = stream.size(); writeNumber(size); - uint32_t checksum = ~0; + Hash::CRC32 checksum; while(size--) { uint8_t data = stream.read(); write(data); - checksum = crc32_adjust(checksum, data); + checksum.data(data); } - writeChecksum(~checksum); + writeChecksum(checksum.value()); } } - writeChecksum(~checksum); + writeChecksum(checksum.value()); fp.close(); return true; } @@ -48,7 +48,7 @@ struct beatArchive : beatBase { if(fp.open(beatname, file::mode::read) == false) return false; if(pathname.endsWith("/") == false) pathname.append("/"); - checksum = ~0; + checksum.reset(); if(readString(4) != "BPA1") return false; unsigned length = readNumber(); while(length--) read(); @@ -65,17 +65,17 @@ struct beatArchive : beatBase { file stream; if(stream.open({pathname, name}, file::mode::write) == false) return false; unsigned size = readNumber(); - uint32_t checksum = ~0; + Hash::CRC32 checksum; while(size--) { uint8_t data = read(); stream.write(data); - checksum = crc32_adjust(checksum, data); + checksum.data(data); } - if(readChecksum(~checksum) == false) return false; + if(readChecksum(checksum.value()) == false) return false; } } - return readChecksum(~checksum); + return readChecksum(checksum.value()); } }; diff --git a/nall/beat/base.hpp b/nall/beat/base.hpp index d35b8e7c..7d021d52 100644 --- a/nall/beat/base.hpp +++ b/nall/beat/base.hpp @@ -6,24 +6,24 @@ namespace nall { struct beatBase { protected: file fp; - uint32_t checksum; + Hash::CRC32 checksum; void ls(lstring& list, const string& path, const string& basepath) { lstring paths = directory::folders(path); for(auto& pathname : paths) { - list.append(string{path, pathname}.ltrim<1>(basepath)); + list.append(string{path, pathname}.ltrim(basepath)); ls(list, {path, pathname}, basepath); } lstring files = directory::files(path); for(auto& filename : files) { - list.append(string{path, filename}.ltrim<1>(basepath)); + list.append(string{path, filename}.ltrim(basepath)); } } void write(uint8_t data) { fp.write(data); - checksum = crc32_adjust(checksum, data); + checksum.data(data); } void writeNumber(uint64_t data) { @@ -50,7 +50,7 @@ protected: uint8_t read() { uint8_t data = fp.read(); - checksum = crc32_adjust(checksum, data); + checksum.data(data); return data; } @@ -68,12 +68,12 @@ protected: string readString(unsigned length) { string text; - text.reserve(length + 1); - for(unsigned n = 0; n < length; n++) { - text[n] = fp.read(); - checksum = crc32_adjust(checksum, text[n]); + text.resize(length + 1); + char* p = text.pointer(); + while(length--) { + *p = fp.read(); + checksum.data(*p++); } - text[length] = 0; return text; } diff --git a/nall/beat/delta.hpp b/nall/beat/delta.hpp index 04145efb..487097fa 100644 --- a/nall/beat/delta.hpp +++ b/nall/beat/delta.hpp @@ -1,7 +1,6 @@ #ifndef NALL_BEAT_DELTA_HPP #define NALL_BEAT_DELTA_HPP -#include #include #include #include @@ -63,12 +62,12 @@ bool bpsdelta::create(const string& filename, const string& metadata) { file modifyFile; if(modifyFile.open(filename, file::mode::write) == false) return false; - uint32_t sourceChecksum = ~0, modifyChecksum = ~0; + Hash::CRC32 sourceChecksum, modifyChecksum; unsigned sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0; auto write = [&](uint8_t data) { modifyFile.write(data); - modifyChecksum = crc32_adjust(modifyChecksum, data); + modifyChecksum.data(data); }; auto encode = [&](uint64_t data) { @@ -103,7 +102,7 @@ bool bpsdelta::create(const string& filename, const string& metadata) { //source tree creation for(unsigned offset = 0; offset < sourceSize; offset++) { uint16_t symbol = sourceData[offset + 0]; - sourceChecksum = crc32_adjust(sourceChecksum, symbol); + sourceChecksum.data(symbol); if(offset < sourceSize - 1) symbol |= sourceData[offset + 1] << 8; Node *node = new Node; node->offset = offset; @@ -199,11 +198,10 @@ bool bpsdelta::create(const string& filename, const string& metadata) { targetReadFlush(); - sourceChecksum = ~sourceChecksum; - for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n); - uint32_t targetChecksum = crc32_calculate(targetData, targetSize); + for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum.value() >> n); + uint32_t targetChecksum = Hash::CRC32(targetData, targetSize).value(); for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n); - uint32_t outputChecksum = ~modifyChecksum; + uint32_t outputChecksum = modifyChecksum.value(); for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n); modifyFile.close(); diff --git a/nall/beat/linear.hpp b/nall/beat/linear.hpp index 4ee44a57..ac13894c 100644 --- a/nall/beat/linear.hpp +++ b/nall/beat/linear.hpp @@ -1,7 +1,6 @@ #ifndef NALL_BEAT_LINEAR_HPP #define NALL_BEAT_LINEAR_HPP -#include #include #include #include @@ -56,12 +55,12 @@ bool bpslinear::create(const string& filename, const string& metadata) { file modifyFile; if(modifyFile.open(filename, file::mode::write) == false) return false; - uint32_t modifyChecksum = ~0; + Hash::CRC32 modifyChecksum; unsigned targetRelativeOffset = 0, outputOffset = 0; auto write = [&](uint8_t data) { modifyFile.write(data); - modifyChecksum = crc32_adjust(modifyChecksum, data); + modifyChecksum.data(data); }; auto encode = [&](uint64_t data) { @@ -136,11 +135,11 @@ bool bpslinear::create(const string& filename, const string& metadata) { targetReadFlush(); - uint32_t sourceChecksum = crc32_calculate(sourceData, sourceSize); + uint32_t sourceChecksum = Hash::CRC32(sourceData, sourceSize).value(); for(unsigned n = 0; n < 32; n += 8) write(sourceChecksum >> n); - uint32_t targetChecksum = crc32_calculate(targetData, targetSize); + uint32_t targetChecksum = Hash::CRC32(targetData, targetSize).value(); for(unsigned n = 0; n < 32; n += 8) write(targetChecksum >> n); - uint32_t outputChecksum = ~modifyChecksum; + uint32_t outputChecksum = modifyChecksum.value(); for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n); modifyFile.close(); diff --git a/nall/beat/metadata.hpp b/nall/beat/metadata.hpp index 2b31fdfd..f83771ca 100644 --- a/nall/beat/metadata.hpp +++ b/nall/beat/metadata.hpp @@ -1,7 +1,6 @@ #ifndef NALL_BEAT_METADATA_HPP #define NALL_BEAT_METADATA_HPP -#include #include #include #include @@ -75,11 +74,11 @@ bool bpsmetadata::save(const string& filename, const string& metadata) { return data; }; - uint32_t checksum = ~0; + Hash::CRC32 checksum; auto write = [&](uint8_t data) { targetFile.write(data); - checksum = crc32_adjust(checksum, data); + checksum.data(data); }; auto encode = [&](uint64_t data) { @@ -105,7 +104,7 @@ bool bpsmetadata::save(const string& filename, const string& metadata) { for(unsigned n = 0; n < targetLength; n++) write(metadata[n]); unsigned length = sourceFile.size() - sourceFile.offset() - 4; for(unsigned n = 0; n < length; n++) write(read()); - uint32_t outputChecksum = ~checksum; + uint32_t outputChecksum = checksum.value(); for(unsigned n = 0; n < 32; n += 8) write(outputChecksum >> n); targetFile.close(); diff --git a/nall/beat/multi.hpp b/nall/beat/multi.hpp index c99001c8..6d9428d6 100644 --- a/nall/beat/multi.hpp +++ b/nall/beat/multi.hpp @@ -23,7 +23,7 @@ struct bpsmulti { bool create(const string& patchName, const string& sourcePath, const string& targetPath, bool delta = false, const string& metadata = "") { if(fp.open()) fp.close(); fp.open(patchName, file::mode::write); - checksum = ~0; + checksum.reset(); writeString("BPM1"); //signature writeNumber(metadata.length()); @@ -35,7 +35,7 @@ struct bpsmulti { for(auto& targetName : targetList) { if(targetName.endsWith("/")) { - targetName.rtrim<1>("/"); + targetName.rtrim("/"); writeNumber(CreatePath | ((targetName.length() - 1) << 2)); writeString(targetName); } else if(auto position = sourceList.find(targetName)) { //if sourceName == targetName @@ -44,19 +44,19 @@ struct bpsmulti { dp.open({targetPath, targetName}, file::mode::read); bool identical = sp.size() == dp.size(); - uint32_t cksum = ~0; + Hash::CRC32 cksum; for(unsigned n = 0; n < sp.size(); n++) { uint8_t byte = sp.read(); if(identical && byte != dp.read()) identical = false; - cksum = crc32_adjust(cksum, byte); + cksum.data(byte); } if(identical) { writeNumber(MirrorFile | ((targetName.length() - 1) << 2)); writeString(targetName); writeNumber(OriginSource); - writeChecksum(~cksum); + writeChecksum(cksum.value()); } else { writeNumber(ModifyFile | ((targetName.length() - 1) << 2)); writeString(targetName); @@ -84,12 +84,12 @@ struct bpsmulti { auto buffer = file::read({targetPath, targetName}); writeNumber(buffer.size()); for(auto &byte : buffer) write(byte); - writeChecksum(crc32_calculate(buffer.data(), buffer.size())); + writeChecksum(Hash::CRC32(buffer.data(), buffer.size()).value()); } } //checksum - writeChecksum(~checksum); + writeChecksum(checksum.value()); fp.close(); return true; } @@ -100,7 +100,7 @@ struct bpsmulti { if(fp.open()) fp.close(); fp.open(patchName, file::mode::read); - checksum = ~0; + checksum.reset(); if(readString(4) != "BPM1") return false; auto metadataLength = readNumber(); @@ -142,7 +142,7 @@ struct bpsmulti { } } - uint32_t cksum = ~checksum; + uint32_t cksum = checksum.value(); if(read() != (uint8_t)(cksum >> 0)) return false; if(read() != (uint8_t)(cksum >> 8)) return false; if(read() != (uint8_t)(cksum >> 16)) return false; @@ -154,25 +154,25 @@ struct bpsmulti { protected: file fp; - uint32_t checksum; + Hash::CRC32 checksum; //create() functions void ls(lstring& list, const string& path, const string& basepath) { lstring paths = directory::folders(path); for(auto& pathname : paths) { - list.append(string{path, pathname}.ltrim<1>(basepath)); + list.append(string{path, pathname}.ltrim(basepath)); ls(list, {path, pathname}, basepath); } lstring files = directory::files(path); for(auto& filename : files) { - list.append(string{path, filename}.ltrim<1>(basepath)); + list.append(string{path, filename}.ltrim(basepath)); } } void write(uint8_t data) { fp.write(data); - checksum = crc32_adjust(checksum, data); + checksum.data(data); } void writeNumber(uint64_t data) { @@ -203,7 +203,7 @@ protected: //apply() functions uint8_t read() { uint8_t data = fp.read(); - checksum = crc32_adjust(checksum, data); + checksum.data(data); return data; } @@ -221,9 +221,9 @@ protected: string readString(unsigned length) { string text; - text.reserve(length + 1); - for(unsigned n = 0; n < length; n++) text[n] = read(); - text[length] = 0; + text.resize(length + 1); + char* p = text.pointer(); + while(length--) *p++ = read(); return text; } diff --git a/nall/beat/patch.hpp b/nall/beat/patch.hpp index 59c6c5d1..081c4ff0 100644 --- a/nall/beat/patch.hpp +++ b/nall/beat/patch.hpp @@ -1,7 +1,6 @@ #ifndef NALL_BEAT_PATCH_HPP #define NALL_BEAT_PATCH_HPP -#include #include #include #include @@ -129,12 +128,12 @@ unsigned bpspatch::size() const { bpspatch::result bpspatch::apply() { if(modifySize < 19) return result::patch_too_small; - uint32_t modifyChecksum = ~0, targetChecksum = ~0; + Hash::CRC32 modifyChecksum, targetChecksum; unsigned modifyOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0, outputOffset = 0; auto read = [&]() -> uint8_t { uint8_t data = modifyData[modifyOffset++]; - modifyChecksum = crc32_adjust(modifyChecksum, data); + modifyChecksum.data(data); return data; }; @@ -152,7 +151,7 @@ bpspatch::result bpspatch::apply() { auto write = [&](uint8_t data) { targetData[outputOffset++] = data; - targetChecksum = crc32_adjust(targetChecksum, data); + targetChecksum.data(data); }; if(read() != 'B') return result::patch_invalid_header; @@ -201,14 +200,13 @@ bpspatch::result bpspatch::apply() { uint32_t modifySourceChecksum = 0, modifyTargetChecksum = 0, modifyModifyChecksum = 0; for(unsigned n = 0; n < 32; n += 8) modifySourceChecksum |= read() << n; for(unsigned n = 0; n < 32; n += 8) modifyTargetChecksum |= read() << n; - uint32_t checksum = ~modifyChecksum; + uint32_t checksum = modifyChecksum.value(); for(unsigned n = 0; n < 32; n += 8) modifyModifyChecksum |= read() << n; - uint32_t sourceChecksum = crc32_calculate(sourceData, modifySourceSize); - targetChecksum = ~targetChecksum; + uint32_t sourceChecksum = Hash::CRC32(sourceData, modifySourceSize).value(); if(sourceChecksum != modifySourceChecksum) return result::source_checksum_invalid; - if(targetChecksum != modifyTargetChecksum) return result::target_checksum_invalid; + if(targetChecksum.value() != modifyTargetChecksum) return result::target_checksum_invalid; if(checksum != modifyModifyChecksum) return result::patch_checksum_invalid; return result::success; diff --git a/nall/config.hpp b/nall/config.hpp index 4c69bce8..0a7d8f55 100644 --- a/nall/config.hpp +++ b/nall/config.hpp @@ -60,7 +60,7 @@ struct Node { for(auto& child : children) { auto leaf = path[child.name]; if(!leaf.exists()) continue; - if(!child.empty()) child.set(leaf.data.trim<1>(" ", "\r")); + if(!child.empty()) child.set(leaf.text()); child.load(leaf); } } diff --git a/nall/crc16.hpp b/nall/crc16.hpp deleted file mode 100644 index be79a502..00000000 --- a/nall/crc16.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef NALL_CRC16_HPP -#define NALL_CRC16_HPP - -#include - -namespace nall { - -inline uint16_t crc16_adjust(uint16_t crc16, uint8_t data) { - for(unsigned n = 0; n < 8; n++) { - if((crc16 & 1) ^ (data & 1)) crc16 = (crc16 >> 1) ^ 0x8408; - else crc16 >>= 1; - data >>= 1; - } - return crc16; -} - -inline uint16_t crc16_calculate(const uint8_t* data, unsigned length) { - uint16_t crc16 = ~0; - for(unsigned n = 0; n < length; n++) { - crc16 = crc16_adjust(crc16, data[n]); - } - return ~crc16; -} - -} - -#endif diff --git a/nall/decode/bmp.hpp b/nall/decode/bmp.hpp new file mode 100644 index 00000000..04330639 --- /dev/null +++ b/nall/decode/bmp.hpp @@ -0,0 +1,8 @@ +#ifndef NALL_DECODE_BMP_HPP +#define NALL_DECODE_BMP_HPP + +namespace nall { + +} + +#endif diff --git a/nall/gzip.hpp b/nall/decode/gzip.hpp similarity index 81% rename from nall/gzip.hpp rename to nall/decode/gzip.hpp index 2d43e7ab..db42100c 100644 --- a/nall/gzip.hpp +++ b/nall/decode/gzip.hpp @@ -1,12 +1,12 @@ -#ifndef NALL_GZIP_HPP -#define NALL_GZIP_HPP +#ifndef NALL_DECODE_GZIP_HPP +#define NALL_DECODE_GZIP_HPP #include -#include +#include -namespace nall { +namespace nall { namespace Decode { -struct gzip { +struct GZIP { string filename; uint8_t* data = nullptr; unsigned size = 0; @@ -14,18 +14,18 @@ struct gzip { inline bool decompress(const string& filename); inline bool decompress(const uint8_t* data, unsigned size); - inline gzip(); - inline ~gzip(); + inline GZIP(); + inline ~GZIP(); }; -bool gzip::decompress(const string& filename) { +bool GZIP::decompress(const string& filename) { if(auto memory = file::read(filename)) { return decompress(memory.data(), memory.size()); } return false; } -bool gzip::decompress(const uint8_t* data, unsigned size) { +bool GZIP::decompress(const uint8_t* data, unsigned size) { if(size < 18) return false; if(data[0] != 0x1f) return false; if(data[1] != 0x8b) return false; @@ -73,13 +73,13 @@ bool gzip::decompress(const uint8_t* data, unsigned size) { return inflate(this->data, this->size, data + p, size - p - 8); } -gzip::gzip() { +GZIP::GZIP() { } -gzip::~gzip() { +GZIP::~GZIP() { if(data) delete[] data; } -} +}} #endif diff --git a/nall/inflate.hpp b/nall/decode/inflate.hpp similarity index 98% rename from nall/inflate.hpp rename to nall/decode/inflate.hpp index d096d173..00fb2305 100644 --- a/nall/inflate.hpp +++ b/nall/decode/inflate.hpp @@ -1,9 +1,9 @@ -#ifndef NALL_INFLATE_HPP -#define NALL_INFLATE_HPP +#ifndef NALL_DECODE_INFLATE_HPP +#define NALL_DECODE_INFLATE_HPP #include -namespace nall { +namespace nall { namespace Decode { namespace puff { inline int puff( @@ -344,6 +344,6 @@ inline int puff( } -} +}} #endif diff --git a/nall/png.hpp b/nall/decode/png.hpp similarity index 93% rename from nall/png.hpp rename to nall/decode/png.hpp index ccdf64eb..3991f823 100644 --- a/nall/png.hpp +++ b/nall/decode/png.hpp @@ -1,15 +1,12 @@ -#ifndef NALL_PNG_HPP -#define NALL_PNG_HPP +#ifndef NALL_DECODE_PNG_HPP +#define NALL_DECODE_PNG_HPP -//PNG image decoder -//author: byuu - -#include #include +#include -namespace nall { +namespace nall { namespace Decode { -struct png { +struct PNG { struct Info { unsigned width; unsigned height; @@ -39,8 +36,8 @@ struct png { inline unsigned readbits(const uint8_t*& data); unsigned bitpos = 0; - inline png(); - inline ~png(); + inline PNG(); + inline ~PNG(); protected: enum class FourCC : unsigned { @@ -57,14 +54,14 @@ protected: inline unsigned read(const uint8_t* data, unsigned length); }; -bool png::decode(const string& filename) { +bool PNG::decode(const string& filename) { if(auto memory = file::read(filename)) { return decode(memory.data(), memory.size()); } return false; } -bool png::decode(const uint8_t* sourceData, unsigned sourceSize) { +bool PNG::decode(const uint8_t* sourceData, unsigned sourceSize) { if(sourceSize < 8) return false; if(read(sourceData + 0, 4) != 0x89504e47) return false; if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false; @@ -170,7 +167,7 @@ bool png::decode(const uint8_t* sourceData, unsigned sourceSize) { return true; } -unsigned png::interlace(unsigned pass, unsigned index) { +unsigned PNG::interlace(unsigned pass, unsigned index) { static const unsigned data[7][4] = { //x-distance, y-distance, x-origin, y-origin {8, 8, 0, 0}, @@ -184,7 +181,7 @@ unsigned png::interlace(unsigned pass, unsigned index) { return data[pass][index]; } -unsigned png::inflateSize() { +unsigned PNG::inflateSize() { if(info.interlaceMethod == 0) { return info.width * info.height * info.bytesPerPixel + info.height; } @@ -201,7 +198,7 @@ unsigned png::inflateSize() { return size; } -bool png::deinterlace(const uint8_t*& inputData, unsigned pass) { +bool PNG::deinterlace(const uint8_t*& inputData, unsigned pass) { unsigned xd = interlace(pass, 0), yd = interlace(pass, 1); unsigned xo = interlace(pass, 2), yo = interlace(pass, 3); unsigned width = (info.width + (xd - xo - 1)) / xd; @@ -227,7 +224,7 @@ bool png::deinterlace(const uint8_t*& inputData, unsigned pass) { return result; } -bool png::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width, unsigned height) { +bool PNG::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width, unsigned height) { uint8_t* wr = outputData; const uint8_t* rd = inputData; int bpp = info.bytesPerPixel, pitch = width * bpp; @@ -290,13 +287,13 @@ bool png::filter(uint8_t* outputData, const uint8_t* inputData, unsigned width, return true; } -unsigned png::read(const uint8_t* data, unsigned length) { +unsigned PNG::read(const uint8_t* data, unsigned length) { unsigned result = 0; while(length--) result = (result << 8) | (*data++); return result; } -unsigned png::readbits(const uint8_t*& data) { +unsigned PNG::readbits(const uint8_t*& data) { unsigned result = 0; switch(info.bitDepth) { case 1: @@ -325,13 +322,13 @@ unsigned png::readbits(const uint8_t*& data) { return result; } -png::png() { +PNG::PNG() { } -png::~png() { +PNG::~PNG() { if(data) delete[] data; } -} +}} #endif diff --git a/nall/unzip.hpp b/nall/decode/zip.hpp similarity index 94% rename from nall/unzip.hpp rename to nall/decode/zip.hpp index 269a15d2..419a99d3 100644 --- a/nall/unzip.hpp +++ b/nall/decode/zip.hpp @@ -1,14 +1,14 @@ -#ifndef NALL_UNZIP_HPP -#define NALL_UNZIP_HPP +#ifndef NALL_DECODE_ZIP_HPP +#define NALL_DECODE_ZIP_HPP #include -#include #include #include +#include -namespace nall { +namespace nall { namespace Decode { -struct unzip { +struct ZIP { struct File { string name; const uint8_t* data; @@ -102,7 +102,7 @@ struct unzip { if(fm.open()) fm.close(); } - ~unzip() { + ~ZIP() { close(); } @@ -121,6 +121,6 @@ public: vector file; }; -} +}} #endif diff --git a/nall/directory.hpp b/nall/directory.hpp index 45a062c7..f2983df6 100644 --- a/nall/directory.hpp +++ b/nall/directory.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -17,7 +18,7 @@ namespace nall { -struct directory { +struct directory : storage { static bool create(const string& pathname, unsigned permissions = 0755); //recursive static bool remove(const string& pathname); //recursive static bool exists(const string& pathname); @@ -73,7 +74,7 @@ private: #if defined(PLATFORM_WINDOWS) inline bool directory::create(const string& pathname, unsigned permissions) { string path; - lstring list = string{pathname}.transform("\\", "/").rtrim<1>("/").split("/"); + lstring list = string{pathname}.transform("\\", "/").rtrim("/").split("/"); bool result = true; for(auto& part : list) { path.append(part, "/"); @@ -93,7 +94,7 @@ private: inline bool directory::exists(const string& pathname) { string name = pathname; - name.trim<1>("\""); + name.trim("\"", "\""); DWORD result = GetFileAttributes(utf16_t(name)); if(result == INVALID_FILE_ATTRIBUTES) return false; return (result & FILE_ATTRIBUTE_DIRECTORY); @@ -103,7 +104,7 @@ private: lstring list; string path = pathname; path.transform("/", "\\"); - if(!strend(path, "\\")) path.append("\\"); + if(!path.endsWith("\\")) path.append("\\"); path.append("*"); HANDLE handle; WIN32_FIND_DATA data; @@ -133,7 +134,7 @@ private: lstring list; string path = pathname; path.transform("/", "\\"); - if(!strend(path, "\\")) path.append("\\"); + if(!path.endsWith("\\")) path.append("\\"); path.append("*"); HANDLE handle; WIN32_FIND_DATA data; @@ -154,12 +155,24 @@ private: return list; } #else + inline bool directory_is_folder(DIR* dp, struct dirent* ep) { + if(ep->d_type == DT_DIR) return true; + if(ep->d_type == DT_LNK || ep->d_type == DT_UNKNOWN) { + //symbolic links must be resolved to determine type + struct stat sp = {0}; + fstatat(dirfd(dp), ep->d_name, &sp, 0); + return S_ISDIR(sp.st_mode); + } + return false; + } + inline bool directory::create(const string& pathname, unsigned permissions) { string path; - lstring list = string{pathname}.rtrim<1>("/").split("/"); + lstring list = string{pathname}.rtrim("/").split("/"); bool result = true; for(auto& part : list) { path.append(part, "/"); + if(directory::exists(path)) continue; result &= (mkdir(path, permissions) == 0); } return result; @@ -175,7 +188,7 @@ private: } inline bool directory::exists(const string& pathname) { - DIR *dp = opendir(pathname); + DIR* dp = opendir(pathname); if(!dp) return false; closedir(dp); return true; @@ -190,15 +203,9 @@ private: while(ep = readdir(dp)) { if(!strcmp(ep->d_name, ".")) continue; if(!strcmp(ep->d_name, "..")) continue; - bool is_directory = ep->d_type & DT_DIR; - if(ep->d_type & DT_UNKNOWN) { - struct stat sp = {0}; - stat(string{pathname, ep->d_name}, &sp); - is_directory = S_ISDIR(sp.st_mode); - } - if(is_directory) { - if(strmatch(ep->d_name, pattern)) list.append(ep->d_name); - } + if(!directory_is_folder(dp, ep)) continue; + string name{ep->d_name}; + if(name.match(pattern)) list.append(std::move(name)); } closedir(dp); } @@ -215,9 +222,9 @@ private: while(ep = readdir(dp)) { if(!strcmp(ep->d_name, ".")) continue; if(!strcmp(ep->d_name, "..")) continue; - if((ep->d_type & DT_DIR) == 0) { - if(strmatch(ep->d_name, pattern)) list.append(ep->d_name); - } + if(directory_is_folder(dp, ep)) continue; + string name{ep->d_name}; + if(name.match(pattern)) list.append(std::move(name)); } closedir(dp); } diff --git a/nall/dl.hpp b/nall/dl.hpp index d0d0151e..baf7e70e 100644 --- a/nall/dl.hpp +++ b/nall/dl.hpp @@ -38,8 +38,10 @@ private: #if defined(PLATFORM_XORG) inline bool library::open(const string& name, const string& path) { if(handle) close(); - handle = (uintptr_t)dlopen(string(path, !path.empty() && !path.endsWith("/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY); + if(path) handle = (uintptr_t)dlopen(string(path, "lib", name, ".so"), RTLD_LAZY); + if(!handle) handle = (uintptr_t)dlopen(string(userpath(), ".local/lib/lib", name, ".so"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY); + if(!handle) handle = (uintptr_t)dlopen(string("lib", name, ".so"), RTLD_LAZY); return handle; } @@ -62,8 +64,10 @@ inline void library::close() { #elif defined(PLATFORM_MACOSX) inline bool library::open(const string& name, const string& path) { if(handle) close(); - handle = (uintptr_t)dlopen(string(path, !path.empty() && !path.endsWith("/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY); + if(path) handle = (uintptr_t)dlopen(string(path, "lib", name, ".dylib"), RTLD_LAZY); + if(!handle) handle = (uintptr_t)dlopen(string(userpath(), ".local/lib/lib", name, ".dylib"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY); + if(!handle) handle = (uintptr_t)dlopen(string("lib", name, ".dylib"), RTLD_LAZY); return handle; } @@ -86,8 +90,14 @@ inline void library::close() { #elif defined(PLATFORM_WINDOWS) inline bool library::open(const string& name, const string& path) { if(handle) close(); - string filepath(path, !path.empty() && !path.endsWith("/") && !path.endsWith("\\") ? "/" : "", name, ".dll"); - handle = (uintptr_t)LoadLibraryW(utf16_t(filepath)); + if(path) { + string filepath = {path, name, ".dll"}; + handle = (uintptr_t)LoadLibraryW(utf16_t(filepath)); + } + if(!handle) { + string filepath = {name, ".dll"}; + handle = (uintptr_t)LoadLibraryW(utf16_t(filepath)); + } return handle; } diff --git a/nall/file.hpp b/nall/file.hpp index 2cd28a13..cdebda4f 100644 --- a/nall/file.hpp +++ b/nall/file.hpp @@ -3,26 +3,18 @@ #include #include +#include #include #include #include -#include +#include #include namespace nall { -inline FILE* fopen_utf8(const string& filename, const string& mode) { - #if !defined(_WIN32) - return fopen(filename, mode); - #else - return _wfopen(utf16_t(filename), utf16_t(mode)); - #endif -} - -struct file : varint { +struct file : storage, varint { enum class mode : unsigned { read, write, modify, append, readwrite = modify, writeread = append }; enum class index : unsigned { absolute, relative }; - enum class time : unsigned { create, modify, access }; static bool copy(const string& sourcename, const string& targetname) { file rd, wr; @@ -32,29 +24,24 @@ struct file : varint { return true; } + //attempt to rename file first + //this will fail if paths point to different file systems; fall back to copy+remove in this case static bool move(const string& sourcename, const string& targetname) { - auto result = rename(sourcename, targetname); - if(result == 0) return true; - if(errno == EXDEV) { - //cannot move files between file systems; copy file instead of failing - if(file::copy(sourcename, targetname)) { - file::remove(sourcename); - return true; - } + if(rename(sourcename, targetname)) return true; + if(!writable(sourcename)) return false; + if(copy(sourcename, targetname)) { + remove(sourcename); + return true; } return false; } - static bool remove(const string& filename) { - return unlink(filename) == 0; - } - static bool truncate(const string& filename, unsigned size) { #if !defined(_WIN32) return truncate(filename, size) == 0; #else bool result = false; - FILE* fp = fopen(filename, "rb+"); + FILE* fp = _wfopen(utf16_t(filename), L"rb+"); if(fp) { result = _chsize(fileno(fp), size) == 0; fclose(fp); @@ -63,6 +50,29 @@ struct file : varint { #endif } + //specialization of storage::exists(); returns false for folders + static bool exists(const string& filename) { + #if !defined(_WIN32) + struct stat data; + if(stat(filename, &data) != 0) return false; + #else + struct __stat64 data; + if(_wstat64(utf16_t(filename), &data) != 0) return false; + #endif + return !(data.st_mode & S_IFDIR); + } + + static uintmax_t size(const string& filename) { + #if !defined(_WIN32) + struct stat data; + stat(filename, &data); + #else + struct __stat64 data; + _wstat64(utf16_t(filename), &data); + #endif + return S_ISREG(data.st_mode) ? data.st_size : 0u; + } + static vector read(const string& filename) { vector memory; file fp; @@ -115,7 +125,7 @@ struct file : varint { static string sha256(const string& filename) { auto buffer = read(filename); - return nall::sha256(buffer.data(), buffer.size()); + return Hash::SHA256(buffer.data(), buffer.size()).digest(); } uint8_t read() { @@ -231,44 +241,6 @@ struct file : varint { return file_offset >= file_size; } - static bool exists(const string& filename) { - #if !defined(_WIN32) - struct stat data; - if(stat(filename, &data) != 0) return false; - #else - struct __stat64 data; - if(_wstat64(utf16_t(filename), &data) != 0) return false; - #endif - //return true if this is a file, and false if this is a directory - return !(data.st_mode & S_IFDIR); - } - - static uintmax_t size(const string& filename) { - #if !defined(_WIN32) - struct stat data; - stat(filename, &data); - #else - struct __stat64 data; - _wstat64(utf16_t(filename), &data); - #endif - return S_ISREG(data.st_mode) ? data.st_size : 0u; - } - - static time_t timestamp(const string& filename, file::time mode = file::time::create) { - #if !defined(_WIN32) - struct stat data; - stat(filename, &data); - #else - struct __stat64 data; - _wstat64(utf16_t(filename), &data); - #endif - switch(mode) { default: - case file::time::create: return data.st_ctime; - case file::time::modify: return data.st_mtime; - case file::time::access: return data.st_atime; - } - } - bool open() const { return fp; } @@ -309,8 +281,9 @@ struct file : varint { fp = nullptr; } - file() { - } + file& operator=(const file&) = delete; + file(const file&) = delete; + file() = default; file(const string& filename, mode mode_) { open(filename, mode_); @@ -320,9 +293,6 @@ struct file : varint { close(); } - file& operator=(const file&) = delete; - file(const file&) = delete; - private: enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 }; char buffer[buffer_size] = {0}; diff --git a/nall/function.hpp b/nall/function.hpp index 77d2f41a..fe7382f1 100644 --- a/nall/function.hpp +++ b/nall/function.hpp @@ -1,6 +1,8 @@ #ifndef NALL_FUNCTION_HPP #define NALL_FUNCTION_HPP +#include + namespace nall { template class function; @@ -16,7 +18,7 @@ template class function { struct global : container { R (*function)(P...); - R operator()(P... p) const { return function(std::forward

(p)...); } + R operator()(P... p) const { return function(forward

(p)...); } container* copy() const { return new global(function); } global(R (*function)(P...)) : function(function) {} }; @@ -24,21 +26,28 @@ template class function { template struct member : container { R (C::*function)(P...); C* object; - R operator()(P... p) const { return (object->*function)(std::forward

(p)...); } + R operator()(P... p) const { return (object->*function)(forward

(p)...); } container* copy() const { return new member(function, object); } member(R (C::*function)(P...), C* object) : function(function), object(object) {} }; template struct lambda : container { mutable L object; - R operator()(P... p) const { return object(std::forward

(p)...); } + R operator()(P... p) const { return object(forward

(p)...); } container* copy() const { return new lambda(object); } lambda(const L& object) : object(object) {} }; + //value = true if R L::operator()(P...) exists + template struct is_compatible { + template static const typename is_same().operator()(declval

()...))>::type exists(T*); + template static const false_type exists(...); + static constexpr bool value = decltype(exists(0))::value; + }; + public: explicit operator bool() const { return callback; } - R operator()(P... p) const { return (*callback)(std::forward

(p)...); } + R operator()(P... p) const { return (*callback)(forward

(p)...); } void reset() { if(callback) { delete callback; callback = nullptr; } } function& operator=(const function& source) { @@ -50,12 +59,12 @@ public: } function() = default; - function(const function &source) { operator=(source); } + function(const function& source) { operator=(source); } function(void* function) { if(function) callback = new global((R (*)(P...))function); } function(R (*function)(P...)) { callback = new global(function); } template function(R (C::*function)(P...), C* object) { callback = new member(function, object); } template function(R (C::*function)(P...) const, C* object) { callback = new member((R (C::*)(P...))function, object); } - template function(const L& object) { callback = new lambda(object); } + template>> function(const L& object) { callback = new lambda(object); } ~function() { if(callback) delete callback; } }; diff --git a/nall/hash/crc16.hpp b/nall/hash/crc16.hpp new file mode 100644 index 00000000..12c582f4 --- /dev/null +++ b/nall/hash/crc16.hpp @@ -0,0 +1,43 @@ +#ifndef NALL_HASH_CRC16_HPP +#define NALL_HASH_CRC16_HPP + +#include + +namespace nall { +struct string; +namespace Hash { + +struct CRC16 { + CRC16() { reset(); } + CRC16(const void* values, unsigned size) : CRC16() { data(values, size); } + + auto reset() -> void { + checksum = ~0; + } + + auto data(uint8_t value) -> void { + for(auto n : range(8)) { + if((checksum & 1) ^ (value & 1)) checksum = (checksum >> 1) ^ 0x8408; + else checksum >>= 1; + value >>= 1; + } + } + + auto data(const void* values, unsigned size) -> void { + auto p = (const uint8_t*)values; + while(size--) data(*p++); + } + + auto value() -> uint16_t { + return ~checksum; + } + + inline auto digest() -> string; + +private: + uint16_t checksum; +}; + +}} + +#endif diff --git a/nall/crc32.hpp b/nall/hash/crc32.hpp similarity index 80% rename from nall/crc32.hpp rename to nall/hash/crc32.hpp index 75700101..3ecdd64f 100644 --- a/nall/crc32.hpp +++ b/nall/hash/crc32.hpp @@ -1,11 +1,13 @@ -#ifndef NALL_CRC32_HPP -#define NALL_CRC32_HPP +#ifndef NALL_HASH_CRC32_HPP +#define NALL_HASH_CRC32_HPP -#include +#include namespace nall { +struct string; +namespace Hash { -const uint32_t crc32_table[256] = { +const uint32_t _crc32_table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, @@ -48,21 +50,36 @@ const uint32_t crc32_table[256] = { 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; -inline uint32_t crc32_adjust(uint32_t crc32, uint8_t input) { - return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff]; -} +struct CRC32 { + CRC32() { reset(); } + CRC32(const void* values, unsigned size) : CRC32() { data(values, size); } -inline uint32_t crc32_calculate(const uint8_t* data, unsigned length) { - uint32_t crc32 = ~0; - for(unsigned i = 0; i < length; i++) { - crc32 = crc32_adjust(crc32, data[i]); + auto reset() -> void { + checksum = ~0; } - return ~crc32; -} -} + auto data(uint8_t value) -> void { + checksum = ((checksum >> 8) & 0xffffff) ^ _crc32_table[(checksum ^ value) & 0xff]; + } + + auto data(const void* values, unsigned size) -> void { + auto p = (const uint8_t*)values; + while(size--) data(*p++); + } + + auto value() const -> uint32_t { + return ~checksum; + } + + inline auto digest() -> string; + +private: + uint32_t checksum; +}; + +}} #endif diff --git a/nall/hash/sha256.hpp b/nall/hash/sha256.hpp new file mode 100644 index 00000000..27105407 --- /dev/null +++ b/nall/hash/sha256.hpp @@ -0,0 +1,111 @@ +#ifndef NALL_HASH_SHA256_HPP +#define NALL_HASH_SHA256_HPP + +#include + +namespace nall { +struct string; +namespace Hash { + +struct SHA256 { + SHA256() { reset(); } + SHA256(const void* values, unsigned size) : SHA256() { data(values, size); } + + auto reset() -> void { + for(auto n : input) n = 0; + for(auto n : w) n = 0; + for(auto n : range(8)) h[n] = square(n); + queued = length = 0; + } + + auto data(uint8_t value) -> void { + byte(value); + length++; + } + + auto data(const void* values, unsigned size) -> void { + length += size; + auto p = (const uint8_t*)values; + while(size--) byte(*p++); + } + + auto value() const -> vector { + SHA256 self(*this); + self.finish(); + vector result; + for(auto n : range(32)) result.append(self.h[n >> 2] >> ((3 - (n & 3)) << 3)); + return result; + } + + inline auto digest() const -> nall::string; + +private: + auto byte(uint8_t value) -> void { + auto shift = (3 - (queued & 3)) * 8; + input[queued >> 2] &= ~(0xff << shift); + input[queued >> 2] |= (value << shift); + if(++queued == 64) block(), queued = 0; + } + + auto block() -> void { + for(auto n : range(16)) w[n] = input[n]; + for(auto n : range(16, 64)) { + uint32_t a = ror(w[n - 15], 7) ^ ror(w[n - 15], 18) ^ (w[n - 15] >> 3); + uint32_t b = ror(w[n - 2], 17) ^ ror(w[n - 2], 19) ^ (w[n - 2] >> 10); + w[n] = w[n - 16] + w[n - 7] + a + b; + } + uint32_t t[8]; + for(auto n : range(8)) t[n] = h[n]; + for(auto n : range(64)) { + uint32_t a = ror(t[0], 2) ^ ror(t[0], 13) ^ ror(t[0], 22); + uint32_t b = ror(t[4], 6) ^ ror(t[4], 11) ^ ror(t[4], 25); + uint32_t c = (t[0] & t[1]) ^ (t[0] & t[2]) ^ (t[1] & t[2]); + uint32_t d = (t[4] & t[5]) ^ (~t[4] & t[6]); + uint32_t e = t[7] + w[n] + cube(n) + b + d; + t[7] = t[6]; t[6] = t[5]; t[5] = t[4]; t[4] = t[3] + e; + t[3] = t[2]; t[2] = t[1]; t[1] = t[0]; t[0] = a + c + e; + } + for(auto n : range(8)) h[n] += t[n]; + } + + auto finish() -> void { + byte(0x80); + while(queued != 56) byte(0x00); + for(auto n : range(8)) byte((length << 3) >> ((7 - n) << 3)); + } + + auto ror(uint32_t x, uint32_t n) -> uint32_t { + return (x >> n) | (x << 32 - n); + } + + auto square(unsigned n) -> uint32_t { + static const uint32_t value[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, + }; + return value[n]; + } + + auto cube(unsigned n) -> uint32_t { + static const uint32_t value[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, + }; + return value[n]; + } + + uint32_t input[16]; + uint32_t queued; + uint32_t w[64]; + uint32_t h[8]; + uint64_t length; +}; + +}} + +#endif diff --git a/nall/http.hpp b/nall/http.hpp deleted file mode 100644 index 55421867..00000000 --- a/nall/http.hpp +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef NALL_HTTP_HPP -#define NALL_HTTP_HPP - -#if !defined(_WIN32) - #include - #include - #include - #include -#else - #include - #include - #include -#endif - -#include -#include - -namespace nall { - -struct http { - string hostname; - addrinfo* serverinfo; - int serversocket; - string header; - - inline void download(const string& path, uint8_t*& data, unsigned& size) { - data = nullptr; - size = 0; - - send({ - "GET ", path, " HTTP/1.1\r\n" - "Host: ", hostname, "\r\n" - "Connection: close\r\n" - "\r\n" - }); - - header = downloadHeader(); - downloadContent(data, size); - } - - inline bool connect(string host, unsigned port) { - hostname = host; - - addrinfo hints; - memset(&hints, 0, sizeof(addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - - int status = getaddrinfo(hostname, string(port), &hints, &serverinfo); - if(status != 0) return false; - - serversocket = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol); - if(serversocket == -1) return false; - - int result = ::connect(serversocket, serverinfo->ai_addr, serverinfo->ai_addrlen); - if(result == -1) return false; - - return true; - } - - inline bool send(const string& data) { - return send((const uint8_t*)(const char*)data, data.length()); - } - - inline bool send(const uint8_t* data, unsigned size) { - while(size) { - int length = ::send(serversocket, (const char*)data, size, 0); - if(length == -1) return false; - data += length; - size -= length; - } - return true; - } - - inline string downloadHeader() { - string output; - do { - char buffer[2]; - int length = recv(serversocket, buffer, 1, 0); - if(length <= 0) return output; - buffer[1] = 0; - output.append(buffer); - } while(output.endsWith("\r\n\r\n") == false); - return output; - } - - inline string downloadChunkLength() { - string output; - do { - char buffer[2]; - int length = recv(serversocket, buffer, 1, 0); - if(length <= 0) return output; - buffer[1] = 0; - output.append(buffer); - } while(output.endsWith("\r\n") == false); - return output; - } - - inline void downloadContent(uint8_t*& data, unsigned& size) { - unsigned capacity = 0; - - if(header.ifind("\r\nTransfer-Encoding: chunked\r\n")) { - while(true) { - unsigned length = hex(downloadChunkLength()); - if(length == 0) break; - capacity += length; - data = (uint8_t*)realloc(data, capacity); - - char buffer[length]; - while(length) { - int packetlength = recv(serversocket, buffer, length, 0); - if(packetlength <= 0) break; - memcpy(data + size, buffer, packetlength); - size += packetlength; - length -= packetlength; - } - } - } else if(auto position = header.ifind("\r\nContent-Length: ")) { - unsigned length = decimal((const char*)header + position() + 18); - while(length) { - char buffer[256]; - int packetlength = recv(serversocket, buffer, min(256, length), 0); - if(packetlength <= 0) break; - capacity += packetlength; - data = (uint8_t*)realloc(data, capacity); - memcpy(data + size, buffer, packetlength); - size += packetlength; - length -= packetlength; - } - } else { - while(true) { - char buffer[256]; - int packetlength = recv(serversocket, buffer, 256, 0); - if(packetlength <= 0) break; - capacity += packetlength; - data = (uint8_t*)realloc(data, capacity); - memcpy(data + size, buffer, packetlength); - size += packetlength; - } - } - - data = (uint8_t*)realloc(data, capacity + 1); - data[capacity] = 0; - } - - inline void disconnect() { - close(serversocket); - freeaddrinfo(serverinfo); - serverinfo = nullptr; - serversocket = -1; - } - - #ifdef _WIN32 - inline int close(int sock) { - return closesocket(sock); - } - - inline http() { - int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if(sock == INVALID_SOCKET && WSAGetLastError() == WSANOTINITIALISED) { - WSADATA wsaData; - if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { - WSACleanup(); - return; - } - } else { - close(sock); - } - } - #endif -}; - -} - -#endif diff --git a/nall/http/client.hpp b/nall/http/client.hpp new file mode 100644 index 00000000..9c578640 --- /dev/null +++ b/nall/http/client.hpp @@ -0,0 +1,59 @@ +#ifndef NALL_HTTP_CLIENT_HPP +#define NALL_HTTP_CLIENT_HPP + +#include + +namespace nall { + +struct httpClient : httpRole { + inline auto open(const string& hostname, unsigned port = 80) -> bool; + inline auto upload(const httpRequest& request) -> bool; + inline auto download(const httpRequest& request) -> httpResponse; + inline auto close() -> void; + ~httpClient() { close(); } + +private: + signed fd = -1; + addrinfo* info = nullptr; +}; + +auto httpClient::open(const string& hostname, unsigned port) -> bool { + addrinfo hint = {0}; + hint.ai_family = AF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + hint.ai_flags = AI_ADDRCONFIG; + + if(getaddrinfo(hostname, string{port}, &hint, &info) != 0) return close(), false; + + fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol); + if(fd < 0) return close(), false; + + if(connect(fd, info->ai_addr, info->ai_addrlen) < 0) return close(), false; + return true; +} + +auto httpClient::upload(const httpRequest& request) -> bool { + return httpRole::upload(fd, request); +} + +auto httpClient::download(const httpRequest& request) -> httpResponse { + httpResponse response(request); + httpRole::download(fd, response); + return response; +} + +auto httpClient::close() -> void { + if(fd) { + ::close(fd); + fd = -1; + } + + if(info) { + freeaddrinfo(info); + info = nullptr; + } +} + +} + +#endif diff --git a/nall/http/message.hpp b/nall/http/message.hpp new file mode 100644 index 00000000..569a789e --- /dev/null +++ b/nall/http/message.hpp @@ -0,0 +1,77 @@ +#ifndef NALL_HTTP_MESSAGE_HPP +#define NALL_HTTP_MESSAGE_HPP + +//httpMessage: base class for httpRequest and httpResponse +//provides shared functionality + +namespace nall { + +struct httpVariable { + string name; + string value; +}; + +struct httpVariables : vector { + auto append(const string& name, const string& value) -> void; + auto get(const string& name) const -> string; + auto remove(const string& name) -> void; + auto set(const string& name, const string& value) -> void; +}; + +auto httpVariables::append(const string& name, const string& value) -> void { + vector::append({name, value}); +} + +auto httpVariables::get(const string& name) const -> string { + for(auto& variable : *this) { + if(variable.name.iequals(name)) return variable.value; + } + return ""; +} + +auto httpVariables::remove(const string& name) -> void { + while(true) { + unsigned n = 0; + bool found = false; + for(auto& variable : *this) { + if(!variable.name.iequals(name)) { n++; continue; } + vector::remove(n); + found = true; + break; + } + if(found == false) break; + } +} + +auto httpVariables::set(const string& name, const string& value) -> void { + for(auto& variable : *this) { + if(!variable.name.iequals(name)) continue; + variable.name = name; + variable.value = value; + return; + } + vector::append({name, value}); +} + +struct httpMessage { + using type = httpMessage; + + virtual auto head(const function& callback) const -> bool = 0; + virtual auto setHead() -> bool = 0; + + virtual auto body(const function& callback) const -> bool = 0; + virtual auto setBody() -> bool = 0; + + virtual auto header(const string& name) const -> string { return _header.get(name); } + virtual auto appendHeader(const string& name, const string& value = "") -> type& { return _header.append(name, value), *this; } + virtual auto removeHeader(const string& name) -> type& { return _header.remove(name), *this; } + virtual auto setHeader(const string& name, const string& value = "") -> type& { return _header.set(name, value), *this; } + + string _head; + string _body; + httpVariables _header; +}; + +} + +#endif diff --git a/nall/http/request.hpp b/nall/http/request.hpp new file mode 100644 index 00000000..934db529 --- /dev/null +++ b/nall/http/request.hpp @@ -0,0 +1,146 @@ +#ifndef NALL_HTTP_REQUEST_HPP +#define NALL_HTTP_REQUEST_HPP + +#include + +namespace nall { + +struct httpRequest : httpMessage { + using type = httpRequest; + + enum class RequestType : unsigned { None, Head, Get, Post }; + + explicit operator bool() const { return requestType() != RequestType::None; } + + inline auto head(const function& callback) const -> bool; + inline auto setHead() -> bool; + + inline auto body(const function& callback) const -> bool; + inline auto setBody() -> bool; + + auto ip() const -> string { + return {(uint8_t)(_ip >> 24), ".", (uint8_t)(_ip >> 16), ".", (uint8_t)(_ip >> 8), ".", (uint8_t)(_ip >> 0)}; + } + + auto requestType() const -> RequestType { return _requestType; } + auto setRequestType(RequestType value) -> void { _requestType = value; } + + auto path() const -> string { return _path; } + auto setPath(const string& value) -> void { _path = value; } + + auto appendHeader(const string& name, const string& value = "") -> type& { return httpMessage::appendHeader(name, value), *this; } + auto removeHeader(const string& name) -> type& { return httpMessage::removeHeader(name), *this; } + auto setHeader(const string& name, const string& value = "") -> type& { return httpMessage::setHeader(name, value), *this; } + + auto get(const string& name) -> string { return _get.get(name); } + auto setGet(const string& name, const string& value = "") -> void { return _get.set(name, value); } + + auto post(const string& name) -> string { return _post.get(name); } + auto setPost(const string& name, const string& value = "") -> void { return _post.set(name, value); } + +//private: + uint32_t _ip = 0; + RequestType _requestType = RequestType::None; + string _path; + httpVariables _cookie; + httpVariables _get; + httpVariables _post; +}; + +auto httpRequest::head(const function& callback) const -> bool { + if(!callback) return false; + string output; + + string request = path(); + if(_get.size()) { + request.append("?"); + for(auto& get : _get) { + request.append(get.name, "=", get.value, "&"); + } + request.rtrim("&"); + } + + switch(requestType()) { + case RequestType::Head: output.append("HEAD ", request, " HTTP/1.1\r\n"); break; + case RequestType::Get : output.append("GET ", request, " HTTP/1.1\r\n"); break; + case RequestType::Post: output.append("POST ", request, " HTTP/1.1\r\n"); break; + default: return false; + } + + for(auto& header : _header) { + output.append(header.name, ": ", header.value, "\r\n"); + } + output.append("\r\n"); + + return callback(output.binary(), output.size()); +} + +auto httpRequest::setHead() -> bool { + lstring headers = _head.split("\n"); + string request = headers.takeFirst().rtrim("\r"); + string requestHost; + + if(irtrim(request, " HTTP/1.0")); + else if(irtrim(request, " HTTP/1.1")); + else return false; + + if(iltrim(request, "HEAD ")) setRequestType(RequestType::Head); + else if(iltrim(request, "GET " )) setRequestType(RequestType::Get ); + else if(iltrim(request, "POST ")) setRequestType(RequestType::Post); + else return false; + + //decode absolute URIs + request.strip().iltrim("http://"); + if(!request.beginsWith("/")) { + lstring components = request.split<1>("/"); + requestHost = components(0); + request = {"/", components(1)}; + } + + lstring components = request.split<1>("?"); + setPath(components(0)); + + if(auto queryString = components(1)) { + for(auto& block : queryString.split("&")) { + lstring variable = block.split<1>("="); + if(variable(0)) setGet(variable(0), variable(1)); + } + } + + for(auto& header : headers) { + if(header.beginsWith(" ") || header.beginsWith("\t")) continue; + auto part = header.split<1>(":").strip(); + if(!part[0] || part.size() != 2) continue; + appendHeader(part[0], part[1]); + } + + if(requestHost) setHeader("Host", requestHost); //request URI overrides host header + return true; +} + +auto httpRequest::body(const function& callback) const -> bool { + if(!callback) return false; + + if(_body) { + return callback(_body.binary(), _body.size()); + } + + return true; +} + +auto httpRequest::setBody() -> bool { + if(requestType() == RequestType::Post) { + if(header("Content-Type").iequals("application/x-www-form-urlencoded")) { + for(auto& block : _body.split("\n")) { + lstring variable = block.rtrim("\r").split<1>("="); + if(variable(0)) setPost(variable(0), variable(1)); + } + } + } + + return true; +} + +} + +#endif diff --git a/nall/http/response.hpp b/nall/http/response.hpp new file mode 100644 index 00000000..7bca9201 --- /dev/null +++ b/nall/http/response.hpp @@ -0,0 +1,253 @@ +#ifndef NALL_HTTP_RESPONSE_HPP +#define NALL_HTTP_RESPONSE_HPP + +#include + +namespace nall { + +struct httpResponse : httpMessage { + using type = httpResponse; + + httpResponse() = default; + httpResponse(const httpRequest& request) { setRequest(request); } + + explicit operator bool() const { return responseType() != 0; } + auto operator()(unsigned responseType) -> type& { return setResponseType(responseType); } + + inline auto head(const function& callback) const -> bool; + inline auto setHead() -> bool; + + inline auto body(const function& callback) const -> bool; + inline auto setBody() -> bool; + + auto request() const -> const httpRequest* { return _request; } + auto setRequest(const httpRequest& value) -> type& { _request = &value; return *this; } + + auto responseType() const -> unsigned { return _responseType; } + auto setResponseType(unsigned value) -> type& { _responseType = value; return *this; } + + auto appendHeader(const string& name, const string& value = "") -> type& { return httpMessage::appendHeader(name, value), *this; } + auto removeHeader(const string& name) -> type& { return httpMessage::removeHeader(name), *this; } + auto setHeader(const string& name, const string& value = "") -> type& { return httpMessage::setHeader(name, value), *this; } + + auto hasData() const -> bool { return (bool)_data; } + auto data() const -> const vector& { return _data; } + inline auto setData(const vector& value) -> type&; + + auto hasFile() const -> bool { return (bool)_file; } + auto file() const -> const string& { return _file; } + inline auto setFile(const string& value) -> type&; + + auto hasText() const -> bool { return (bool)_text; } + auto text() const -> const string& { return _text; } + inline auto setText(const string& value) -> type&; + + inline auto hasBody() const -> bool; + inline auto findContentLength() const -> unsigned; + inline auto findContentType() const -> string; + inline auto findContentType(const string& suffix) const -> string; + inline auto findResponseType() const -> string; + inline auto setFileETag() -> void; + + const httpRequest* _request = nullptr; + unsigned _responseType = 0; + vector _data; + string _file; + string _text; +}; + +auto httpResponse::head(const function& callback) const -> bool { + if(!callback) return false; + string output; + + if(auto request = this->request()) { + if(auto eTag = header("ETag")) { + if(eTag == request->header("If-None-Match")) { + output.append("HTTP/1.1 304 Not Modified\r\n"); + output.append("Connection: close\r\n"); + output.append("\r\n"); + return callback(output.binary(), output.size()); + } + } + } + + output.append("HTTP/1.1 ", findResponseType(), "\r\n"); + for(auto& header : _header) { + output.append(header.name, ": ", header.value, "\r\n"); + } + if(hasBody()) { + if(!header("Content-Length") && !header("Transfer-Encoding").iequals("chunked")) { + output.append("Content-Length: ", findContentLength(), "\r\n"); + } + if(!header("Content-Type")) { + output.append("Content-Type: ", findContentType(), "\r\n"); + } + } + if(!header("Connection")) { + output.append("Connection: close\r\n"); + } + output.append("\r\n"); + + return callback(output.binary(), output.size()); +} + +auto httpResponse::setHead() -> bool { + lstring headers = _head.split("\n"); + string response = headers.takeFirst().rtrim("\r"); + + if(iltrim(response, "HTTP/1.0 ")); + else if(iltrim(response, "HTTP/1.1 ")); + else return false; + + setResponseType(decimal(response)); + + for(auto& header : headers) { + if(header.beginsWith(" ") || header.beginsWith("\t")) continue; + lstring variable = header.split<1>(":").strip(); + if(variable.size() != 2) continue; + appendHeader(variable[0], variable[1]); + } + + return true; +} + +auto httpResponse::body(const function& callback) const -> bool { + if(!callback) return false; + if(!hasBody()) return true; + bool chunked = header("Transfer-Encoding") == "chunked"; + + if(chunked) { + string prefix = {hex(findContentLength()), "\r\n"}; + if(!callback(prefix.binary(), prefix.size())) return false; + } + + if(_body) { + if(!callback(_body.binary(), _body.size())) return false; + } else if(hasData()) { + if(!callback(data().data(), data().size())) return false; + } else if(hasFile()) { + filemap map(file(), filemap::mode::read); + if(!callback(map.data(), map.size())) return false; + } else if(hasText()) { + if(!callback(text().binary(), text().size())) return false; + } else { + string response = findResponseType(); + if(!callback(response.binary(), response.size())) return false; + } + + if(chunked) { + string suffix = {"\r\n0\r\n\r\n"}; + if(!callback(suffix.binary(), suffix.size())) return false; + } + + return true; +} + +auto httpResponse::setBody() -> bool { + return true; +} + +auto httpResponse::hasBody() const -> bool { + if(auto request = this->request()) { + if(request->requestType() == httpRequest::RequestType::Head) return false; + } + if(responseType() == 301) return false; + if(responseType() == 302) return false; + if(responseType() == 303) return false; + if(responseType() == 304) return false; + if(responseType() == 307) return false; + return true; +} + +auto httpResponse::findContentLength() const -> unsigned { + if(auto contentLength = header("Content-Length")) return decimal(contentLength); + if(_body) return _body.size(); + if(hasData()) return data().size(); + if(hasFile()) return file::size(file()); + if(hasText()) return text().size(); + return findResponseType().size(); +} + +auto httpResponse::findContentType() const -> string { + if(auto contentType = header("Content-Type")) return contentType; + if(hasData()) return "application/octet-stream"; + if(hasFile()) return findContentType(file().suffixname()); + return "text/html; charset=utf-8"; +} + +auto httpResponse::findContentType(const string& s) const -> string { + if(s == ".7z" ) return "application/x-7z-compressed"; + if(s == ".avi" ) return "video/avi"; + if(s == ".bml" ) return "text/plain; charset=utf-8"; + if(s == ".bz2" ) return "application/x-bzip2"; + if(s == ".css" ) return "text/css; charset=utf-8"; + if(s == ".gif" ) return "image/gif"; + if(s == ".gz" ) return "application/gzip"; + if(s == ".htm" ) return "text/html; charset=utf-8"; + if(s == ".html") return "text/html; charset=utf-8"; + if(s == ".jpg" ) return "image/jpeg"; + if(s == ".jpeg") return "image/jpeg"; + if(s == ".js" ) return "application/javascript"; + if(s == ".mka" ) return "audio/x-matroska"; + if(s == ".mkv" ) return "video/x-matroska"; + if(s == ".mp3" ) return "audio/mpeg"; + if(s == ".mp4" ) return "video/mp4"; + if(s == ".mpeg") return "video/mpeg"; + if(s == ".mpg" ) return "video/mpeg"; + if(s == ".ogg" ) return "audio/ogg"; + if(s == ".pdf" ) return "application/pdf"; + if(s == ".png" ) return "image/png"; + if(s == ".rar" ) return "application/x-rar-compressed"; + if(s == ".svg" ) return "image/svg+xml"; + if(s == ".tar" ) return "application/x-tar"; + if(s == ".txt" ) return "text/plain; charset=utf-8"; + if(s == ".wav" ) return "audio/vnd.wave"; + if(s == ".webm") return "video/webm"; + if(s == ".xml" ) return "text/xml; charset=utf-8"; + if(s == ".xz" ) return "application/x-xz"; + if(s == ".zip" ) return "application/zip"; + return "application/octet-stream"; //binary +} + +auto httpResponse::findResponseType() const -> string { + switch(responseType()) { + case 200: return "200 OK"; + case 301: return "301 Moved Permanently"; + case 302: return "302 Found"; + case 303: return "303 See Other"; + case 304: return "304 Not Modified"; + case 307: return "307 Temporary Redirect"; + case 400: return "400 Bad Request"; + case 403: return "403 Forbidden"; + case 404: return "404 Not Found"; + case 500: return "500 Internal Server Error"; + case 501: return "501 Not Implemented"; + case 503: return "503 Service Unavailable"; + } + return "501 Not Implemented"; +} + +auto httpResponse::setData(const vector& value) -> type& { + _data = value; + setHeader("Content-Length", value.size()); + return *this; +} + +auto httpResponse::setFile(const string& value) -> type& { + _file = value; + string eTag = {"\"", string::datetime(file::timestamp(value, file::time::modify)), "\""}; + setHeader("Content-Length", file::size(value)); + setHeader("Cache-Control", "public"); + setHeader("ETag", eTag); + return *this; +} + +auto httpResponse::setText(const string& value) -> type& { + _text = value; + setHeader("Content-Length", value.size()); + return *this; +} + +} + +#endif diff --git a/nall/http/role.hpp b/nall/http/role.hpp new file mode 100644 index 00000000..7a1970e2 --- /dev/null +++ b/nall/http/role.hpp @@ -0,0 +1,161 @@ +#ifndef NALL_HTTP_ROLE_HPP +#define NALL_HTTP_ROLE_HPP + +//httpRole: base class for httpClient and httpServer +//provides shared functionality + +#include +#include + +namespace nall { + +struct httpRole { + struct Settings { + signed connectionLimit = 1024; //server + signed headSizeLimit = 16384; //client, server + signed bodySizeLimit = 65536; //client, server + signed chunkSize = 32768; //client, server + signed threadStackSize = 131072; //server + signed timeoutReceive = 15000; //server + signed timeoutSend = 15000; //server + } settings; + + inline auto configure(const string& parameters) -> bool; + inline auto download(signed fd, httpMessage& message) -> bool; + inline auto upload(signed fd, const httpMessage& message) -> bool; +}; + +auto httpRole::configure(const string& parameters) -> bool { + auto document = Markup::Document(parameters); + for(auto& parameter : document) { + string& name = parameter.name; + signed value = parameter.integer(); + + if(0); + else if(name == "connectionLimit") settings.connectionLimit = value; + else if(name == "headSizeLimit") settings.headSizeLimit = value; + else if(name == "bodySizeLimit") settings.bodySizeLimit = value; + else if(name == "chunkSize") settings.chunkSize = value; + else if(name == "threadStackSize") settings.threadStackSize = value; + else if(name == "timeoutReceive") settings.timeoutReceive = value; + else if(name == "timeoutSend") settings.timeoutSend = value; + } + return true; +} + +auto httpRole::download(signed fd, httpMessage& message) -> bool { + auto& head = message._head; + auto& body = message._body; + string chunk; + uint8_t packet[settings.chunkSize], *p = nullptr; + + head.reset(), head.reserve(4095); + body.reset(), body.reserve(4095); + + bool headReceived = false; + bool chunked = false; + bool chunkReceived = false; + bool chunkFooterReceived = true; + signed length = 0; + signed chunkLength = 0; + signed contentLength = 0; + + while(true) { + if(auto limit = settings.headSizeLimit) if(head.size() >= limit) return false; + if(auto limit = settings.bodySizeLimit) if(body.size() >= limit) return false; + + if(headReceived && !chunked && body.size() >= contentLength) { + body.resize(contentLength); + break; + } + + if(length == 0) { + length = recv(fd, packet, settings.chunkSize, MSG_NOSIGNAL); + if(length <= 0) return false; + p = packet; + } + + if(!headReceived) { + head.append((char)*p++); + --length; + + if(head.endsWith("\r\n\r\n") || head.endsWith("\n\n")) { + headReceived = true; + if(!message.setHead()) return false; + chunked = message.header("Transfer-Encoding").iequals("chunked"); + contentLength = decimal(message.header("Content-Length")); + } + + continue; + } + + if(chunked && !chunkReceived) { + char n = *p++; + --length; + + if(!chunkFooterReceived) { + if(n == '\n') chunkFooterReceived = true; + continue; + } + + chunk.append(n); + + if(chunk.endsWith("\r\n") || chunk.endsWith("\n")) { + chunkReceived = true; + chunkLength = hex(chunk); + if(chunkLength == 0) break; + chunk.reset(); + } + + continue; + } + + if(!chunked) { + body.resize(body.size() + length); + memory::copy(body.pointer() + body.size() - length, p, length); + + p += length; + length = 0; + } else { + signed transferLength = min(length, chunkLength); + body.resize(body.size() + transferLength); + memory::copy(body.pointer() + body.size() - transferLength, p, transferLength); + + p += transferLength; + length -= transferLength; + chunkLength -= transferLength; + + if(chunkLength == 0) { + chunkReceived = false; + chunkFooterReceived = false; + } + } + } + + if(!message.setBody()) return false; + return true; +} + +auto httpRole::upload(signed fd, const httpMessage& message) -> bool { + auto transfer = [&](const uint8_t* data, unsigned size) -> bool { + while(size) { + signed length = send(fd, data, min(size, settings.chunkSize), MSG_NOSIGNAL); + if(length < 0) return false; + data += length; + size -= length; + } + return true; + }; + + if(message.head([&](const uint8_t* data, unsigned size) -> bool { return transfer(data, size); })) { + if(message.body([&](const uint8_t* data, unsigned size) -> bool { return transfer(data, size); })) { + return true; + } + } + + return false; +} + +} + +#endif diff --git a/nall/http/server.hpp b/nall/http/server.hpp new file mode 100644 index 00000000..41a57e07 --- /dev/null +++ b/nall/http/server.hpp @@ -0,0 +1,136 @@ +#ifndef NALL_HTTP_SERVER_HPP +#define NALL_HTTP_SERVER_HPP + +#include +#include + +#include +#include + +namespace nall { + +struct httpServer : httpRole, service { + inline auto open(unsigned port = 8080, const string& serviceName = "", const string& command = "") -> bool; + inline auto main(const function& function = {}) -> void; + inline auto scan() -> string; + inline auto close() -> void; + ~httpServer() { close(); } + +private: + signed fd = -1; + function callback; + struct sockaddr_in addrin = {0}; + std::atomic connections{0}; +}; + +auto httpServer::open(unsigned port, const string& serviceName, const string& command) -> bool { + if(serviceName) { + if(!service::command(serviceName, command)) return false; + } + + fd = socket(AF_INET, SOCK_STREAM, 0); + if(fd < 0) return false; + + { + #if defined(SO_RCVTIMEO) + if(settings.timeoutReceive) { + struct timeval rcvtimeo; + rcvtimeo.tv_sec = settings.timeoutReceive / 1000; + rcvtimeo.tv_usec = settings.timeoutReceive % 1000 * 1000; + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval)); + } + #endif + + #if defined(SO_SNDTIMEO) + if(settings.timeoutSend) { + struct timeval sndtimeo; + sndtimeo.tv_sec = settings.timeoutSend / 1000; + sndtimeo.tv_usec = settings.timeoutSend % 1000 * 1000; + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval)); + } + #endif + + #if defined(SO_NOSIGPIPE) //BSD, OSX + signed nosigpipe = 1; + setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(signed)); + #endif + + #if defined(SO_REUSEADDR) //BSD, Linux, OSX + signed reuseaddr = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(signed)); + #endif + + #if defined(SO_REUSEPORT) //BSD, OSX + signed reuseport = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(signed)); + #endif + } + + addrin.sin_family = AF_INET; + addrin.sin_addr.s_addr = htonl(INADDR_ANY); + addrin.sin_port = htons(port); + + signed result = bind(fd, (struct sockaddr*)&addrin, sizeof(addrin)); + if(result < 0) return close(), false; + + result = listen(fd, SOMAXCONN); //system-wide limit (per port) + if(result < 0) return close(), false; + + return true; +} + +auto httpServer::main(const function& function) -> void { + callback = function; +} + +auto httpServer::scan() -> string { + if(auto command = service::receive()) return command; + + if(connections >= settings.connectionLimit) return "busy"; + + struct pollfd query = {0}; + query.fd = fd; + query.events = POLLIN; + poll(&query, 1, 0); + + if(query.fd == fd && query.revents & POLLIN) { + ++connections; + + thread::create([&](uintptr_t) { + thread::detach(); + + signed clientfd = -1; + struct sockaddr_in settings = {0}; + socklen_t socklen = sizeof(sockaddr_in); + + clientfd = accept(fd, (struct sockaddr*)&settings, &socklen); + if(clientfd < 0) return; + + httpRequest request; + request._ip = ntohl(settings.sin_addr.s_addr); + + if(download(clientfd, request) && callback) { + auto response = callback(request); + upload(clientfd, response); + } else { + upload(clientfd, httpResponse()); //"501 Not Implemented" + } + + ::close(clientfd); + --connections; + }, 0, settings.threadStackSize); + } + + return "ok"; +} + +auto httpServer::close() -> void { + if(fd) { + ::close(fd); + fd = -1; + } +} + +} + +#endif diff --git a/nall/image.hpp b/nall/image.hpp index 5f39fce5..b1c865ea 100644 --- a/nall/image.hpp +++ b/nall/image.hpp @@ -6,9 +6,8 @@ #include #include #include -#include #include - +#include #include #include #include diff --git a/nall/image/base.hpp b/nall/image/base.hpp index 5697ec8d..a530671a 100644 --- a/nall/image/base.hpp +++ b/nall/image/base.hpp @@ -47,6 +47,7 @@ struct image { static inline uint64_t normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth); //core.hpp + inline explicit operator bool() const; inline bool operator==(const image& source); inline bool operator!=(const image& source); @@ -56,6 +57,7 @@ struct image { inline image(image&& source); inline image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask); inline image(const string& filename); + inline image(const vector& buffer); inline image(const uint8_t* data, unsigned size); inline image(); inline ~image(); diff --git a/nall/image/core.hpp b/nall/image/core.hpp index 5ee04042..c0f0a63c 100644 --- a/nall/image/core.hpp +++ b/nall/image/core.hpp @@ -3,6 +3,10 @@ namespace nall { +image::operator bool() const { + return !empty(); +} + bool image::operator==(const image& source) { if(width != source.width) return false; if(height != source.height) return false; @@ -88,6 +92,10 @@ image::image(const string& filename) { load(filename); } +image::image(const vector& buffer) { + loadPNG(buffer.data(), buffer.size()); +} + image::image(const uint8_t* data, unsigned size) { loadPNG(data, size); } diff --git a/nall/image/load.hpp b/nall/image/load.hpp index 6ac17d80..9c5b6f4e 100644 --- a/nall/image/load.hpp +++ b/nall/image/load.hpp @@ -35,7 +35,7 @@ bool image::loadPNG(const string& filename) { } bool image::loadPNG(const uint8_t* pngData, unsigned pngSize) { - png source; + Decode::PNG source; if(source.decode(pngData, pngSize) == false) return false; allocate(source.info.width, source.info.height); diff --git a/nall/intrinsics.hpp b/nall/intrinsics.hpp index da41094b..eadf33e5 100644 --- a/nall/intrinsics.hpp +++ b/nall/intrinsics.hpp @@ -15,16 +15,22 @@ struct Intrinsics { static inline Endian endian(); }; +} + /* Compiler detection */ +namespace nall { + #if defined(__clang__) #define COMPILER_CLANG Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::Clang; } + #pragma clang diagnostic ignored "-Wunknown-pragmas" #pragma clang diagnostic ignored "-Wempty-body" #pragma clang diagnostic ignored "-Wparentheses" #pragma clang diagnostic ignored "-Wreturn-type" #pragma clang diagnostic ignored "-Wswitch" + #pragma clang diagnostic ignored "-Wswitch-bool" #pragma clang diagnostic ignored "-Wtautological-compare" #elif defined(__GNUC__) #define COMPILER_GCC @@ -40,8 +46,12 @@ struct Intrinsics { Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::Unknown; } #endif +} + /* Platform detection */ +namespace nall { + #if defined(_WIN32) #define PLATFORM_WINDOWS Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Windows; } @@ -62,6 +72,8 @@ struct Intrinsics { Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Unknown; } #endif +} + /* Architecture Detection */ #if defined(PLATFORM_MACOSX) @@ -72,6 +84,8 @@ struct Intrinsics { #include #endif +namespace nall { + #if defined(__i386__) || defined(_M_IX86) #define ARCH_X86 Intrinsics::Architecture Intrinsics::architecture() { return Intrinsics::Architecture::x86; } @@ -84,8 +98,12 @@ struct Intrinsics { Intrinsics::Architecture Intrinsics::architecture() { return Intrinsics::Architecture::Unknown; } #endif +} + /* Endian detection */ +namespace nall { + #if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN__) || defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64) #define ENDIAN_LSB Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::LSB; } diff --git a/nall/invoke.hpp b/nall/invoke.hpp index 078f7f5b..a697fbe8 100644 --- a/nall/invoke.hpp +++ b/nall/invoke.hpp @@ -36,7 +36,7 @@ template inline void invoke(const string& name, Args&&... args const char** argp = argv; lstring argl(std::forward(args)...); *argp++ = (const char*)name; - for(auto &arg : argl) *argp++ = (const char*)arg; + for(auto& arg : argl) *argp++ = (const char*)arg; *argp++ = nullptr; if(execvp(name, (char* const*)argv) < 0) { diff --git a/nall/main.hpp b/nall/main.hpp new file mode 100644 index 00000000..98a433ab --- /dev/null +++ b/nall/main.hpp @@ -0,0 +1,29 @@ +#ifndef NALL_MAIN_HPP +#define NALL_MAIN_HPP + +#include +#include + +namespace nall { + auto main(lstring arguments) -> void; + + auto main(int argc, char** argv) -> int { + #if defined(PLATFORM_WINDOWS) + CoInitialize(0); + WSAData wsaData = {0}; + WSAStartup(MAKEWORD(2, 2), &wsaData); + utf8_args(argc, argv); + #endif + + lstring arguments; + for(auto n : range(argc)) arguments.append(argv[n]); + + return main(move(arguments)), EXIT_SUCCESS; + } +} + +auto main(int argc, char** argv) -> int { + return nall::main(argc, argv); +} + +#endif diff --git a/nall/maybe.hpp b/nall/maybe.hpp index 4f806dac..425f98e0 100644 --- a/nall/maybe.hpp +++ b/nall/maybe.hpp @@ -6,7 +6,7 @@ namespace nall { struct nothing_t {}; static nothing_t nothing; -template +template class maybe { T* value = nullptr; @@ -15,28 +15,32 @@ public: maybe(nothing_t) {} maybe(const T& source) { operator=(source); } maybe(const maybe& source) { operator=(source); } - maybe(maybe&& source) { operator=(std::move(source)); } + maybe(maybe&& source) { operator=(move(source)); } ~maybe() { reset(); } - maybe& operator=(nothing_t) { reset(); return *this; } - maybe& operator=(const T& source) { reset(); value = new T(source); return *this; } - maybe& operator=(const maybe& source) { reset(); if(source) value = new T(source()); return *this; } - maybe& operator=(maybe&& source) { reset(); value = source.value; source.value = nullptr; return *this; } + auto operator=(nothing_t) -> maybe& { reset(); return *this; } + auto operator=(const T& source) -> maybe& { reset(); value = new T(source); return *this; } + auto operator=(const maybe& source) -> maybe& { reset(); if(source) value = new T(source()); return *this; } + auto operator=(maybe&& source) -> maybe& { reset(); value = source.value; source.value = nullptr; return *this; } - bool operator==(const maybe& source) const { + auto operator==(const maybe& source) const -> bool { if(value && source.value) return *value == *source.value; return !value && !source.value; } - bool operator!=(const maybe& source) const { return !operator==(source); } + auto operator!=(const maybe& source) const -> bool { return !operator==(source); } explicit operator bool() const { return value; } - T& operator()() { assert(value); return *value; } - const T& operator()() const { assert(value); return *value; } - const T& operator()(const T& invalid) const { if(value) return *value; return invalid; } + auto operator->() -> T* { assert(value); return value; } + auto operator->() const -> T* { assert(value); return value; } + auto operator*() -> T& { assert(value); return *value; } + auto operator*() const -> T& { assert(value); return *value; } + auto operator()() -> T& { assert(value); return *value; } + auto operator()() const -> T& { assert(value); return *value; } + auto operator()(const T& invalid) const -> T& { if(value) return *value; return invalid; } - bool empty() const { return value == nullptr; } - void reset() { if(value) { delete value; value = nullptr; } } - void swap(maybe& source) { std::swap(value, source.value); } + auto empty() const -> bool { return value == nullptr; } + auto reset() -> void { if(value) { delete value; value = nullptr; } } + auto swap(maybe& source) -> void { std::swap(value, source.value); } }; template @@ -48,27 +52,64 @@ public: maybe(nothing_t) {} maybe(const T& source) { operator=(source); } maybe(const maybe& source) { operator=(source); } - maybe(maybe&& source) { operator=(std::move(source)); } + maybe(maybe&& source) { operator=(move(source)); } - maybe& operator=(nothing_t) { value = nullptr; return *this; } - maybe& operator=(const T& source) { value = (T*)&source; return *this; } - maybe& operator=(const maybe& source) { value = source.value; return *this; } - maybe& operator=(maybe&& source) { value = source.value; source.value = nullptr; return *this; } + auto operator=(nothing_t) -> maybe& { value = nullptr; return *this; } + auto operator=(const T& source) -> maybe& { value = (T*)&source; return *this; } + auto operator=(const maybe& source) -> maybe& { value = source.value; return *this; } + auto operator=(maybe&& source) -> maybe& { value = source.value; source.value = nullptr; return *this; } - bool operator==(const maybe& source) const { + auto operator==(const maybe& source) const -> bool { if(value && source.value) return *value == *source.value; return !value && !source.value; } - bool operator!=(const maybe& source) const { return !operator==(source); } + auto operator!=(const maybe& source) const -> bool { return !operator==(source); } explicit operator bool() const { return value; } - T& operator()() { assert(value); return *value; } - const T& operator()() const { assert(value); return *value; } - const T& operator()(const T& invalid) const { if(value) return *value; return invalid; } + auto operator->() -> T* { assert(value); return value; } + auto operator->() const -> T* { assert(value); return *value; } + auto operator*() -> T& { assert(value); return *value; } + auto operator*() const -> T& { assert(value); return *value; } + auto operator()() -> T& { assert(value); return *value; } + auto operator()() const -> T& { assert(value); return *value; } + auto operator()(const T& invalid) const -> T& { if(value) return *value; return invalid; } - bool empty() const { return value == nullptr; } - void reset() { value = nullptr; } - void swap(maybe& source) { std::swap(value, source.value); } + auto empty() const -> bool { return value == nullptr; } + auto reset() -> void { value = nullptr; } + auto swap(maybe& source) -> void { std::swap(value, source.value); } +}; + +template +class maybe>> { + T value = 0; + bool valid = false; + +public: + maybe() {} + maybe(nothing_t) {} + maybe(const T& source) { operator=(source); } + maybe(const maybe& source) { operator=(source); } + maybe(maybe&& source) { operator=(move(source)); } + + auto operator=(nothing_t) -> maybe& { valid = false; return *this; } + auto operator=(const T& source) -> maybe& { valid = true; value = source; return *this; } + auto operator=(const maybe& source) -> maybe& { valid = source.valid; value = source.value; return *this; } + auto operator=(maybe&& source) -> maybe& { valid = source.valid; value = source.value; source.valid = false; return *this; } + + auto operator==(const maybe& source) const -> bool { + if(valid && source.valid) return value == source.value; + return !valid && !source.valid; + } + auto operator!=(const maybe& source) const -> bool { return !operator==(source); } + + explicit operator bool() const { return valid; } + auto operator*() const -> T { assert(valid); return value; } + auto operator()() const -> T { assert(valid); return value; } + auto operator()(const T& invalid) const -> T { if(valid) return value; return invalid; } + + auto empty() const -> bool { return !valid; } + auto reset() -> void { valid = false; } + auto swap(maybe& source) -> void { std::swap(valid, source.valid); std::swap(value, source.value); } }; } diff --git a/nall/memory.hpp b/nall/memory.hpp new file mode 100644 index 00000000..17dc6180 --- /dev/null +++ b/nall/memory.hpp @@ -0,0 +1,8 @@ +#ifndef NALL_MEMORY_HPP +#define NALL_MEMORY_HPP + +#define NALL_MEMORY_INTERNAL_HPP +#include +#undef NALL_MEMORY_INTERNAL_HPP + +#endif diff --git a/nall/memory/memory.hpp b/nall/memory/memory.hpp new file mode 100644 index 00000000..3df31894 --- /dev/null +++ b/nall/memory/memory.hpp @@ -0,0 +1,131 @@ +#ifdef NALL_MEMORY_INTERNAL_HPP + +#include + +namespace nall { + +namespace memory { + inline auto allocate(unsigned size) -> void*; + inline auto allocate(unsigned size, uint8_t data) -> void*; + + inline auto resize(void* target, unsigned size) -> void*; + + inline auto free(void* target) -> void; + + inline auto compare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed; + inline auto compare(const void* target, const void* source, unsigned size) -> signed; + + inline auto icompare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed; + inline auto icompare(const void* target, const void* source, unsigned size) -> signed; + + inline auto copy(void* target, unsigned capacity, const void* source, unsigned size) -> void*; + inline auto copy(void* target, const void* source, unsigned size) -> void*; + + inline auto move(void* target, unsigned capacity, const void* source, unsigned size) -> void*; + inline auto move(void* target, const void* source, unsigned size) -> void*; + + inline auto fill(void* target, unsigned capacity, uint8_t data = 0x00) -> void*; +} + +} + +#include + +namespace nall { + +//implementation notes: +//memcmp, memcpy, memmove have terrible performance on small block sizes (FreeBSD 10.0-amd64) +//as this library is used extensively by nall/string, and most strings tend to be small, +//this library hand-codes these functions instead. surprisingly, it's a substantial speedup + +auto memory::allocate(unsigned size) -> void* { + return malloc(size); +} + +auto memory::allocate(unsigned size, uint8_t data) -> void* { + auto result = malloc(size); + if(result) fill(result, size, data); + return result; +} + +auto memory::resize(void* target, unsigned size) -> void* { + return realloc(target, size); +} + +auto memory::free(void* target) -> void { + ::free(target); +} + +auto memory::compare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed { + auto t = (int8_t*)target; + auto s = (int8_t*)source; + auto l = min(capacity, size); + while(l--) { + auto x = *t++; + auto y = *s++; + if(x != y) return x - y; + } + return 0; +} + +auto memory::compare(const void* target, const void* source, unsigned size) -> signed { + return compare(target, size, source, size); +} + +auto memory::icompare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed { + auto t = (int8_t*)target; + auto s = (int8_t*)source; + auto l = min(capacity, size); + while(l--) { + auto x = *t++; + auto y = *s++; + if(x - 'A' < 26) x += 32; + if(y - 'A' < 26) y += 32; + if(x != y) return x - y; + } + return 0; +} + +auto memory::icompare(const void* target, const void* source, unsigned size) -> signed { + return icompare(target, size, source, size); +} + +auto memory::copy(void* target, unsigned capacity, const void* source, unsigned size) -> void* { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size); + while(l--) *t++ = *s++; + return target; +} + +auto memory::copy(void* target, const void* source, unsigned size) -> void* { + return copy(target, size, source, size); +} + +auto memory::move(void* target, unsigned capacity, const void* source, unsigned size) -> void* { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size); + if(t < s) { + while(l--) *t++ = *s++; + } else { + t += l; + s += l; + while(l--) *--t = *--s; + } + return target; +} + +auto memory::move(void* target, const void* source, unsigned size) -> void* { + return move(target, size, source, size); +} + +auto memory::fill(void* target, unsigned capacity, uint8_t data) -> void* { + auto t = (uint8_t*)target; + while(capacity--) *t++ = data; + return target; +} + +} + +#endif diff --git a/nall/memory/pool.hpp b/nall/memory/pool.hpp new file mode 100644 index 00000000..8d162886 --- /dev/null +++ b/nall/memory/pool.hpp @@ -0,0 +1,64 @@ +#ifdef NALL_MEMORY_INTERNAL_HPP + +namespace nall { +namespace memory { + +template +struct pool_spsc { + signed* list = nullptr; + uint8_t* data = nullptr; + unsigned slot = 0; + + pool_spsc() { + list = (signed*)memory::allocate(Capacity * sizeof(signed)); + data = (uint8_t*)memory::allocate(Capacity * Size); + for(unsigned n = 0; n < Capacity; n++) list[n] = n; + } + + ~pool_spsc() { + memory::free(list); + memory::free(data); + } + + auto allocate(unsigned size) -> void* { + if(size == 0) return nullptr; + if(size > Size) return memory::allocate(size); + signed offset = list[slot]; + if(offset < 0) return memory::allocate(size); + list[slot] = -1; + slot = (slot + 1) % Capacity; + return (void*)(data + offset * Size); + } + + auto allocate(unsigned size, uint8_t data) -> void* { + auto result = allocate(size); + memset(result, data, size); + return result; + } + + auto resize(void* target, unsigned size) -> void* { + if(target == nullptr) return allocate(size); + signed offset = ((uint8_t*)target - data) / Size; + if(offset < 0 || offset >= Capacity) return memory::resize(target, size); + if(size <= Size) return target; + slot = (slot - 1) % Capacity; + list[slot] = offset; + return memory::allocate(size); + } + + auto free(void* target) -> void { + if(target == nullptr) return; + signed offset = ((uint8_t*)target - data) / Size; + if(offset < 0 || offset >= Capacity) return memory::free(target); + slot = (slot - 1) % Capacity; + list[slot] = offset; + } + + pool_spsc(const pool_spsc&) = delete; + pool_spsc& operator=(const pool_spsc&) = delete; +}; + +} +} + +#endif diff --git a/nall/method.hpp b/nall/method.hpp new file mode 100644 index 00000000..c79eab0a --- /dev/null +++ b/nall/method.hpp @@ -0,0 +1,59 @@ +#ifndef NALL_METHOD_HPP +#define NALL_METHOD_HPP + +//provides extension-method and chaining-method support to classes +//extension: class(function, params...); +//chaining: class[function](params...)[function](params...); + +//usage: +//struct object : method { +// using method::operator[]; //if object::operator[] defined +// using method::operator(); //if object::operator() defined +//}; + +//note: extension-methods would be obsolete if C++17 introduces unified function call syntax +//currently proposed as N4165 and N4174 + +namespace nall { + +template struct method { + template struct chain { + chain(T& self, const F& f) : self(self), f(f) {} + template auto operator()(P&&... p) -> T& { + return f(self, std::forward

(p)...), self; + } + private: + T& self; + const F& f; + }; + + template struct const_chain { + const_chain(const T& self, const F& f) : self(self), f(f) {} + template auto operator()(P&&... p) const -> const T& { + return f(self, std::forward

(p)...), self; + } + private: + const T& self; + const F& f; + }; + + template>> + auto operator[](const F& f) -> chain { return chain((T&)*this, f); } + + template>> + auto operator[](const F& f) const -> const_chain { return const_chain((const T&)*this, f); } + + template>> + auto operator()(const F& f, P&&... p) -> decltype(f((T&)*this, std::forward

(p)...)) { + return f((T&)*this, std::forward

(p)...); + } + + template>> + auto operator()(const F& f, P&&... p) const -> decltype(f((const T&)*this, std::forward

(p)...)) { + return f((const T&)*this, std::forward

(p)...); + } +}; + +} + +#endif diff --git a/nall/mosaic/context.hpp b/nall/mosaic/context.hpp index ee6b5d53..97719ffa 100644 --- a/nall/mosaic/context.hpp +++ b/nall/mosaic/context.hpp @@ -62,12 +62,11 @@ struct context { lstring list = expression.split(","); for(auto& item : list) { - item.trim(); + item.strip(); if(item.match("f(?*) ?*")) { - item.ltrim<1>("f("); + item.ltrim("f("); lstring part = item.split<1>(") "); - lstring args = part[0].split<3>(";"); - for(auto &item : args) item.trim(); + lstring args = part[0].split<3>(";").strip(); unsigned length = eval(args(0, "0")); unsigned offset = eval(args(1, "0")); @@ -86,14 +85,14 @@ struct context { } } else if(item.match("base64*")) { unsigned offset = 0; - item.ltrim<1>("base64"); + item.ltrim("base64"); if(item.match("(?*) *")) { - item.ltrim<1>("("); + item.ltrim("("); lstring part = item.split<1>(") "); offset = eval(part[0]); item = part(1, ""); } - item.trim(); + item.strip(); for(auto& c : item) { if(c >= 'A' && c <= 'Z') buffer.append(offset + c - 'A' + 0); if(c >= 'a' && c <= 'z') buffer.append(offset + c - 'a' + 26); @@ -102,8 +101,8 @@ struct context { if(c == '_') buffer.append(offset + 63); } } else if(item.match("file *")) { - item.ltrim<1>("file "); - item.trim(); + item.ltrim("file "); + item.strip(); //... } else if(item.empty() == false) { buffer.append(eval(item)); @@ -116,10 +115,8 @@ struct context { lstring lines = data.split("\n"); for(auto& line : lines) { - lstring part = line.split<1>(":"); + lstring part = line.split<1>(":").strip(); if(part.size() != 2) continue; - part[0].trim(); - part[1].trim(); if(part[0] == "offset") offset = eval(part[1]); if(part[0] == "width") width = eval(part[1]); diff --git a/nall/nall.hpp b/nall/nall.hpp index 3898aa67..6e4264c4 100644 --- a/nall/nall.hpp +++ b/nall/nall.hpp @@ -1,3 +1,11 @@ +/* nall + * author: byuu + * license: ISC + * + * nall is a header library that provides both fundamental and useful classes + * its goals are portability, consistency, minimalism and reusability + */ + #ifndef NALL_HPP #define NALL_HPP @@ -14,8 +22,6 @@ #include #include #include -#include -#include #include #include #include @@ -23,35 +29,41 @@ #include #include #include -#include #include #include -#include #include -#include #include #include #include #include #include #include -#include +#include #include #include +#include #include #include -#include +#include #include #include +#include #include #include #include #include -#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #if defined(PLATFORM_WINDOWS) #include diff --git a/nall/platform.hpp b/nall/platform.hpp index d6d85da8..2cc2c0c0 100644 --- a/nall/platform.hpp +++ b/nall/platform.hpp @@ -9,13 +9,17 @@ namespace Math { } #if defined(PLATFORM_WINDOWS) - //minimum version needed for _wstat64, etc + //minimum version needed for _wstat64, AI_ADDRCONFIG, etc + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0601 #undef __MSVCRT_VERSION__ - #define __MSVCRT_VERSION__ 0x0601 + #define __MSVCRT_VERSION__ _WIN32_WINNT #include #endif +#include #include +#include #include #include @@ -27,6 +31,7 @@ namespace Math { #include #include #include +#include #include #include @@ -36,13 +41,16 @@ namespace Math { #include #include #include - #undef interface - #define dllexport __declspec(dllexport) + #include + #include #else #include #include #include - #define dllexport + #include + #include + #include + #include #endif #if defined(COMPILER_CL) @@ -50,26 +58,35 @@ namespace Math { #endif #if defined(PLATFORM_WINDOWS) - __declspec(dllimport) int _fileno(FILE*); + #undef interface + #define dllexport __declspec(dllexport) + #define MSG_NOSIGNAL 0 + __declspec(dllimport) auto _fileno(FILE*) -> int; - inline int access(const char* path, int amode) { return _waccess(nall::utf16_t(path), amode); } - inline int fileno(FILE* stream) { return _fileno(stream); } - inline char* getcwd(char* buf, size_t size) { wchar_t wpath[PATH_MAX] = L""; if(!_wgetcwd(wpath, size)) return nullptr; strcpy(buf, nall::utf8_t(wpath)); return buf; } - inline int putenv(char* string) { return _wputenv(nall::utf16_t(string)); } - inline char* realpath(const char* file_name, char* resolved_name) { wchar_t wfile_name[PATH_MAX] = L""; if(!_wfullpath(wfile_name, nall::utf16_t(file_name), PATH_MAX)) return nullptr; strcpy(resolved_name, nall::utf8_t(wfile_name)); return resolved_name; } - inline int rename(const char* oldname, const char* newname) { return _wrename(nall::utf16_t(oldname), nall::utf16_t(newname)); } - inline void usleep(unsigned milliseconds) { Sleep(milliseconds / 1000); } + inline auto access(const char* path, int amode) -> int { return _waccess(nall::utf16_t(path), amode); } + inline auto fileno(FILE* stream) -> int { return _fileno(stream); } + inline auto getcwd(char* buf, size_t size) -> char* { wchar_t wpath[PATH_MAX] = L""; if(!_wgetcwd(wpath, size)) return nullptr; strcpy(buf, nall::utf8_t(wpath)); return buf; } + inline auto mkdir(const char* path, int mode) -> int { return _wmkdir(nall::utf16_t(path)); } + inline auto putenv(const char* value) -> int { return _wputenv(nall::utf16_t(value)); } + inline auto realpath(const char* file_name, char* resolved_name) -> char* { wchar_t wfile_name[PATH_MAX] = L""; if(!_wfullpath(wfile_name, nall::utf16_t(file_name), PATH_MAX)) return nullptr; strcpy(resolved_name, nall::utf8_t(wfile_name)); return resolved_name; } + inline auto rename(const char* oldname, const char* newname) -> int { return _wrename(nall::utf16_t(oldname), nall::utf16_t(newname)); } + inline auto usleep(unsigned milliseconds) -> void { Sleep(milliseconds / 1000); } +#else + #define dllexport #endif #if defined(COMPILER_CLANG) || defined(COMPILER_GCC) #define neverinline __attribute__((noinline)) #define alwaysinline inline __attribute__((always_inline)) + #define deprecated __attribute__((deprecated)) #elif defined(COMPILER_CL) #define neverinline __declspec(noinline) #define alwaysinline inline __forceinline + #define deprecated __declspec(deprecated) #else #define neverinline #define alwaysinline inline + #define deprecated #endif #if defined(COMPILER_CLANG) || defined(COMPILER_GCC) @@ -78,4 +95,12 @@ namespace Math { #define unreachable throw #endif +#if defined(COMPILER_GCC) && __GNUC__ == 4 && __GNUC_MINOR__ <= 7 + //GCC 4.7.x has a bug (#54849) when specifying override with a trailing return type: + //auto function() -> return_type override; //this is the syntax that the C++11 standard requires + //auto function() override -> return_type; //this is the syntax that GCC 4.7.x requires + //in order to compile code correctly with both compilers, we disable the override keyword for GCC + #define override +#endif + #endif diff --git a/nall/range.hpp b/nall/range.hpp new file mode 100644 index 00000000..54efbb25 --- /dev/null +++ b/nall/range.hpp @@ -0,0 +1,48 @@ +#ifndef NALL_RANGE_HPP +#define NALL_RANGE_HPP + +namespace nall { + +struct range_t { + struct iterator { + signed operator*() const { return position; } + bool operator!=(const iterator& source) const { return step > 0 ? position < source.position : position > source.position; } + iterator& operator++() { position += step; return *this; } + iterator(signed position, signed step = 0) : position(position), step(step) {} + + private: + signed position; + const signed step; + }; + + const iterator begin() const { return iterator(origin, stride); } + const iterator end() const { return iterator(target); } + + signed origin; + signed target; + signed stride; +}; + +inline range_t range(signed size) { + return range_t{0, size, 1}; +} + +inline range_t range(signed offset, signed size) { + return range_t{offset, size, 1}; +} + +inline range_t range(signed offset, signed size, signed step) { + return range_t{offset, size, step}; +} + +inline range_t range_reverse(signed size) { + return range_t{size - 1, -1, -1}; +} + +template inline range_t range(const vector& container) { + return range_t{0, (signed)container.size(), 1}; +} + +} + +#endif diff --git a/nall/service.hpp b/nall/service.hpp new file mode 100644 index 00000000..19b9f072 --- /dev/null +++ b/nall/service.hpp @@ -0,0 +1,120 @@ +#ifndef NALL_SERVICE_HPP +#define NALL_SERVICE_HPP + +//service model template built on top of shared-memory + +#include +#include + +namespace nall { + +struct service { + inline explicit operator bool() const; + inline auto command(const string& name, const string& command) -> bool; + inline auto receive() -> string; + inline auto name() const -> string; + inline auto stop() const -> bool; + +private: + shared_memory shared; + string _name; + bool _stop = false; +}; + +service::operator bool() const { + return (bool)shared; +} + +//returns true on new service process creation (false is not necessarily an error) +auto service::command(const string& name, const string& command) -> bool { + if(!name) return false; + if(!command) return print("[{0}] usage: {service} command\n" + "commands:\n" + " status : query whether service is running\n" + " start : start service if it is not running\n" + " stop : stop service if it is running\n" + " remove : remove semaphore lock if service crashed\n" + " {value} : send custom command to service\n" + "", format{name}), false; + + if(shared.open(name, 4096)) { + if(command == "start") { + print("[{0}] already started\n", format{name}); + } else if(command == "status") { + print("[{0}] running\n", format{name}); + } + if(auto data = shared.acquire()) { + if(command == "stop") print("[{0}] stopped\n", format{name}); + memory::copy(data, command.data(), min(command.size(), 4096)); + shared.release(); + } + if(command == "remove") { + shared.remove(); + print("[{0}] removed\n", format{name}); + } + return false; + } + + if(command == "start") { + if(shared.create(name, 4096)) { + print("[{0}] started\n", format{name}); + auto pid = fork(); + if(pid == 0) { + signal(SIGHUP, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + _name = name; + return true; + } + shared.close(); + } else { + print("[{0}] start failed ({1})\n", format{name, strerror(errno)}); + } + return false; + } + + if(command == "status") { + print("[{0}] stopped\n", format{name}); + return false; + } + + return false; +} + +auto service::receive() -> string { + string command; + if(shared) { + if(auto data = shared.acquire()) { + if(*data) { + command.resize(4095); + memory::copy(command.pointer(), data, 4095); + memory::fill(data, 4096); + } + shared.release(); + if(command == "remove") { + _stop = true; + return ""; + } else if(command == "start") { + return ""; + } else if(command == "status") { + return ""; + } else if(command == "stop") { + _stop = true; + shared.remove(); + return ""; + } + } + } + return command; +} + +auto service::name() const -> string { + return _name; +} + +auto service::stop() const -> bool { + return _stop; +} + +} + +#endif diff --git a/nall/sha256.hpp b/nall/sha256.hpp deleted file mode 100644 index 2be2d7b2..00000000 --- a/nall/sha256.hpp +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef NALL_SHA256_HPP -#define NALL_SHA256_HPP - -//author: vladitx - -#include - -namespace nall { - -#define PTR(t, a) ((t*)(a)) - -#define SWAP32(x) ((uint32_t)( \ - (((uint32_t)(x) & 0x000000ff) << 24) | \ - (((uint32_t)(x) & 0x0000ff00) << 8) | \ - (((uint32_t)(x) & 0x00ff0000) >> 8) | \ - (((uint32_t)(x) & 0xff000000) >> 24) \ -)) - -#define ST32(a, d) *PTR(uint32_t, a) = (d) -#define ST32BE(a, d) ST32(a, SWAP32(d)) - -#define LD32(a) *PTR(uint32_t, a) -#define LD32BE(a) SWAP32(LD32(a)) - -#define LSL32(x, n) ((uint32_t)(x) << (n)) -#define LSR32(x, n) ((uint32_t)(x) >> (n)) -#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n))) - -//first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19 -static const uint32_t T_H[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, -}; - -//first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311 -static const uint32_t T_K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -}; - -struct sha256_ctx { - uint8_t in[64]; - unsigned inlen; - - uint32_t w[64]; - uint32_t h[8]; - uint64_t len; -}; - -inline void sha256_init(sha256_ctx* p) { - memset(p, 0, sizeof(sha256_ctx)); - memcpy(p->h, T_H, sizeof(T_H)); -} - -static void sha256_block(sha256_ctx* p) { - unsigned i; - uint32_t s0, s1; - uint32_t a, b, c, d, e, f, g, h; - uint32_t t1, t2, maj, ch; - - for(i = 0; i < 16; i++) p->w[i] = LD32BE(p->in + i * 4); - - for(i = 16; i < 64; i++) { - s0 = ROR32(p->w[i - 15], 7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15], 3); - s1 = ROR32(p->w[i - 2], 17) ^ ROR32(p->w[i - 2], 19) ^ LSR32(p->w[i - 2], 10); - p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1; - } - - a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3]; - e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7]; - - for(i = 0; i < 64; i++) { - s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22); - maj = (a & b) ^ (a & c) ^ (b & c); - t2 = s0 + maj; - s1 = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25); - ch = (e & f) ^ (~e & g); - t1 = h + s1 + ch + T_K[i] + p->w[i]; - - h = g; g = f; f = e; e = d + t1; - d = c; c = b; b = a; a = t1 + t2; - } - - p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d; - p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h; - - //next block - p->inlen = 0; -} - -inline void sha256_chunk(sha256_ctx* p, const uint8_t* s, unsigned len) { - unsigned l; - p->len += len; - - while(len) { - l = 64 - p->inlen; - l = (len < l) ? len : l; - - memcpy(p->in + p->inlen, s, l); - s += l; - p->inlen += l; - len -= l; - - if(p->inlen == 64) sha256_block(p); - } -} - -inline void sha256_final(sha256_ctx* p) { - uint64_t len; - p->in[p->inlen++] = 0x80; - - if(p->inlen > 56) { - memset(p->in + p->inlen, 0, 64 - p->inlen); - sha256_block(p); - } - - memset(p->in + p->inlen, 0, 56 - p->inlen); - - len = p->len << 3; - ST32BE(p->in + 56, len >> 32); - ST32BE(p->in + 60, len); - sha256_block(p); -} - -inline void sha256_hash(sha256_ctx* p, uint8_t* s) { - uint32_t *t = (uint32_t*)s; - for(unsigned i = 0; i < 8; i++) ST32BE(t++, p->h[i]); -} - -#undef PTR -#undef SWAP32 -#undef ST32 -#undef ST32BE -#undef LD32 -#undef LD32BE -#undef LSL32 -#undef LSR32 -#undef ROR32 - -} - -#endif diff --git a/nall/shared-memory.hpp b/nall/shared-memory.hpp new file mode 100644 index 00000000..ad237613 --- /dev/null +++ b/nall/shared-memory.hpp @@ -0,0 +1,157 @@ +#ifndef NALL_SHARED_MEMORY_HPP +#define NALL_SHARED_MEMORY_HPP + +#include +#include + +#include +#include + +namespace nall { + +struct shared_memory { + shared_memory() = default; + shared_memory(const shared_memory&) = delete; + shared_memory& operator=(const shared_memory&) = delete; + + ~shared_memory() { + reset(); + } + + explicit operator bool() const { + return _mode != mode::inactive; + } + + auto empty() const -> bool { + return _mode == mode::inactive; + } + + auto size() const -> unsigned { + return _size; + } + + auto acquired() const -> bool { + return _acquired; + } + + auto acquire() -> uint8_t* { + if(!acquired()) { + sem_wait(_semaphore); + _acquired = true; + } + return _data; + } + + auto release() -> void { + if(acquired()) { + sem_post(_semaphore); + _acquired = false; + } + } + + auto reset() -> void { + release(); + if(_mode == mode::server) return remove(); + if(_mode == mode::client) return close(); + } + + auto create(const string& name, unsigned size) -> bool { + reset(); + + _name = {"/nall::", string{name}.transform("/", ":")}; + _size = size; + + //O_CREAT | O_EXCL seems to throw ENOENT even when semaphore does not exist ... + _semaphore = sem_open(_name, O_CREAT, 0644, 1); + if(_semaphore == SEM_FAILED) return remove(), false; + + _descriptor = shm_open(_name, O_CREAT | O_TRUNC | O_RDWR, 0644); + if(_descriptor < 0) return remove(), false; + + if(ftruncate(_descriptor, _size) != 0) return remove(), false; + + _data = (uint8_t*)mmap(nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _descriptor, 0); + if(_data == MAP_FAILED) return remove(), false; + + memory::fill(_data, _size); + + _mode = mode::server; + return true; + } + + auto remove() -> void { + if(_data) { + munmap(_data, _size); + _data = nullptr; + } + + if(_descriptor) { + ::close(_descriptor); + shm_unlink(_name); + _descriptor = -1; + } + + if(_semaphore) { + sem_close(_semaphore); + sem_unlink(_name); + _semaphore = nullptr; + } + + _mode = mode::inactive; + _name = ""; + _size = 0; + } + + auto open(const string& name, unsigned size) -> bool { + reset(); + + _name = {"/nall::", string{name}.transform("/", ":")}; + _size = size; + + _semaphore = sem_open(_name, 0, 0644); + if(_semaphore == SEM_FAILED) return close(), false; + + _descriptor = shm_open(_name, O_RDWR, 0644); + if(_descriptor < 0) return close(), false; + + _data = (uint8_t*)mmap(nullptr, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _descriptor, 0); + if(_data == MAP_FAILED) return close(), false; + + _mode = mode::client; + return true; + } + + auto close() -> void { + if(_data) { + munmap(_data, _size); + _data = nullptr; + } + + if(_descriptor) { + ::close(_descriptor); + _descriptor = -1; + } + + if(_semaphore) { + sem_close(_semaphore); + _semaphore = nullptr; + } + + _mode = mode::inactive; + _name = ""; + _size = 0; + } + +private: + enum class mode : unsigned { server, client, inactive } _mode = mode::inactive; + string _name; + sem_t* _semaphore = nullptr; + signed _descriptor = -1; + uint8_t* _data = nullptr; + unsigned _size = 0; + bool _acquired = false; +}; + +} + +#endif diff --git a/nall/shared-pointer.hpp b/nall/shared-pointer.hpp new file mode 100644 index 00000000..f3e6271a --- /dev/null +++ b/nall/shared-pointer.hpp @@ -0,0 +1,268 @@ +#ifndef NALL_SHARED_POINTER_HPP +#define NALL_SHARED_POINTER_HPP + +#include +#include +#include +#include + +namespace nall { + +template struct shared_pointer; + +struct shared_pointer_manager { + void* pointer = nullptr; + function deleter; + unsigned strong = 0; + unsigned weak = 0; + + shared_pointer_manager(void* pointer) : pointer(pointer) { + } +}; + +template struct shared_pointer; +template struct shared_pointer_weak; + +template +struct shared_pointer { + using type = T; + shared_pointer_manager* manager = nullptr; + + template + struct is_compatible { + static constexpr bool value = is_base_of::value || is_base_of::value; + }; + + shared_pointer() { + } + + shared_pointer(T* source) { + operator=(source); + } + + shared_pointer(T* source, const function& deleter) { + operator=(source); + manager->deleter = [=](void* p) { deleter((T*)p); }; + } + + shared_pointer(const shared_pointer& source) { + operator=(source); + } + + shared_pointer(shared_pointer&& source) { + operator=(move(source)); + } + + template>> + shared_pointer(const shared_pointer& source) { + operator=(source); + } + + template>> + shared_pointer(shared_pointer&& source) { + operator=(move(source)); + } + + template>> + shared_pointer(const shared_pointer_weak& source) { + operator=(source); + } + + template>> + shared_pointer(const shared_pointer& source, T* pointer) { + if((bool)source && (T*)source.manager->pointer == pointer) { + manager = source.manager; + manager->strong++; + } + } + + ~shared_pointer() { + reset(); + } + + shared_pointer& operator=(T* source) { + reset(); + if(source) { + manager = new shared_pointer_manager((void*)source); + manager->strong++; + } + return *this; + } + + shared_pointer& operator=(const shared_pointer& source) { + if(this != &source) { + reset(); + if((bool)source) { + manager = source.manager; + manager->strong++; + } + } + return *this; + } + + shared_pointer& operator=(shared_pointer&& source) { + if(this != &source) { + reset(); + manager = source.manager; + source.manager = nullptr; + } + return *this; + } + + template>> + shared_pointer& operator=(const shared_pointer& source) { + if((uintptr_t)this != (uintptr_t)&source) { + reset(); + if((bool)source) { + manager = source.manager; + manager->strong++; + } + } + return *this; + } + + template>> + shared_pointer& operator=(shared_pointer&& source) { + if((uintptr_t)this != (uintptr_t)&source) { + reset(); + manager = source.manager; + source.manager = nullptr; + } + return *this; + } + + template>> + shared_pointer& operator=(const shared_pointer_weak& source) { + reset(); + if((bool)source) { + manager = source.manager; + manager->strong++; + } + return *this; + } + + T* data() { + if(manager) return (T*)manager->pointer; + return nullptr; + } + + const T* data() const { + if(manager) return (T*)manager->pointer; + return nullptr; + } + + T* operator->() { return data(); } + const T* operator->() const { return data(); } + + T& operator*() { return *data(); } + const T& operator*() const { return *data(); } + + T& operator()() { return *data(); } + const T& operator()() const { return *data(); } + + template + bool operator==(const shared_pointer& source) const { + return manager == source.manager; + } + + template + bool operator!=(const shared_pointer& source) const { + return manager != source.manager; + } + + explicit operator bool() const { + return !empty(); + } + + bool empty() const { + return !manager || !manager->strong; + } + + bool unique() const { + return manager && manager->strong == 1; + } + + void reset() { + if(manager && manager->strong) { + //pointer may contain weak references; if strong==0 it may destroy manager + //as such, we must destroy strong before decrementing it to zero + if(manager->strong == 1) { + if(manager->deleter) { + manager->deleter(manager->pointer); + } else { + delete (T*)manager->pointer; + } + manager->pointer = nullptr; + } + if(--manager->strong == 0) { + if(manager->weak == 0) { + delete manager; + } + } + } + manager = nullptr; + } + + template + shared_pointer cast() { + if(auto pointer = dynamic_cast(data())) { + return {*this, pointer}; + } + return {}; + } +}; + +template +struct shared_pointer_weak { + using type = T; + shared_pointer_manager* manager = nullptr; + + shared_pointer_weak() { + } + + shared_pointer_weak(const shared_pointer& source) { + operator=(source); + } + + shared_pointer_weak& operator=(const shared_pointer& source) { + reset(); + if(manager = source.manager) manager->weak++; + return *this; + } + + ~shared_pointer_weak() { + reset(); + } + + explicit operator bool() const { + return !empty(); + } + + bool empty() const { + return !manager || !manager->strong; + } + + shared_pointer acquire() const { + return shared_pointer(*this); + } + + void reset() { + if(manager && --manager->weak == 0) { + if(manager->strong == 0) { + delete manager; + } + } + manager = nullptr; + } +}; + +template +struct shared_pointer_new : shared_pointer { + template + shared_pointer_new(P&&... p) : shared_pointer(new T(forward

(p)...)) { + } +}; + +} + +#endif diff --git a/nall/smtp.hpp b/nall/smtp.hpp index ce1a02ad..54197e9a 100644 --- a/nall/smtp.hpp +++ b/nall/smtp.hpp @@ -273,7 +273,7 @@ string SMTP::contacts(const vector& contacts) { for(auto& contact : contacts) { result.append(this->contact(contact), "; "); } - result.rtrim<1>("; "); + result.rtrim("; "); return result; } diff --git a/nall/storage.hpp b/nall/storage.hpp new file mode 100644 index 00000000..3d9b7bb7 --- /dev/null +++ b/nall/storage.hpp @@ -0,0 +1,95 @@ +#ifndef NALL_STORAGE_HPP +#define NALL_STORAGE_HPP + +//generic abstraction layer for common storage operations against both files and directories +//these functions are not recursive; use directory::create() and directory::remove() for recursion + +#include +#include + +namespace nall { + +struct storage { + enum class time : unsigned { access, modify }; + + static auto exists(const string& name) -> bool; + static auto readable(const string& name) -> bool; + static auto writable(const string& name) -> bool; + static auto executable(const string& name) -> bool; + static auto uid(const string& name) -> unsigned; + static auto gid(const string& name) -> unsigned; + static auto mode(const string& name) -> unsigned; + static auto timestamp(const string& name, storage::time mode = storage::time::modify) -> time_t; + + static auto create(const string& name, unsigned permissions = 0755) -> bool; + static auto rename(const string& name, const string& targetname) -> bool; + static auto remove(const string& name) -> bool; +}; + +inline auto storage::exists(const string& name) -> bool { + return access(name, F_OK) == 0; +} + +inline auto storage::readable(const string& name) -> bool { + return access(name, R_OK) == 0; +} + +inline auto storage::writable(const string& name) -> bool { + return access(name, W_OK) == 0; +} + +inline auto storage::executable(const string& name) -> bool { + return access(name, X_OK) == 0; +} + +inline auto storage::uid(const string& name) -> unsigned { + struct stat data = {0}; + stat(name, &data); + return data.st_uid; +} + +inline auto storage::gid(const string& name) -> unsigned { + struct stat data = {0}; + stat(name, &data); + return data.st_gid; +} + +inline auto storage::mode(const string& name) -> unsigned { + struct stat data = {0}; + stat(name, &data); + return data.st_mode; +} + +inline auto storage::timestamp(const string& name, storage::time mode) -> time_t { + struct stat data = {0}; + stat(name, &data); + switch(mode) { + case storage::time::access: return data.st_atime; + case storage::time::modify: return data.st_mtime; + } + throw; +} + +//returns true if 'name' already exists +inline auto storage::create(const string& name, unsigned permissions) -> bool { + if(storage::exists(name)) return true; + if(name.endsWith("/")) return mkdir(name, permissions) == 0; + int fd = open(name, O_CREAT | O_EXCL, permissions); + if(fd < 0) return false; + return close(fd), true; +} + +//returns false if 'name' and 'targetname' are on different file systems (requires copy) +inline auto storage::rename(const string& name, const string& targetname) -> bool { + return ::rename(name, targetname) == 0; +} + +//returns false if 'name' is a directory that is not empty +inline auto storage::remove(const string& name) -> bool { + if(name.endsWith("/")) return rmdir(name) == 0; + return unlink(name) == 0; +} + +} + +#endif diff --git a/nall/stream.hpp b/nall/stream.hpp index 586ccda7..b43ae41e 100644 --- a/nall/stream.hpp +++ b/nall/stream.hpp @@ -6,18 +6,16 @@ #include #include -#include -#include #include #include -#include +#include +#include #define NALL_STREAM_INTERNAL_HPP #include #include #include #include -#include #include #include #include diff --git a/nall/stream/auto.hpp b/nall/stream/auto.hpp index 0e4d8705..a410a975 100644 --- a/nall/stream/auto.hpp +++ b/nall/stream/auto.hpp @@ -6,7 +6,6 @@ namespace nall { #define autostream(...) (*makestream(__VA_ARGS__)) inline std::unique_ptr makestream(const string& path) { - if(path.ibeginsWith("http://")) return std::unique_ptr(new httpstream(path, 80)); if(path.iendsWith(".gz")) return std::unique_ptr(new gzipstream(filestream{path})); if(path.iendsWith(".zip")) return std::unique_ptr(new zipstream(filestream{path})); return std::unique_ptr(new mmapstream(path)); diff --git a/nall/stream/gzip.hpp b/nall/stream/gzip.hpp index 4af7a24d..9bccbebe 100644 --- a/nall/stream/gzip.hpp +++ b/nall/stream/gzip.hpp @@ -1,7 +1,7 @@ #ifndef NALL_STREAM_GZIP_HPP #define NALL_STREAM_GZIP_HPP -#include +#include namespace nall { @@ -14,7 +14,7 @@ struct gzipstream : memorystream { uint8_t *data = new uint8_t[size]; stream.read(data, size); - gzip archive; + Decode::GZIP archive; bool result = archive.decompress(data, size); delete[] data; if(result == false) return; diff --git a/nall/stream/http.hpp b/nall/stream/http.hpp deleted file mode 100644 index fb38a770..00000000 --- a/nall/stream/http.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef NALL_STREAM_HTTP_HPP -#define NALL_STREAM_HTTP_HPP - -#include - -namespace nall { - -struct httpstream : stream { - using stream::read; - using stream::write; - - bool seekable() const { return true; } - bool readable() const { return true; } - bool writable() const { return true; } - bool randomaccess() const { return true; } - - unsigned size() const { return psize; } - unsigned offset() const { return poffset; } - void seek(unsigned offset) const { poffset = offset; } - - uint8_t read() const { return pdata[poffset++]; } - void write(uint8_t data) const { pdata[poffset++] = data; } - - uint8_t read(unsigned offset) const { return pdata[offset]; } - void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } - - httpstream(const string& url, unsigned port) : pdata(nullptr), psize(0), poffset(0) { - string uri = url; - uri.ltrim<1>("http://"); - lstring part = uri.split<1>("/"); - part[1] = { "/", part[1] }; - - http connection; - if(connection.connect(part[0], port) == false) return; - connection.download(part[1], pdata, psize); - } - - ~httpstream() { - if(pdata) delete[] pdata; - } - -private: - mutable uint8_t* pdata; - mutable unsigned psize, poffset; -}; - -} - -#endif diff --git a/nall/stream/stream.hpp b/nall/stream/stream.hpp index 6e78b18a..2b10bf17 100644 --- a/nall/stream/stream.hpp +++ b/nall/stream/stream.hpp @@ -51,7 +51,6 @@ struct stream { string text() const { string buffer; buffer.resize(size() + 1); - buffer[size()] = 0; seek(0); read((uint8_t*)buffer.data(), size()); return buffer; diff --git a/nall/stream/zip.hpp b/nall/stream/zip.hpp index dfb4767b..c7730897 100644 --- a/nall/stream/zip.hpp +++ b/nall/stream/zip.hpp @@ -1,7 +1,7 @@ #ifndef NALL_STREAM_ZIP_HPP #define NALL_STREAM_ZIP_HPP -#include +#include namespace nall { @@ -14,7 +14,7 @@ struct zipstream : memorystream { uint8_t* data = new uint8_t[size]; stream.read(data, size); - unzip archive; + Decode::ZIP archive; if(archive.open(data, size) == false) return; delete[] data; diff --git a/nall/string.hpp b/nall/string.hpp index adf86b31..32f15f4c 100644 --- a/nall/string.hpp +++ b/nall/string.hpp @@ -12,34 +12,37 @@ #include #include -#include #include #include -#include +#include +#include #include #include #include #include - -#include +#include +#include +#include #define NALL_STRING_INTERNAL_HPP -#include #include #include #include +#include +#include #include #include -#include -#include +#include #include +#include #include +#include +#include #include #include #include +#include #include -#include -#include #include #include #include @@ -48,6 +51,8 @@ #include #include #include +#include +#include #undef NALL_STRING_INTERNAL_HPP #endif diff --git a/nall/string/allocator/adaptive.hpp b/nall/string/allocator/adaptive.hpp new file mode 100644 index 00000000..0a9f75fe --- /dev/null +++ b/nall/string/allocator/adaptive.hpp @@ -0,0 +1,123 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +/***** + adaptive allocator + sizeof(string) == SSO + 8 + + aggressively tries to avoid heap allocations + small strings are stored on the stack + large strings are shared via copy-on-write + + SSO alone is very slow on large strings due to copying + SSO alone is very slightly faster than this allocator on small strings + + COW alone is very slow on small strings due to heap allocations + COW alone is very slightly faster than this allocator on large strings + + adaptive is thus very fast for all string sizes +*****/ + +namespace nall { + +string::string() : _data(nullptr), _capacity(SSO - 1), _size(0) { +} + +auto string::pointer() -> char* { + if(_capacity < SSO) return _text; + if(*_refs > 1) _copy(); + return _data; +} + +auto string::data() const -> const char* { + if(_capacity < SSO) return _text; + return _data; +} + +auto string::reset() -> type& { + if(_capacity >= SSO && !--*_refs) memory::free(_data); + _data = nullptr; + _capacity = SSO - 1; + _size = 0; + return *this; +} + +auto string::reserve(unsigned capacity) -> type& { + if(capacity <= _capacity) return *this; + capacity = bit::round(capacity + 1) - 1; + if(_capacity < SSO) { + _capacity = capacity; + _allocate(); + } else if(*_refs > 1) { + _capacity = capacity; + _copy(); + } else { + _capacity = capacity; + _resize(); + } + return *this; +} + +auto string::resize(unsigned size) -> type& { + reserve(size); + pointer()[_size = size] = 0; + return *this; +} + +auto string::operator=(const string& source) -> type& { + if(&source == this) return *this; + reset(); + if(source._capacity >= SSO) { + _data = source._data; + _refs = source._refs; + _capacity = source._capacity; + _size = source._size; + ++*_refs; + } else { + memory::copy(_text, source._text, SSO); + _capacity = source._capacity; + _size = source._size; + } + return *this; +} + +auto string::operator=(string&& source) -> type& { + if(&source == this) return *this; + reset(); + memory::copy(this, &source, sizeof(string)); + source._data = nullptr; + source._capacity = SSO - 1; + source._size = 0; + return *this; +} + +//SSO -> COW +auto string::_allocate() -> void { + char _temp[SSO]; + memory::copy(_temp, _text, SSO); + _data = (char*)memory::allocate(_capacity + 1 + sizeof(unsigned)); + memory::copy(_data, _temp, SSO); + _refs = (unsigned*)(_data + _capacity + 1); //always aligned by 32 via reserve() + *_refs = 1; +} + +//COW -> Unique +auto string::_copy() -> void { + auto _temp = (char*)memory::allocate(_capacity + 1 + sizeof(unsigned)); + memory::copy(_temp, _data, _size = min(_capacity, _size)); + _temp[_size] = 0; + --*_refs; + _data = _temp; + _refs = (unsigned*)(_data + _capacity + 1); + *_refs = 1; +} + +//COW -> Resize +auto string::_resize() -> void { + _data = (char*)memory::resize(_data, _capacity + 1 + sizeof(unsigned)); + _refs = (unsigned*)(_data + _capacity + 1); + *_refs = 1; +} + +} + +#endif diff --git a/nall/string/allocator/copy-on-write.hpp b/nall/string/allocator/copy-on-write.hpp index 3890ce4c..574dde97 100644 --- a/nall/string/allocator/copy-on-write.hpp +++ b/nall/string/allocator/copy-on-write.hpp @@ -1,102 +1,90 @@ #ifdef NALL_STRING_INTERNAL_HPP -/* -copy on write (COW) allocator -sizeof(string) == 24 (amd64) - -utilizes a shared_ptr to reference count strings -allows string copies to execute as fast as string moves -requires extra computations, which will be slower for all string sizes - -pros: -* lower memory usage -* pass-by-value does not require heap allocation; obviates pass-by-const-reference - -cons: -* added overhead to fetch data() -* added heap allocation for reference-count pool -* no potential for in-place resize (always copies) -* larger sizeof(string) - -*/ - namespace nall { -char* string::data() { - if(!_data.unique()) _copy(); - return _data.get(); +string::string() : _data(nullptr), _refs(nullptr), _capacity(0), _size(0) { } -const char* string::data() const { - if(!_data) return ""; - return _data.get(); +auto string::pointer() -> char* { + static char _null[] = ""; + if(!_data) return _null; + if(*_refs > 1) _data = _copy(); //make unique for write operations + return _data; } -//copy _data (to make unique or to grow in size) -void string::_copy() { - auto copy = new char[_capacity + 1]; - if(_data.get()) memcpy(copy, _data.get(), min(_capacity, _size)); - copy[_size] = 0; - copy[_capacity] = 0; - _data.reset(copy); +auto string::data() const -> const char* { + static const char _null[] = ""; + if(!_data) return _null; + return _data; } -//amortize growth to O(log n) -//allocate one extra byte to always store null-terminator for libc usage -void string::reserve(unsigned capacity) { - if(capacity > _capacity) { - _capacity = bit::round(capacity + 1) - 1; - _copy(); +auto string::reset() -> type& { + if(_data && !--*_refs) { + memory::free(_data); + _data = nullptr; //_refs = nullptr; is unnecessary } -} - -void string::resize(unsigned size) { - reserve(size); - data()[_size = size] = 0; -} - -void string::reset() { - _data.reset(); _capacity = 0; _size = 0; -} - -string& string::operator=(const string& source) { - if(&source == this) return *this; - reset(); - _data = source._data; - _capacity = source._capacity; - _size = source._size; return *this; } -string& string::operator=(string&& source) { +auto string::reserve(unsigned capacity) -> type& { + if(capacity > _capacity) { + _capacity = bit::round(max(31u, capacity) + 1) - 1; + _data = _data ? _copy() : _allocate(); + } + return *this; +} + +auto string::resize(unsigned size) -> type& { + reserve(size); + pointer()[_size = size] = 0; + return *this; +} + +auto string::operator=(const string& source) -> string& { if(&source == this) return *this; reset(); - _data = std::move(source._data); + if(source._data) { + _data = source._data; + _refs = source._refs; + _capacity = source._capacity; + _size = source._size; + ++*_refs; + } + return *this; +} + +auto string::operator=(string&& source) -> string& { + if(&source == this) return *this; + reset(); + _data = source._data; + _refs = source._refs; _capacity = source._capacity; _size = source._size; + source._data = nullptr; + source._refs = nullptr; source._capacity = 0; source._size = 0; return *this; } -template string::string(T&& source, Args&&... args) { - construct(); - sprint(*this, std::forward(source), std::forward(args)...); +auto string::_allocate() -> char* { + auto _temp = (char*)memory::allocate(_capacity + 1 + sizeof(unsigned)); + *_temp = 0; + _refs = (unsigned*)(_temp + _capacity + 1); //this will always be aligned by 32 via reserve() + *_refs = 1; + return _temp; } -string::string() { - construct(); -} - -string::~string() { - reset(); -} - -void string::construct() { - _capacity = 0; - _size = 0; +auto string::_copy() -> char* { + auto _temp = (char*)memory::allocate(_capacity + 1 + sizeof(unsigned)); + memory::copy(_temp, _data, _size = min(_capacity, _size)); + _temp[_size] = 0; + --*_refs; + _refs = (unsigned*)(_temp + _capacity + 1); + *_refs = 1; + return _temp; } } diff --git a/nall/string/allocator/small-string-optimization.hpp b/nall/string/allocator/small-string-optimization.hpp index 8e3c4117..0430abbf 100644 --- a/nall/string/allocator/small-string-optimization.hpp +++ b/nall/string/allocator/small-string-optimization.hpp @@ -2,7 +2,7 @@ /* small string optimization (SSO) allocator -sizeof(string) == 16 (amd64) +sizeof(string) == 8 + string::SSO utilizes a union to store small strings directly into text pointer bypasses the need to allocate heap memory for small strings @@ -10,102 +10,86 @@ requires extra computations, which can be slower for large strings pros: * potential for in-place resize -* no heap allocation when (capacity < 8) +* no heap allocation when (capacity < SSO) cons: * added overhead to fetch data() -* 32-bit platforms limited to (capacity < 4) -* pass-by-value requires heap allocation +* pass-by-value requires heap allocation when (capacity >= SSO) */ namespace nall { -char* string::data() { - if(_capacity < SSO) return _text; - return _data; -} - -const char* string::data() const { - if(_capacity < SSO) return _text; - return _data; -} - -void string::reserve(unsigned capacity) { - if(capacity > _capacity) { - if(capacity >= SSO) { - capacity = bit::round(capacity + 1) - 1; - if(_capacity < SSO) { - char temp[SSO]; - memcpy(temp, _text, SSO); - _data = (char*)malloc(capacity + 1); - memcpy(_data, temp, SSO); - } else { - _data = (char*)realloc(_data, capacity + 1); - } - } - _capacity = capacity; - data()[_capacity] = 0; - } -} - -void string::resize(unsigned size) { - reserve(size); - data()[_size = size] = 0; -} - -void string::reset() { - if(_capacity >= SSO) free(_data); +string::string() { _data = nullptr; _capacity = SSO - 1; _size = 0; } -string& string::operator=(const string& source) { - if(&source == this) return *this; - reset(); - if(source._capacity >= SSO) { - _data = (char*)malloc(source._capacity + 1); - _capacity = source._capacity; - _size = source._size; - memcpy(_data, source.data(), source.size() + 1); +auto string::pointer() -> char* { + if(_capacity < SSO) return _text; + return _data; +} + +auto string::data() const -> const char* { + if(_capacity < SSO) return _text; + return _data; +} + +auto string::reset() -> type& { + if(_capacity >= SSO) memory::free(_data); + _data = nullptr; + _capacity = SSO - 1; + _size = 0; + return *this; +} + +auto string::reserve(unsigned capacity) -> type& { + if(capacity <= _capacity) return *this; + capacity = bit::round(capacity + 1) - 1; + if(_capacity < SSO) { + char _temp[SSO]; + memory::copy(_temp, _text, SSO); + _data = (char*)memory::allocate(_capacity = capacity + 1); + memory::copy(_data, _temp, SSO); } else { - memcpy(_text, source._text, SSO); - _capacity = SSO - 1; - _size = strlen(_text); + _data = (char*)memory::resize(_data, _capacity = capacity + 1); } return *this; } -string& string::operator=(string&& source) { +auto string::resize(unsigned size) -> type& { + reserve(size); + pointer()[_size = size] = 0; + return *this; +} + +auto string::operator=(const string& source) -> type& { if(&source == this) return *this; reset(); - memcpy(this, &source, sizeof(string)); + if(source._capacity >= SSO) { + _data = (char*)memory::allocate(source._capacity + 1); + _capacity = source._capacity; + _size = source._size; + memory::copy(_data, source._data, source._size + 1); + } else { + memory::copy(_text, source._text, SSO); + _capacity = SSO - 1; + _size = source._size; + } + return *this; +} + +auto string::operator=(string&& source) -> type& { + if(&source == this) return *this; + reset(); + memory::copy(this, &source, sizeof(string)); source._data = nullptr; source._capacity = SSO - 1; source._size = 0; return *this; } -template string::string(T&& source, Args&&... args) { - construct(); - sprint(*this, std::forward(source), std::forward(args)...); -} - -string::string() { - construct(); -} - -string::~string() { - reset(); -} - -void string::construct() { - _data = nullptr; - _capacity = SSO - 1; - _size = 0; -} - } #endif diff --git a/nall/string/allocator/vector.hpp b/nall/string/allocator/vector.hpp index 7b7aaaaf..856221a5 100644 --- a/nall/string/allocator/vector.hpp +++ b/nall/string/allocator/vector.hpp @@ -19,46 +19,49 @@ cons: namespace nall { -char* string::data() { +auto string::pointer() -> char* { if(_capacity == 0) reserve(1); return _data; } -const char* string::data() const { +auto string::data() const -> const char* { if(_capacity == 0) return ""; return _data; } -void string::reserve(unsigned capacity) { - if(capacity > _capacity) { - _capacity = bit::round(capacity + 1) - 1; - _data = (char*)realloc(_data, _capacity + 1); - _data[_capacity] = 0; - } -} - -void string::resize(unsigned size) { - reserve(size); - data()[_size = size] = 0; -} - -void string::reset() { - if(_data) { free(_data); _data = nullptr; } +auto string::reset() -> type& { + if(_data) { memory::free(_data); _data = nullptr; } _capacity = 0; _size = 0; -} - -string& string::operator=(const string& source) { - if(&source == this) return *this; - reset(); - _data = (char*)malloc(source._size + 1); - _capacity = source._size; - _size = source._size; - memcpy(_data, source.data(), source.size() + 1); return *this; } -string& string::operator=(string&& source) { +auto string::reserve(unsigned capacity) -> type& { + if(capacity > _capacity) { + _capacity = bit::round(capacity + 1) - 1; + _data = (char*)memory::resize(_data, _capacity + 1); + _data[_capacity] = 0; + } + return *this; +} + +auto string::resize(unsigned size) -> type& { + reserve(size); + pointer()[_size = size] = 0; + return *this; +} + +auto string::operator=(const string& source) -> type& { + if(&source == this) return *this; + reset(); + _data = (char*)memory::allocate(source._size + 1); + _capacity = source._size; + _size = source._size; + memory::copy(_data, source.data(), source.size() + 1); + return *this; +} + +auto string::operator=(string&& source) -> type& { if(&source == this) return *this; reset(); _data = source._data; @@ -70,20 +73,7 @@ string& string::operator=(string&& source) { return *this; } -template string::string(T&& source, Args&&... args) { - construct(); - sprint(*this, std::forward(source), std::forward(args)...); -} - string::string() { - construct(); -} - -string::~string() { - reset(); -} - -void string::construct() { _data = nullptr; _capacity = 0; _size = 0; diff --git a/nall/string/base.hpp b/nall/string/base.hpp index 8da9d880..178a77dd 100644 --- a/nall/string/base.hpp +++ b/nall/string/base.hpp @@ -3,19 +3,165 @@ namespace nall { struct string; +struct format; struct stringref; struct lstring; -typedef const stringref& rstring; +using cstring = const string&; +using rstring = const stringref&; +#define NALL_STRING_ALLOCATOR_ADAPTIVE //#define NALL_STRING_ALLOCATOR_COPY_ON_WRITE -#define NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION +//#define NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION //#define NALL_STRING_ALLOCATOR_VECTOR +//cast.hpp +template struct stringify; + +//compare.hpp +inline auto compare(const string& self, rstring source) -> signed; +inline auto icompare(const string& self, rstring source) -> signed; + +inline auto equals(const string& self, rstring source) -> bool; +inline auto iequals(const string& self, rstring source) -> bool; + +inline auto beginsWith(const string& self, rstring source) -> bool; +inline auto ibeginsWith(const string& self, rstring source) -> bool; + +inline auto endsWith(const string& self, rstring source) -> bool; +inline auto iendsWith(const string& self, rstring source) -> bool; + +//convert.hpp +inline auto downcase(string& self) -> string&; +inline auto qdowncase(string& self) -> string&; + +inline auto upcase(string& self) -> string&; +inline auto qupcase(string& self) -> string&; + +inline auto transform(string& self, rstring from, rstring to) -> string&; + +//core.hpp +template inline auto assign(string& self, P&&... p) -> string&; +template inline auto append(string& self, const T& value, P&&... p) -> string&; +template inline auto append(string& self, const format& value, P&&... p) -> string&; +inline auto append(string& self) -> string&; +template inline auto _append(string& self, const stringify& source) -> string&; +inline auto empty(const string& self) -> bool; +inline auto length(const string& self) -> unsigned; + +//find.hpp +template inline auto _find(const string& self, signed offset, rstring source) -> maybe; +inline auto find(const string& self, rstring source) -> maybe; +inline auto ifind(const string& self, rstring source) -> maybe; +inline auto qfind(const string& self, rstring source) -> maybe; +inline auto iqfind(const string& self, rstring source) -> maybe; +inline auto findFrom(const string& self, signed offset, rstring source) -> maybe; +inline auto ifindFrom(const string& self, signed offset, rstring source) -> maybe; + +//format.hpp +template inline auto print(P&&...) -> void; +template inline auto integer(intmax_t value) -> string; +template inline auto decimal(uintmax_t value) -> string; +template inline auto hex(uintmax_t value) -> string; +template inline auto octal(uintmax_t value) -> string; +template inline auto binary(uintmax_t value) -> string; +template inline auto pointer(const T* value) -> string; +template inline auto pointer(uintptr_t value) -> string; +inline auto real(long double value) -> string; + +//hash.hpp +inline auto crc16(const string& self) -> string; +inline auto crc32(const string& self) -> string; +inline auto sha256(const string& self) -> string; + +//match.hpp +inline auto match(const string& self, rstring source) -> bool; +inline auto imatch(const string& self, rstring source) -> bool; +inline auto tokenize(lstring& list, const char* s, const char* p) -> bool; + +//path.hpp +inline auto pathname(const string& self) -> string; +inline auto filename(const string& self) -> string; + +inline auto dirname(const string& self) -> string; +inline auto basename(const string& self) -> string; +inline auto prefixname(const string& self) -> string; +inline auto suffixname(const string& self) -> string; + +//platform.hpp +inline auto activepath() -> string; +inline auto realpath(rstring name) -> string; +inline auto programpath() -> string; +inline auto userpath() -> string; +inline auto configpath() -> string; +inline auto sharedpath() -> string; +inline auto temppath() -> string; + +//replace.hpp +template inline auto _replace(string& self, rstring from, rstring to) -> string&; +template inline auto replace(string& self, rstring from, rstring to) -> string&; +template inline auto ireplace(string& self, rstring from, rstring to) -> string&; +template inline auto qreplace(string& self, rstring from, rstring to) -> string&; +template inline auto iqreplace(string& self, rstring from, rstring to) -> string&; + +//split.hpp +template inline auto _split(lstring& self, rstring source, rstring find) -> lstring&; +template inline auto split(string& self, rstring key) -> lstring; +template inline auto isplit(string& self, rstring key) -> lstring; +template inline auto qsplit(string& self, rstring key) -> lstring; +template inline auto iqsplit(string& self, rstring key) -> lstring; + +//trim.hpp +inline auto trim(string& self, rstring lhs, rstring rhs) -> bool; +inline auto ltrim(string& self, rstring lhs) -> bool; +inline auto rtrim(string& self, rstring rhs) -> bool; + +inline auto itrim(string& self, rstring lhs, rstring rhs) -> bool; +inline auto iltrim(string& self, rstring lhs) -> bool; +inline auto irtrim(string& self, rstring rhs) -> bool; + +inline auto strip(string& self) -> bool; +inline auto lstrip(string& self) -> bool; +inline auto rstrip(string& self) -> bool; + +//utility.hpp +inline auto fill(string& self, char fill = ' ') -> string&; +inline auto hash(const string& self) -> unsigned; +inline auto remove(string& self, unsigned offset, unsigned length) -> string&; +inline auto reverse(string& self) -> string&; +inline auto size(string& self, signed length, char fill = ' ') -> string&; +inline auto slice(const string& self, signed offset = 0, signed length = -1) -> string; +inline auto substr(rstring source, signed offset = 0, signed length = -1) -> string; + +inline auto integer(char* result, intmax_t value) -> char*; +inline auto decimal(char* result, uintmax_t value) -> char*; +inline auto real(char* str, long double value) -> unsigned; + struct string { + using type = string; + struct exception_out_of_bounds{}; + protected: + #if defined(NALL_STRING_ALLOCATOR_ADAPTIVE) + enum : unsigned { SSO = 24 }; + union { + struct { //copy-on-write + char* _data; + unsigned* _refs; + }; + struct { //small-string-optimization + char _text[SSO]; + }; + }; + inline auto _allocate() -> void; + inline auto _copy() -> void; + inline auto _resize() -> void; + #endif + #if defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE) - inline void _copy(); - std::shared_ptr _data; + char* _data; + mutable unsigned* _refs; + inline auto _allocate() -> char*; + inline auto _copy() -> char*; #endif #if defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION) @@ -34,194 +180,213 @@ protected: unsigned _size; public: + inline string(); + inline auto pointer() -> char*; + inline auto data() const -> const char*; + inline auto reset() -> type&; + inline auto reserve(unsigned) -> type&; + inline auto resize(unsigned) -> type&; + inline auto operator=(const string&) -> type&; + inline auto operator=(string&&) -> type&; + + template string(T&& s, P&&... p) : string() { append(std::forward(s), std::forward

(p)...); } + ~string() { reset(); } + + explicit operator bool() const { return _size; } + operator const uint8_t*() const { return (const uint8_t*)data(); } + operator const char*() const { return (const char*)data(); } + + auto binary() const -> const uint8_t* { return (const uint8_t*)data(); } + auto size() const -> unsigned { return _size; } + auto capacity() const -> unsigned { return _capacity; } + + auto operator==(const string& s) const -> bool { return size() == s.size() && memory::compare(data(), s.data(), s.size()) == 0; } + auto operator!=(const string& s) const -> bool { return size() != s.size() || memory::compare(data(), s.data(), s.size()) != 0; } + + auto operator==(const char* s) const -> bool { return strcmp(data(), s) == 0; } + auto operator!=(const char* s) const -> bool { return strcmp(data(), s) != 0; } + auto operator< (const char* s) const -> bool { return strcmp(data(), s) < 0; } + auto operator<=(const char* s) const -> bool { return strcmp(data(), s) <= 0; } + auto operator> (const char* s) const -> bool { return strcmp(data(), s) > 0; } + auto operator>=(const char* s) const -> bool { return strcmp(data(), s) >= 0; } + + string(const string& source) : string() { operator=(source); } + string(string&& source) : string() { operator=(std::move(source)); } + + auto begin() -> char* { return &pointer()[0]; } + auto end() -> char* { return &pointer()[size()]; } + auto begin() const -> const char* { return &data()[0]; } + auto end() const -> const char* { return &data()[size()]; } + + //nall/atoi.hpp + inline auto integer() const -> intmax_t { return nall::integer(*this); } + inline auto decimal() const -> uintmax_t { return nall::decimal(*this); } + inline auto hex() const -> uintmax_t { return nall::hex(*this); } + //core.hpp - inline char* data(); - inline const char* data() const; - inline unsigned length() const; - inline unsigned size() const; - inline unsigned capacity() const; - inline bool empty() const; - - inline void reset(); - inline void reserve(unsigned); - inline void resize(unsigned); - inline void clear(char); - - inline unsigned hash() const; - - template inline string& assign(Args&&... args); - template inline string& append(Args&&... args); - - //file.hpp - inline static string read(const string& filename); + inline auto operator[](signed) const -> const char&; //datetime.hpp - inline static string date(); - inline static string time(); - inline static string datetime(); + inline static auto date(time_t = 0) -> string; + inline static auto time(time_t = 0) -> string; + inline static auto datetime(time_t = 0) -> string; - //replace.hpp - template inline string& replace(rstring, rstring); - template inline string& ireplace(rstring, rstring); - template inline string& qreplace(rstring, rstring); - template inline string& iqreplace(rstring, rstring); + //format.hpp + inline auto format(const nall::format& params) -> type&; - //wrapper.hpp - template inline lstring split(rstring) const; - template inline lstring isplit(rstring) const; - template inline lstring qsplit(rstring) const; - template inline lstring iqsplit(rstring) const; + //utility.hpp + inline static auto read(const string& filename) -> string; + template inline static auto repeat(const string& pattern) -> string; - inline signed compare(rstring) const; - inline signed icompare(rstring) const; + //extension methods + //================= - inline bool equals(rstring) const; - inline bool iequals(rstring) const; + //compare.hpp + auto compare(rstring source) const -> signed { return nall::compare(*this, source); } + auto icompare(rstring source) const -> signed { return nall::compare(*this, source); } - inline bool match(rstring) const; - inline bool imatch(rstring) const; + auto equals(rstring source) const -> bool { return nall::equals(*this, source); } + auto iequals(rstring source) const -> bool { return nall::iequals(*this, source); } - inline bool beginsWith(rstring) const; - inline bool ibeginsWith(rstring) const; - inline bool endsWith(rstring) const; - inline bool iendsWith(rstring) const; + auto beginsWith(rstring source) const -> bool { return nall::beginsWith(*this, source); } + auto ibeginsWith(rstring source) const -> bool { return nall::ibeginsWith(*this, source); } - inline string slice(unsigned offset, unsigned length = ~0u) const; + auto endsWith(rstring source) const -> bool { return nall::endsWith(*this, source); } + auto iendsWith(rstring source) const -> bool { return nall::iendsWith(*this, source); } - inline string& lower(); - inline string& upper(); - inline string& qlower(); - inline string& qupper(); - inline string& transform(rstring before, rstring after); - inline string& reverse(); + //convert.hpp + auto downcase() -> type& { return nall::downcase(*this); } + auto upcase() -> type& { return nall::upcase(*this); } - template inline string& ltrim() { return ltrim(" "); } - template inline string& ltrim(rstring key); + auto qdowncase() -> type& { return nall::qdowncase(*this); } + auto qupcase() -> type& { return nall::qupcase(*this); } - template inline string& rtrim() { return rtrim(" "); } - template inline string& rtrim(rstring key); - - template inline string& trim() { return trim(" "); } - template inline string& trim(rstring key); - template inline string& trim(rstring key, rstring rkey); - - inline string& strip(); - - inline maybe find(rstring key) const; - inline maybe ifind(rstring key) const; - inline maybe qfind(rstring key) const; - inline maybe iqfind(rstring key) const; + auto transform(rstring from, rstring to) -> type& { return nall::transform(*this, from, to); } //core.hpp - inline explicit operator bool() const; - inline operator const char*() const; - inline char& operator[](signed); - inline const char& operator[](signed) const; + template auto assign(P&&... p) -> type& { return nall::assign(*this, std::forward

(p)...); } + template auto append(P&&... p) -> type& { return nall::append(*this, std::forward

(p)...); } + auto empty() const -> bool { return nall::empty(*this); } + auto length() const -> unsigned { return nall::length(*this); } - inline bool operator==(const char*) const; - inline bool operator!=(const char*) const; - inline bool operator< (const char*) const; - inline bool operator<=(const char*) const; - inline bool operator> (const char*) const; - inline bool operator>=(const char*) const; + //find.hpp + auto find(rstring source) const -> maybe { return nall::find(*this, source); } + auto ifind(rstring source) const -> maybe { return nall::ifind(*this, source); } + auto qfind(rstring source) const -> maybe { return nall::qfind(*this, source); } + auto iqfind(rstring source) const -> maybe { return nall::iqfind(*this, source); } - inline string& operator=(const string&); - inline string& operator=(string&&); + auto findFrom(signed offset, rstring source) const -> maybe { return nall::findFrom(*this, offset, source); } + auto ifindFrom(signed offset, rstring source) const -> maybe { return nall::ifindFrom(*this, offset, source); } - template inline string(T&& source, Args&&... args); - inline string(); - inline string(const string&); - inline string(string&&); - inline ~string(); + //hash.hpp + auto crc16() const -> string { return nall::crc16(*this); } + auto crc32() const -> string { return nall::crc32(*this); } + auto sha256() const -> string { return nall::sha256(*this); } - inline char* begin() { return &data()[0]; } - inline char* end() { return &data()[size()]; } - inline const char* begin() const { return &data()[0]; } - inline const char* end() const { return &data()[size()]; } + //match.hpp + auto match(rstring source) const -> bool { return nall::match(*this, source); } + auto imatch(rstring source) const -> bool { return nall::imatch(*this, source); } -//protected: - struct exception_out_of_bounds{}; - template inline string& ureplace(rstring, rstring); - inline string& _append(const char*); + //path.hpp + auto pathname() const -> string { return nall::pathname(*this); } + auto filename() const -> string { return nall::filename(*this); } -private: - inline void construct(); + auto dirname() const -> string { return nall::dirname(*this); } + auto basename() const -> string { return nall::basename(*this); } + auto prefixname() const -> string { return nall::prefixname(*this); } + auto suffixname() const -> string { return nall::suffixname(*this); } -#if defined(QSTRING_H) -public: + //replace.hpp + template auto replace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } + template auto ireplace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } + template auto qreplace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } + template auto iqreplace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } + + //split.hpp + template inline auto split(rstring key) const -> lstring; + template inline auto isplit(rstring key) const -> lstring; + template inline auto qsplit(rstring key) const -> lstring; + template inline auto iqsplit(rstring key) const -> lstring; + + //trim.hpp + auto trim(rstring lhs, rstring rhs) -> type& { return nall::trim(*this, lhs, rhs), *this; } + auto ltrim(rstring lhs) -> type& { return nall::ltrim(*this, lhs), *this; } + auto rtrim(rstring rhs) -> type& { return nall::rtrim(*this, rhs), *this; } + + auto itrim(rstring lhs, rstring rhs) -> type& { return nall::itrim(*this, lhs, rhs), *this; } + auto iltrim(rstring lhs) -> type& { return nall::iltrim(*this, lhs), *this; } + auto irtrim(rstring rhs) -> type& { return nall::irtrim(*this, rhs), *this; } + + auto strip() -> type& { return nall::strip(*this), *this; } + auto lstrip() -> type& { return nall::lstrip(*this), *this; } + auto rstrip() -> type& { return nall::rstrip(*this), *this; } + + //utility.hpp + auto fill(char fill = ' ') -> type& { return nall::fill(*this, fill); } + auto hash() const -> const type& { return nall::hash(*this), *this; } + auto remove(unsigned offset, unsigned length) -> type& { return nall::remove(*this, offset, length); } + auto reverse() -> type& { return nall::reverse(*this); } + auto size(signed length, char fill = ' ') -> type& { return nall::size(*this, length, fill); } + auto slice(signed offset = 0, signed length = -1) const -> string { return nall::slice(*this, offset, length); } + + #if defined(QSTRING_H) inline operator QString() const; -#endif + #endif }; //list.hpp +template auto append(lstring& self, const string& value, P&&... p) -> lstring&; +inline auto append(lstring& self) -> lstring&; +inline auto find(const lstring& self, const string& source) -> maybe; +inline auto ifind(const lstring& self, const string& source) -> maybe; +inline auto merge(const lstring& self, const string& separator) -> string; +inline auto strip(lstring& self) -> lstring&; + struct lstring : vector { - inline maybe find(rstring) const; - inline string merge(const string&) const; - inline lstring& isort(); - inline lstring& strip(); - inline void append() {} - template inline void append(const string&, Args&&...); + using type = lstring; - inline bool operator==(const lstring&) const; - inline bool operator!=(const lstring&) const; + lstring(const lstring& source) { vector::operator=(source); } + lstring(lstring& source) { vector::operator=(source); } + lstring(lstring&& source) { vector::operator=(std::move(source)); } + template lstring(P&&... p) { append(std::forward

(p)...); } - inline lstring& operator=(const lstring&); - inline lstring& operator=(lstring&); - inline lstring& operator=(lstring&&); + //list.hpp + inline auto operator==(const lstring&) const -> bool; + inline auto operator!=(const lstring&) const -> bool; - template inline lstring(Args&&... args); - inline lstring(const lstring&); - inline lstring(lstring&); - inline lstring(lstring&&); + inline auto operator=(const lstring& source) -> type& { return vector::operator=(source), *this; } + inline auto operator=(lstring& source) -> type& { return vector::operator=(source), *this; } + inline auto operator=(lstring&& source) -> type& { return vector::operator=(std::move(source)), *this; } + + inline auto isort() -> type&; + + //extension methods + //================= + + //list.hpp + template auto append(P&&... p) -> type& { return nall::append(*this, std::forward

(p)...); } + auto find(const string& source) const -> maybe { return nall::find(*this, source); } + auto ifind(const string& source) const -> maybe { return nall::ifind(*this, source); } + auto merge(const string& separator) const -> string { return nall::merge(*this, separator); } + auto strip() -> type& { return nall::strip(*this); } //split.hpp - template inline lstring& split(rstring, rstring); - template inline lstring& isplit(rstring, rstring); - template inline lstring& qsplit(rstring, rstring); - template inline lstring& iqsplit(rstring, rstring); - -protected: - template inline lstring& usplit(rstring, rstring); + template auto split(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } + template auto isplit(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } + template auto qsplit(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } + template auto iqsplit(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } }; -//filename.hpp -inline string dir(string name); -inline string notdir(string name); -inline string parentdir(string name); -inline string basename(string name); -inline string extension(string name); -inline string tempname(); - //format.hpp -template inline string format(const string& value); -template inline string hex(uintmax_t value); -template inline string octal(uintmax_t value); -template inline string binary(uintmax_t value); +template inline auto append(format& self, const T& value, P&&... p) -> format&; +inline auto append(format& self) -> format&; -//platform.hpp -inline string activepath(); -inline string realpath(const string& name); -inline string programpath(); -inline string userpath(); -inline string configpath(); -inline string sharedpath(); -inline string temppath(); +struct format : vector { + using type = format; -//utility.hpp -inline string substr(rstring source, unsigned offset = 0, unsigned length = ~0u); -inline string sha256(const uint8_t* data, unsigned size); -inline bool tokenize(lstring& list, const char* s, const char* p); - -inline char* integer(char* result, intmax_t value); -inline char* decimal(char* result, uintmax_t value); - -inline unsigned real(char* str, long double value); -inline string real(long double value); - -//variadic.hpp -inline void sprint(string& output); -template inline void sprint(string& output, const T& value, Args&&... args); -template inline void print(Args&&... args); + template format(P&&... p) { reserve(sizeof...(p)); append(std::forward

(p)...); } + template auto append(P&&... p) -> type& { return nall::append(*this, std::forward

(p)...); } +}; } diff --git a/nall/string/cast.hpp b/nall/string/cast.hpp index ef79a47d..5b7d13f0 100644 --- a/nall/string/cast.hpp +++ b/nall/string/cast.hpp @@ -1,185 +1,209 @@ #ifdef NALL_STRING_INTERNAL_HPP +//convert any (supported) type to a const char* without constructing a new nall::string +//this is used inside string{...} to build nall::string values + namespace nall { -//convert any (supported) type to a const char* without constructing a new nall::string -//this is used inside istring(...) to build nall::string values -template struct stringify; - -// base types +//base types template<> struct stringify { - bool value; - operator const char*() const { return value ? "true" : "false"; } - stringify(bool value) : value(value) {} + bool _value; + auto data() const -> const char* { return _value ? "true" : "false"; } + auto size() const -> unsigned { return _value ? 4 : 5; } + stringify(bool value) : _value(value) {} }; template<> struct stringify { - char data[2]; - operator const char*() const { return data; } - stringify(char value) { data[0] = value, data[1] = 0; } + char _data[2]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return 1; } + stringify(char source) { _data[0] = source; _data[1] = 0; } }; -// signed integers +//signed integers template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(signed char value) { integer(data, value); } + char _data[2 + sizeof(signed char) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(signed char source) { integer(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(signed short value) { integer(data, value); } + char _data[2 + sizeof(signed short) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(signed short source) { integer(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(signed int value) { integer(data, value); } + char _data[2 + sizeof(signed int) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(signed int source) { integer(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(signed long value) { integer(data, value); } + char _data[2 + sizeof(signed long) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(signed long source) { integer(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(signed long long value) { integer(data, value); } + char _data[2 + sizeof(signed long long) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(signed long long source) { integer(_data, source); } }; template struct stringify> { - char data[256]; - operator const char*() const { return data; } - stringify(int_t value) { integer(data, value); } + char _data[2 + sizeof(intmax_t) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(int_t source) { integer(_data, source); } }; -// unsigned integers +//unsigned integers template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(unsigned char value) { decimal(data, value); } + char _data[1 + sizeof(unsigned char) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(unsigned char source) { decimal(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(unsigned short value) { decimal(data, value); } + char _data[1 + sizeof(unsigned short) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(unsigned short source) { decimal(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(unsigned int value) { decimal(data, value); } + char _data[1 + sizeof(unsigned int) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(unsigned int source) { decimal(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(unsigned long value) { decimal(data, value); } + char _data[1 + sizeof(unsigned long) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(unsigned long source) { decimal(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(unsigned long long value) { decimal(data, value); } + char _data[1 + sizeof(unsigned long long) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(unsigned long long source) { decimal(_data, source); } }; template struct stringify> { - char data[256]; - operator const char*() const { return data; } - stringify(uint_t value) { decimal(data, value); } + char _data[1 + sizeof(uintmax_t) * 3]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(uint_t source) { decimal(_data, source); } }; -// floating-point +//floating-point template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(float value) { real(data, value); } + char _data[256]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(float source) { real(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(double value) { real(data, value); } + char _data[256]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(double source) { real(_data, source); } }; template<> struct stringify { - char data[256]; - operator const char*() const { return data; } - stringify(long double value) { real(data, value); } + char _data[256]; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(long double source) { real(_data, source); } }; -// arrays +//arrays template<> struct stringify> { - char* text; - operator const char*() const { return text; } - stringify(vector value) { - text = new char[value.size() + 1](); - memcpy(text, value.data(), value.size()); - } - ~stringify() { - delete[] text; + vector _text; + auto data() const -> const char* { return _text.data(); } + auto size() const -> unsigned { return _text.size(); } + stringify(vector source) { + _text.resize(source.size() + 1); + memory::copy(_text.data(), source.data(), source.size()); + _text[_text.size()] = 0; } }; template<> struct stringify&> { - char* text; - operator const char*() const { return text; } - stringify(const vector& value) { - text = new char[value.size() + 1](); - memcpy(text, value.data(), value.size()); - } - ~stringify() { - delete[] text; + vector _text; + auto data() const -> const char* { return _text.data(); } + auto size() const -> unsigned { return _text.size(); } + stringify(const vector& source) { + _text.resize(source.size() + 1); + memory::copy(_text.data(), source.data(), source.size()); + _text[_text.size()] = 0; } }; -// strings +//char arrays template<> struct stringify { - const char* value; - operator const char*() const { return value; } - stringify(char* value) : value(value) {} + const char* _data; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(char* source) : _data(source) {} }; template<> struct stringify { - const char* value; - operator const char*() const { return value; } - stringify(const char* value) : value(value) {} + const char* _data; + auto data() const -> const char* { return _data; } + auto size() const -> unsigned { return strlen(_data); } + stringify(const char* source) : _data(source) {} }; +//strings + template<> struct stringify { - const string& value; - operator const char*() const { return value; } - stringify(const string& value) : value(value) {} + const string& _text; + auto data() const -> const char* { return _text.data(); } + auto size() const -> unsigned { return _text.size(); } + stringify(const string& source) : _text(source) {} }; template<> struct stringify { - const string& value; - operator const char*() const { return value; } - stringify(const string& value) : value(value) {} + const string& _text; + auto data() const -> const char* { return _text.data(); } + auto size() const -> unsigned { return _text.size(); } + stringify(const string& source) : _text(source) {} }; #if defined(QSTRING_H) +//Qt + template<> struct stringify { - const QString& value; - operator const char*() const { return value.toUtf8().constData(); } - stringify(const QString& value) : value(value) {} + const QString& _text; + auto data() const -> const char* { return _text.toUtf8().constData(); } + auto size() const -> unsigned { return _text.size(); } + stringify(const QString& source) : _text(source) {} }; template<> struct stringify { - const QString& value; - operator const char*() const { return value.toUtf8().constData(); } - stringify(const QString& value) : value(value) {} + const QString& _text; + auto data() const -> const char* { return _text.toUtf8().constData(); } + auto size() const -> unsigned { return _text.size(); } + stringify(const QString& source) : _text(source) {} }; string::operator QString() const { @@ -190,7 +214,7 @@ string::operator QString() const { // -template stringify make_string(T value) { +template auto make_string(T value) -> stringify { return stringify(std::forward(value)); } diff --git a/nall/string/char.hpp b/nall/string/char.hpp deleted file mode 100644 index 29ac2c77..00000000 --- a/nall/string/char.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif diff --git a/nall/string/char/base.hpp b/nall/string/char/base.hpp deleted file mode 100644 index 49b2fc22..00000000 --- a/nall/string/char/base.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -//collection of functions to extend libc -//none of these functions require nall::string -//and thus, require no changes when nall::string is modified - -namespace nall { - -//compare.hpp -inline char chrlower(char c); -inline char chrupper(char c); -inline int imemcmp(const char* str1, const char* str2, unsigned size); -inline int istrcmp(const char* str1, const char* str2); -inline bool strbegin(const char* str, const char* key); -inline bool istrbegin(const char* str, const char* key); -inline bool strend(const char* str, const char* key); -inline bool istrend(const char* str, const char* key); - -//convert.hpp -inline char* strlower(char* str); -inline char* strupper(char* str); -inline char* qstrlower(char* str); -inline char* qstrupper(char* str); -inline char* strtr(char* dest, const char* before, const char* after); - -//match.hpp -inline bool strmatch(const char* str, const char* pattern); -inline bool istrmatch(const char* str, const char* pattern); -inline bool tokenize(const char* s, const char* p); - -//strm.hpp -inline unsigned strmcpy(char* target, const char* source, unsigned length); -inline unsigned strmcat(char* target, const char* source, unsigned length); -inline bool strccpy(char* target, const char* source, unsigned length); -inline bool strccat(char* target, const char* source, unsigned length); -inline void strpcpy(char*& target, const char* source, unsigned& length); - -//strpos.hpp -inline maybe strpos(const char* str, const char* key); -inline maybe istrpos(const char* str, const char* key); -inline maybe qstrpos(const char* str, const char* key); -inline maybe iqstrpos(const char* str, const char* key); -template inline maybe ustrpos(const char* str, const char* key); - -//trim.hpp -template inline char* ltrim(char* str, const char* key = " "); -template inline char* rtrim(char* str, const char* key = " "); -template inline char* trim(char* str, const char* key = " "); -template inline char* trim(char* str, const char* lkey, const char* rkey); -inline char* strip(char* s); - -//utf8.hpp -struct UTF8 { - unsigned size; //size of encoded codepoint - uint64_t data; //encoded codepoint - unsigned codepoint; //decoded codepoint -}; -inline UTF8 utf8_read(const char* s); -inline void utf8_write(char* s, const UTF8& utf8); - -//utility.hpp -template alwaysinline bool chrequal(char x, char y); -template alwaysinline bool quoteskip(T*& p); -template alwaysinline bool quotecopy(char*& t, T*& p); -inline char* strduplicate(const char* s); - -} - -#endif diff --git a/nall/string/char/compare.hpp b/nall/string/char/compare.hpp deleted file mode 100644 index ff9bf54b..00000000 --- a/nall/string/char/compare.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -char chrlower(char c) { - return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; -} - -char chrupper(char c) { - return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c; -} - -int imemcmp(const char* str1, const char* str2, unsigned size) { - while(size--) { - if(chrlower(*str1) != chrlower(*str2)) break; - str1++, str2++; - } - return (int)chrlower(*str1) - (int)chrlower(*str2); -} - -int istrcmp(const char* str1, const char* str2) { - while(*str1) { - if(chrlower(*str1) != chrlower(*str2)) break; - str1++, str2++; - } - return (int)chrlower(*str1) - (int)chrlower(*str2); -} - -bool strbegin(const char* str, const char* key) { - if(!str || !key) return false; - int i, ssl = strlen(str), ksl = strlen(key); - - if(ksl > ssl) return false; - return (!memcmp(str, key, ksl)); -} - -bool istrbegin(const char* str, const char* key) { - if(!str || !key) return false; - int ssl = strlen(str), ksl = strlen(key); - - if(ksl > ssl) return false; - for(int i = 0; i < ksl; i++) { - if(str[i] >= 'A' && str[i] <= 'Z') { - if(str[i] != key[i] && str[i]+0x20 != key[i])return false; - } else if(str[i] >= 'a' && str[i] <= 'z') { - if(str[i] != key[i] && str[i]-0x20 != key[i])return false; - } else { - if(str[i] != key[i])return false; - } - } - return true; -} - -bool strend(const char* str, const char* key) { - if(!str || !key) return false; - int ssl = strlen(str), ksl = strlen(key); - - if(ksl > ssl) return false; - return (!memcmp(str + ssl - ksl, key, ksl)); -} - -bool istrend(const char* str, const char* key) { - if(!str || !key) return false; - int ssl = strlen(str), ksl = strlen(key); - - if(ksl > ssl) return false; - for(int i = ssl - ksl, z = 0; i < ssl; i++, z++) { - if(str[i] >= 'A' && str[i] <= 'Z') { - if(str[i] != key[z] && str[i]+0x20 != key[z])return false; - } else if(str[i] >= 'a' && str[i] <= 'z') { - if(str[i] != key[z] && str[i]-0x20 != key[z])return false; - } else { - if(str[i] != key[z])return false; - } - } - return true; -} - -} - -#endif diff --git a/nall/string/char/convert.hpp b/nall/string/char/convert.hpp deleted file mode 100644 index aa003a49..00000000 --- a/nall/string/char/convert.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -char* strlower(char* str) { - if(!str) return nullptr; - int i = 0; - while(str[i]) { - str[i] = chrlower(str[i]); - i++; - } - return str; -} - -char* strupper(char* str) { - if(!str) return nullptr; - int i = 0; - while(str[i]) { - str[i] = chrupper(str[i]); - i++; - } - return str; -} - -char* qstrlower(char* s) { - if(!s) return nullptr; - char* base = s; - bool quoted = false; - while(*s) { - if(*s == '\"' || *s == '\'') quoted ^= 1; - if(quoted == false && *s >= 'A' && *s <= 'Z') *s += 0x20; - s++; - } - return base; -} - -char* qstrupper(char* s) { - if(!s) return nullptr; - char* base = s; - bool quoted = false; - while(*s) { - if(*s == '\"' || *s == '\'') quoted ^= 1; - if(quoted == false && *s >= 'a' && *s <= 'z') *s -= 0x20; - s++; - } - return base; -} - -char* strtr(char* dest, const char* before, const char* after) { - if(!dest || !before || !after) return dest; - int sl = strlen(dest), bsl = strlen(before), asl = strlen(after); - - if(bsl != asl || bsl == 0) return dest; //patterns must be the same length for 1:1 replace - for(unsigned i = 0; i < sl; i++) { - for(unsigned l = 0; l < bsl; l++) { - if(dest[i] == before[l]) { - dest[i] = after[l]; - break; - } - } - } - - return dest; -} - -} - -#endif diff --git a/nall/string/char/strm.hpp b/nall/string/char/strm.hpp deleted file mode 100644 index 7e2b6e7c..00000000 --- a/nall/string/char/strm.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -//return = strlen(target) -unsigned strmcpy(char* target, const char* source, unsigned length) { - const char* origin = target; - if(length) { - while(*source && --length) *target++ = *source++; - *target = 0; - } - return target - origin; -} - -//return = strlen(target) -unsigned strmcat(char* target, const char* source, unsigned length) { - const char* origin = target; - while(*target && length) target++, length--; - return (target - origin) + strmcpy(target, source, length); -} - -//return = true when all of source was copied -bool strccpy(char* target, const char* source, unsigned length) { - return !source[strmcpy(target, source, length)]; -} - -//return = true when all of source was copied -bool strccat(char* target, const char* source, unsigned length) { - while(*target && length) target++, length--; - return !source[strmcpy(target, source, length)]; -} - -//return = reserved for future use -void strpcpy(char*& target, const char* source, unsigned& length) { - unsigned offset = strmcpy(target, source, length); - target += offset, length -= offset; -} - -} - -#endif diff --git a/nall/string/char/strpos.hpp b/nall/string/char/strpos.hpp deleted file mode 100644 index 8c0baa44..00000000 --- a/nall/string/char/strpos.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -//usage example: -//if(auto position = strpos(str, key)) print(position(), "\n"); -//prints position of key within str; but only if it is found - -namespace nall { - -template -maybe ustrpos(const char* str, const char* key) { - const char* base = str; - - while(*str) { - if(quoteskip(str)) continue; - for(unsigned n = 0;; n++) { - if(key[n] == 0) return (unsigned)(str - base); - if(str[n] == 0) return nothing; - if(!chrequal(str[n], key[n])) break; - } - str++; - } - - return nothing; -} - -maybe strpos(const char* str, const char* key) { return ustrpos(str, key); } -maybe istrpos(const char* str, const char* key) { return ustrpos(str, key); } -maybe qstrpos(const char* str, const char* key) { return ustrpos(str, key); } -maybe iqstrpos(const char* str, const char* key) { return ustrpos(str, key); } - -} - -#endif diff --git a/nall/string/char/trim.hpp b/nall/string/char/trim.hpp deleted file mode 100644 index 969b6926..00000000 --- a/nall/string/char/trim.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -//limit defaults to zero, which will underflow on first compare; equivalent to no limit -template char* ltrim(char* str, const char* key) { - if(!str || !key || !*key) return str; - unsigned limit = Limit; - while(strbegin(str, key)) { - char* dest = str; - char* src = str + strlen(key); - while(true) { - *dest = *src++; - if(!*dest) break; - dest++; - } - if(--limit == 0) break; - } - return str; -} - -template char* rtrim(char* str, const char* key) { - if(!str || !key || !*key) return str; - unsigned limit = Limit; - while(strend(str, key)) { - str[strlen(str) - strlen(key)] = 0; - if(--limit == 0) break; - } - return str; -} - -template char* trim(char* str, const char* key) { - return ltrim(rtrim(str, key), key); -} - -template char* trim(char* str, const char* lkey, const char* rkey) { - return ltrim(rtrim(str, rkey), lkey); -} - -//remove whitespace characters from both left and right sides of string -char* strip(char* s) { - if(!s) return nullptr; - - signed n = 0, p = 0; - while(s[n]) { - if(s[n] != ' ' && s[n] != '\t' && s[n] != '\r' && s[n] != '\n') break; - n++; - } - while(s[n]) s[p++] = s[n++]; - s[p--] = 0; - while(p >= 0) { - if(s[p] != ' ' && s[p] != '\t' && s[p] != '\r' && s[p] != '\n') break; - p--; - } - s[++p] = 0; - - return s; -} - -} - -#endif diff --git a/nall/string/char/utf8.hpp b/nall/string/char/utf8.hpp deleted file mode 100644 index 03eb5ef0..00000000 --- a/nall/string/char/utf8.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -UTF8 utf8_read(const char* s) { - UTF8 utf8; - - if((*s & 0xfe) == 0xfc) utf8.size = 6; - else if((*s & 0xfc) == 0xf8) utf8.size = 5; - else if((*s & 0xf8) == 0xf0) utf8.size = 4; - else if((*s & 0xf0) == 0xe0) utf8.size = 3; - else if((*s & 0xe0) == 0xc0) utf8.size = 2; - else utf8.size = 1; - - utf8.data = 0; - for(unsigned n = 0; n < utf8.size; n++) { - utf8.data = (utf8.data << 8) | (uint8_t)s[n]; - } - - static uint8_t mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; - utf8.codepoint = s[0] & mask[utf8.size]; - for(unsigned n = 1; n < utf8.size; n++) { - utf8.codepoint = (utf8.codepoint << 6) | (s[n] & 0x3f); - } - - return utf8; -} - -void utf8_write(char* s, const UTF8& utf8) { - for(signed n = utf8.size - 1, shift = 0; n >= 0; n--, shift += 8) { - s[n] = utf8.data >> shift; - } -} - -} - -#endif diff --git a/nall/string/char/utility.hpp b/nall/string/char/utility.hpp deleted file mode 100644 index bb35c020..00000000 --- a/nall/string/char/utility.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -template -bool chrequal(char x, char y) { - if(Insensitive) return chrlower(x) == chrlower(y); - return x == y; -} - -template -bool quoteskip(T*& p) { - if(Quoted == false) return false; - if(*p != '\"') return false; - - while(*p == '\"') { - char x = *p++; - while(*p && *p++ != x); - } - - return true; -} - -template -bool quotecopy(char*& t, T*& p) { - if(Quoted == false) return false; - if(*p != '\"') return false; - - while(*p == '\"') { - char x = *p++; - *t++ = x; - while(*p && *p != x) *t++ = *p++; - *t++ = *p++; - } - - return true; -} - -//strdup() is not a standard function, so recreate it -char* strduplicate(const char* s) { - if(s == nullptr) return nullptr; - unsigned length = strlen(s); - char* result = (char*)malloc(length + 1); - strcpy(result, s); - return result; -} - -} - -#endif diff --git a/nall/string/compare.hpp b/nall/string/compare.hpp new file mode 100644 index 00000000..7c4f49d6 --- /dev/null +++ b/nall/string/compare.hpp @@ -0,0 +1,50 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +template inline auto _compare(const char* target, unsigned capacity, const char* source, unsigned size) -> signed { + if(Insensitive) return memory::icompare(target, capacity, source, size); + return memory::compare(target, capacity, source, size); +} + +auto compare(const string& self, rstring source) -> signed { + return memory::compare(self.data(), self.size(), source.data(), source.size()); +} + +auto icompare(const string& self, rstring source) -> signed { + return memory::icompare(self.data(), self.size(), source.data(), source.size()); +} + +auto equals(const string& self, rstring source) -> bool { + if(self.size() != source.size()) return false; + return memory::compare(self.data(), source.data(), source.size()) == 0; +} + +auto iequals(const string& self, rstring source) -> bool { + if(self.size() != source.size()) return false; + return memory::icompare(self.data(), source.data(), source.size()) == 0; +} + +auto beginsWith(const string& self, rstring source) -> bool { + if(source.size() > self.size()) return false; + return memory::compare(self.data(), source.data(), source.size()) == 0; +} + +auto ibeginsWith(const string& self, rstring source) -> bool { + if(source.size() > self.size()) return false; + return memory::icompare(self.data(), source.data(), source.size()) == 0; +} + +auto endsWith(const string& self, rstring source) -> bool { + if(source.size() > self.size()) return false; + return memory::compare(self.data() + self.size() - source.size(), source.data(), source.size()) == 0; +} + +auto iendsWith(const string& self, rstring source) -> bool { + if(source.size() > self.size()) return false; + return memory::icompare(self.data() + self.size() - source.size(), source.data(), source.size()) == 0; +} + +} + +#endif diff --git a/nall/string/convert.hpp b/nall/string/convert.hpp new file mode 100644 index 00000000..3ffb5a6d --- /dev/null +++ b/nall/string/convert.hpp @@ -0,0 +1,55 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +auto downcase(string& self) -> string& { + char* p = self.pointer(); + for(unsigned n = 0; n < self.size(); n++) { + if(p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20; + } + return self; +} + +auto qdowncase(string& self) -> string& { + char* p = self.pointer(); + for(unsigned n = 0, quoted = 0; n < self.size(); n++) { + if(p[n] == '\"') quoted ^= 1; + if(!quoted && p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20; + } + return self; +} + +auto upcase(string& self) -> string& { + char* p = self.pointer(); + for(unsigned n = 0; n < self.size(); n++) { + if(p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20; + } + return self; +} + +auto qupcase(string& self) -> string& { + char* p = self.pointer(); + for(unsigned n = 0, quoted = 0; n < self.size(); n++) { + if(p[n] == '\"') quoted ^= 1; + if(!quoted && p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20; + } + return self; +} + +auto transform(string& self, rstring from, rstring to) -> string& { + if(from.size() != to.size() || from.size() == 0) return self; //patterns must be the same length + char* p = self.pointer(); + for(unsigned n = 0; n < self.size(); n++) { + for(unsigned s = 0; s < from.size(); s++) { + if(p[n] == from[s]) { + p[n] = to[s]; + break; + } + } + } + return self; +} + +} + +#endif diff --git a/nall/string/core.hpp b/nall/string/core.hpp index 8a00645e..dee9bfd0 100644 --- a/nall/string/core.hpp +++ b/nall/string/core.hpp @@ -3,7 +3,9 @@ //only allocators may access _data or modify _size and _capacity //all other functions must use data(), size(), capacity() -#if defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE) +#if defined(NALL_STRING_ALLOCATOR_ADAPTIVE) + #include +#elif defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE) #include #elif defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION) #include @@ -13,75 +15,44 @@ namespace nall { -unsigned string::length() const { return strlen(data()); } -unsigned string::size() const { return _size; } -unsigned string::capacity() const { return _capacity; } -bool string::empty() const { return _size == 0; } - -void string::clear(char c) { - for(unsigned n = 0; n < size(); n++) data()[n] = c; -} - -unsigned string::hash() const { - const char* p = data(); - unsigned result = 5381; - while(*p) result = (result << 5) + result + *p++; - return result; -} - -template string& string::assign(Args&&... args) { - resize(0); - sprint(*this, std::forward(args)...); - return *this; -} - -template string& string::append(Args&&... args) { - sprint(*this, std::forward(args)...); - return *this; -} - -string& string::_append(const char* s) { - if(s == nullptr) return *this; - unsigned basesize = size(), length = strlen(s); - reserve(basesize + length); - memcpy(data() + basesize, s, length); - resize(basesize + length); - return *this; -} - -string::operator bool() const { - return !empty(); -} - -string::operator const char*() const { - return data(); -} - -char& string::operator[](signed position) { +auto string::operator[](signed position) const -> const char& { if(position > size() + 1) throw exception_out_of_bounds{}; return data()[position]; } -const char& string::operator[](signed position) const { - if(position > size() + 1) throw exception_out_of_bounds{}; - return data()[position]; +template auto assign(string& self, P&&... p) -> string& { + self.resize(0); + return self.append(std::forward

(p)...); } -bool string::operator==(const char* str) const { return strcmp(data(), str) == 0; } -bool string::operator!=(const char* str) const { return strcmp(data(), str) != 0; } -bool string::operator< (const char* str) const { return strcmp(data(), str) < 0; } -bool string::operator<=(const char* str) const { return strcmp(data(), str) <= 0; } -bool string::operator> (const char* str) const { return strcmp(data(), str) > 0; } -bool string::operator>=(const char* str) const { return strcmp(data(), str) >= 0; } - -string::string(const string& source) { - construct(); - operator=(source); +template auto append(string& self, const T& value, P&&... p) -> string& { + _append(self, make_string(value)); + return self.append(std::forward

(p)...); } -string::string(string&& source) { - construct(); - operator=(std::move(source)); +template auto append(string& self, const format& value, P&&... p) -> string& { + self.format(value); + return self.append(std::forward

(p)...); +} + +auto append(string& self) -> string& { + return self; +} + +template auto _append(string& self, const stringify& source) -> string& { + unsigned size = self.size(); + unsigned length = source.size(); + self.resize(size + length); + memory::copy(self.pointer() + size, source.data(), length); + return self; +} + +auto empty(const string& self) -> bool { + return self.size() == 0; +} + +auto length(const string& self) -> unsigned { + return strlen(self.data()); } } diff --git a/nall/string/datetime.hpp b/nall/string/datetime.hpp index b55659a1..bf27007c 100644 --- a/nall/string/datetime.hpp +++ b/nall/string/datetime.hpp @@ -2,28 +2,29 @@ namespace nall { -string string::date() { - time_t timestamp = ::time(nullptr); +auto string::date(time_t timestamp) -> string { + if(timestamp == 0) timestamp = ::time(nullptr); tm* info = localtime(×tamp); return { - format<4, '0'>(1900 + info->tm_year), "-", - format<2, '0'>(1 + info->tm_mon), "-", - format<2, '0'>(info->tm_mday) + nall::decimal<4>(1900 + info->tm_year), "-", + nall::decimal<2>(1 + info->tm_mon), "-", + nall::decimal<2>(info->tm_mday) }; } -string string::time() { - time_t timestamp = ::time(nullptr); +auto string::time(time_t timestamp) -> string { + if(timestamp == 0) timestamp = ::time(nullptr); tm* info = localtime(×tamp); return { - format<2, '0'>(info->tm_hour), ":", - format<2, '0'>(info->tm_min), ":", - format<2, '0'>(info->tm_sec) + nall::decimal<2>(info->tm_hour), ":", + nall::decimal<2>(info->tm_min), ":", + nall::decimal<2>(info->tm_sec) }; } -string string::datetime() { - return {string::date(), " ", string::time()}; +auto string::datetime(time_t timestamp) -> string { + if(timestamp == 0) timestamp = ::time(nullptr); + return {string::date(timestamp), " ", string::time(timestamp)}; } } diff --git a/nall/string/eval/evaluator.hpp b/nall/string/eval/evaluator.hpp index 8957a30c..5e77ff7f 100644 --- a/nall/string/eval/evaluator.hpp +++ b/nall/string/eval/evaluator.hpp @@ -29,7 +29,7 @@ inline string evaluateExpression(Node* node) { for(auto& link : node->link) { result.append(evaluateExpression(link), ", "); } - return result.rtrim<1>(", ").append(")"); + return result.rtrim(", ").append(")"); } } #undef p diff --git a/nall/string/file.hpp b/nall/string/file.hpp deleted file mode 100644 index 1b809c2f..00000000 --- a/nall/string/file.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -string string::read(const string& filename) { - string result; - - #if !defined(_WIN32) - FILE* fp = fopen(filename, "rb"); - #else - FILE* fp = _wfopen(utf16_t(filename), L"rb"); - #endif - if(!fp) return result; - - fseek(fp, 0, SEEK_END); - unsigned fsize = ftell(fp); - rewind(fp); - char* fdata = new char[fsize + 1]; - unsigned unused = fread(fdata, 1, fsize, fp); - fclose(fp); - fdata[fsize] = 0; - result.resize(fsize); - memcpy(result.data(), fdata, fsize); - delete[] fdata; - - return result; -} - -} - -#endif diff --git a/nall/string/filename.hpp b/nall/string/filename.hpp deleted file mode 100644 index d748a8ba..00000000 --- a/nall/string/filename.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -// "/foo/bar.c" -> "/foo/" -// "/foo/" -> "/foo/" -// "bar.c" -> "./" -string dir(string name) { - for(signed i = name.length(); i >= 0; i--) { - if(name[i] == '/' || name[i] == '\\') { - name.resize(i + 1); - break; - } - if(i == 0) name = "./"; - } - return name; -} - -// "/foo/bar.c" -> "bar.c" -// "/foo/" -> "" -// "bar.c" -> "bar.c" -string notdir(string name) { - for(signed i = name.length(); i >= 0; i--) { - if(name[i] == '/' || name[i] == '\\') { - return (const char*)name + i + 1; - } - } - return name; -} - -// "/foo/bar/baz" -> "/foo/bar/" -// "/foo/bar/" -> "/foo/" -// "/foo/bar" -> "/foo/" -string parentdir(string name) { - unsigned length = name.length(), paths = 0, prev, last; - for(unsigned i = 0; i < length; i++) { - if(name[i] == '/' || name[i] == '\\') { - paths++; - prev = last; - last = i; - } - } - if(last + 1 == length) last = prev; //if name ends in slash; use previous slash - if(paths > 1) name.resize(last + 1); - return name; -} - -// "/foo/bar.c" -> "/foo/bar" -string basename(string name) { - for(signed i = name.length(); i >= 0; i--) { - if(name[i] == '/' || name[i] == '\\') break; //file has no extension - if(name[i] == '.') { - name.resize(i); - break; - } - } - return name; -} - -// "/foo/bar.c" -> "c" -// "/foo/bar" -> "" -string extension(string name) { - for(signed i = name.length(); i >= 0; i--) { - if(name[i] == '/' || name[i] == '\\') return ""; //file has no extension - if(name[i] == '.') { - return (const char*)name + i + 1; - } - } - return name; -} - -string tempname() { - string path = temppath(); - srand(time(nullptr)); - while(true) { - uint32_t seed = rand(); - string filename = {path, ".temporary-", hex<8>(seed)}; - if(access(filename, F_OK) != 0) return filename; - } -} - -} - -#endif diff --git a/nall/string/find.hpp b/nall/string/find.hpp new file mode 100644 index 00000000..5886b3d3 --- /dev/null +++ b/nall/string/find.hpp @@ -0,0 +1,30 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +template auto _find(const string& self, signed offset, rstring source) -> maybe { + if(source.size() == 0) return nothing; + + const char* p = self.data(); + unsigned size = self.size(); + + for(unsigned n = offset, quoted = 0; n < size;) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(_compare(p + n, size - n, source.data(), source.size())) { n++; continue; } + return n - offset; + } + + return nothing; +} + +auto find(const string& self, rstring source) -> maybe { return _find<0, 0>(self, 0, source); } +auto ifind(const string& self, rstring source) -> maybe { return _find<1, 0>(self, 0, source); } +auto qfind(const string& self, rstring source) -> maybe { return _find<0, 1>(self, 0, source); } +auto iqfind(const string& self, rstring source) -> maybe { return _find<1, 1>(self, 0, source); } + +auto findFrom(const string& self, signed offset, rstring source) -> maybe { return _find<0, 0>(self, offset, source); } +auto ifindFrom(const string& self, signed offset, rstring source) -> maybe { return _find<1, 0>(self, offset, source); } + +} + +#endif diff --git a/nall/string/format.hpp b/nall/string/format.hpp index 98c0c5b7..827850c5 100644 --- a/nall/string/format.hpp +++ b/nall/string/format.hpp @@ -2,69 +2,176 @@ namespace nall { -template string format(const string& value) { - if(precision == 0) return value; +//nall::format is a vector of parameters that can be applied to a string +//each {#} token will be replaced with its appropriate format parameter - bool padright = precision >= 0; - unsigned padding = abs(precision); +auto string::format(const nall::format& params) -> type& { + signed size = this->size(); + char* data = (char*)memory::allocate(size); + memory::copy(data, this->data(), size); - if(padding <= value.size()) { - if(padright) return substr(value, value.size() - padding); - else return substr(value, 0, padding); + signed x = 0; + while(x < size - 2) { //2 = minimum tag length + if(data[x] != '{') { x++; continue; } + + signed y = x + 1; + while(y < size - 1) { //-1 avoids going out of bounds on test after this loop + if(data[y] != '}') { y++; continue; } + break; + } + + if(data[y++] != '}') { x++; continue; } + + static auto isNumeric = [](char* s, char* e) -> bool { + if(s == e) return false; //ignore empty tags: {} + while(s < e) { + if(*s >= '0' && *s <= '9') { s++; continue; } + return false; + } + return true; + }; + if(!isNumeric(&data[x + 1], &data[y - 1])) { x++; continue; } + + unsigned index = nall::decimal(&data[x + 1]); + if(index >= params.size()) { x++; continue; } + + unsigned sourceSize = y - x; + unsigned targetSize = params[index].size(); + unsigned remaining = size - x; + + if(sourceSize > targetSize) { + unsigned difference = sourceSize - targetSize; + memory::move(&data[x], &data[x + difference], remaining); + size -= difference; + } else if(targetSize > sourceSize) { + unsigned difference = targetSize - sourceSize; + data = (char*)realloc(data, size + difference); + size += difference; + memory::move(&data[x + difference], &data[x], remaining); + } + memory::copy(&data[x], params[index].data(), targetSize); + x += targetSize; } - string buffer; - buffer.resize(padding); - buffer.clear(padchar); + resize(size); + memory::copy(pointer(), data, size); + memory::free(data); + return *this; +} - memcpy(buffer.data() + (padright ? padding - value.size() : 0), value, value.size()); +template auto append(format& self, const T& value, P&&... p) -> format& { + self.vector::append(value); + append(self, std::forward

(p)...); +} + +auto append(format& self) -> format& { + return self; +} + +template auto print(P&&... p) -> void { + string s{std::forward

(p)...}; + fputs(s.data(), stdout); +} + +template auto integer(intmax_t value) -> string { + string buffer; + buffer.resize(1 + sizeof(intmax_t) * 3); + char* p = buffer.pointer(); + + bool negative = value < 0; + value = abs(value); + unsigned size = 0; + do { + p[size++] = '0' + (value % 10); + value /= 10; + } while(value); + if(negative) p[size++] = '-'; + buffer.resize(size); + buffer.reverse(); + if(precision) buffer.size(precision, padchar); return buffer; } -template string hex(uintmax_t value) { +template auto decimal(uintmax_t value) -> string { + string buffer; + buffer.resize(sizeof(uintmax_t) * 3); + char* p = buffer.pointer(); + + unsigned size = 0; + do { + p[size++] = '0' + (value % 10); + value /= 10; + } while(value); + buffer.resize(size); + buffer.reverse(); + if(precision) buffer.size(precision, padchar); + return buffer; +} + +template auto hex(uintmax_t value) -> string { string buffer; buffer.resize(sizeof(uintmax_t) * 2); + char* p = buffer.pointer(); unsigned size = 0; do { unsigned n = value & 15; - buffer[size++] = n < 10 ? '0' + n : 'a' + n - 10; + p[size++] = n < 10 ? '0' + n : 'a' + n - 10; value >>= 4; } while(value); buffer.resize(size); buffer.reverse(); - - return format(buffer); + if(precision) buffer.size(precision, padchar); + return buffer; } -template string octal(uintmax_t value) { +template auto octal(uintmax_t value) -> string { string buffer; buffer.resize(sizeof(uintmax_t) * 3); + char* p = buffer.pointer(); unsigned size = 0; do { - buffer[size++] = '0' + (value & 7); + p[size++] = '0' + (value & 7); value >>= 3; } while(value); buffer.resize(size); buffer.reverse(); - - return format(buffer); + if(precision) buffer.size(precision, padchar); + return buffer; } -template string binary(uintmax_t value) { +template auto binary(uintmax_t value) -> string { string buffer; buffer.resize(sizeof(uintmax_t) * 8); + char* p = buffer.pointer(); unsigned size = 0; do { - buffer[size++] = '0' + (value & 1); + p[size++] = '0' + (value & 1); value >>= 1; } while(value); buffer.resize(size); buffer.reverse(); + if(precision) buffer.size(precision, padchar); + return buffer; +} - return format(buffer); +template auto pointer(const T* value) -> string { + if(value == nullptr) return "(null)"; + return {"0x", hex((uintptr_t)value)}; +} + +template auto pointer(uintptr_t value) -> string { + if(value == 0) return "(null)"; + return {"0x", hex(value)}; +} + +auto real(long double value) -> string { + string temp; + temp.resize(real(nullptr, value)); + real(temp.pointer(), value); + return temp; } } diff --git a/nall/string/hash.hpp b/nall/string/hash.hpp new file mode 100644 index 00000000..98084ec4 --- /dev/null +++ b/nall/string/hash.hpp @@ -0,0 +1,35 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +namespace Hash { + auto CRC16::digest() -> string { + return hex<4>(value()); + } + + auto CRC32::digest() -> string { + return hex<8>(value()); + } + + auto SHA256::digest() const -> string { + string result; + for(auto n : value()) result.append(hex<2>(n)); + return result; + } +} + +auto crc16(const string& self) -> string { + return Hash::CRC16(self.data(), self.size()).digest(); +} + +auto crc32(const string& self) -> string { + return Hash::CRC32(self.data(), self.size()).digest(); +} + +auto sha256(const string& self) -> string { + return Hash::SHA256(self.data(), self.size()).digest(); +} + +} + +#endif diff --git a/nall/string/list.hpp b/nall/string/list.hpp index 55b2e76e..6b9f4f78 100644 --- a/nall/string/list.hpp +++ b/nall/string/list.hpp @@ -2,42 +2,7 @@ namespace nall { -maybe lstring::find(rstring key) const { - for(unsigned i = 0; i < size(); i++) { - if(operator[](i) == key) return i; - } - return nothing; -} - -string lstring::merge(const string& separator) const { - string output; - for(unsigned i = 0; i < size(); i++) { - output.append(operator[](i)); - if(i < size() - 1) output.append(separator); - } - return output; -} - -lstring& lstring::isort() { - nall::sort(pool, objectsize, [](const string& x, const string& y) { - return istrcmp(x, y) < 0; - }); - return *this; -} - -lstring& lstring::strip() { - for(unsigned n = 0; n < size(); n++) { - operator[](n).strip(); - } - return *this; -} - -template void lstring::append(const string& data, Args&&... args) { - vector::append(data); - append(std::forward(args)...); -} - -bool lstring::operator==(const lstring& source) const { +auto lstring::operator==(const lstring& source) const -> bool { if(this == &source) return true; if(size() != source.size()) return false; for(unsigned n = 0; n < size(); n++) { @@ -46,39 +11,55 @@ bool lstring::operator==(const lstring& source) const { return true; } -bool lstring::operator!=(const lstring& source) const { +auto lstring::operator!=(const lstring& source) const -> bool { return !operator==(source); } -lstring& lstring::operator=(const lstring& source) { - vector::operator=(source); +auto lstring::isort() -> lstring& { + nall::sort(pool, objectsize, [](const string& x, const string& y) { + return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0; + }); return *this; } -lstring& lstring::operator=(lstring& source) { - vector::operator=(source); - return *this; +template auto append(lstring& self, const string& data, P&&... p) -> lstring& { + self.vector::append(data); + append(self, std::forward

(p)...); + return self; } -lstring& lstring::operator=(lstring&& source) { - vector::operator=(std::move(source)); - return *this; +auto append(lstring& self) -> lstring& { + return self; } -template lstring::lstring(Args&&... args) { - append(std::forward(args)...); +auto find(const lstring& self, const string& source) -> maybe { + for(unsigned n = 0; n < self.size(); n++) { + if(self[n].equals(source)) return n; + } + return nothing; } -lstring::lstring(const lstring& source) { - vector::operator=(source); +auto ifind(const lstring& self, const string& source) -> maybe { + for(unsigned n = 0; n < self.size(); n++) { + if(self[n].iequals(source)) return n; + } + return nothing; } -lstring::lstring(lstring& source) { - vector::operator=(source); +auto merge(const lstring& self, const string& separator) -> string { + string output; + for(unsigned n = 0; n < self.size(); n++) { + output.append(self[n]); + if(n < self.size() - 1) output.append(separator); + } + return output; } -lstring::lstring(lstring&& source) { - vector::operator=(std::move(source)); +auto strip(lstring& self) -> lstring& { + for(unsigned n = 0; n < self.size(); n++) { + self[n].strip(); + } + return self; } } diff --git a/nall/string/markup/bml.hpp b/nall/string/markup/bml.hpp index 6743a80e..7f5e8252 100644 --- a/nall/string/markup/bml.hpp +++ b/nall/string/markup/bml.hpp @@ -71,7 +71,7 @@ protected: if(length == 0) throw "Invalid attribute name"; node.name = substr(p, 0, length); node.parseData(p += length); - node.data.rtrim<1>("\n"); + node.data.rtrim("\n"); children.append(node); } } @@ -98,7 +98,7 @@ protected: children.append(node); } - data.rtrim<1>("\n"); + data.rtrim("\n"); } //read top-level nodes diff --git a/nall/string/markup/node.hpp b/nall/string/markup/node.hpp index ff7ea3d6..fbf2ae46 100644 --- a/nall/string/markup/node.hpp +++ b/nall/string/markup/node.hpp @@ -20,6 +20,10 @@ struct Node { return string{data}.strip(); } + bool boolean() const { + return text() != "false"; + } + intmax_t integer() const { return numeral(text()); } @@ -93,7 +97,7 @@ struct Node { if(name.match("*[*]")) { lstring side = name.split<1>("["); name = side(0); - side = side(1).rtrim<1>("]").split<1>("-"); + side = side(1).rtrim("]").split<1>("-"); lo = side(0).empty() ? 0u : numeral(side(0)); hi = side(1).empty() ? ~0u : numeral(side(1)); } @@ -101,7 +105,7 @@ struct Node { if(name.match("*(*)")) { lstring side = name.split<1>("("); name = side(0); - rule = side(1).rtrim<1>(")"); + rule = side(1).rtrim(")"); } unsigned position = 0; diff --git a/nall/string/markup/xml.hpp b/nall/string/markup/xml.hpp index 6debcc37..fd9fe787 100644 --- a/nall/string/markup/xml.hpp +++ b/nall/string/markup/xml.hpp @@ -39,34 +39,34 @@ protected: target.reserve(length + 1); #if defined(NALL_XML_LITERAL) - memcpy(target(), source, length); + memory::copy(target.pointer(), source, length); target[length] = 0; return; #endif - char* output = target.data(); + char* output = target.pointer(); while(length) { if(*source == '&') { - if(!memcmp(source, "<", 4)) { *output++ = '<'; source += 4; length -= 4; continue; } - if(!memcmp(source, ">", 4)) { *output++ = '>'; source += 4; length -= 4; continue; } - if(!memcmp(source, "&", 5)) { *output++ = '&'; source += 5; length -= 5; continue; } - if(!memcmp(source, "'", 6)) { *output++ = '\''; source += 6; length -= 6; continue; } - if(!memcmp(source, """, 6)) { *output++ = '\"'; source += 6; length -= 6; continue; } + if(!memory::compare(source, "<", 4)) { *output++ = '<'; source += 4; length -= 4; continue; } + if(!memory::compare(source, ">", 4)) { *output++ = '>'; source += 4; length -= 4; continue; } + if(!memory::compare(source, "&", 5)) { *output++ = '&'; source += 5; length -= 5; continue; } + if(!memory::compare(source, "'", 6)) { *output++ = '\''; source += 6; length -= 6; continue; } + if(!memory::compare(source, """, 6)) { *output++ = '\"'; source += 6; length -= 6; continue; } } if(attribute == false && source[0] == '<' && source[1] == '!') { //comment - if(!memcmp(source, "", 3)) source++, length--; + while(memory::compare(source, "-->", 3)) source++, length--; source += 3, length -= 3; continue; } //CDATA - if(!memcmp(source, "", 3)) *output++ = *source++, length--; + while(memory::compare(source, "]]>", 3)) *output++ = *source++, length--; source += 3, length -= 3; continue; } @@ -81,23 +81,23 @@ protected: if(*(p + 1) != '!') return false; //comment - if(!memcmp(p, "", 3)) p++; + if(!memory::compare(p, "", 3)) p++; if(!*p) throw "unclosed comment"; p += 3; return true; } //CDATA - if(!memcmp(p, "", 3)) p++; + if(!memory::compare(p, "", 3)) p++; if(!*p) throw "unclosed CDATA"; p += 3; return true; } //DOCTYPE - if(!memcmp(p, "') p++; if(*p != '>') throw "unclosed closure element"; const char* nameEnd = p++; - if(memcmp(name, nameStart, nameEnd - nameStart)) throw "closure element name mismatch"; + if(memory::compare(name.data(), nameStart, nameEnd - nameStart)) throw "closure element name mismatch"; return true; } diff --git a/nall/string/char/match.hpp b/nall/string/match.hpp similarity index 55% rename from nall/string/char/match.hpp rename to nall/string/match.hpp index 2471d1ce..3cff8b8a 100644 --- a/nall/string/char/match.hpp +++ b/nall/string/match.hpp @@ -2,7 +2,12 @@ namespace nall { -bool strmatch(const char* s, const char* p) { +//todo: these functions are not binary-safe + +auto match(const string& self, rstring source) -> bool { + const char* s = self.data(); + const char* p = source.data(); + const char* cp = nullptr; const char* mp = nullptr; while(*s && *p != '*') { @@ -23,7 +28,14 @@ bool strmatch(const char* s, const char* p) { return !*p; } -bool istrmatch(const char* s, const char* p) { +auto imatch(const string& self, rstring source) -> bool { + static auto chrlower = [](char c) -> char { + return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; + }; + + const char* s = self.data(); + const char* p = source.data(); + const char* cp = nullptr; const char* mp = nullptr; while(*s && *p != '*') { @@ -44,7 +56,7 @@ bool istrmatch(const char* s, const char* p) { return !*p; } -bool tokenize(const char* s, const char* p) { +inline bool tokenize(const char* s, const char* p) { while(*s) { if(*p == '*') { while(*s) if(tokenize(s++, p + 1)) return true; @@ -56,6 +68,25 @@ bool tokenize(const char* s, const char* p) { return !*p; } +auto tokenize(lstring& list, const char* s, const char* p) -> bool { + while(*s) { + if(*p == '*') { + const char* b = s; + while(*s) { + if(tokenize(list, s++, p + 1)) { + list.prepend(substr(b, 0, --s - b)); + return true; + } + } + list.prepend(b); + return !*++p; + } + if(*s++ != *p++) return false; + } + while(*p == '*') { list.prepend(s); p++; } + return !*p; +} + } #endif diff --git a/nall/string/path.hpp b/nall/string/path.hpp new file mode 100644 index 00000000..5ef4b7be --- /dev/null +++ b/nall/string/path.hpp @@ -0,0 +1,73 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +// (/parent/child.type/) +// (/parent/child.type/)name.type +auto pathname(const string& self) -> string { + const char* p = self.data() + self.size() - 1; + for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/') return slice(self, 0, offset + 1); + } + return ""; +} + +// /parent/child.type/() +// /parent/child.type/(name.type) +auto filename(const string& self) -> string { + const char* p = self.data() + self.size() - 1; + for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/') return slice(self, offset + 1); + } + return ""; +} + +// (/parent/)child.type/ +// (/parent/child.type/)name.type +auto dirname(const string& self) -> string { + const char* p = self.data() + self.size() - 1, *last = p; + for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/' && p == last) continue; + if(*p == '/') return slice(self, 0, offset + 1); + } + return self; //this is the root directory +} + +// /parent/(child.type/) +// /parent/child.type/(name.type) +auto basename(const string& self) -> string { + const char* p = self.data() + self.size() - 1, *last = p; + for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/' && p == last) continue; + if(*p == '/') return slice(self, offset + 1); + } + return ""; +} + +// /parent/(child).type/ +// /parent/child.type/(name).type +auto prefixname(const string& self) -> string { + const char* p = self.data() + self.size() - 1, *last = p; + for(signed offset = self.size() - 1, suffix = 0; offset >= 0; offset--, p--) { + if(*p == '/' && p == last) continue; + if(*p == '/') return slice(self, offset + 1, suffix ? suffix - offset - 1 : 0).rtrim("/"); + if(*p == '.' && suffix == 0) suffix = offset; + } + return ""; +} + +// /parent/child(.type)/ +// /parent/child.type/name(.type) +auto suffixname(const string& self) -> string { + const char* p = self.data() + self.size() - 1, *last = p; + for(signed offset = self.size() - 1; offset >= 0; offset--, p--) { + if(*p == '/' && p == last) continue; + if(*p == '/') break; + if(*p == '.') return slice(self, offset).rtrim("/"); + } + return ""; +} + +} + +#endif diff --git a/nall/string/platform.hpp b/nall/string/platform.hpp index d80060f3..f78de306 100644 --- a/nall/string/platform.hpp +++ b/nall/string/platform.hpp @@ -2,7 +2,7 @@ namespace nall { -string activepath() { +auto activepath() -> string { char path[PATH_MAX] = ""; auto unused = getcwd(path, PATH_MAX); string result = path; @@ -12,17 +12,17 @@ string activepath() { return result; } -string realpath(const string& name) { +auto realpath(rstring name) -> string { string result; char path[PATH_MAX] = ""; - if(::realpath(name, path)) result = dir(path); + if(::realpath(name, path)) result = string{path}.pathname(); if(result.empty()) result = activepath(); result.transform("\\", "/"); if(result.endsWith("/") == false) result.append("/"); return result; } -string programpath() { +auto programpath() -> string { #if defined(PLATFORM_WINDOWS) int argc = 0; wchar_t** argv = CommandLineToArgvW(GetCommandLine(), &argc); @@ -38,7 +38,7 @@ string programpath() { // /home/username/ // c:/users/username/ -string userpath() { +auto userpath() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_PROFILE | CSIDL_FLAG_CREATE, nullptr, 0, path); @@ -55,7 +55,7 @@ string userpath() { // /home/username/.config/ // c:/users/username/appdata/roaming/ -string configpath() { +auto configpath() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); @@ -74,7 +74,7 @@ string configpath() { // /usr/share // /Library/Application Support/ // c:/ProgramData/ -string sharedpath() { +auto sharedpath() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); @@ -92,7 +92,7 @@ string sharedpath() { // /tmp // c:/users/username/AppData/Local/Temp/ -string temppath() { +auto temppath() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; GetTempPathW(PATH_MAX, path); diff --git a/nall/string/ref.hpp b/nall/string/ref.hpp index 19200891..2c07dbbb 100644 --- a/nall/string/ref.hpp +++ b/nall/string/ref.hpp @@ -7,37 +7,54 @@ struct stringref { return _data; } - const char* data() const { + auto data() const -> const char* { return _data; } - unsigned size() const { - if(!_initialized) { - _initialized = true; - _size = strlen(_data); - } + auto size() const -> unsigned { + if(!_initialized) _size = strlen(_data), _initialized = true; return _size; } - stringref() = delete; - stringref(const stringref& source) = delete; - stringref(stringref&& source) = delete; + stringref() { + _string = nullptr; + _data = ""; + _size = 0; + _initialized = true; + } stringref(const char* source) { + _string = nullptr; _data = source; _initialized = false; } stringref(const string& source) { + _string = nullptr; _data = source.data(); _size = source.size(); _initialized = true; } + template stringref(P&&... p) { + _string = new string{std::forward

(p)...}; + _data = _string->data(); + _size = _string->size(); + _initialized = true; + } + + ~stringref() { + if(_string) delete _string; + } + + stringref(const stringref& source) = delete; + stringref(stringref&& source) = delete; + protected: + string* _string; const char* _data; - mutable unsigned _size; - mutable bool _initialized; + mutable signed _size; + mutable unsigned _initialized; }; } diff --git a/nall/string/replace.hpp b/nall/string/replace.hpp index 65af7be3..f27b06ad 100644 --- a/nall/string/replace.hpp +++ b/nall/string/replace.hpp @@ -3,52 +3,93 @@ namespace nall { template -string& string::ureplace(rstring key, rstring token) { - if(key.size() == 0) return *this; - enum : unsigned { limit = Limit ? Limit : ~0u }; +auto _replace(string& self, rstring from, rstring to) -> string& { + if(Limit == 0 || from.size() == 0) return self; - const char* p = data(); - unsigned counter = 0; + signed size = self.size(); + signed matches = 0; + signed quoted = 0; - while(*p) { - if(quoteskip(p)) continue; - for(unsigned n = 0;; n++) { - if(key[n] == 0) { counter++; p += n; break; } - if(!chrequal(key[n], p[n])) { p++; break; } + //count matches first, so that we only need to reallocate memory once + //(recording matches would also require memory allocation, so this is not done) + { const char* p = self.data(); + for(signed n = 0; n <= size - (signed)from.size();) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(_compare(p + n, size - n, from.data(), from.size())) { n++; continue; } + + if(++matches >= Limit) break; + n += from.size(); } } - if(counter == 0) return *this; - if(Limit) counter = min(counter, Limit); + if(matches == 0) return self; - char* t = data(); - char* base = nullptr; - signed displacement = token.size() - key.size(); - signed displacementSize = displacement * counter; + //in-place overwrite + if(to.size() == from.size()) { + char* p = self.pointer(); - if(token.size() > key.size()) { - t = base = strduplicate(data()); - reserve((unsigned)(p - data()) + displacementSize); - } - char* o = data(); + for(signed n = 0, remaining = matches, quoted = 0; n <= size - (signed)from.size();) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(_compare(p + n, size - n, from.data(), from.size())) { n++; continue; } - while(*t && counter) { - if(quotecopy(o, t)) continue; - for(unsigned n = 0;; n++) { - if(key[n] == 0) { counter--; memcpy(o, token, token.size()); t += key.size(); o += token.size(); break; } - if(!chrequal(key[n], t[n])) { *o++ = *t++; break; } + memory::copy(p + n, to.data(), to.size()); + + if(!--remaining) break; + n += from.size(); } } - do *o++ = *t; while(*t++); - if(base) free(base); - resize(_size + displacementSize); - return *this; + //left-to-right shrink + else if(to.size() < from.size()) { + char* p = self.pointer(); + signed offset = 0; + signed base = 0; + + for(signed n = 0, remaining = matches, quoted = 0; n <= size - (signed)from.size();) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(_compare(p + n, size - n, from.data(), from.size())) { n++; continue; } + + if(offset) memory::move(p + offset, p + base, n - base); + memory::copy(p + offset + (n - base), to.data(), to.size()); + offset += (n - base) + to.size(); + + n += from.size(); + base = n; + if(!--remaining) break; + } + + memory::move(p + offset, p + base, size - base); + self.resize(size - matches * (from.size() - to.size())); + } + + //right-to-left expand + else if(to.size() > from.size()) { + self.resize(size + matches * (to.size() - from.size())); + char* p = self.pointer(); + + signed offset = self.size(); + signed base = size; + + for(signed n = size, remaining = matches; n >= (signed)from.size();) { //quoted reused from parent scope since we are iterating backward + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n--; continue; } if(quoted) { n--; continue; } } + if(_compare(p + n - from.size(), size - n + from.size(), from.data(), from.size())) { n--; continue; } + + memory::move(p + offset - (base - n), p + base - (base - n), base - n); + memory::copy(p + offset - (base - n) - to.size(), to.data(), to.size()); + offset -= (base - n) + to.size(); + + if(!--remaining) break; + n -= from.size(); + base = n; + } + } + + return self; } -template string& string::replace(rstring key, rstring token) { return ureplace(key, token); } -template string& string::ireplace(rstring key, rstring token) { return ureplace(key, token); } -template string& string::qreplace(rstring key, rstring token) { return ureplace(key, token); } -template string& string::iqreplace(rstring key, rstring token) { return ureplace(key, token); } +template auto replace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } +template auto ireplace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } +template auto qreplace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } +template auto iqreplace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } }; diff --git a/nall/string/split.hpp b/nall/string/split.hpp index 90521e1f..f5c5e516 100644 --- a/nall/string/split.hpp +++ b/nall/string/split.hpp @@ -2,36 +2,46 @@ namespace nall { -template lstring& lstring::usplit(rstring key, rstring base) { - reset(); - if(key.size() == 0) return *this; +template auto _split(lstring& self, rstring source, rstring find) -> lstring& { + self.reset(); + if(find.size() == 0) return self; - const char* b = base; - const char* p = base; + const char* p = source.data(); + signed size = source.size(); + signed base = 0; + signed matches = 0; - while(*p) { - if(Limit) if(size() >= Limit) break; - if(quoteskip(p)) continue; - for(unsigned n = 0;; n++) { - if(key[n] == 0) { - append(substr(b, 0, p - b)); - p += n; - b = p; - break; - } - if(!chrequal(key[n], p[n])) { p++; break; } - } + for(signed n = 0, quoted = 0; n <= size - (signed)find.size();) { + if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } + if(_compare(p + n, size - n, find.data(), find.size())) { n++; continue; } + if(matches >= Limit) break; + + string& s = self(matches); + s.resize(n - base); + memory::copy(s.pointer(), p + base, n - base); + + n += find.size(); + base = n; + matches++; } - append(b); - return *this; + string& s = self(matches); + s.resize(size - base); + memory::copy(s.pointer(), p + base, size - base); + + return self; } -template lstring& lstring::split(rstring key, rstring src) { return usplit(key, src); } -template lstring& lstring::isplit(rstring key, rstring src) { return usplit(key, src); } -template lstring& lstring::qsplit(rstring key, rstring src) { return usplit(key, src); } -template lstring& lstring::iqsplit(rstring key, rstring src) { return usplit(key, src); } +template auto split(string& self, rstring on) -> lstring { return lstring().split(self, on); } +template auto isplit(string& self, rstring on) -> lstring { return lstring().isplit(self, on); } +template auto qsplit(string& self, rstring on) -> lstring { return lstring().qsplit(self, on); } +template auto iqsplit(string& self, rstring on) -> lstring { return lstring().iqsplit(self, on); } -}; +template auto string::split(rstring on) const -> lstring { return lstring().split(*this, on); } +template auto string::isplit(rstring on) const -> lstring { return lstring().isplit(*this, on); } +template auto string::qsplit(rstring on) const -> lstring { return lstring().qsplit(*this, on); } +template auto string::iqsplit(rstring on) const -> lstring { return lstring().iqsplit(*this, on); } + +} #endif diff --git a/nall/string/transform/cml.hpp b/nall/string/transform/cml.hpp new file mode 100644 index 00000000..17a1b266 --- /dev/null +++ b/nall/string/transform/cml.hpp @@ -0,0 +1,93 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +/* CSS Markup Language (CML) v1.0 parser + * revision 0.01 + */ + +namespace nall { namespace { + +struct CML { + CML(const string& filedata, const string& pathname); + CML(const string& filename); + auto output() -> string; + +private: + struct State { + string output; + } state; + + struct Variable { + string name; + string value; + }; + vector variables; + + auto parse(const string& filedata, const string& pathname) -> bool; +}; + +CML::CML(const string& filedata, const string& pathname) { + parse(filedata, pathname); +} + +CML::CML(const string& filename) { + parse(string::read(filename), filename.pathname()); +} + +auto CML::output() -> string { + return state.output; +} + +auto CML::parse(const string& filedata, const string& pathname) -> bool { + auto vendorAppend = [&](const string& name, const string& value) { + state.output.append(" -moz-", name, ": ", value, ";\n"); + state.output.append(" -webkit-", name, ": ", value, ";\n"); + }; + + for(auto& block : filedata.split("\n\n")) { + lstring lines = block.rstrip().split("\n"); + string name = lines.takeFirst(); + + if(ltrim(name, "include ")) { + string filename{pathname, name}; + parse(string::read(filename), filename.pathname()); + continue; + } + + if(name == "variables") { + for(auto& line : lines) { + auto data = line.split<1>(":").strip(); + variables.append({data(0), data(1)}); + } + continue; + } + + state.output.append(name, " {\n"); + for(auto& line : lines) { + auto data = line.split<1>(":").strip(); + auto name = data(0), value = data(1); + while(auto offset = value.find("var(")) { + bool found = false; + if(auto length = value.findFrom(*offset, ")")) { + string name = value.slice(*offset + 4, *length - 4); + for(auto& variable : variables) { + if(variable.name == name) { + value = {value.slice(0, *offset), variable.value, value.slice(*offset + *length + 1)}; + found = true; + break; + } + } + } + if(!found) break; + } + state.output.append(" ", name, ": ", value, ";\n"); + if(name == "box-sizing") vendorAppend(name, value); + } + state.output.append("}\n\n"); + } + + return true; +} + +}} + +#endif diff --git a/nall/string/transform/dml.hpp b/nall/string/transform/dml.hpp new file mode 100644 index 00000000..0c5e94d5 --- /dev/null +++ b/nall/string/transform/dml.hpp @@ -0,0 +1,259 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +/* Document Markup Language (DML) v1.0 parser + * revision 0.01 + */ + +namespace nall { namespace { + +struct DML { + struct Settings { + bool allowHTML = true; + bool sectioned = true; + } settings; + + DML(const string& filedata, const string& pathname); + DML(const string& filename); + auto output() -> string; + +private: + struct State { + string output; + unsigned sections = 0; + } state; + + auto parse(const string& filedata, const string& pathname) -> bool; + auto parseBlock(string& block, const string& pathname) -> bool; + auto count(const string& text, char value) -> unsigned; + auto escape(const string& text) -> string; + auto markup(const string& text) -> string; +}; + +DML::DML(const string& filedata, const string& pathname) { + parse(filedata, pathname); +} + +DML::DML(const string& filename) { + parse(string::read(filename), filename.pathname()); +} + +auto DML::output() -> string { + return state.output; +} + +auto DML::parse(const string& filedata, const string& pathname) -> bool { + auto blocks = filedata.split("\n\n"); + for(auto& block : blocks) parseBlock(block, pathname); + if(settings.sectioned && state.sections) state.output.append("\n"); + return true; +} + +auto DML::parseBlock(string& block, const string& pathname) -> bool { + if(block.rstrip().empty()) return true; + auto lines = block.split("\n"); + + //include + if(block.beginsWith("{{include}}")) { + string filename{pathname, block.ltrim("{{include}}").strip()}; + parse(string::read(filename), filename.pathname()); + } + + //html + else if(ltrim(block, "{{html}}") && settings.allowHTML) { + auto data = lines.takeFirst(); + if(ltrim(data, "{{html}} ")) state.output.append(data, "\n"); + for(auto& line : lines) { + if(ltrim(line, " ")) state.output.append(line, "\n"); + } + } + + //header + else if(block.beginsWith("# ")) { + if(settings.sectioned) { + if(state.sections++) state.output.append(""); + state.output.append("

"); + } + auto content = lines.takeFirst().ltrim("# ").split<1>(" => "); + auto data = markup(content[0]); + auto name = escape(content(1, data.crc32())); + state.output.append("
", data); + for(auto& line : lines) { + if(!line.beginsWith("# ")) continue; + state.output.append("", line.ltrim("# "), ""); + } + state.output.append("
\n"); + } + + //subheader + else if(auto depth = count(block, '=')) { + auto content = lines.takeFirst().slice(depth + 1).split<1>(" => "); + auto data = markup(content[0]); + auto name = escape(content(1, data.crc32())); + if(depth <= 6) { + state.output.append("", data); + for(auto& line : lines) { + if(count(line, '=') != depth) continue; + state.output.append("", line.slice(depth + 1), ""); + } + state.output.append("\n"); + } + } + + //contents + else if(count(block, '-')) { + state.output.append("\n"); + } + + //list + else if(count(block, '*')) { + unsigned level = 0; + for(auto& line : lines) { + if(auto depth = count(line, '*')) { + while(level < depth) level++, state.output.append("
    \n"); + while(level > depth) level--, state.output.append("
\n"); + auto data = markup(line.slice(depth + 1)); + state.output.append("
  • ", data, "
  • \n"); + } + } + while(level--) state.output.append("\n"); + } + + //quote + else if(count(block, '>')) { + unsigned level = 0; + for(auto& line : lines) { + if(auto depth = count(line, '>')) { + while(level < depth) level++, state.output.append("
    \n"); + while(level > depth) level--, state.output.append("
    \n"); + auto data = markup(line.slice(depth + 1)); + state.output.append(data, "\n"); + } + } + while(level--) state.output.append("\n"); + } + + //code + else if(block.beginsWith(" ")) { + state.output.append("
    ");
    +    for(auto& line : lines) {
    +      if(!ltrim(line, "  ")) continue;
    +      state.output.append(escape(line), "\n");
    +    }
    +    state.output.rtrim("\n").append("
    \n"); + } + + //divider + else if(block.equals("---")) { + state.output.append("
    \n"); + } + + //paragraph + else { + state.output.append("

    ", markup(block), "

    \n"); + } + + return true; +} + +auto DML::count(const string& text, char value) -> unsigned { + for(unsigned n = 0; n < text.size(); n++) { + if(text[n] != value) { + if(text[n] == ' ') return n; + break; + } + } + return 0; +} + +auto DML::escape(const string& text) -> string { + string output; + for(unsigned n = 0; n < text.size();) { + char x = text[n++]; + if(x == '&') { output.append("&"); continue; } + if(x == '<') { output.append("<"); continue; } + if(x == '>') { output.append(">"); continue; } + if(x == '"') { output.append("""); continue; } + output.append(x); + } + return output; +} + +auto DML::markup(const string& text) -> string { + string output; + char flagStrong = 0; + char flagEmphasis = 0; + char flagInsert = 0; + char flagDelete = 0; + char flagCode = 0; + + for(unsigned n = 0; n < text.size();) { + char x = text[n], y = text[n + 1]; + + if(x == '[' && y == '\\') { output.append('['); n += 2; continue; } + + if(x == '[' && y == '*' && flagStrong == 0) { flagStrong = 1; output.append(""); n += 2; continue; } + if(x == '*' && y == ']' && flagStrong == 1) { flagStrong = 0; output.append(""); n += 2; continue; } + + if(x == '[' && y == '/' && flagEmphasis == 0) { flagEmphasis = 1; output.append(""); n += 2; continue; } + if(x == '/' && y == ']' && flagEmphasis == 1) { flagEmphasis = 0; output.append(""); n += 2; continue; } + + if(x == '[' && y == '_' && flagInsert == 0) { flagInsert = 1; output.append(""); n += 2; continue; } + if(x == '_' && y == ']' && flagInsert == 1) { flagInsert = 0; output.append(""); n += 2; continue; } + + if(x == '[' && y == '-' && flagDelete == 0) { flagDelete = 1; output.append(""); n += 2; continue; } + if(x == '-' && y == ']' && flagDelete == 1) { flagDelete = 0; output.append(""); n += 2; continue; } + + if(x == '[' && y == '|' && flagCode == 0) { flagCode = 1; output.append(""); n += 2; continue; } + if(x == '|' && y == ']' && flagCode == 1) { flagCode = 0; output.append(""); n += 2; continue; } + + if(x == '[' && y == '[') { + if(auto length = text.findFrom(n + 2, "]]")) { + lstring content = text.slice(n + 2, *length).split<1>(" => "); + output.append("", escape(content(1, content[0])), ""); + n += *length + 4; + continue; + } + } + + if(x == '[' && y == '{') { + if(auto length = text.findFrom(n + 2, "}]")) { + lstring content = text.slice(n + 2, *length).split<1>(" => "); + output.append("\"","); + n += *length + 4; + continue; + } + } + + if(x == '&') { output.append("&"); n++; continue; } + if(x == '<') { output.append("<"); n++; continue; } + if(x == '>') { output.append(">"); n++; continue; } + if(x == '"') { output.append("""); n++; continue; } + + output.append(x); + n++; + } + + if(flagStrong) output.append(""); + if(flagEmphasis) output.append(""); + if(flagInsert) output.append(""); + if(flagDelete) output.append(""); + if(flagCode) output.append(""); + return output; +} + +}} + +#endif diff --git a/nall/string/trim.hpp b/nall/string/trim.hpp new file mode 100644 index 00000000..5aaff55d --- /dev/null +++ b/nall/string/trim.hpp @@ -0,0 +1,82 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +auto trim(string& self, rstring lhs, rstring rhs) -> bool { + if(lhs.size() + rhs.size() > self.size()) return false; + if(memory::compare(self.data(), lhs.data(), lhs.size()) != 0) return false; + if(memory::compare(self.data() + self.size() - rhs.size(), rhs.data(), rhs.size()) != 0) return false; + self.resize(self.size() - rhs.size()); + self.remove(0, lhs.size()); + return true; +} + +auto ltrim(string& self, rstring lhs) -> bool { + if(lhs.size() > self.size()) return false; + if(memory::compare(self.data(), lhs.data(), lhs.size()) != 0) return false; + self.remove(0, lhs.size()); + return true; +} + +auto rtrim(string& self, rstring rhs) -> bool { + if(rhs.size() > self.size()) return false; + if(memory::compare(self.data() + self.size() - rhs.size(), rhs.data(), rhs.size()) != 0) return false; + self.resize(self.size() - rhs.size()); + return true; +} + +auto itrim(string& self, rstring lhs, rstring rhs) -> bool { + if(lhs.size() + rhs.size() > self.size()) return false; + if(memory::icompare(self.data(), lhs.data(), lhs.size()) != 0) return false; + if(memory::icompare(self.data() + self.size() - rhs.size(), rhs.data(), rhs.size()) != 0) return false; + self.resize(self.size() - rhs.size()); + self.remove(0, lhs.size()); + return true; +} + +auto iltrim(string& self, rstring lhs) -> bool { + if(lhs.size() > self.size()) return false; + if(memory::icompare(self.data(), lhs.data(), lhs.size()) != 0) return false; + self.remove(0, lhs.size()); + return true; +} + +auto irtrim(string& self, rstring rhs) -> bool { + if(rhs.size() > self.size()) return false; + if(memory::icompare(self.data() + self.size() - rhs.size(), rhs.data(), rhs.size()) != 0) return false; + self.resize(self.size() - rhs.size()); + return true; +} + +auto strip(string& self) -> bool { + return rstrip(self) | lstrip(self); +} + +auto lstrip(string& self) -> bool { + unsigned size = 0; + while(size < self.size()) { + char input = self[size]; + if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break; + size++; + } + if(size == 0) return false; + self.remove(0, size); + return true; +} + +auto rstrip(string& self) -> bool { + unsigned size = 0; + while(size < self.size()) { + bool matched = false; + char input = self[self.size() - size - 1]; + if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break; + size++; + } + if(size == 0) return false; + self.resize(self.size() - size); + return true; +} + +} + +#endif diff --git a/nall/string/utility.hpp b/nall/string/utility.hpp index 429636cd..e4f01107 100644 --- a/nall/string/utility.hpp +++ b/nall/string/utility.hpp @@ -2,46 +2,107 @@ namespace nall { -string substr(rstring source, unsigned offset, unsigned length) { +auto string::read(const string& filename) -> string { + #if !defined(_WIN32) + FILE* fp = fopen(filename, "rb"); + #else + FILE* fp = _wfopen(utf16_t(filename), L"rb"); + #endif + string result; - if(length == ~0u) length = source.size() - offset; - result.resize(length); - memcpy(result.data(), source.data() + offset, length); + if(!fp) return result; + + fseek(fp, 0, SEEK_END); + signed filesize = ftell(fp); + if(filesize < 0) return fclose(fp), result; + + rewind(fp); + result.resize(filesize); + fread(result.pointer(), 1, filesize, fp); + return fclose(fp), result; +} + +template auto string::repeat(const string& pattern) -> string { + string result; + unsigned times = L; + while(times--) result.append(pattern); return result; } -string sha256(const uint8_t* data, unsigned size) { - sha256_ctx sha; - uint8_t hash[32]; - sha256_init(&sha); - sha256_chunk(&sha, data, size); - sha256_final(&sha); - sha256_hash(&sha, hash); - string result; - for(auto& byte : hash) result.append(hex<2>(byte)); +auto fill(string& self, char fill) -> string& { + memory::fill(self.pointer(), self.size(), fill); + return self; +} + +auto hash(const string& self) -> unsigned { + const char* p = self.data(); + unsigned size = self.size(); + unsigned result = 5381; + while(size--) result = (result << 5) + result + *p++; return result; } -bool tokenize(lstring& list, const char* s, const char* p) { - while(*s) { - if(*p == '*') { - const char* b = s; - while(*s) { - if(tokenize(list, s++, p + 1)) { - list.prepend(substr(b, 0, --s - b)); - return true; - } - } - list.prepend(b); - return !*++p; - } - if(*s++ != *p++) return false; +auto remove(string& self, unsigned offset, unsigned length) -> string& { + char* p = self.pointer(); + length = min(length, self.size()); + memory::move(p + offset, p + offset + length, self.size() - length); + return self.resize(self.size() - length); +} + +auto reverse(string& self) -> string& { + char* p = self.pointer(); + unsigned size = self.size(); + unsigned pivot = size >> 1; + for(signed x = 0, y = size - 1; x < pivot && y >= 0; x++, y--) std::swap(p[x], p[y]); + return self; +} + +//+length => insert/delete from start (right justify) +//-length => insert/delete from end (left justify) +auto size(string& self, signed length, char fill) -> string& { + unsigned size = self.size(); + if(size == length) return self; + + bool right = length >= 0; + length = abs(length); + + if(size < length) { //expand + self.resize(length); + char* p = self.pointer(); + unsigned displacement = length - size; + if(right) memory::move(p + displacement, p, size); + else p += size; + while(displacement--) *p++ = fill; + } else { //shrink + char* p = self.pointer(); + unsigned displacement = size - length; + if(right) memory::move(p, p + displacement, length); + self.resize(length); } - while(*p == '*') { list.prepend(s); p++; } - return !*p; + + return self; } -char* integer(char* result, intmax_t value) { +auto slice(const string& self, signed offset, signed length) -> string { + string result; + if(offset < self.size()) { + if(length < 0) length = self.size() - offset; + result.resize(length); + memory::copy(result.pointer(), self.data() + offset, length); + } + return result; +} + +//legacy function: required for some library functions, do not use in newly written code +auto substr(rstring source, signed offset, signed length) -> string { + string result; + if(length < 0) length = source.size() - offset; + result.resize(length); + memory::copy(result.pointer(), source.data() + offset, length); + return result; +} + +auto integer(char* result, intmax_t value) -> char* { bool negative = value < 0; if(negative) value = -value; @@ -54,14 +115,13 @@ char* integer(char* result, intmax_t value) { value /= 10; } while(value); if(negative) buffer[size++] = '-'; -//buffer[size++] = negative ? '-' : '+'; for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y]; result[size] = 0; return result; } -char* decimal(char* result, uintmax_t value) { +auto decimal(char* result, uintmax_t value) -> char* { char buffer[64]; unsigned size = 0; @@ -79,7 +139,7 @@ char* decimal(char* result, uintmax_t value) { //using sprintf is certainly not the most ideal method to convert //a double to a string ... but attempting to parse a double by //hand, digit-by-digit, results in subtle rounding errors. -unsigned real(char* str, long double value) { +auto real(char* result, long double value) -> unsigned { char buffer[256]; #ifdef _WIN32 //Windows C-runtime does not support long double via sprintf() @@ -101,17 +161,10 @@ unsigned real(char* str, long double value) { } unsigned length = strlen(buffer); - if(str) strcpy(str, buffer); + if(result) strcpy(result, buffer); return length + 1; } -string real(long double value) { - string temp; - temp.resize(real(nullptr, value)); - real(temp.data(), value); - return temp; -} - } #endif diff --git a/nall/string/variadic.hpp b/nall/string/variadic.hpp deleted file mode 100644 index fed6b7f3..00000000 --- a/nall/string/variadic.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -void sprint(string& output) { -} - -template -void sprint(string& output, const T& value, Args&&... args) { - output._append(make_string(value)); - sprint(output, std::forward(args)...); -} - -template void print(Args&&... args) { - printf("%s", (const char*)string(std::forward(args)...)); -} - -} - -#endif diff --git a/nall/string/wrapper.hpp b/nall/string/wrapper.hpp deleted file mode 100644 index 0eadf3dd..00000000 --- a/nall/string/wrapper.hpp +++ /dev/null @@ -1,124 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -template lstring string::split(rstring key) const { lstring result; result.split(key, data()); return result; } -template lstring string::isplit(rstring key) const { lstring result; result.isplit(key, data()); return result; } -template lstring string::qsplit(rstring key) const { lstring result; result.qsplit(key, data()); return result; } -template lstring string::iqsplit(rstring key) const { lstring result; result.iqsplit(key, data()); return result; } - -bool string::match(rstring source) const { return nall::strmatch(data(), source); } -bool string::imatch(rstring source) const { return nall::istrmatch(data(), source); } - -signed string::compare(rstring source) const { - return strcmp(data(), source.data()); -} - -signed string::icompare(rstring source) const { - return istrcmp(data(), source.data()); -} - -bool string::equals(rstring source) const { - if(size() != source.size()) return false; - return compare(source) == 0; -} - -bool string::iequals(rstring source) const { - if(size() != source.size()) return false; - return icompare(source) == 0; -} - -bool string::beginsWith(rstring source) const { - if(source.size() > size()) return false; - return memcmp(data(), source.data(), source.size()) == 0; -} - -bool string::ibeginsWith(rstring source) const { - if(source.size() > size()) return false; - return imemcmp(data(), source.data(), source.size()) == 0; -} - -bool string::endsWith(rstring source) const { - if(source.size() > size()) return false; - return memcmp(data() + size() - source.size(), source.data(), source.size()) == 0; -} - -bool string::iendsWith(rstring source) const { - if(source.size() > size()) return false; - return imemcmp(data() + size() - source.size(), source.data(), source.size()) == 0; -} - -string string::slice(unsigned offset, unsigned length) const { - if(offset >= size()) return ""; - if(length == ~0u) length = size() - offset; - return substr(data(), offset, length); -} - -string& string::lower() { nall::strlower(data()); return *this; } -string& string::upper() { nall::strupper(data()); return *this; } -string& string::qlower() { nall::qstrlower(data()); return *this; } -string& string::qupper() { nall::qstrupper(data()); return *this; } - -string& string::transform(rstring before, rstring after) { nall::strtr(data(), before, after); return *this; } - -string& string::reverse() { - unsigned length = size(), pivot = length >> 1; - for(signed x = 0, y = length - 1; x < pivot && y >= 0; x++, y--) std::swap(data()[x], data()[y]); - return *this; -} - -template string& string::ltrim(rstring key) { - if(key.size() == 0) return *this; - unsigned limit = Limit ? Limit : ~0u, offset = 0; - - while(limit && size() - offset >= key.size()) { - if(memcmp(data() + offset, key.data(), key.size())) break; - offset += key.size(); - limit--; - } - - if(offset) memmove(data(), data() + offset, size() - offset); - resize(size() - offset); - return *this; -} - -template string& string::rtrim(rstring key) { - if(key.size() == 0) return *this; - unsigned limit = Limit ? Limit : ~0u, offset = 0; - - while(limit && size() - offset >= key.size()) { - if(memcmp(data() + size() - key.size() - offset, key.data(), key.size())) break; - offset += key.size(); - limit--; - } - - resize(size() - offset); - return *this; -} - -template string& string::trim(rstring key) { - rtrim(key); - ltrim(key); - return *this; -} - -template string& string::trim(rstring lkey, rstring rkey) { - rtrim(rkey); - ltrim(lkey); - return *this; -} - -string& string::strip() { - nall::strip(data()); - resize(length()); - return *this; -} - -maybe string::find(rstring key) const { return strpos(data(), key); } -maybe string::ifind(rstring key) const { return istrpos(data(), key); } -maybe string::qfind(rstring key) const { return qstrpos(data(), key); } -maybe string::iqfind(rstring key) const { return iqstrpos(data(), key); } - -} - -#endif diff --git a/nall/thread.hpp b/nall/thread.hpp index 5cd2846c..e07339c6 100644 --- a/nall/thread.hpp +++ b/nall/thread.hpp @@ -1,66 +1,69 @@ #ifndef NALL_THREAD_HPP #define NALL_THREAD_HPP +//simple thread library +//primary rationale is that std::thread does not support custom stack sizes +//this is highly critical in certain applications such as threaded web servers +//an added bonus is that it avoids licensing issues on Windows +//win32-pthreads (needed for std::thread) is licensed under the GPL only + #include #include #include -#if defined(PLATFORM_XORG) || defined(PLATFORM_MACOSX) +#if defined(PLATFORM_BSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_MACOSX) #include namespace nall { -inline void* thread_entry_point(void*); - struct thread { - thread(function entryPoint) : entryPoint(entryPoint), completed(false), dead(false) { - initialize(); - pthread_create(&pthread, nullptr, thread_entry_point, (void*)this); - } + inline auto join() -> void; - ~thread() { - join(); - } + static inline auto create(const function& callback, uintptr_t parameter = 0, unsigned stacksize = 0) -> thread; + static inline auto detach() -> void; + static inline auto exit() -> void; - bool active() const { - return completed == false; - } - - void join() { - if(dead) return; - dead = true; - pthread_join(pthread, nullptr); - } - - static bool primary() { - initialize(); - return pthread_equal(primaryThread(), pthread_self()); - } + struct context { + function callback; + uintptr_t parameter = 0; + }; private: - pthread_t pthread; - function entryPoint; - volatile bool completed, dead; - friend void* thread_entry_point(void*); - - static void initialize() { - static bool initialized = false; - if(initialized) return; - initialized = true; - primaryThread() = pthread_self(); - } - - static pthread_t& primaryThread() { - static pthread_t thread; - return thread; - } + pthread_t handle; }; -void* thread_entry_point(void* parameter) { - thread* context = (thread*)parameter; - context->entryPoint(); - context->completed = true; +inline auto _threadCallback(void* parameter) -> void* { + auto context = (thread::context*)parameter; + context->callback(context->parameter); + delete context; + return nullptr; +} + +auto thread::join() -> void { + pthread_join(handle, nullptr); +} + +auto thread::create(const function& callback, uintptr_t parameter, unsigned stacksize) -> thread { + thread instance; + + auto context = new thread::context; + context->callback = callback; + context->parameter = parameter; + + pthread_attr_t attr; + pthread_attr_init(&attr); + if(stacksize) pthread_attr_setstacksize(&attr, max(PTHREAD_STACK_MIN, stacksize)); + + pthread_create(&instance.handle, &attr, _threadCallback, (void*)context); + return instance; +} + +auto thread::detach() -> void { + pthread_detach(pthread_self()); +} + +auto thread::exit() -> void { pthread_exit(nullptr); } @@ -70,60 +73,66 @@ void* thread_entry_point(void* parameter) { namespace nall { -inline DWORD WINAPI thread_entry_point(LPVOID); - struct thread { - thread(function entryPoint) : entryPoint(entryPoint), completed(false), dead(false) { - initialize(); - hthread = CreateThread(nullptr, 0, thread_entry_point, (void*)this, 0, nullptr); - } + inline ~thread(); + inline auto join() -> void; - ~thread() { - join(); - } + static inline auto create(const function& callback, uintptr_t parameter = 0, unsigned stacksize = 0) -> thread; + static inline auto detach() -> void; + static inline auto exit() -> void; - bool active() const { - return completed == false; - } - - void join() { - if(dead) return; - dead = true; - WaitForSingleObject(hthread, INFINITE); - CloseHandle(hthread); - } - - static bool primary() { - initialize(); - return primaryThread() == GetCurrentThreadId(); - } + struct context { + function callback; + uintptr_t parameter = 0; + }; private: - HANDLE hthread; - function entryPoint; - volatile bool completed, dead; - friend DWORD WINAPI thread_entry_point(LPVOID); - - static void initialize() { - static bool initialized = false; - if(initialized) return; - initialized = true; - primaryThread() = GetCurrentThreadId(); - } - - static DWORD& primaryThread() { - static DWORD thread; - return thread; - } + HANDLE handle = 0; }; -inline DWORD WINAPI thread_entry_point(LPVOID parameter) { - thread *context = (thread*)parameter; - context->entryPoint(); - context->completed = true; +inline auto WINAPI _threadCallback(void* parameter) -> DWORD { + auto context = (thread::context*)parameter; + context->callback(context->parameter); + delete context; return 0; } +thread::~thread() { + if(handle) { + CloseHandle(handle); + handle = 0; + } +} + +auto thread::join() -> void { + if(handle) { + WaitForSingleObject(handle, INFINITE); + CloseHandle(handle); + handle = 0; + } +} + +auto thread::create(const function& callback, uintptr_t parameter, unsigned stacksize) -> thread { + thread instance; + + auto context = new thread::context; + context->callback = callback; + context->parameter = parameter; + + instance.handle = CreateThread(nullptr, stacksize, _threadCallback, (void*)context, 0, nullptr); + return instance; +} + +auto thread::detach() -> void { + //Windows threads do not use this concept: + //~thread() frees resources via CloseHandle() + //thread continues to run even after handle is closed +} + +auto thread::exit() -> void { + ExitThread(0); +} + } #endif diff --git a/nall/traits.hpp b/nall/traits.hpp index 6a140c2b..8550714c 100644 --- a/nall/traits.hpp +++ b/nall/traits.hpp @@ -2,32 +2,51 @@ #define NALL_TRAITS_HPP #include +#include namespace nall { + using std::forward; + using std::move; + using std::decay; + using std::declval; -template class has_default_constructor { - template class receive_size{}; - template static signed sfinae(receive_size*); - template static char sfinae(...); + using true_type = std::true_type; + using false_type = std::false_type; -public: - enum : bool { value = sizeof(sfinae(0)) == sizeof(signed) }; -}; + template using is_same = std::is_same; + template using is_base_of = std::is_base_of; + template using is_array = std::is_array; + template using is_function = std::is_function; + template using is_integral = std::is_integral; +} -template struct enable_if { typedef T type; }; -template struct enable_if {}; +namespace nall { + template struct expression { static constexpr bool value = C; }; +} -template struct type_if { typedef T type; }; -template struct type_if { typedef F type; }; +namespace nall { + namespace traits { + enum class enable_type {}; + enum class disable_type {}; -template struct static_and { enum { value = false }; }; -template<> struct static_and { enum { value = true }; }; + template struct enable_if { using type = T; }; + template struct enable_if {}; -template struct static_or { enum { value = false }; }; -template<> struct static_or { enum { value = true }; }; -template<> struct static_or { enum { value = true }; }; -template<> struct static_or { enum { value = true }; }; + template struct disable_if { using type = T; }; + template struct disable_if {}; + } + template using enable_if = typename traits::enable_if::type; + template using disable_if = typename traits::disable_if::type; +} + +namespace nall { + namespace traits { + template struct type_if { using type = T; }; + template struct type_if { using type = F; }; + } + + template using type_if = typename traits::type_if::type; } #endif diff --git a/nall/varint.hpp b/nall/varint.hpp index 944e193e..e77ffb30 100644 --- a/nall/varint.hpp +++ b/nall/varint.hpp @@ -52,7 +52,7 @@ struct varint { template struct uint_t { private: - typedef typename type_if::type type_t; + using type_t = type_if, unsigned, uintmax_t>; type_t data; public: @@ -84,7 +84,7 @@ public: template struct int_t { private: - typedef typename type_if::type type_t; + using type_t = type_if, signed, intmax_t>; type_t data; public: diff --git a/nall/vector.hpp b/nall/vector.hpp index d1da089b..2e866bab 100644 --- a/nall/vector.hpp +++ b/nall/vector.hpp @@ -109,7 +109,10 @@ public: } void insert(unsigned position, const T& data) { - if(position == 0) return prepend(data); + if(position == 0) { + prepend(data); + return; + } append(data); if(position == ~0u) return; for(signed n = objectsize - 1; n > position; n--) { @@ -165,7 +168,7 @@ public: nall::sort(pool + poolbase, objectsize, lessthan); } - maybe find(const T& data) { + maybe find(const T& data) const { for(unsigned n = 0; n < objectsize; n++) if(pool[poolbase + n] == data) return n; return nothing; } @@ -243,6 +246,7 @@ public: //copy inline vector& operator=(const vector& source) { + if(this == &source) return *this; reset(); reserve(source.size()); for(auto& data : source) append(data); @@ -251,6 +255,7 @@ public: //move inline vector& operator=(vector&& source) { + if(this == &source) return *this; reset(); pool = source.pool; poolbase = source.poolbase; diff --git a/nall/windows/detour.hpp b/nall/windows/detour.hpp index 34a5d3f8..ce583912 100644 --- a/nall/windows/detour.hpp +++ b/nall/windows/detour.hpp @@ -75,7 +75,7 @@ bool detour::insert(const string& moduleName, const string& functionName, void*& #if 1 string output = { "detour::insert(", moduleName, "::", functionName, ") failed: " }; for(unsigned n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " "); - output.rtrim<1>(" "); + output.rtrim(" "); MessageBoxA(0, output, "nall::detour", MB_OK); #endif return false; diff --git a/nall/windows/registry.hpp b/nall/windows/registry.hpp index f702afe4..7c9aff2c 100644 --- a/nall/windows/registry.hpp +++ b/nall/windows/registry.hpp @@ -92,7 +92,7 @@ struct registry { wchar_t name[NWR_SIZE] = L""; DWORD size = NWR_SIZE * sizeof(wchar_t); RegEnumKeyEx(handle, n, (wchar_t*)&name, &size, nullptr, nullptr, nullptr, nullptr); - result.append({(const char*)utf8_t(name), "/"}); + result.append(string{(const char*)utf8_t(name), "/"}); } for(unsigned n = 0; n < nodes; n++) { wchar_t name[NWR_SIZE] = L""; diff --git a/nall/windows/utf8.hpp b/nall/windows/utf8.hpp index dc3ea3bb..d6e8a480 100644 --- a/nall/windows/utf8.hpp +++ b/nall/windows/utf8.hpp @@ -6,11 +6,9 @@ #if defined(_WIN32) -#undef UNICODE -#undef _WIN32_WINNT -#undef NOMINMAX +#undef UNICODE #define UNICODE -#define _WIN32_WINNT 0x0501 +#undef NOMINMAX #define NOMINMAX #include #include diff --git a/nall/zip.hpp b/nall/zip.hpp index 2c27a328..a0f05e30 100644 --- a/nall/zip.hpp +++ b/nall/zip.hpp @@ -3,8 +3,8 @@ //creates uncompressed ZIP archives -#include #include +#include namespace nall { @@ -21,7 +21,7 @@ struct zip { //append file: append("path/file", data, size); void append(string filename, const uint8_t* data = nullptr, unsigned size = 0u) { filename.transform("\\", "/"); - uint32_t checksum = crc32_calculate(data, size); + uint32_t checksum = Hash::CRC32(data, size).value(); directory.append({filename, checksum, size, fp.offset()}); fp.writel(0x04034b50, 4); //signature diff --git a/out/.gitignore b/out/.gitignore index cc3f712d..98f54497 100644 --- a/out/.gitignore +++ b/out/.gitignore @@ -1,2 +1 @@ higan -loki diff --git a/phoenix/Makefile b/phoenix/Makefile deleted file mode 100644 index 957e361b..00000000 --- a/phoenix/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -ifeq ($(platform),) - phoenixflags = $(cppflags) $(flags) -DPHOENIX_REFERENCE - phoenixlink = -else ifeq ($(platform),windows) - phoenixflags = $(cppflags) $(flags) -DPHOENIX_WINDOWS - phoenixlink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi -else ifeq ($(platform),macosx) - phoenixflags = $(objcppflags) $(flags) -DPHOENIX_COCOA - phoenixlink = -framework Cocoa -framework Carbon -else - ifeq ($(phoenix),) - phoenix := gtk - endif - - ifeq ($(phoenix),gtk) - phoenixflags = $(cppflags) $(flags) -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0` - phoenixlink = `pkg-config --libs gtk+-2.0` - endif - - ifeq ($(phoenix),qt) - phoenixflags = $(cppflags) $(flags) -DPHOENIX_QT `pkg-config --cflags QtCore QtGui` - phoenixlink = `pkg-config --libs QtCore QtGui` - endif -endif diff --git a/phoenix/core/core.cpp b/phoenix/core/core.cpp deleted file mode 100644 index ac4cd54b..00000000 --- a/phoenix/core/core.cpp +++ /dev/null @@ -1,2046 +0,0 @@ -#if defined(PHOENIX_WINDOWS) - #include "../windows/header.hpp" -#elif defined(PHOENIX_QT) - #include "../qt/header.hpp" -#elif defined(PHOENIX_GTK) - #include "../gtk/header.hpp" -#elif defined(PHOENIX_COCOA) - #include "../cocoa/header.hpp" -#elif defined(PHOENIX_REFERENCE) - #include "../reference/header.hpp" -#endif - -#include "core.hpp" -using namespace nall; - -namespace phoenix { - #include "state.hpp" - #include "layout/fixed-layout.cpp" - #include "layout/horizontal-layout.cpp" - #include "layout/vertical-layout.cpp" -} - -#if defined(PHOENIX_WINDOWS) - #include "../windows/platform.cpp" -#elif defined(PHOENIX_QT) - #include "../qt/platform.cpp" -#elif defined(PHOENIX_GTK) - #include "../gtk/platform.cpp" -#elif defined(PHOENIX_COCOA) - #include "../cocoa/platform.cpp" -#elif defined(PHOENIX_REFERENCE) - #include "../reference/platform.cpp" -#endif - -namespace phoenix { - -//Application -//=========== - -function Application::main; - -function Application::Windows::onModalBegin; -function Application::Windows::onModalEnd; - -function Application::Cocoa::onAbout; -function Application::Cocoa::onActivate; -function Application::Cocoa::onPreferences; -function Application::Cocoa::onQuit; - -void Application::run() { - return pApplication::run(); -} - -bool Application::pendingEvents() { - return pApplication::pendingEvents(); -} - -void Application::processEvents() { - return pApplication::processEvents(); -} - -void Application::quit() { - applicationState.quit = true; - return pApplication::quit(); -} - -void Application::setName(const string& name) { - applicationState.name = name; -} - -void Application::initialize() { - static bool initialized = false; - if(initialized == false) { - initialized = true; - return pApplication::initialize(); - } -} - -//Color -//===== - -uint32_t Color::rgb() const { - return (255 << 24) + (red << 16) + (green << 8) + (blue << 0); -} - -uint32_t Color::argb() const { - return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0); -} - -//Geometry -//======== - -Position Geometry::position() const { - return {x, y}; -} - -Size Geometry::size() const { - return {width, height}; -} - -string Geometry::text() const { - return {x, ",", y, ",", width, ",", height}; -} - -Geometry::Geometry(const string& text) { - lstring part = text.split(","); - x = integer(part(0, "256")); - y = integer(part(1, "256")); - width = decimal(part(2, "256")); - height = decimal(part(3, "256")); -} - -//Font -//==== - -string Font::serif(unsigned size, const string& style) { - return pFont::serif(size, style); -} - -string Font::sans(unsigned size, const string& style) { - return pFont::sans(size, style); -} - -string Font::monospace(unsigned size, const string& style) { - return pFont::monospace(size, style); -} - -Size Font::size(const string& font, const string& text) { - return pFont::size(font, text); -} - -//Desktop -//======= - -Size Desktop::size() { - return pDesktop::size(); -} - -Geometry Desktop::workspace() { - return pDesktop::workspace(); -} - -//Monitor -//======= - -unsigned Monitor::count() { - return pMonitor::count(); -} - -Geometry Monitor::geometry(unsigned monitor) { - return pMonitor::geometry(monitor); -} - -unsigned Monitor::primary() { - return pMonitor::primary(); -} - -//Keyboard -//======== - -bool Keyboard::pressed(Keyboard::Scancode scancode) { - return pKeyboard::pressed(scancode); -} - -bool Keyboard::released(Keyboard::Scancode scancode) { - return !pressed(scancode); -} - -vector Keyboard::state() { - return pKeyboard::state(); -} - -//Mouse -//===== - -Position Mouse::position() { - return pMouse::position(); -} - -bool Mouse::pressed(Mouse::Button button) { - return pMouse::pressed(button); -} - -bool Mouse::released(Mouse::Button button) { - return !pressed(button); -} - -//BrowserWindow -//============= - -string BrowserWindow::directory() { - return pBrowserWindow::directory(state); -} - -string BrowserWindow::open() { - return pBrowserWindow::open(state); -} - -string BrowserWindow::save() { - return pBrowserWindow::save(state); -} - -BrowserWindow& BrowserWindow::setFilters(const lstring& filters) { - state.filters = filters; - return *this; -} - -BrowserWindow& BrowserWindow::setParent(Window& parent) { - state.parent = &parent; - return *this; -} - -BrowserWindow& BrowserWindow::setPath(const string& path) { - state.path = path; - return *this; -} - -BrowserWindow& BrowserWindow::setTitle(const string& title) { - state.title = title; - return *this; -} - -BrowserWindow::BrowserWindow(): -state(*new State) { -} - -BrowserWindow::~BrowserWindow() { - delete &state; -} - -//MessageWindow -//============= - -MessageWindow::Response MessageWindow::error(MessageWindow::Buttons buttons) { - state.buttons = buttons; - return pMessageWindow::error(state); -} - -MessageWindow::Response MessageWindow::information(MessageWindow::Buttons buttons) { - state.buttons = buttons; - return pMessageWindow::information(state); -} - -MessageWindow::Response MessageWindow::question(MessageWindow::Buttons buttons) { - state.buttons = buttons; - return pMessageWindow::question(state); -} - -MessageWindow& MessageWindow::setParent(Window& parent) { - state.parent = &parent; - return *this; -} - -MessageWindow& MessageWindow::setText(const string& text) { - state.text = text; - return *this; -} - -MessageWindow& MessageWindow::setTitle(const string& title) { - state.title = title; - return *this; -} - -MessageWindow::Response MessageWindow::warning(MessageWindow::Buttons buttons) { - state.buttons = buttons; - return pMessageWindow::warning(state); -} - -MessageWindow::MessageWindow(const string& text): -state(*new State) { - state.text = text; -} - -MessageWindow::~MessageWindow() { - delete &state; -} - -//Object -//====== - -Object::Object(pObject& p): -p(p) { - Application::initialize(); - p.constructor(); -} - -Object::~Object() { - p.destructor(); - delete &p; -} - -//Timer -//===== - -bool Timer::enabled() const { - return state.enabled; -} - -unsigned Timer::interval() const { - return state.interval; -} - -void Timer::setEnabled(bool enabled) { - state.enabled = enabled; - return p.setEnabled(enabled); -} - -void Timer::setInterval(unsigned interval) { - state.interval = interval; - return p.setInterval(interval); -} - -Timer::Timer(): -state(*new State), -base_from_member(*new pTimer(*this)), -Object(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Timer::~Timer() { - p.destructor(); - delete &state; -} - -//Window -//====== - -void Window::append(Layout& layout) { - if(state.layout.append(layout)) { - layout.Sizable::state.parent = nullptr; - layout.Sizable::state.window = this; - p.append(layout); - layout.synchronizeLayout(); - } -} - -void Window::append(Menu& menu) { - if(state.menu.append(menu)) { - menu.Action::state.window = this; - p.append(menu); - } -} - -void Window::append(Widget& widget) { - if(state.widget.append(widget)) { - widget.Sizable::state.window = this; - p.append(widget); - widget.synchronizeLayout(); - } -} - -Color Window::backgroundColor() const { - return state.backgroundColor; -} - -bool Window::droppable() const { - return state.droppable; -} - -Geometry Window::frameGeometry() { - Geometry geometry = p.geometry(); - Geometry margin = p.frameMargin(); - return { - geometry.x - margin.x, geometry.y - margin.y, - geometry.width + margin.width, geometry.height + margin.height - }; -} - -Geometry Window::frameMargin() { - return p.frameMargin(); -} - -bool Window::focused() { - return p.focused(); -} - -bool Window::fullScreen() const { - return state.fullScreen; -} - -Geometry Window::geometry() { - return p.geometry(); -} - -string Window::menuFont() const { - return state.menuFont; -} - -bool Window::menuVisible() const { - return state.menuVisible; -} - -bool Window::modal() const { - return state.modal; -} - -void Window::remove(Layout& layout) { - if(state.layout.remove(layout)) { - p.remove(layout); - layout.Sizable::state.window = nullptr; - } -} - -void Window::remove(Menu& menu) { - if(state.menu.remove(menu)) { - p.remove(menu); - menu.Action::state.window = nullptr; - } -} - -void Window::remove(Widget& widget) { - if(state.widget.remove(widget)) { - p.remove(widget); - widget.Sizable::state.window = nullptr; - } -} - -bool Window::resizable() const { - return state.resizable; -} - -void Window::setBackgroundColor(Color color) { - state.backgroundColorOverride = true; - state.backgroundColor = color; - return p.setBackgroundColor(color); -} - -void Window::setDroppable(bool droppable) { - state.droppable = droppable; - return p.setDroppable(droppable); -} - -void Window::setFrameGeometry(Geometry geometry) { - Geometry margin = p.frameMargin(); - return setGeometry({ - geometry.x + margin.x, geometry.y + margin.y, - geometry.width - margin.width, geometry.height - margin.height - }); -} - -void Window::setFocused() { - return p.setFocused(); -} - -void Window::setFullScreen(bool fullScreen) { - state.fullScreen = fullScreen; - return p.setFullScreen(fullScreen); -} - -void Window::setGeometry(Geometry geometry) { - state.geometry = geometry; - return p.setGeometry(geometry); -} - -void Window::setMenuFont(const string& font) { - state.menuFont = font; - return p.setMenuFont(font); -} - -void Window::setMenuVisible(bool visible) { - state.menuVisible = visible; - return p.setMenuVisible(visible); -} - -void Window::setModal(bool modal) { - state.modal = modal; - return p.setModal(modal); -} - -void Window::setResizable(bool resizable) { - state.resizable = resizable; - return p.setResizable(resizable); -} - -void Window::setStatusFont(const string& font) { - state.statusFont = font; - return p.setStatusFont(font); -} - -void Window::setStatusText(const string& text) { - state.statusText = text; - return p.setStatusText(text); -} - -void Window::setStatusVisible(bool visible) { - state.statusVisible = visible; - return p.setStatusVisible(visible); -} - -void Window::setTitle(const string& text) { - state.title = text; - return p.setTitle(text); -} - -void Window::setVisible(bool visible) { - state.visible = visible; - synchronizeLayout(); - return p.setVisible(visible); -} - -void Window::setWidgetFont(const string& font) { - state.widgetFont = font; - return p.setWidgetFont(font); -} - -void Window::setWindowGeometry(Geometry geometry) { - Geometry margin = p.frameMargin(); - return setGeometry({ - geometry.x + margin.x, geometry.y + margin.y, - geometry.width, geometry.height - }); -} - -string Window::statusFont() const { - return state.statusFont; -} - -string Window::statusText() const { - return state.statusText; -} - -bool Window::statusVisible() const { - return state.statusVisible; -} - -void Window::synchronizeLayout() { - if(visible() && applicationState.quit == false) setGeometry(geometry()); -} - -string Window::title() const { - return state.title; -} - -bool Window::visible() const { - return state.visible; -} - -string Window::widgetFont() const { - return state.widgetFont; -} - -Window::Window(): -state(*new State), -base_from_member(*new pWindow(*this)), -Object(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Window::~Window() { - p.destructor(); - delete &state; -} - -//Action -//====== - -bool Action::enabled() const { - return state.enabled; -} - -void Action::setEnabled(bool enabled) { - state.enabled = enabled; - return p.setEnabled(enabled); -} - -void Action::setVisible(bool visible) { - state.visible = visible; - return p.setVisible(visible); -} - -bool Action::visible() const { - return state.visible; -} - -Action::Action(pAction& p): -state(*new State), -Object(p), -p(p) { - p.constructor(); -} - -Action::~Action() { - p.destructor(); - delete &state; -} - -//Menu -//==== - -void Menu::append(const group& list) { - for(auto& action : list) { - if(state.action.append(action)) { - action.state.menu = this; - p.append(action); - } - } -} - -image Menu::image() const { - return state.image; -} - -void Menu::remove(const group& list) { - for(auto& action : list) { - if(state.action.remove(action)) { - action.state.menu = nullptr; - return p.remove(action); - } - } -} - -void Menu::setImage(const nall::image& image) { - state.image = image; - return p.setImage(image); -} - -void Menu::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string Menu::text() const { - return state.text; -} - -Menu::Menu(): -state(*new State), -base_from_member(*new pMenu(*this)), -Action(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Menu::~Menu() { - p.destructor(); - delete &state; -} - -//Separator -//========= - -Separator::Separator(): -base_from_member(*new pSeparator(*this)), -Action(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Separator::~Separator() { - p.destructor(); -} - -//Item -//==== - -image Item::image() const { - return state.image; -} - -void Item::setImage(const nall::image& image) { - state.image = image; - return p.setImage(image); -} - -void Item::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string Item::text() const { - return state.text; -} - -Item::Item(): -state(*new State), -base_from_member(*new pItem(*this)), -Action(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Item::~Item() { - p.destructor(); - delete &state; -} - -//CheckItem -//========= - -bool CheckItem::checked() const { - return state.checked; -} - -void CheckItem::setChecked(bool checked) { - state.checked = checked; - return p.setChecked(checked); -} - -void CheckItem::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string CheckItem::text() const { - return state.text; -} - -CheckItem::CheckItem(): -state(*new State), -base_from_member(*new pCheckItem(*this)), -Action(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -CheckItem::~CheckItem() { - p.destructor(); - delete &state; -} - -//RadioItem -//========= - -void RadioItem::group(const nall::group& list) { - for(auto& item : list) item.p.setGroup(item.state.group = list); - if(list.size()) list.first().setChecked(); -} - -bool RadioItem::checked() const { - return state.checked; -} - -void RadioItem::setChecked() { - for(auto& item : state.group) item.state.checked = false; - state.checked = true; - return p.setChecked(); -} - -void RadioItem::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string RadioItem::text() const { - return state.text; -} - -RadioItem::RadioItem(): -state(*new State), -base_from_member(*new pRadioItem(*this)), -Action(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -RadioItem::~RadioItem() { - for(auto& item : state.group) { - if(&item != this) item.state.group.remove(*this); - } - p.destructor(); - delete &state; -} - -//Sizable -//======= - -bool Sizable::enabled() const { - return state.enabled; -} - -bool Sizable::enabledToAll() const { - if(state.enabled == false) return false; - if(state.parent) return state.parent->enabledToAll(); - return true; -} - -Layout* Sizable::layout() const { - if(state.parent && dynamic_cast(state.parent)) return (Layout*)state.parent; - return nullptr; -} - -Sizable* Sizable::parent() const { - return state.parent; -} - -bool Sizable::visible() const { - return state.visible; -} - -bool Sizable::visibleToAll() const { - if(state.visible == false) return false; - if(state.parent) return state.parent->visibleToAll(); - return true; -} - -Window* Sizable::window() const { - return state.window; -} - -Sizable::Sizable(pSizable& p): -state(*new State), -Object(p), -p(p) { - p.constructor(); -} - -Sizable::~Sizable() { - if(layout()) layout()->remove(*this); - p.destructor(); - delete &state; -} - -//Layout -//====== - -void Layout::append(Sizable& sizable) { - sizable.state.parent = this; - sizable.state.window = Sizable::state.window; - - if(dynamic_cast(&sizable)) { - Layout& layout = (Layout&)sizable; - layout.synchronizeLayout(); - } - - if(dynamic_cast(&sizable)) { - Widget& widget = (Widget&)sizable; - if(sizable.window()) sizable.window()->append(widget); - } -} - -void Layout::remove(Sizable& sizable) { - if(dynamic_cast(&sizable)) { - Widget& widget = (Widget&)sizable; - if(sizable.window()) sizable.window()->remove(widget); - } - - sizable.state.parent = nullptr; - sizable.state.window = nullptr; -} - -void Layout::reset() { -} - -Layout::Layout(): -state(*new State), -base_from_member(*new pLayout(*this)), -Sizable(base_from_member::value), -p(base_from_member::value) { -} - -Layout::Layout(pLayout& p): -state(*new State), -base_from_member(p), -Sizable(p), -p(p) { -} - -Layout::~Layout() { - if(layout()) layout()->remove(*this); - if(window()) window()->remove(*this); - p.destructor(); - delete &state; -} - -//Widget -//====== - -bool Widget::focused() { - return p.focused(); -} - -string Widget::font() const { - return state.font; -} - -Geometry Widget::geometry() const { - return state.geometry; -} - -Size Widget::minimumSize() { - return p.minimumSize(); -} - -void Widget::setEnabled(bool enabled) { - Sizable::state.enabled = enabled; - return p.setEnabled(enabled); -} - -void Widget::setFocused() { - return p.setFocused(); -} - -void Widget::setFont(const string& font) { - state.font = font; - return p.setFont(font); -} - -void Widget::setGeometry(Geometry geometry) { - state.geometry = geometry; - return p.setGeometry(geometry); -} - -void Widget::setVisible(bool visible) { - Sizable::state.visible = visible; - return p.setVisible(visible); -} - -void Widget::synchronizeLayout() { -} - -Widget::Widget(): -state(*new State), -base_from_member(*new pWidget(*this)), -Sizable(base_from_member::value), -p(base_from_member::value) { - state.abstract = true; - p.constructor(); -} - -Widget::Widget(pWidget& p): -state(*new State), -base_from_member(p), -Sizable(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Widget::~Widget() { - p.destructor(); - delete &state; -} - -//Button -//====== - -image Button::image() const { - return state.image; -} - -Orientation Button::orientation() const { - return state.orientation; -} - -void Button::setImage(const nall::image& image, Orientation orientation) { - state.image = image; - state.orientation = orientation; - return p.setImage(image, orientation); -} - -void Button::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -nall::string Button::text() const { - return state.text; -} - -Button::Button(): -state(*new State), -base_from_member(*new pButton(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Button::~Button() { - p.destructor(); - delete &state; -} - -//Canvas -//====== - -Color Canvas::color() const { - return state.color; -} - -uint32_t* Canvas::data() const { - return state.data; -} - -bool Canvas::droppable() const { - return state.droppable; -} - -vector Canvas::gradient() const { - return state.gradient; -} - -image Canvas::image() const { - return state.image; -} - -Canvas::Mode Canvas::mode() const { - return state.mode; -} - -void Canvas::setColor(Color color) { - state.color = color; - return setMode(Canvas::Mode::Color); -} - -void Canvas::setData() { - if(state.width == 0 || state.height == 0) return; //dynamic sizing not supported in Mode::Data - return setMode(Canvas::Mode::Data); -} - -void Canvas::setDroppable(bool droppable) { - state.droppable = droppable; - return p.setDroppable(droppable); -} - -void Canvas::setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) { - state.gradient[0] = topLeft; - state.gradient[1] = topRight; - state.gradient[2] = bottomLeft; - state.gradient[3] = bottomRight; - return setMode(Canvas::Mode::Gradient); -} - -void Canvas::setHorizontalGradient(Color left, Color right) { - state.gradient[0] = state.gradient[2] = left; - state.gradient[1] = state.gradient[3] = right; - return setMode(Canvas::Mode::Gradient); -} - -void Canvas::setImage(const nall::image& image) { - state.image = image; - return setMode(Canvas::Mode::Image); -} - -void Canvas::setMode(Mode mode) { - state.mode = mode; - return p.setMode(mode); -} - -void Canvas::setSize(Size size) { - if(size.width == Size::Maximum) size.width = 0; - if(size.height == Size::Maximum) size.height = 0; - state.width = size.width; - state.height = size.height; - delete[] state.data; - state.data = new uint32_t[state.width * state.height](); - return setMode(state.mode); -} - -void Canvas::setVerticalGradient(Color top, Color bottom) { - state.gradient[0] = state.gradient[1] = top; - state.gradient[2] = state.gradient[3] = bottom; - return setMode(Canvas::Mode::Gradient); -} - -Size Canvas::size() const { - return {state.width, state.height}; -} - -Canvas::Canvas(): -state(*new State), -base_from_member(*new pCanvas(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - state.data = new uint32_t[state.width * state.height](); - p.constructor(); -} - -Canvas::~Canvas() { - p.destructor(); - delete[] state.data; - delete &state; -} - -//CheckButton -//=========== - -bool CheckButton::checked() const { - return state.checked; -} - -image CheckButton::image() const { - return state.image; -} - -void CheckButton::setChecked(bool checked) { - state.checked = checked; - return p.setChecked(checked); -} - -void CheckButton::setImage(const nall::image& image, Orientation orientation) { - state.image = image; - state.orientation = orientation; - return p.setImage(image, orientation); -} - -void CheckButton::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string CheckButton::text() const { - return state.text; -} - -CheckButton::CheckButton(): -state(*new State), -base_from_member(*new pCheckButton(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -CheckButton::~CheckButton() { - p.destructor(); - delete &state; -} - -//CheckLabel -//========== - -bool CheckLabel::checked() const { - return state.checked; -} - -void CheckLabel::setChecked(bool checked) { - state.checked = checked; - return p.setChecked(checked); -} - -void CheckLabel::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string CheckLabel::text() const { - return state.text; -} - -CheckLabel::CheckLabel(): -state(*new State), -base_from_member(*new pCheckLabel(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -CheckLabel::~CheckLabel() { - p.destructor(); - delete &state; -} - - -//ComboButton -//=========== - -void ComboButton::append(const string& text) { - state.text.append(text); - return p.append(text); -} - -void ComboButton::remove(unsigned selection) { - if(selection >= state.text.size()) return; - state.text.remove(selection); - p.remove(selection); -} - -void ComboButton::reset() { - state.selection = 0; - state.text.reset(); - return p.reset(); -} - -unsigned ComboButton::rows() const { - return state.text.size(); -} - -unsigned ComboButton::selection() const { - return state.selection; -} - -void ComboButton::setSelection(unsigned selection) { - if(selection >= state.text.size()) return; - state.selection = selection; - return p.setSelection(selection); -} - -void ComboButton::setText(unsigned selection, const string& text) { - if(selection >= state.text.size()) return; - state.text[selection] = text; - p.setText(selection, text); -} - -string ComboButton::text() const { - if(state.text.empty()) return ""; - return state.text[state.selection]; -} - -string ComboButton::text(unsigned selection) const { - if(selection >= state.text.size()) return ""; - return state.text[selection]; -} - -ComboButton::ComboButton(): -state(*new State), -base_from_member(*new pComboButton(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -ComboButton::~ComboButton() { - p.destructor(); - delete &state; -} - -//Console -//======= - -Color Console::backgroundColor() const { - return state.backgroundColor; -} - -Color Console::foregroundColor() const { - return state.foregroundColor; -} - -void Console::print(const string& text) { - return p.print(text); -} - -string Console::prompt() const { - return state.prompt; -} - -void Console::reset() { - return p.reset(); -} - -void Console::setBackgroundColor(Color color) { - state.backgroundColor = color; - return p.setBackgroundColor(color); -} - -void Console::setForegroundColor(Color color) { - state.foregroundColor = color; - return p.setForegroundColor(color); -} - -void Console::setPrompt(const string& prompt) { - state.prompt = prompt; - return p.setPrompt(prompt); -} - -Console::Console(): -state(*new State), -base_from_member(*new pConsole(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Console::~Console() { - p.destructor(); - delete &state; -} - -//Frame -//===== - -void Frame::setLayout(Layout& layout) { - state.layout = &layout; - synchronizeLayout(); -} - -void Frame::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -void Frame::synchronizeLayout() { - if(state.layout == nullptr) return; - state.layout->Sizable::state.window = Sizable::state.window; - state.layout->Sizable::state.parent = this; - state.layout->state.widget = this; - state.layout->synchronizeLayout(); -} - -string Frame::text() const { - return state.text; -} - -Frame::Frame(): -state(*new State), -base_from_member(*new pFrame(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Frame::~Frame() { - p.destructor(); - delete &state; -} - -//HexEdit -//======= - -Color HexEdit::backgroundColor() const { - return state.backgroundColor; -} - -unsigned HexEdit::columns() const { - return state.columns; -} - -Color HexEdit::foregroundColor() const { - return state.foregroundColor; -} - -unsigned HexEdit::length() const { - return state.length; -} - -unsigned HexEdit::offset() const { - return state.offset; -} - -unsigned HexEdit::rows() const { - return state.rows; -} - -void HexEdit::setBackgroundColor(Color color) { - state.backgroundColor = color; - return p.setBackgroundColor(color); -} - -void HexEdit::setColumns(unsigned columns) { - state.columns = columns; - return p.setColumns(columns); -} - -void HexEdit::setForegroundColor(Color color) { - state.foregroundColor = color; - return p.setForegroundColor(color); -} - -void HexEdit::setLength(unsigned length) { - state.length = length; - return p.setLength(length); -} - -void HexEdit::setOffset(unsigned offset) { - state.offset = offset; - return p.setOffset(offset); -} - -void HexEdit::setRows(unsigned rows) { - state.rows = rows; - return p.setRows(rows); -} - -void HexEdit::update() { - return p.update(); -} - -HexEdit::HexEdit(): -state(*new State), -base_from_member(*new pHexEdit(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -HexEdit::~HexEdit() { - p.destructor(); - delete &state; -} - -//HorizontalScroller -//================== - -unsigned HorizontalScroller::length() const { - return state.length; -} - -unsigned HorizontalScroller::position() const { - return state.position; -} - -void HorizontalScroller::setLength(unsigned length) { - state.length = length; - return p.setLength(length); -} - -void HorizontalScroller::setPosition(unsigned position) { - state.position = position; - return p.setPosition(position); -} - -HorizontalScroller::HorizontalScroller(): -state(*new State), -base_from_member(*new pHorizontalScroller(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -HorizontalScroller::~HorizontalScroller() { - p.destructor(); - delete &state; -} - -//HorizontalSlider -//================ - -unsigned HorizontalSlider::length() const { - return state.length; -} - -unsigned HorizontalSlider::position() const { - return state.position; -} - -void HorizontalSlider::setLength(unsigned length) { - state.length = length; - return p.setLength(length); -} - -void HorizontalSlider::setPosition(unsigned position) { - state.position = position; - return p.setPosition(position); -} - -HorizontalSlider::HorizontalSlider(): -state(*new State), -base_from_member(*new pHorizontalSlider(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -HorizontalSlider::~HorizontalSlider() { - p.destructor(); - delete &state; -} - -//Label -//===== - -void Label::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string Label::text() const { - return state.text; -} - -Label::Label(): -state(*new State), -base_from_member(*new pLabel(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Label::~Label() { - p.destructor(); - delete &state; -} - -//LineEdit -//======== - -Color LineEdit::backgroundColor() const { - return state.backgroundColor; -} - -bool LineEdit::editable() const { - return state.editable; -} - -Color LineEdit::foregroundColor() const { - return state.foregroundColor; -} - -void LineEdit::setBackgroundColor(Color color) { - state.backgroundColor = color; - return p.setBackgroundColor(color); -} - -void LineEdit::setEditable(bool editable) { - state.editable = editable; - return p.setEditable(editable); -} - -void LineEdit::setForegroundColor(Color color) { - state.foregroundColor = color; - return p.setForegroundColor(color); -} - -void LineEdit::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string LineEdit::text() { - return p.text(); -} - -LineEdit::LineEdit(): -state(*new State), -base_from_member(*new pLineEdit(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -LineEdit::~LineEdit() { - p.destructor(); - delete &state; -} - -//ListView -//======== - -void ListView::append(const lstring& text) { - state.checked.append(false); - state.image.append({}); - state.text.append(text); - return p.append(text); -} - -void ListView::autoSizeColumns() { - return p.autoSizeColumns(); -} - -Color ListView::backgroundColor() const { - return state.backgroundColor; -} - -bool ListView::checkable() const { - return state.checkable; -} - -bool ListView::checked(unsigned selection) const { - if(selection >= state.text.size()) return false; - return state.checked[selection]; -} - -unsigned ListView::columns() const { - return max(1u, state.headerText.size()); -} - -Color ListView::foregroundColor() const { - return state.foregroundColor; -} - -bool ListView::headerVisible() const { - return state.headerVisible; -} - -image ListView::image(unsigned selection, unsigned position) const { - if(selection >= state.text.size()) return {}; - return state.image[selection](position); -} - -void ListView::remove(unsigned selection) { - if(selection >= state.text.size()) return; - state.checked.remove(selection); - state.image.remove(selection); - state.text.remove(selection); - return p.remove(selection); -} - -void ListView::reset() { - state.checked.reset(); - state.image.reset(); - state.selected = false; - state.selection = 0; - state.text.reset(); - return p.reset(); -} - -unsigned ListView::rows() const { - return state.text.size(); -} - -bool ListView::selected() const { - return state.selected; -} - -unsigned ListView::selection() const { - return state.selection; -} - -void ListView::setBackgroundColor(Color color) { - state.backgroundColor = color; - return p.setBackgroundColor(color); -} - -void ListView::setCheckable(bool checkable) { - state.checkable = checkable; - return p.setCheckable(checkable); -} - -void ListView::setChecked(unsigned selection, bool checked) { - if(selection >= state.text.size()) return; - state.checked[selection] = checked; - return p.setChecked(selection, checked); -} - -void ListView::setForegroundColor(Color color) { - state.foregroundColor = color; - return p.setForegroundColor(color); -} - -void ListView::setHeaderText(const lstring& text) { - state.headerText = text; - return p.setHeaderText(text); -} - -void ListView::setHeaderVisible(bool visible) { - state.headerVisible = visible; - return p.setHeaderVisible(visible); -} - -void ListView::setImage(unsigned selection, unsigned position, const nall::image& image) { - if(selection >= state.text.size()) return; - state.image[selection](position) = image; - return p.setImage(selection, position, image); -} - -void ListView::setSelected(bool selected) { - state.selected = selected; - return p.setSelected(selected); -} - -void ListView::setSelection(unsigned selection) { - if(selection >= state.text.size()) return; - state.selected = true; - state.selection = selection; - return p.setSelection(selection); -} - -void ListView::setText(unsigned selection, const lstring& text) { - if(selection >= state.text.size()) return; - for(unsigned position = 0; position < text.size(); position++) { - setText(selection, position, text[position]); - } -} - -void ListView::setText(unsigned selection, unsigned position, const string& text) { - if(selection >= state.text.size()) return; - state.text[selection](position) = text; - return p.setText(selection, position, text); -} - -string ListView::text(unsigned selection, unsigned position) const { - if(selection >= state.text.size()) return ""; - return state.text[selection](position); -} - -ListView::ListView(): -state(*new State), -base_from_member(*new pListView(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -ListView::~ListView() { - p.destructor(); - delete &state; -} - -//ProgressBar -//=========== - -unsigned ProgressBar::position() const { - return state.position; -} - -void ProgressBar::setPosition(unsigned position) { - state.position = position; - return p.setPosition(position); -} - -ProgressBar::ProgressBar(): -state(*new State), -base_from_member(*new pProgressBar(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -ProgressBar::~ProgressBar() { - p.destructor(); - delete &state; -} - -//RadioButton -//=========== - -void RadioButton::group(const nall::group& list) { - for(auto& item : list) item.p.setGroup(item.state.group = list); - if(list.size()) list.first().setChecked(); -} - -bool RadioButton::checked() const { - return state.checked; -} - -image RadioButton::image() const { - return state.image; -} - -void RadioButton::setChecked() { - for(auto& item : state.group) item.state.checked = false; - state.checked = true; - return p.setChecked(); -} - -void RadioButton::setImage(const nall::image& image, Orientation orientation) { - state.image = image; - state.orientation = orientation; - return p.setImage(image, orientation); -} - -void RadioButton::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string RadioButton::text() const { - return state.text; -} - -RadioButton::RadioButton(): -state(*new State), -base_from_member(*new pRadioButton(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -RadioButton::~RadioButton() { - for(auto& item : state.group) { - if(&item != this) item.state.group.remove(*this); - } - p.destructor(); - delete &state; -} - -//RadioLabel -//========== - -void RadioLabel::group(const nall::group& list) { - for(auto& item : list) item.p.setGroup(item.state.group = list); - if(list.size()) list.first().setChecked(); -} - -bool RadioLabel::checked() const { - return state.checked; -} - -void RadioLabel::setChecked() { - for(auto &item : state.group) item.state.checked = false; - state.checked = true; - return p.setChecked(); -} - -void RadioLabel::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -string RadioLabel::text() const { - return state.text; -} - -RadioLabel::RadioLabel(): -state(*new State), -base_from_member(*new pRadioLabel(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -RadioLabel::~RadioLabel() { - for(auto& item : state.group) { - if(&item != this) item.state.group.remove(*this); - } - p.destructor(); - delete &state; -} - -//TabFrame -//======== - -void TabFrame::append(const string& text, const nall::image& image) { - state.image.append(image); - state.layout.append(nullptr); - state.text.append(text); - return p.append(text, image); -} - -image TabFrame::image(unsigned selection) const { - if(selection >= state.text.size()) return {}; - return state.image[selection]; -} - -void TabFrame::remove(unsigned selection) { - if(selection >= state.text.size()) return; - state.image.remove(selection); - state.layout.remove(selection); - state.text.remove(selection); - return p.remove(selection); -} - -unsigned TabFrame::selection() const { - return state.selection; -} - -void TabFrame::setImage(unsigned selection, const nall::image& image) { - if(selection >= state.text.size()) return; - state.image[selection] = image; - return p.setImage(selection, image); -} - -void TabFrame::setLayout(unsigned selection, Layout& layout) { - if(selection >= state.text.size()) return; - state.layout[selection] = &layout; - synchronizeLayout(); -} - -void TabFrame::setSelection(unsigned selection) { - state.selection = selection; - return p.setSelection(selection); -} - -void TabFrame::setText(unsigned selection, const string& text) { - if(selection >= state.text.size()) return; - state.text[selection] = text; - return p.setText(selection, text); -} - -void TabFrame::synchronizeLayout() { - for(unsigned n = 0; n < state.layout.size(); n++) { - Layout* layout = state.layout[n]; - if(layout == nullptr) continue; - layout->Sizable::state.parent = this; - layout->Sizable::state.window = Sizable::state.window; - layout->state.widget = this; - layout->state.widgetSelection = n; - layout->synchronizeLayout(); - } -} - -unsigned TabFrame::tabs() const { - return state.text.size(); -} - -string TabFrame::text(unsigned selection) const { - if(selection >= state.text.size()) return ""; - return state.text[selection]; -} - -TabFrame::TabFrame(): -state(*new State), -base_from_member(*new pTabFrame(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -TabFrame::~TabFrame() { - p.destructor(); - delete &state; -} - -//TextEdit -//======== - -Color TextEdit::backgroundColor() const { - return state.backgroundColor; -} - -bool TextEdit::editable() const { - return state.editable; -} - -Color TextEdit::foregroundColor() const { - return state.foregroundColor; -} - -void TextEdit::setBackgroundColor(Color color) { - state.backgroundColor = color; - return p.setBackgroundColor(color); -} - -void TextEdit::setCursorPosition(unsigned position) { - state.cursorPosition = position; - return p.setCursorPosition(position); -} - -void TextEdit::setEditable(bool editable) { - state.editable = editable; - return p.setEditable(editable); -} - -void TextEdit::setForegroundColor(Color color) { - state.foregroundColor = color; - return p.setForegroundColor(color); -} - -void TextEdit::setText(const string& text) { - state.text = text; - return p.setText(text); -} - -void TextEdit::setWordWrap(bool wordWrap) { - state.wordWrap = wordWrap; - return p.setWordWrap(wordWrap); -} - -string TextEdit::text() { - return p.text(); -} - -bool TextEdit::wordWrap() const { - return state.wordWrap; -} - -TextEdit::TextEdit(): -state(*new State), -base_from_member(*new pTextEdit(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -TextEdit::~TextEdit() { - p.destructor(); - delete &state; -} - -//VerticalScroller -//================ - -unsigned VerticalScroller::length() const { - return state.length; -} - -unsigned VerticalScroller::position() const { - return state.position; -} - -void VerticalScroller::setLength(unsigned length) { - state.length = length; - return p.setLength(length); -} - -void VerticalScroller::setPosition(unsigned position) { - state.position = position; - return p.setPosition(position); -} - -VerticalScroller::VerticalScroller(): -state(*new State), -base_from_member(*new pVerticalScroller(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -VerticalScroller::~VerticalScroller() { - p.destructor(); - delete &state; -} - -//VerticalSlider -//============== - -unsigned VerticalSlider::length() const { - return state.length; -} - -unsigned VerticalSlider::position() const { - return state.position; -} - -void VerticalSlider::setLength(unsigned length) { - state.length = length; - return p.setLength(length); -} - -void VerticalSlider::setPosition(unsigned position) { - state.position = position; - return p.setPosition(position); -} - -VerticalSlider::VerticalSlider(): -state(*new State), -base_from_member(*new pVerticalSlider(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -VerticalSlider::~VerticalSlider() { - p.destructor(); - delete &state; -} - -//Viewport -//======== - -bool Viewport::droppable() const { - return state.droppable; -} - -uintptr_t Viewport::handle() { - return p.handle(); -} - -void Viewport::setDroppable(bool droppable) { - state.droppable = droppable; - return p.setDroppable(droppable); -} - -Viewport::Viewport(): -state(*new State), -base_from_member(*new pViewport(*this)), -Widget(base_from_member::value), -p(base_from_member::value) { - p.constructor(); -} - -Viewport::~Viewport() { - p.destructor(); - delete &state; -} - -} diff --git a/phoenix/core/core.hpp b/phoenix/core/core.hpp deleted file mode 100644 index cc25c5ba..00000000 --- a/phoenix/core/core.hpp +++ /dev/null @@ -1,826 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace phoenix { - -struct Application; -struct Font; -struct Window; -struct Menu; -struct Sizable; -struct Layout; -struct Widget; - -struct pApplication; -struct pFont; -struct pObject; -struct pTimer; -struct pWindow; -struct pAction; -struct pMenu; -struct pSeparator; -struct pItem; -struct pCheckItem; -struct pRadioItem; -struct pSizable; -struct pLayout; -struct pWidget; -struct pButton; -struct pCanvas; -struct pCheckButton; -struct pCheckLabel; -struct pComboButton; -struct pConsole; -struct pFrame; -struct pHexEdit; -struct pHorizontalScroller; -struct pHorizontalSlider; -struct pLabel; -struct pLineEdit; -struct pListView; -struct pProgressBar; -struct pRadioButton; -struct pRadioLabel; -struct pTabFrame; -struct pTextEdit; -struct pVerticalScroller; -struct pVerticalSlider; -struct pViewport; - -struct Application { - static nall::function main; - - static void run(); - static bool pendingEvents(); - static void processEvents(); - static void quit(); - static void setName(const nall::string& name); - - Application() = delete; - struct State; - static void initialize(); - - struct Windows { - static nall::function onModalBegin; - static nall::function onModalEnd; - }; - - struct Cocoa { - static nall::function onAbout; - static nall::function onActivate; - static nall::function onPreferences; - static nall::function onQuit; - }; -}; - -struct Color { - uint8_t red, green, blue, alpha; - uint32_t rgb() const; - uint32_t argb() const; - inline Color() : alpha(255), red(0), green(0), blue(0) {} - inline Color(uint8_t red, uint8_t green, uint8_t blue) : alpha(255), red(red), green(green), blue(blue) {} - inline Color(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue) : alpha(alpha), red(red), green(green), blue(blue) {} -}; - -struct Position { - signed x, y; - inline Position() : x(0), y(0) {} - template inline Position(X x, Y y) : x(x), y(y) {} -}; - -struct Size { - static const unsigned Maximum = ~0u; - static const unsigned Minimum = 0u; - - unsigned width, height; - inline Size() : width(0), height(0) {} - template inline Size(W width, H height) : width(width), height(height) {} -}; - -struct Geometry { - signed x, y; - unsigned width, height; - Position position() const; - Size size() const; - nall::string text() const; - inline Geometry() : x(0), y(0), width(0), height(0) {} - inline Geometry(Position position, Size size) : x(position.x), y(position.y), width(size.width), height(size.height) {} - template inline Geometry(X x, Y y, W width, H height) : x(x), y(y), width(width), height(height) {} - Geometry(const nall::string& text); -}; - -enum class Orientation : unsigned { Horizontal, Vertical }; - -struct Font { - static nall::string serif(unsigned size = 0, const nall::string& style = ""); - static nall::string sans(unsigned size = 0, const nall::string& style = ""); - static nall::string monospace(unsigned size = 0, const nall::string& style = ""); - static Size size(const nall::string& font, const nall::string& text); - Font() = delete; -}; - -struct Desktop { - static Size size(); - static Geometry workspace(); - Desktop() = delete; -}; - -struct Monitor { - static unsigned count(); - static Geometry geometry(unsigned monitor); - static unsigned primary(); -}; - -struct Keyboard { - #include "keyboard.hpp" - static bool pressed(Scancode scancode); - static bool released(Scancode scancode); - static nall::vector state(); - Keyboard() = delete; -}; - -struct Mouse { - enum class Button : unsigned { Left, Middle, Right }; - static Position position(); - static bool pressed(Button); - static bool released(Button); - Mouse() = delete; -}; - -struct BrowserWindow { - nall::string directory(); - nall::string open(); - nall::string save(); - BrowserWindow& setFilters(const nall::lstring& filters); - BrowserWindow& setParent(Window& parent); - BrowserWindow& setPath(const nall::string& path); - BrowserWindow& setTitle(const nall::string& title); - - BrowserWindow(); - ~BrowserWindow(); - struct State; - State& state; -}; - -struct MessageWindow { - enum class Buttons : unsigned { - Ok, - OkCancel, - YesNo, - YesNoCancel, - }; - - enum class Response : unsigned { - Ok, - Cancel, - Yes, - No, - }; - - Response error(Buttons = Buttons::Ok); - Response information(Buttons = Buttons::Ok); - Response question(Buttons = Buttons::YesNo); - MessageWindow& setParent(Window& parent); - MessageWindow& setText(const nall::string& text); - MessageWindow& setTitle(const nall::string& title); - Response warning(Buttons = Buttons::Ok); - - MessageWindow(const nall::string& text = ""); - ~MessageWindow(); - struct State; - State& state; -}; - -struct Object { - Object(pObject& p); - Object& operator=(const Object&) = delete; - Object(const Object&) = delete; - virtual ~Object(); - pObject& p; -}; - -struct Timer : private nall::base_from_member, Object { - nall::function onActivate; - - bool enabled() const; - unsigned interval() const; - void setEnabled(bool enabled = true); - void setInterval(unsigned interval); //in milliseconds - - Timer(); - ~Timer(); - struct State; - State& state; - pTimer& p; -}; - -struct Window : private nall::base_from_member, Object { - nall::function onClose; - nall::function onDrop; - nall::function onKeyPress; - nall::function onKeyRelease; - nall::function onMove; - nall::function onSize; - - void append(Layout& layout); - void append(Menu& menu); - void append(Widget& widget); - Color backgroundColor() const; - bool droppable() const; - Geometry frameGeometry(); - Geometry frameMargin(); - bool focused(); - bool fullScreen() const; - Geometry geometry(); - nall::string menuFont() const; - bool menuVisible() const; - bool modal() const; - void remove(Layout& layout); - void remove(Menu& menu); - void remove(Widget& widget); - bool resizable() const; - void setBackgroundColor(Color color); - void setDroppable(bool droppable = true); - void setFrameGeometry(Geometry geometry); - void setFocused(); - void setFullScreen(bool fullScreen = true); - void setGeometry(Geometry geometry); - void setMenuFont(const nall::string& font); - void setMenuVisible(bool visible = true); - void setModal(bool modal = true); - void setResizable(bool resizable = true); - void setStatusFont(const nall::string& font); - void setStatusText(const nall::string& text); - void setStatusVisible(bool visible = true); - void setTitle(const nall::string& text); - void setVisible(bool visible = true); - void setWidgetFont(const nall::string& font); - void setWindowGeometry(Geometry geometry); - nall::string statusFont() const; - nall::string statusText() const; - bool statusVisible() const; - void synchronizeLayout(); - nall::string title() const; - bool visible() const; - nall::string widgetFont() const; - - Window(); - ~Window(); - struct State; - State& state; - pWindow& p; -}; - -struct Action : Object { - bool enabled() const; - void setEnabled(bool enabled = true); - void setVisible(bool visible = true); - bool visible() const; - - Action(pAction& p); - ~Action(); - struct State; - State& state; - pAction& p; -}; - -struct Menu : private nall::base_from_member, Action { - void append(const nall::group& list); - nall::image image() const; - void remove(const nall::group& list); - void setImage(const nall::image& image = nall::image{}); - void setText(const nall::string& text); - nall::string text() const; - - Menu(); - ~Menu(); - struct State; - State& state; - pMenu& p; -}; - -struct Separator : private nall::base_from_member, Action { - Separator(); - ~Separator(); - pSeparator& p; -}; - -struct Item : private nall::base_from_member, Action { - nall::function onActivate; - - nall::image image() const; - void setImage(const nall::image& image = nall::image{}); - void setText(const nall::string& text); - nall::string text() const; - - Item(); - ~Item(); - struct State; - State& state; - pItem& p; -}; - -struct CheckItem : private nall::base_from_member, Action { - nall::function onToggle; - - bool checked() const; - void setChecked(bool checked = true); - void setText(const nall::string& text); - nall::string text() const; - - CheckItem(); - ~CheckItem(); - struct State; - State& state; - pCheckItem& p; -}; - -struct RadioItem : private nall::base_from_member, Action { - template static void group(Args&&... args) { group({std::forward(args)...}); } - static void group(const nall::group& list); - - nall::function onActivate; - - bool checked() const; - void setChecked(); - void setText(const nall::string& text); - nall::string text() const; - - RadioItem(); - ~RadioItem(); - struct State; - State& state; - pRadioItem& p; -}; - -struct Sizable : Object { - bool enabled() const; - bool enabledToAll() const; - Layout* layout() const; - virtual Size minimumSize() = 0; - Sizable* parent() const; - virtual void setEnabled(bool enabled = true) = 0; - virtual void setGeometry(Geometry geometry) = 0; - virtual void setVisible(bool visible = true) = 0; - virtual void synchronizeLayout() = 0; - bool visible() const; - bool visibleToAll() const; - Window* window() const; - - Sizable(pSizable& p); - ~Sizable(); - struct State; - State& state; - pSizable& p; -}; - -struct Layout : private nall::base_from_member, Sizable { - virtual void append(Sizable& sizable); - virtual void remove(Sizable& sizable); - virtual void reset(); - - Layout(); - Layout(pLayout& p); - ~Layout(); - struct State; - State& state; - pLayout& p; -}; - -struct Widget : private nall::base_from_member, Sizable { - nall::function onSize; - - bool focused(); - nall::string font() const; - Geometry geometry() const; - Size minimumSize(); - void setEnabled(bool enabled = true); - void setFocused(); - void setFont(const nall::string& font); - void setGeometry(Geometry geometry); - void setVisible(bool visible = true); - void synchronizeLayout(); - - Widget(); - Widget(pWidget& p); - ~Widget(); - struct State; - State& state; - pWidget& p; -}; - -struct Button : private nall::base_from_member, Widget { - nall::function onActivate; - - nall::image image() const; - Orientation orientation() const; - void setImage(const nall::image& image = nall::image{}, Orientation orientation = Orientation::Horizontal); - void setText(const nall::string& text); - nall::string text() const; - - Button(); - ~Button(); - struct State; - State& state; - pButton& p; -}; - -struct Canvas : private nall::base_from_member, Widget { - enum class Mode : unsigned { Color, Gradient, Image, Data }; - - nall::function onDrop; - nall::function onMouseLeave; - nall::function onMouseMove; - nall::function onMousePress; - nall::function onMouseRelease; - - Color color() const; - uint32_t* data() const; - bool droppable() const; - nall::vector gradient() const; - nall::image image() const; - Mode mode() const; - void setColor(Color color); - void setData(); - void setDroppable(bool droppable = true); - void setHorizontalGradient(Color left, Color right); - void setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight); - void setImage(const nall::image& image); - void setMode(Mode mode); - void setSize(Size size); - void setVerticalGradient(Color top, Color bottom); - Size size() const; - - Canvas(); - ~Canvas(); - struct State; - State& state; - pCanvas& p; -}; - -struct CheckButton : private nall::base_from_member, Widget { - nall::function onToggle; - - bool checked() const; - nall::image image() const; - void setChecked(bool checked = true); - void setImage(const nall::image& image = nall::image{}, Orientation orientation = Orientation::Horizontal); - void setText(const nall::string& text); - nall::string text() const; - - CheckButton(); - ~CheckButton(); - struct State; - State& state; - pCheckButton& p; -}; - -struct CheckLabel : private nall::base_from_member, Widget { - nall::function onToggle; - - bool checked() const; - void setChecked(bool checked = true); - void setText(const nall::string& text); - nall::string text() const; - - CheckLabel(); - ~CheckLabel(); - struct State; - State& state; - pCheckLabel& p; -}; - -struct ComboButton : private nall::base_from_member, Widget { - nall::function onChange; - - void append(const nall::string& text = ""); - void remove(unsigned selection); - void reset(); - unsigned rows() const; - unsigned selection() const; - void setSelection(unsigned selection); - void setText(unsigned selection, const nall::string& text); - nall::string text() const; - nall::string text(unsigned selection) const; - - ComboButton(); - ~ComboButton(); - struct State; - State& state; - pComboButton& p; -}; - -struct Console : private nall::base_from_member, Widget { - nall::function onActivate; - - template void print(Args&&... args) { print({args...}); } - - Color backgroundColor() const; - Color foregroundColor() const; - void print(const nall::string& text); - nall::string prompt() const; - void reset(); - void setBackgroundColor(Color color); - void setForegroundColor(Color color); - void setPrompt(const nall::string& prompt); - - Console(); - ~Console(); - struct State; - State& state; - pConsole& p; -}; - -struct Frame : private nall::base_from_member, Widget { - void setLayout(Layout& layout); - void setText(const nall::string& text); - void synchronizeLayout(); - nall::string text() const; - - Frame(); - ~Frame(); - struct State; - State& state; - pFrame& p; -}; - -struct HexEdit : private nall::base_from_member, Widget { - nall::function onRead; - nall::function onWrite; - - Color backgroundColor() const; - unsigned columns() const; - Color foregroundColor() const; - unsigned length() const; - unsigned offset() const; - unsigned rows() const; - void setBackgroundColor(Color color); - void setColumns(unsigned columns); - void setForegroundColor(Color color); - void setLength(unsigned length); - void setOffset(unsigned offset); - void setRows(unsigned rows); - void update(); - - HexEdit(); - ~HexEdit(); - struct State; - State& state; - pHexEdit& p; -}; - -struct HorizontalScroller : private nall::base_from_member, Widget { - nall::function onChange; - - unsigned length() const; - unsigned position() const; - void setLength(unsigned length); - void setPosition(unsigned position); - - HorizontalScroller(); - ~HorizontalScroller(); - struct State; - State& state; - pHorizontalScroller& p; -}; - -struct HorizontalSlider : private nall::base_from_member, Widget { - nall::function onChange; - - unsigned length() const; - unsigned position() const; - void setLength(unsigned length); - void setPosition(unsigned position); - - HorizontalSlider(); - ~HorizontalSlider(); - struct State; - State& state; - pHorizontalSlider& p; -}; - -struct Label : private nall::base_from_member, Widget { - void setText(const nall::string& text); - nall::string text() const; - - Label(); - ~Label(); - struct State; - State& state; - pLabel& p; -}; - -struct LineEdit : private nall::base_from_member, Widget { - nall::function onActivate; - nall::function onChange; - - Color backgroundColor() const; - bool editable() const; - Color foregroundColor() const; - void setBackgroundColor(Color color); - void setEditable(bool editable = true); - void setForegroundColor(Color color); - void setText(const nall::string& text); - nall::string text(); - - LineEdit(); - ~LineEdit(); - struct State; - State& state; - pLineEdit& p; -}; - -struct ListView : private nall::base_from_member, Widget { - nall::function onActivate; - nall::function onChange; - nall::function onToggle; - - void append(const nall::lstring& text); - void autoSizeColumns(); - Color backgroundColor() const; - bool checkable() const; - bool checked(unsigned selection) const; - unsigned columns() const; - Color foregroundColor() const; - bool headerVisible() const; - nall::image image(unsigned selection, unsigned position) const; - void remove(unsigned selection); - void reset(); - unsigned rows() const; - bool selected() const; - unsigned selection() const; - void setBackgroundColor(Color color); - void setCheckable(bool checkable = true); - void setChecked(unsigned selection, bool checked = true); - void setForegroundColor(Color color); - void setHeaderText(const nall::lstring& text); - void setHeaderVisible(bool visible = true); - void setImage(unsigned selection, unsigned position, const nall::image& image = nall::image{}); - void setSelected(bool selected = true); - void setSelection(unsigned selection); - void setText(unsigned selection, const nall::lstring& text); - void setText(unsigned selection, unsigned position, const nall::string& text); - nall::string text(unsigned selection, unsigned position) const; - - ListView(); - ~ListView(); - struct State; - State& state; - pListView& p; -}; - -struct ProgressBar : private nall::base_from_member, Widget { - unsigned position() const; - void setPosition(unsigned position); - - ProgressBar(); - ~ProgressBar(); - struct State; - State& state; - pProgressBar& p; -}; - -struct RadioButton : private nall::base_from_member, Widget { - template static void group(Args&&... args) { group({std::forward(args)...}); } - static void group(const nall::group& list); - - nall::function onActivate; - - bool checked() const; - nall::image image() const; - void setChecked(); - void setImage(const nall::image& image = nall::image{}, Orientation orientation = Orientation::Horizontal); - void setText(const nall::string& text); - nall::string text() const; - - RadioButton(); - ~RadioButton(); - struct State; - State& state; - pRadioButton& p; -}; - -struct RadioLabel : private nall::base_from_member, Widget { - template static void group(Args&&... args) { group({std::forward(args)...}); } - static void group(const nall::group& list); - - nall::function onActivate; - - bool checked() const; - void setChecked(); - void setText(const nall::string& text); - nall::string text() const; - - RadioLabel(); - ~RadioLabel(); - struct State; - State& state; - pRadioLabel& p; -}; - -struct TabFrame : private nall::base_from_member, Widget { - nall::function onChange; - - void append(const nall::string& text = "", const nall::image& image = nall::image{}); - nall::image image(unsigned selection) const; - void remove(unsigned selection); - unsigned selection() const; - void setImage(unsigned selection, const nall::image& image = nall::image{}); - void setLayout(unsigned selection, Layout& layout); - void setSelection(unsigned selection); - void setText(unsigned selection, const nall::string& text); - void synchronizeLayout(); - unsigned tabs() const; - nall::string text(unsigned selection) const; - - TabFrame(); - ~TabFrame(); - struct State; - State& state; - pTabFrame& p; -}; - -struct TextEdit : private nall::base_from_member, Widget { - nall::function onChange; - - Color backgroundColor() const; - bool editable() const; - Color foregroundColor() const; - void setBackgroundColor(Color color); - void setCursorPosition(unsigned position); - void setEditable(bool editable = true); - void setForegroundColor(Color color); - void setText(const nall::string& text); - void setWordWrap(bool wordWrap = true); - nall::string text(); - bool wordWrap() const; - - TextEdit(); - ~TextEdit(); - struct State; - State& state; - pTextEdit& p; -}; - -struct VerticalScroller : private nall::base_from_member, Widget { - nall::function onChange; - - unsigned length() const; - unsigned position() const; - void setLength(unsigned length); - void setPosition(unsigned position); - - VerticalScroller(); - ~VerticalScroller(); - struct State; - State& state; - pVerticalScroller& p; -}; - -struct VerticalSlider : private nall::base_from_member, Widget { - nall::function onChange; - - unsigned length() const; - unsigned position() const; - void setLength(unsigned length); - void setPosition(unsigned position); - - VerticalSlider(); - ~VerticalSlider(); - struct State; - State& state; - pVerticalSlider& p; -}; - -struct Viewport : private nall::base_from_member, Widget { - nall::function onDrop; - nall::function onMouseLeave; - nall::function onMouseMove; - nall::function onMousePress; - nall::function onMouseRelease; - - bool droppable() const; - uintptr_t handle(); - void setDroppable(bool droppable = true); - - Viewport(); - ~Viewport(); - struct State; - State& state; - pViewport& p; -}; - -#include "layout/fixed-layout.hpp" -#include "layout/horizontal-layout.hpp" -#include "layout/vertical-layout.hpp" - -} diff --git a/phoenix/core/keyboard.hpp b/phoenix/core/keyboard.hpp deleted file mode 100644 index ed04ec05..00000000 --- a/phoenix/core/keyboard.hpp +++ /dev/null @@ -1,45 +0,0 @@ -//each code refers to a physical key -//names are taken assuming: NumLock on, CapsLock off, Shift off -//layout uses US-104 keyboard -enum class Scancode : unsigned { - None, - - Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, - PrintScreen, ScrollLock, Pause, - Insert, Delete, Home, End, PageUp, PageDown, - Up, Down, Left, Right, - - Grave, Number1, Number2, Number3, Number4, Number5, Number6, Number7, Number8, Number9, Number0, Minus, Equal, Backspace, - BracketLeft, BracketRight, Backslash, Semicolon, Apostrophe, Comma, Period, Slash, - Tab, CapsLock, Return, ShiftLeft, ShiftRight, ControlLeft, ControlRight, SuperLeft, SuperRight, AltLeft, AltRight, Space, Menu, - A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, - - NumLock, Divide, Multiply, Subtract, Add, Enter, Point, - Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0, - - Limit, -}; - -//each enum refers to a translated scancode (eg Shift+1 = !) -enum class Keycode : unsigned { - None, - - Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, - PrintScreen, SysRq, ScrollLock, Pause, Break, - Insert, Delete, Home, End, PageUp, PageDown, - Up, Down, Left, Right, - - Grave, Number1, Number2, Number3, Number4, Number5, Number6, Number7, Number8, Number9, Number0, Minus, Equal, Backspace, - Tilde, Exclamation, At, Pound, Dollar, Percent, Power, Ampersand, Asterisk, ParenthesisLeft, ParenthesisRight, Underscore, Plus, - BracketLeft, BracketRight, Backslash, Semicolon, Apostrophe, Comma, Period, Slash, - BraceLeft, BraceRight, Pipe, Colon, Quote, CaretLeft, CaretRight, Question, - Tab, CapsLock, Return, ShiftLeft, ShiftRight, ControlLeft, ControlRight, SuperLeft, SuperRight, AltLeft, AltRight, Space, Menu, - A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, - a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, - - NumLock, Divide, Multiply, Subtract, Add, Enter, Point, - Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0, - KeypadInsert, KeypadDelete, KeypadHome, KeypadEnd, KeypadPageUp, KeypadPageDown, KeypadUp, KeypadDown, KeypadLeft, KeypadRight, KeypadCenter, - - Limit, -}; diff --git a/phoenix/core/layout/fixed-layout.cpp b/phoenix/core/layout/fixed-layout.cpp deleted file mode 100644 index d29189e5..00000000 --- a/phoenix/core/layout/fixed-layout.cpp +++ /dev/null @@ -1,68 +0,0 @@ -void FixedLayout::append(Sizable& sizable, Geometry geometry) { - children.append({&sizable, geometry}); - synchronizeLayout(); - if(window()) window()->synchronizeLayout(); -} - -void FixedLayout::append(Sizable& sizable) { - for(auto& child : children) if(child.sizable == &sizable) return; - Layout::append(sizable); - if(window()) window()->synchronizeLayout(); -} - -Size FixedLayout::minimumSize() { - unsigned width = Size::Minimum, height = Size::Minimum; - for(auto& child : children) { - width = max(width, child.sizable->minimumSize().width); - height = max(height, child.sizable->minimumSize().height); - } - return {width, height}; -} - -void FixedLayout::remove(Sizable& sizable) { - for(unsigned n = 0; n < children.size(); n++) { - if(children[n].sizable == &sizable) { - children.remove(n); - Layout::remove(sizable); - if(window()) window()->synchronizeLayout(); - break; - } - } -} - -void FixedLayout::reset() { - for(auto& child : children) { - if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); - } -} - -void FixedLayout::setEnabled(bool enabled) { - Sizable::state.enabled = enabled; - for(auto& child : children) { - child.sizable->setEnabled(child.sizable->enabled()); - } -} - -void FixedLayout::setGeometry(Geometry geometry) { -} - -void FixedLayout::setVisible(bool visible) { - Sizable::state.visible = visible; - for(auto& child : children) { - child.sizable->setVisible(child.sizable->visible()); - } -} - -void FixedLayout::synchronizeLayout() { - for(auto& child : children) { - Layout::append(*child.sizable); - Geometry childGeometry = child.geometry; - if((signed)childGeometry.width < 1) childGeometry.width = 1; - if((signed)childGeometry.height < 1) childGeometry.height = 1; - child.sizable->setGeometry(childGeometry); - } -} - -FixedLayout::~FixedLayout() { - while(children.size()) remove(*children[0].sizable); -} diff --git a/phoenix/core/layout/fixed-layout.hpp b/phoenix/core/layout/fixed-layout.hpp deleted file mode 100644 index 881bee76..00000000 --- a/phoenix/core/layout/fixed-layout.hpp +++ /dev/null @@ -1,19 +0,0 @@ -struct FixedLayout : Layout { - void append(Sizable& sizable, Geometry geometry); - void append(Sizable& sizable); - Size minimumSize(); - void remove(Sizable& sizable); - void reset(); - void setEnabled(bool enabled = true); - void setGeometry(Geometry geometry); - void setVisible(bool visible = true); - void synchronizeLayout(); - ~FixedLayout(); - -//private: - struct Children { - Sizable* sizable; - Geometry geometry; - }; - nall::vector children; -}; diff --git a/phoenix/core/layout/horizontal-layout.cpp b/phoenix/core/layout/horizontal-layout.cpp deleted file mode 100644 index 574d48e3..00000000 --- a/phoenix/core/layout/horizontal-layout.cpp +++ /dev/null @@ -1,127 +0,0 @@ -void HorizontalLayout::append(Sizable& sizable, Size size, unsigned spacing) { - for(auto& child : children) if(child.sizable == &sizable) return; - children.append({&sizable, size.width, size.height, spacing}); - synchronizeLayout(); - if(window()) window()->synchronizeLayout(); -} - -void HorizontalLayout::append(Sizable& sizable) { - for(auto& child : children) if(child.sizable == &sizable) return; - Layout::append(sizable); - if(window()) window()->synchronizeLayout(); -} - -Size HorizontalLayout::minimumSize() { - unsigned width = 0, height = 0; - - for(auto& child : children) { - width += child.spacing; - if(child.width == Size::Minimum || child.width == Size::Maximum) { - width += child.sizable->minimumSize().width; - continue; - } - width += child.width; - } - - for(auto& child : children) { - if(child.height == Size::Minimum || child.height == Size::Maximum) { - height = max(height, child.sizable->minimumSize().height); - continue; - } - height = max(height, child.height); - } - - return {state.margin * 2 + width, state.margin * 2 + height}; -} - -void HorizontalLayout::remove(Sizable& sizable) { - for(unsigned n = 0; n < children.size(); n++) { - if(children[n].sizable == &sizable) { - if(dynamic_cast(children[n].sizable)) { - Layout* layout = (Layout*)children[n].sizable; - layout->reset(); - } - children.remove(n); - Layout::remove(sizable); - if(window()) window()->synchronizeLayout(); - break; - } - } -} - -void HorizontalLayout::reset() { - for(auto& child : children) { - if(window() && dynamic_cast(child.sizable)) ((Layout*)child.sizable)->reset(); - if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); - } -} - -void HorizontalLayout::setAlignment(double alignment) { - state.alignment = max(0.0, min(1.0, alignment)); -} - -void HorizontalLayout::setEnabled(bool enabled) { - Sizable::state.enabled = enabled; - for(auto& child : children) { - child.sizable->setEnabled(child.sizable->enabled()); - } -} - -void HorizontalLayout::setGeometry(Geometry containerGeometry) { - auto children = this->children; - for(auto& child : children) { - if(child.width == Size::Minimum) child.width = child.sizable->minimumSize().width; - if(child.height == Size::Minimum) child.height = child.sizable->minimumSize().height; - } - - Geometry geometry = containerGeometry; - geometry.x += state.margin; - geometry.y += state.margin; - geometry.width -= state.margin * 2; - geometry.height -= state.margin * 2; - - unsigned minimumWidth = 0, maximumWidthCounter = 0; - for(auto& child : children) { - if(child.width == Size::Maximum) maximumWidthCounter++; - if(child.width != Size::Maximum) minimumWidth += child.width; - minimumWidth += child.spacing; - } - - for(auto& child : children) { - if(child.width == Size::Maximum) child.width = (geometry.width - minimumWidth) / maximumWidthCounter; - if(child.height == Size::Maximum) child.height = geometry.height; - } - - unsigned maximumHeight = 0; - for(auto& child : children) maximumHeight = max(maximumHeight, child.height); - - for(auto& child : children) { - unsigned pivot = (maximumHeight - child.height) * state.alignment; - Geometry childGeometry = {geometry.x, geometry.y + pivot, child.width, child.height}; - if((signed)childGeometry.width < 1) childGeometry.width = 1; - if((signed)childGeometry.height < 1) childGeometry.height = 1; - child.sizable->setGeometry(childGeometry); - - geometry.x += child.width + child.spacing; - geometry.width -= child.width + child.spacing; - } -} - -void HorizontalLayout::setMargin(unsigned margin) { - state.margin = margin; -} - -void HorizontalLayout::setVisible(bool visible) { - Sizable::state.visible = visible; - for(auto& child : children) { - child.sizable->setVisible(child.sizable->visible()); - } -} - -void HorizontalLayout::synchronizeLayout() { - for(auto& child : children) Layout::append(*child.sizable); -} - -HorizontalLayout::~HorizontalLayout() { - while(children.size()) remove(*children[0].sizable); -} diff --git a/phoenix/core/layout/horizontal-layout.hpp b/phoenix/core/layout/horizontal-layout.hpp deleted file mode 100644 index c12eda8b..00000000 --- a/phoenix/core/layout/horizontal-layout.hpp +++ /dev/null @@ -1,26 +0,0 @@ -struct HorizontalLayout : public Layout { - void append(Sizable& sizable, Size size, unsigned spacing = 0); - void append(Sizable& sizable); - Size minimumSize(); - void remove(Sizable& sizable); - void reset(); - void setAlignment(double alignment); - void setEnabled(bool enabled = true); - void setGeometry(Geometry geometry); - void setMargin(unsigned margin); - void setVisible(bool visible = true); - void synchronizeLayout(); - ~HorizontalLayout(); - -//private: - struct State { - double alignment = 0.5; - unsigned margin = 0; - } state; - - struct Children { - Sizable* sizable; - unsigned width, height, spacing; - }; - nall::vector children; -}; diff --git a/phoenix/core/layout/vertical-layout.cpp b/phoenix/core/layout/vertical-layout.cpp deleted file mode 100644 index 804a26db..00000000 --- a/phoenix/core/layout/vertical-layout.cpp +++ /dev/null @@ -1,127 +0,0 @@ -void VerticalLayout::append(Sizable& sizable, Size size, unsigned spacing) { - for(auto& child : children) if(child.sizable == &sizable) return; - children.append({&sizable, size.width, size.height, spacing}); - synchronizeLayout(); - if(window()) window()->synchronizeLayout(); -} - -void VerticalLayout::append(Sizable& sizable) { - for(auto& child : children) if(child.sizable == &sizable) return; - Layout::append(sizable); - if(window()) window()->synchronizeLayout(); -} - -Size VerticalLayout::minimumSize() { - unsigned width = 0, height = 0; - - for(auto& child : children) { - if(child.width == Size::Minimum || child.width == Size::Maximum) { - width = max(width, child.sizable->minimumSize().width); - continue; - } - width = max(width, child.width); - } - - for(auto& child : children) { - height += child.spacing; - if(child.height == Size::Minimum || child.height == Size::Maximum) { - height += child.sizable->minimumSize().height; - continue; - } - height += child.height; - } - - return {state.margin * 2 + width, state.margin * 2 + height}; -} - -void VerticalLayout::remove(Sizable& sizable) { - for(unsigned n = 0; n < children.size(); n++) { - if(children[n].sizable == &sizable) { - if(dynamic_cast(children[n].sizable)) { - Layout* layout = (Layout*)children[n].sizable; - layout->reset(); - } - children.remove(n); - Layout::remove(sizable); - if(window()) window()->synchronizeLayout(); - break; - } - } -} - -void VerticalLayout::reset() { - for(auto& child : children) { - if(window() && dynamic_cast(child.sizable)) ((Layout*)child.sizable)->reset(); - if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); - } -} - -void VerticalLayout::setAlignment(double alignment) { - state.alignment = max(0.0, min(1.0, alignment)); -} - -void VerticalLayout::setEnabled(bool enabled) { - Sizable::state.enabled = enabled; - for(auto& child : children) { - child.sizable->setEnabled(child.sizable->enabled()); - } -} - -void VerticalLayout::setGeometry(Geometry containerGeometry) { - auto children = this->children; - for(auto& child : children) { - if(child.width == Size::Minimum) child.width = child.sizable->minimumSize().width; - if(child.height == Size::Minimum) child.height = child.sizable->minimumSize().height; - } - - Geometry geometry = containerGeometry; - geometry.x += state.margin; - geometry.y += state.margin; - geometry.width -= state.margin * 2; - geometry.height -= state.margin * 2; - - unsigned minimumHeight = 0, maximumHeightCounter = 0; - for(auto& child : children) { - if(child.height == Size::Maximum) maximumHeightCounter++; - if(child.height != Size::Maximum) minimumHeight += child.height; - minimumHeight += child.spacing; - } - - for(auto& child : children) { - if(child.width == Size::Maximum) child.width = geometry.width; - if(child.height == Size::Maximum) child.height = (geometry.height - minimumHeight) / maximumHeightCounter; - } - - unsigned maximumWidth = 0; - for(auto& child : children) maximumWidth = max(maximumWidth, child.width); - - for(auto& child : children) { - unsigned pivot = (maximumWidth - child.width) * state.alignment; - Geometry childGeometry = {geometry.x + pivot, geometry.y, child.width, child.height}; - if((signed)childGeometry.width < 1) childGeometry.width = 1; - if((signed)childGeometry.height < 1) childGeometry.height = 1; - child.sizable->setGeometry(childGeometry); - - geometry.y += child.height + child.spacing; - geometry.height -= child.height + child.spacing; - } -} - -void VerticalLayout::setMargin(unsigned margin) { - state.margin = margin; -} - -void VerticalLayout::setVisible(bool visible) { - Sizable::state.visible = visible; - for(auto& child : children) { - child.sizable->setVisible(child.sizable->visible()); - } -} - -void VerticalLayout::synchronizeLayout() { - for(auto& child : children) Layout::append(*child.sizable); -} - -VerticalLayout::~VerticalLayout() { - while(children.size()) remove(*children[0].sizable); -} diff --git a/phoenix/core/layout/vertical-layout.hpp b/phoenix/core/layout/vertical-layout.hpp deleted file mode 100644 index db96d6e7..00000000 --- a/phoenix/core/layout/vertical-layout.hpp +++ /dev/null @@ -1,26 +0,0 @@ -struct VerticalLayout : public Layout { - void append(Sizable& sizable, Size size, unsigned spacing = 0); - void append(Sizable& sizable); - Size minimumSize(); - void remove(Sizable& sizable); - void reset(); - void setAlignment(double alignment); - void setEnabled(bool enabled = true); - void setGeometry(Geometry geometry); - void setMargin(unsigned margin); - void setVisible(bool visible = true); - void synchronizeLayout(); - ~VerticalLayout(); - -//private: - struct State { - double alignment = 0.0; - unsigned margin = 0; - } state; - - struct Children { - Sizable* sizable; - unsigned width, height, spacing; - }; - nall::vector children; -}; diff --git a/phoenix/core/state.hpp b/phoenix/core/state.hpp deleted file mode 100644 index 3a48de87..00000000 --- a/phoenix/core/state.hpp +++ /dev/null @@ -1,227 +0,0 @@ -struct Application::State { - string name; - bool quit = false; -} applicationState; - -struct Timer::State { - bool enabled = false; - unsigned interval = 0; -}; - -struct BrowserWindow::State { - lstring filters; - Window* parent = nullptr; - string path; - string title; -}; - -struct MessageWindow::State { - MessageWindow::Buttons buttons = MessageWindow::Buttons::Ok; - Window* parent = nullptr; - string text; - string title; -}; - -struct Window::State { - bool backgroundColorOverride = false; - Color backgroundColor = {0, 0, 0}; - bool droppable = false; - bool fullScreen = false; - Geometry geometry = {128, 128, 256, 256}; - group layout; - group menu; - string menuFont; - bool menuVisible = false; - bool modal = false; - bool resizable = true; - string statusFont; - string statusText; - bool statusVisible = false; - string title; - bool visible = false; - group widget; - string widgetFont; -}; - -struct Action::State { - bool enabled = true; - Menu* menu = nullptr; - bool visible = true; - Window* window = nullptr; -}; - -struct Menu::State { - group action; - nall::image image; - string text; -}; - -struct Item::State { - nall::image image; - string text; -}; - -struct CheckItem::State { - bool checked = false; - string text; -}; - -struct RadioItem::State { - bool checked = true; - nall::group group; - string text; -}; - -struct Sizable::State { - bool enabled = true; - Sizable* parent = nullptr; - bool visible = true; - Window* window = nullptr; -}; - -struct Layout::State { - Widget* widget = nullptr; - unsigned widgetSelection = 0; -}; - -struct Widget::State { - bool abstract = false; - string font; - Geometry geometry = {0, 0, 0, 0}; -}; - -struct Button::State { - nall::image image; - Orientation orientation = Orientation::Horizontal; - string text; -}; - -struct Canvas::State { - Color color; - uint32_t* data = nullptr; - bool droppable = false; - vector gradient = {{}, {}, {}, {}}; - nall::image image; - Canvas::Mode mode = Canvas::Mode::Color; - unsigned width = 0; - unsigned height = 0; -}; - -struct CheckButton::State { - bool checked = false; - nall::image image; - Orientation orientation = Orientation::Horizontal; - string text; -}; - -struct CheckLabel::State { - bool checked = false; - string text; -}; - -struct ComboButton::State { - unsigned selection = 0; - vector text; -}; - -struct Console::State { - Color backgroundColor = {255, 255, 255}; - Color foregroundColor = {0, 0, 0}; - string prompt; -}; - -struct Frame::State { - Layout* layout = nullptr; - string text; -}; - -struct HexEdit::State { - Color backgroundColor = {255, 255, 255}; - unsigned columns = 16; - Color foregroundColor = {0, 0, 0}; - unsigned length = 0; - unsigned offset = 0; - unsigned rows = 16; -}; - -struct HorizontalScroller::State { - unsigned length = 101; - unsigned position = 0; -}; - -struct HorizontalSlider::State { - unsigned length = 101; - unsigned position = 0; -}; - -struct Label::State { - string text; -}; - -struct LineEdit::State { - Color backgroundColor = {255, 255, 255}; - bool editable = true; - Color foregroundColor = {0, 0, 0}; - string text; -}; - -struct ListView::State { - Color backgroundColor = {255, 255, 255}; - bool checkable = false; - vector checked; - Color foregroundColor = {0, 0, 0}; - lstring headerText; - bool headerVisible = false; - vector> image; - bool selected = false; - unsigned selection = 0; - vector text; -}; - -struct ProgressBar::State { - unsigned position = 0; -}; - -struct RadioButton::State { - bool checked = true; - nall::group group; - nall::image image; - Orientation orientation = Orientation::Horizontal; - string text; -}; - -struct RadioLabel::State { - bool checked = true; - nall::group group; - string text; -}; - -struct TabFrame::State { - vector image; - vector layout; - unsigned selection = 0; - lstring text; -}; - -struct TextEdit::State { - Color backgroundColor = {255, 255, 255}; - unsigned cursorPosition = 0; - bool editable = true; - Color foregroundColor = {0, 0, 0}; - string text; - bool wordWrap = true; -}; - -struct VerticalScroller::State { - unsigned length = 101; - unsigned position = 0; -}; - -struct VerticalSlider::State { - unsigned length = 101; - unsigned position = 0; -}; - -struct Viewport::State { - bool droppable = false; -}; diff --git a/phoenix/gtk/action/check-item.cpp b/phoenix/gtk/action/check-item.cpp deleted file mode 100644 index 59d6299b..00000000 --- a/phoenix/gtk/action/check-item.cpp +++ /dev/null @@ -1,34 +0,0 @@ -namespace phoenix { - -static void CheckItem_toggle(GtkCheckMenuItem* gtkCheckMenuItem, CheckItem* self) { - self->state.checked = gtk_check_menu_item_get_active(gtkCheckMenuItem); - if(!self->p.locked && self->onToggle) self->onToggle(); -} - -void pCheckItem::setChecked(bool checked) { - locked = true; - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), checked); - locked = false; -} - -void pCheckItem::setText(string text) { - gtk_menu_item_set_label(GTK_MENU_ITEM(widget), mnemonic(text)); -} - -void pCheckItem::constructor() { - widget = gtk_check_menu_item_new_with_mnemonic(""); - setChecked(checkItem.state.checked); - setText(checkItem.state.text); - g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(CheckItem_toggle), (gpointer)&checkItem); -} - -void pCheckItem::destructor() { - gtk_widget_destroy(widget); -} - -void pCheckItem::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/action/item.cpp b/phoenix/gtk/action/item.cpp deleted file mode 100644 index 29b053e4..00000000 --- a/phoenix/gtk/action/item.cpp +++ /dev/null @@ -1,35 +0,0 @@ -namespace phoenix { - -static void Item_activate(Item* self) { - if(self->onActivate) self->onActivate(); -} - -void pItem::setImage(const image& image) { - if(image.empty() == false) { - GtkImage* gtkImage = CreateImage(image, true); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); - } else { - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); - } -} - -void pItem::setText(string text) { - gtk_menu_item_set_label(GTK_MENU_ITEM(widget), mnemonic(text)); -} - -void pItem::constructor() { - widget = gtk_image_menu_item_new_with_mnemonic(""); - g_signal_connect_swapped(G_OBJECT(widget), "activate", G_CALLBACK(Item_activate), (gpointer)&item); - setText(item.state.text); -} - -void pItem::destructor() { - gtk_widget_destroy(widget); -} - -void pItem::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/action/menu.cpp b/phoenix/gtk/action/menu.cpp deleted file mode 100644 index c0e4b375..00000000 --- a/phoenix/gtk/action/menu.cpp +++ /dev/null @@ -1,55 +0,0 @@ -namespace phoenix { - -void pMenu::append(Action& action) { - action.state.window = this->action.state.window; - - gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), action.p.widget); - if(action.state.window && action.state.window->state.menuFont != "") { - action.p.setFont(action.state.window->state.menuFont); - } - gtk_widget_show(action.p.widget); -} - -void pMenu::remove(Action& action) { - action.p.orphan(); - action.state.window = nullptr; -} - -void pMenu::setImage(const image& image) { - if(image.empty() == false) { - GtkImage* gtkImage = CreateImage(image, true); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); - } else { - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); - } -} - -void pMenu::setText(string text) { - gtk_menu_item_set_label(GTK_MENU_ITEM(widget), mnemonic(text)); -} - -void pMenu::constructor() { - gtkMenu = gtk_menu_new(); - widget = gtk_image_menu_item_new_with_mnemonic(""); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), gtkMenu); - setText(menu.state.text); -} - -void pMenu::destructor() { - gtk_widget_destroy(gtkMenu); - gtk_widget_destroy(widget); -} - -void pMenu::orphan() { - for(auto& action : menu.state.action) action.p.orphan(); - destructor(); - constructor(); - for(auto& action : menu.state.action) append(action); -} - -void pMenu::setFont(string font) { - pAction::setFont(font); - for(auto& item : menu.state.action) item.p.setFont(font); -} - -} diff --git a/phoenix/gtk/action/radio-item.cpp b/phoenix/gtk/action/radio-item.cpp deleted file mode 100644 index f00f9a76..00000000 --- a/phoenix/gtk/action/radio-item.cpp +++ /dev/null @@ -1,62 +0,0 @@ -namespace phoenix { - -static void RadioItem_activate(GtkCheckMenuItem* gtkCheckMenuItem, RadioItem* self) { - self->p.onActivate(); -} - -void pRadioItem::setChecked() { - parent().locked = true; - for(auto& item : radioItem.state.group) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item.p.widget), false); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), true); - parent().locked = false; -} - -void pRadioItem::setGroup(const group& group) { - parent().locked = true; - for(auto& item : group) { - if(&item == &group.first()) continue; - GSList* currentGroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(group.first().p.widget)); - if(currentGroup != gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item.p.widget))) { - gtk_radio_menu_item_set_group(GTK_RADIO_MENU_ITEM(item.p.widget), currentGroup); - } - } - parent().locked = false; -} - -void pRadioItem::setText(string text) { - gtk_menu_item_set_label(GTK_MENU_ITEM(widget), mnemonic(text)); -} - -void pRadioItem::constructor() { - widget = gtk_radio_menu_item_new_with_mnemonic(0, ""); - setGroup(radioItem.state.group); - setText(radioItem.state.text); - for(auto& item : radioItem.state.group) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item.p.widget), item.state.checked); - } - g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(RadioItem_activate), (gpointer)&radioItem); -} - -void pRadioItem::destructor() { - gtk_widget_destroy(widget); -} - -void pRadioItem::orphan() { - destructor(); - constructor(); -} - -void pRadioItem::onActivate() { - if(parent().locked) return; - bool wasChecked = radioItem.state.checked; - radioItem.setChecked(); - if(wasChecked) return; - if(radioItem.onActivate) radioItem.onActivate(); -} - -pRadioItem& pRadioItem::parent() { - if(radioItem.state.group.size()) return radioItem.state.group.first().p; - return *this; -} - -} diff --git a/phoenix/gtk/action/separator.cpp b/phoenix/gtk/action/separator.cpp deleted file mode 100644 index 0db95b2c..00000000 --- a/phoenix/gtk/action/separator.cpp +++ /dev/null @@ -1,16 +0,0 @@ -namespace phoenix { - -void pSeparator::constructor() { - widget = gtk_separator_menu_item_new(); -} - -void pSeparator::destructor() { - gtk_widget_destroy(widget); -} - -void pSeparator::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/application.cpp b/phoenix/gtk/application.cpp deleted file mode 100644 index 35091107..00000000 --- a/phoenix/gtk/application.cpp +++ /dev/null @@ -1,60 +0,0 @@ -namespace phoenix { - -XlibDisplay* pApplication::display = nullptr; - -void pApplication::run() { - if(Application::main) { - while(applicationState.quit == false) { - processEvents(); - Application::main(); - } - } else { - gtk_main(); - } -} - -bool pApplication::pendingEvents() { - return gtk_events_pending(); -} - -void pApplication::processEvents() { - while(pendingEvents()) gtk_main_iteration_do(false); -} - -void pApplication::quit() { - //if gtk_main() was invoked, call gtk_main_quit() - if(gtk_main_level()) gtk_main_quit(); -} - -void pApplication::initialize() { - display = XOpenDisplay(nullptr); - - settings = new Settings; - settings->load(); - - int argc = 1; - char* argv[] = {new char[8], nullptr}; - strcpy(argv[0], "phoenix"); - char** argvp = argv; - gtk_init(&argc, &argvp); - - GtkSettings* gtkSettings = gtk_settings_get_default(); -//g_object_set(gtkSettings, "gtk-button-images", true, nullptr); - - gtk_rc_parse_string(R"( - style "phoenix-gtk" - { - GtkWindow::resize-grip-width = 0 - GtkWindow::resize-grip-height = 0 - GtkTreeView::vertical-separator = 0 - GtkComboBox::appears-as-list = 1 - } - class "GtkWindow" style "phoenix-gtk" - class "GtkTreeView" style "phoenix-gtk" - # class "GtkComboBox" style "phoenix-gtk" - )"); - - pKeyboard::initialize(); -} - -} diff --git a/phoenix/gtk/platform.hpp b/phoenix/gtk/platform.hpp deleted file mode 100644 index ead42f24..00000000 --- a/phoenix/gtk/platform.hpp +++ /dev/null @@ -1,640 +0,0 @@ -namespace phoenix { - -struct pApplication { - static XlibDisplay* display; - - static void run(); - static bool pendingEvents(); - static void processEvents(); - static void quit(); - - static void initialize(); -}; - -struct Settings : Configuration::Document { - bimap keymap; - - struct Geometry : Configuration::Node { - unsigned frameX; - unsigned frameY; - unsigned frameWidth; - unsigned frameHeight; - unsigned menuHeight; - unsigned statusHeight; - } geometry; - - struct Window : Configuration::Node { - unsigned backgroundColor; - } window; - - void load(); - void save(); - Settings(); -}; - -struct pWindow; -struct pMenu; -struct pLayout; -struct pWidget; - -struct pFont { - static string serif(unsigned size, string style); - static string sans(unsigned size, string style); - static string monospace(unsigned size, string style); - static Size size(string font, string text); - - static PangoFontDescription* create(string description); - static void free(PangoFontDescription* font); - static Size size(PangoFontDescription* font, string text); - static void setFont(GtkWidget* widget, string font); - static void setFont(GtkWidget* widget, gpointer font); -}; - -struct pDesktop { - static Size size(); - static Geometry workspace(); -}; - -struct pMonitor { - static unsigned count(); - static Geometry geometry(unsigned monitor); - static unsigned primary(); -}; - -struct pKeyboard { - static bool pressed(Keyboard::Scancode scancode); - static vector state(); - - static void initialize(); -}; - -struct pMouse { - static Position position(); - static bool pressed(Mouse::Button button); -}; - -struct pBrowserWindow { - static string directory(BrowserWindow::State& state); - static string open(BrowserWindow::State& state); - static string save(BrowserWindow::State& state); -}; - -struct pMessageWindow { - static MessageWindow::Response error(MessageWindow::State& state); - static MessageWindow::Response information(MessageWindow::State& state); - static MessageWindow::Response question(MessageWindow::State& state); - static MessageWindow::Response warning(MessageWindow::State& state); -}; - -struct pObject { - Object& object; - bool locked; - - pObject(Object& object) : object(object), locked(false) {} - virtual ~pObject() {} - - void constructor() {} - void destructor() {} -}; - -struct pTimer : public pObject { - Timer& timer; - - void setEnabled(bool enabled); - void setInterval(unsigned interval); - - pTimer(Timer& timer) : pObject(timer), timer(timer) {} - void constructor(); -}; - -struct pWindow : public pObject { - Window& window; - GtkWidget* widget; - GtkWidget* menuContainer; - GtkWidget* formContainer; - GtkWidget* statusContainer; - GtkWidget* menu; - GtkWidget* status; - GtkAllocation lastAllocation; - bool onSizePending; - - static Window& none(); - - void append(Layout& layout); - void append(Menu& menu); - void append(Widget& widget); - bool focused(); - Geometry frameMargin(); - Geometry geometry(); - void remove(Layout& layout); - void remove(Menu& menu); - void remove(Widget& widget); - void setBackgroundColor(Color color); - void setDroppable(bool droppable); - void setFocused(); - void setFullScreen(bool fullScreen); - void setGeometry(Geometry geometry); - void setMenuFont(string font); - void setMenuVisible(bool visible); - void setModal(bool modal); - void setResizable(bool resizable); - void setStatusFont(string font); - void setStatusText(string text); - void setStatusVisible(bool visible); - void setTitle(string text); - void setVisible(bool visible); - void setWidgetFont(string font); - - pWindow(Window& window) : pObject(window), window(window) {} - void constructor(); - unsigned menuHeight(); - unsigned statusHeight(); -}; - -struct pAction : public pObject { - Action& action; - GtkWidget* widget; - - void setEnabled(bool enabled); - void setVisible(bool visible); - - pAction(Action& action) : pObject(action), action(action) {} - void constructor(); - virtual void orphan(); - string mnemonic(string text); - virtual void setFont(string font); -}; - -struct pMenu : public pAction { - Menu& menu; - GtkWidget* gtkMenu; - - void append(Action& action); - void remove(Action& action); - void setImage(const image& image); - void setText(string text); - - pMenu(Menu &menu) : pAction(menu), menu(menu) {} - void constructor(); - void destructor(); - void orphan(); - void setFont(string font); -}; - -struct pSeparator : public pAction { - Separator& separator; - - pSeparator(Separator& separator) : pAction(separator), separator(separator) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pItem : public pAction { - Item& item; - - void setImage(const image& image); - void setText(string text); - - pItem(Item& item) : pAction(item), item(item) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pCheckItem : public pAction { - CheckItem& checkItem; - - void setChecked(bool checked); - void setText(string text); - - pCheckItem(CheckItem& checkItem) : pAction(checkItem), checkItem(checkItem) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pRadioItem : public pAction { - RadioItem& radioItem; - - void setChecked(); - void setGroup(const group& group); - void setText(string text); - - pRadioItem(RadioItem& radioItem) : pAction(radioItem), radioItem(radioItem) {} - void constructor(); - void destructor(); - void orphan(); - void onActivate(); - pRadioItem& parent(); -}; - -struct pSizable : public pObject { - Sizable& sizable; - - virtual Position displacement() { return {0, 0}; } - - pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} -}; - -struct pLayout : public pSizable { - Layout& layout; - - pLayout(Layout& layout) : pSizable(layout), layout(layout) {} -}; - -struct pWidget : public pSizable { - Widget& widget; - GtkWidget* gtkWidget = nullptr; - GtkWidget* gtkParent = nullptr; - - virtual GtkWidget* container(Widget& widget); - virtual bool focused(); - virtual Size minimumSize(); - virtual void setEnabled(bool enabled); - virtual void setFocused(); - virtual void setFont(string font); - virtual void setGeometry(Geometry geometry); - virtual void setVisible(bool visible); - - pWidget(Widget& widget) : pSizable(widget), widget(widget) {} - void constructor(); - void destructor(); - virtual void orphan(); -}; - -struct pButton : public pWidget { - Button& button; - - Size minimumSize(); - void setImage(const image& image, Orientation orientation); - void setText(string text); - - pButton(Button& button) : pWidget(button), button(button) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pCanvas : public pWidget { - Canvas& canvas; - GdkPixbuf* surface = nullptr; - unsigned surfaceWidth = 0; - unsigned surfaceHeight = 0; - - Size minimumSize(); - void setDroppable(bool droppable); - void setGeometry(Geometry geometry); - void setMode(Canvas::Mode mode); - void setSize(Size size); - - pCanvas(Canvas& canvas) : pWidget(canvas), canvas(canvas) {} - void constructor(); - void destructor(); - void orphan(); - void onExpose(GdkEventExpose* event); - void rasterize(); - void redraw(); - void release(); -}; - -struct pCheckButton : public pWidget { - CheckButton& checkButton; - - Size minimumSize(); - void setChecked(bool checked); - void setImage(const image& image, Orientation orientation); - void setText(string text); - - pCheckButton(CheckButton& checkButton) : pWidget(checkButton), checkButton(checkButton) {} - void constructor(); - void destructor(); - void orphan(); - void onToggle(); -}; - -struct pCheckLabel : public pWidget { - CheckLabel& checkLabel; - - Size minimumSize(); - void setChecked(bool checked); - void setText(string text); - - pCheckLabel(CheckLabel& checkLabel) : pWidget(checkLabel), checkLabel(checkLabel) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pComboButton : public pWidget { - ComboButton& comboButton; - unsigned itemCounter; - - void append(string text); - Size minimumSize(); - void remove(unsigned selection); - void reset(); - void setSelection(unsigned selection); - void setText(unsigned selection, string text); - - pComboButton(ComboButton& comboButton) : pWidget(comboButton), comboButton(comboButton) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pConsole : public pWidget { - Console& console; - GtkWidget* subWidget; - GtkTextBuffer* textBuffer; - string previousPrompt; - lstring history; - unsigned historyOffset = 0; - - void print(string text); - void reset(); - void setBackgroundColor(Color color); - void setForegroundColor(Color color); - void setPrompt(string prompt); - - pConsole(Console& console) : pWidget(console), console(console) {} - void constructor(); - void destructor(); - void orphan(); - bool keyPress(unsigned scancode, unsigned mask); - void seekToEnd(); - void seekToMark(); -}; - -struct pFrame : public pWidget { - Frame& frame; - - GtkWidget* container(Widget& widget); - Position containerOffset(); - void setEnabled(bool enabled); - void setGeometry(Geometry geometry); - void setText(string text); - void setVisible(bool visible); - - pFrame(Frame& frame) : pWidget(frame), frame(frame) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pHexEdit : public pWidget { - HexEdit& hexEdit; - GtkWidget* container; - GtkWidget* subWidget; - GtkWidget* scrollBar; - GtkTextBuffer* textBuffer; - GtkTextMark* textCursor; - - bool focused(); - void setBackgroundColor(Color color); - void setColumns(unsigned columns); - void setForegroundColor(Color color); - void setLength(unsigned length); - void setOffset(unsigned offset); - void setRows(unsigned rows); - void update(); - - pHexEdit(HexEdit& hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} - void constructor(); - void destructor(); - void orphan(); - unsigned cursorPosition(); - bool keyPress(unsigned scancode, unsigned mask); - signed rows(); - signed rowsScrollable(); - void scroll(signed position); - void setCursorPosition(unsigned position); - void setScroll(); - void updateScroll(); -}; - -struct pHorizontalScroller : public pWidget { - HorizontalScroller& horizontalScroller; - - Size minimumSize(); - void setLength(unsigned length); - void setPosition(unsigned position); - - pHorizontalScroller(HorizontalScroller& horizontalScroller) : pWidget(horizontalScroller), horizontalScroller(horizontalScroller) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pHorizontalSlider : public pWidget { - HorizontalSlider& horizontalSlider; - - Size minimumSize(); - void setLength(unsigned length); - void setPosition(unsigned position); - - pHorizontalSlider(HorizontalSlider& horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pLabel : public pWidget { - Label& label; - - Size minimumSize(); - void setText(string text); - - pLabel(Label& label) : pWidget(label), label(label) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pLineEdit : public pWidget { - LineEdit& lineEdit; - - Size minimumSize(); - void setBackgroundColor(Color color); - void setEditable(bool editable); - void setForegroundColor(Color color); - void setText(string text); - string text(); - - pLineEdit(LineEdit& lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pListView : public pWidget { - ListView& listView; - GtkWidget* subWidget; - GtkListStore* store; - struct GtkColumn { - GtkTreeViewColumn* column; - GtkCellRenderer* checkbutton; - GtkCellRenderer* icon; - GtkCellRenderer* text; - GtkWidget *label; - }; - vector column; - - void append(const lstring& text); - void autoSizeColumns(); - bool focused(); - void remove(unsigned selection); - void reset(); - void setBackgroundColor(Color color); - void setCheckable(bool checkable); - void setChecked(unsigned selection, bool checked); - void setForegroundColor(Color color); - void setHeaderText(const lstring& text); - void setHeaderVisible(bool visible); - void setImage(unsigned selection, unsigned position, const image& image); - void setSelected(bool selected); - void setSelection(unsigned row); - void setText(unsigned selection, unsigned position, string text); - - pListView(ListView& listView) : pWidget(listView), listView(listView) {} - void constructor(); - void destructor(); - void orphan(); - void setFocused(); - void setFont(string font); -}; - -struct pProgressBar : public pWidget { - ProgressBar& progressBar; - - Size minimumSize(); - void setPosition(unsigned position); - - pProgressBar(ProgressBar& progressBar) : pWidget(progressBar), progressBar(progressBar) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pRadioButton : public pWidget { - RadioButton& radioButton; - - Size minimumSize(); - void setChecked(); - void setGroup(const group& group); - void setImage(const image& image, Orientation orientation); - void setText(string text); - - pRadioButton(RadioButton& radioButton) : pWidget(radioButton), radioButton(radioButton) {} - void constructor(); - void destructor(); - void orphan(); - void onActivate(); - pRadioButton& parent(); -}; - -struct pRadioLabel : public pWidget { - RadioLabel& radioLabel; - - Size minimumSize(); - void setChecked(); - void setGroup(const group& group); - void setText(string text); - - pRadioLabel(RadioLabel& radioLabel) : pWidget(radioLabel), radioLabel(radioLabel) {} - void onActivate(); - pRadioLabel& parent(); - void constructor(); - void destructor(); - void orphan(); -}; - -struct pTabFrame : public pWidget { - TabFrame& tabFrame; - struct Tab { - GtkWidget* child; - GtkWidget* container; - GtkWidget* layout; - GtkWidget* image; - GtkWidget* title; - }; - vector tabs; - - void append(string text, const image& image); - GtkWidget* container(Widget& widget); - Position displacement(); - void remove(unsigned selection); - void setEnabled(bool enabled); - void setGeometry(Geometry geometry); - void setImage(unsigned selection, const image& image); - void setSelection(unsigned selection); - void setText(unsigned selection, string text); - void setVisible(bool visible); - - pTabFrame(TabFrame& tabFrame) : pWidget(tabFrame), tabFrame(tabFrame) {} - void constructor(); - void destructor(); - void orphan(); - void setFont(string font); - void synchronizeLayout(); -}; - -struct pTextEdit : public pWidget { - TextEdit& textEdit; - GtkWidget* subWidget; - GtkTextBuffer* textBuffer; - - bool focused(); - void setBackgroundColor(Color color); - void setCursorPosition(unsigned position); - void setEditable(bool editable); - void setForegroundColor(Color color); - void setText(string text); - void setWordWrap(bool wordWrap); - string text(); - - pTextEdit(TextEdit& textEdit) : pWidget(textEdit), textEdit(textEdit) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pVerticalScroller : public pWidget { - VerticalScroller& verticalScroller; - - Size minimumSize(); - void setLength(unsigned length); - void setPosition(unsigned position); - - pVerticalScroller(VerticalScroller& verticalScroller) : pWidget(verticalScroller), verticalScroller(verticalScroller) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pVerticalSlider : public pWidget { - VerticalSlider& verticalSlider; - - Size minimumSize(); - void setLength(unsigned length); - void setPosition(unsigned position); - - pVerticalSlider(VerticalSlider& verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} - void constructor(); - void destructor(); - void orphan(); -}; - -struct pViewport : public pWidget { - Viewport& viewport; - - uintptr_t handle(); - void setDroppable(bool droppable); - - pViewport(Viewport& viewport) : pWidget(viewport), viewport(viewport) {} - void constructor(); - void destructor(); - void orphan(); -}; - -} diff --git a/phoenix/gtk/timer.cpp b/phoenix/gtk/timer.cpp deleted file mode 100644 index 3be9964f..00000000 --- a/phoenix/gtk/timer.cpp +++ /dev/null @@ -1,28 +0,0 @@ -namespace phoenix { - -static guint Timer_trigger(pTimer* self) { - //timer may have been disabled prior to triggering, so check state - if(self->timer.state.enabled) { - if(self->timer.onActivate) self->timer.onActivate(); - } - //callback may have disabled timer, so check state again - if(self->timer.state.enabled) { - g_timeout_add(self->timer.state.interval, (GSourceFunc)Timer_trigger, (gpointer)self); - } - //kill this timer instance (it is spawned above if needed again) - return false; -} - -void pTimer::setEnabled(bool enabled) { - if(enabled) { - g_timeout_add(timer.state.interval, (GSourceFunc)Timer_trigger, (gpointer)this); - } -} - -void pTimer::setInterval(unsigned interval) { -} - -void pTimer::constructor() { -} - -} diff --git a/phoenix/gtk/utility.cpp b/phoenix/gtk/utility.cpp deleted file mode 100644 index 1645ab76..00000000 --- a/phoenix/gtk/utility.cpp +++ /dev/null @@ -1,259 +0,0 @@ -namespace phoenix { - -static GdkColor CreateColor(uint8_t r, uint8_t g, uint8_t b) { - GdkColor color; - color.pixel = (r << 16) | (g << 8) | (b << 0); - color.red = (r << 8) | (r << 0); - color.green = (g << 8) | (g << 0); - color.blue = (b << 8) | (b << 0); - return color; -} - -static GdkPixbuf* CreatePixbuf(const nall::image& image, bool scale = false) { - nall::image gdkImage = image; - gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); - if(scale) gdkImage.scale(15, 15); - - GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, gdkImage.width, gdkImage.height); - memcpy(gdk_pixbuf_get_pixels(pixbuf), gdkImage.data, gdkImage.width * gdkImage.height * 4); - - return pixbuf; -} - -static GtkImage* CreateImage(const nall::image& image, bool scale = false) { - GdkPixbuf* pixbuf = CreatePixbuf(image, scale); - GtkImage* gtkImage = (GtkImage*)gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); - return gtkImage; -} - -static lstring DropPaths(GtkSelectionData* data) { - gchar** uris = gtk_selection_data_get_uris(data); - if(uris == nullptr) return {}; - - lstring paths; - for(unsigned n = 0; uris[n] != nullptr; n++) { - gchar* pathname = g_filename_from_uri(uris[n], nullptr, nullptr); - if(pathname == nullptr) continue; - - string path = pathname; - g_free(pathname); - if(directory::exists(path) && !path.endsWith("/")) path.append("/"); - paths.append(path); - } - - g_strfreev(uris); - return paths; -} - -static Position GetDisplacement(Sizable* sizable) { - Position position; - while(sizable->state.parent) { - Position displacement = sizable->state.parent->p.displacement(); - position.x += displacement.x; - position.y += displacement.y; - sizable = sizable->state.parent; - } - return position; -} - -static Layout* GetParentWidgetLayout(Sizable* sizable) { - while(sizable) { - if(sizable->state.parent && dynamic_cast(sizable->state.parent)) return (Layout*)sizable; - sizable = sizable->state.parent; - } - return nullptr; -} - -static Widget* GetParentWidget(Sizable* sizable) { - while(sizable) { - if(sizable->state.parent && dynamic_cast(sizable->state.parent)) return (Widget*)sizable->state.parent; - sizable = sizable->state.parent; - } - return nullptr; -} - -static Keyboard::Keycode Keysym(unsigned keysym) { - switch(keysym) { - case GDK_Escape: return Keyboard::Keycode::Escape; - case GDK_F1: return Keyboard::Keycode::F1; - case GDK_F2: return Keyboard::Keycode::F2; - case GDK_F3: return Keyboard::Keycode::F3; - case GDK_F4: return Keyboard::Keycode::F4; - case GDK_F5: return Keyboard::Keycode::F5; - case GDK_F6: return Keyboard::Keycode::F6; - case GDK_F7: return Keyboard::Keycode::F7; - case GDK_F8: return Keyboard::Keycode::F8; - case GDK_F9: return Keyboard::Keycode::F9; - case GDK_F10: return Keyboard::Keycode::F10; - case GDK_F11: return Keyboard::Keycode::F11; - case GDK_F12: return Keyboard::Keycode::F12; - - case GDK_Print: return Keyboard::Keycode::PrintScreen; - //Keyboard::Keycode::SysRq - case GDK_Scroll_Lock: return Keyboard::Keycode::ScrollLock; - case GDK_Pause: return Keyboard::Keycode::Pause; - //Keyboard::Keycode::Break - - case GDK_Insert: return Keyboard::Keycode::Insert; - case GDK_Delete: return Keyboard::Keycode::Delete; - case GDK_Home: return Keyboard::Keycode::Home; - case GDK_End: return Keyboard::Keycode::End; - case GDK_Prior: return Keyboard::Keycode::PageUp; - case GDK_Next: return Keyboard::Keycode::PageDown; - - case GDK_Up: return Keyboard::Keycode::Up; - case GDK_Down: return Keyboard::Keycode::Down; - case GDK_Left: return Keyboard::Keycode::Left; - case GDK_Right: return Keyboard::Keycode::Right; - - case GDK_grave: return Keyboard::Keycode::Grave; - case GDK_1: return Keyboard::Keycode::Number1; - case GDK_2: return Keyboard::Keycode::Number2; - case GDK_3: return Keyboard::Keycode::Number3; - case GDK_4: return Keyboard::Keycode::Number4; - case GDK_5: return Keyboard::Keycode::Number5; - case GDK_6: return Keyboard::Keycode::Number6; - case GDK_7: return Keyboard::Keycode::Number7; - case GDK_8: return Keyboard::Keycode::Number8; - case GDK_9: return Keyboard::Keycode::Number9; - case GDK_0: return Keyboard::Keycode::Number0; - case GDK_minus: return Keyboard::Keycode::Minus; - case GDK_equal: return Keyboard::Keycode::Equal; - case GDK_BackSpace: return Keyboard::Keycode::Backspace; - - case GDK_asciitilde: return Keyboard::Keycode::Tilde; - case GDK_exclam: return Keyboard::Keycode::Exclamation; - case GDK_at: return Keyboard::Keycode::At; - case GDK_numbersign: return Keyboard::Keycode::Pound; - case GDK_dollar: return Keyboard::Keycode::Dollar; - case GDK_percent: return Keyboard::Keycode::Percent; - case GDK_asciicircum: return Keyboard::Keycode::Power; - case GDK_ampersand: return Keyboard::Keycode::Ampersand; - case GDK_asterisk: return Keyboard::Keycode::Asterisk; - case GDK_parenleft: return Keyboard::Keycode::ParenthesisLeft; - case GDK_parenright: return Keyboard::Keycode::ParenthesisRight; - case GDK_underscore: return Keyboard::Keycode::Underscore; - case GDK_plus: return Keyboard::Keycode::Plus; - - case GDK_bracketleft: return Keyboard::Keycode::BracketLeft; - case GDK_bracketright: return Keyboard::Keycode::BracketRight; - case GDK_backslash: return Keyboard::Keycode::Backslash; - case GDK_semicolon: return Keyboard::Keycode::Semicolon; - case GDK_apostrophe: return Keyboard::Keycode::Apostrophe; - case GDK_comma: return Keyboard::Keycode::Comma; - case GDK_period: return Keyboard::Keycode::Period; - case GDK_slash: return Keyboard::Keycode::Slash; - - case GDK_braceleft: return Keyboard::Keycode::BraceLeft; - case GDK_braceright: return Keyboard::Keycode::BraceRight; - case GDK_bar: return Keyboard::Keycode::Pipe; - case GDK_colon: return Keyboard::Keycode::Colon; - case GDK_quotedbl: return Keyboard::Keycode::Quote; - case GDK_less: return Keyboard::Keycode::CaretLeft; - case GDK_greater: return Keyboard::Keycode::CaretRight; - case GDK_question: return Keyboard::Keycode::Question; - - case GDK_Tab: return Keyboard::Keycode::Tab; - case GDK_Caps_Lock: return Keyboard::Keycode::CapsLock; - case GDK_Return: return Keyboard::Keycode::Return; - case GDK_Shift_L: return Keyboard::Keycode::ShiftLeft; - case GDK_Shift_R: return Keyboard::Keycode::ShiftRight; - case GDK_Control_L: return Keyboard::Keycode::ControlLeft; - case GDK_Control_R: return Keyboard::Keycode::ControlRight; - case GDK_Super_L: return Keyboard::Keycode::SuperLeft; - case GDK_Super_R: return Keyboard::Keycode::SuperRight; - case GDK_Alt_L: return Keyboard::Keycode::AltLeft; - case GDK_Alt_R: return Keyboard::Keycode::AltRight; - case GDK_space: return Keyboard::Keycode::Space; - case GDK_Menu: return Keyboard::Keycode::Menu; - - case GDK_A: return Keyboard::Keycode::A; - case GDK_B: return Keyboard::Keycode::B; - case GDK_C: return Keyboard::Keycode::C; - case GDK_D: return Keyboard::Keycode::D; - case GDK_E: return Keyboard::Keycode::E; - case GDK_F: return Keyboard::Keycode::F; - case GDK_G: return Keyboard::Keycode::G; - case GDK_H: return Keyboard::Keycode::H; - case GDK_I: return Keyboard::Keycode::I; - case GDK_J: return Keyboard::Keycode::J; - case GDK_K: return Keyboard::Keycode::K; - case GDK_L: return Keyboard::Keycode::L; - case GDK_M: return Keyboard::Keycode::M; - case GDK_N: return Keyboard::Keycode::N; - case GDK_O: return Keyboard::Keycode::O; - case GDK_P: return Keyboard::Keycode::P; - case GDK_Q: return Keyboard::Keycode::Q; - case GDK_R: return Keyboard::Keycode::R; - case GDK_S: return Keyboard::Keycode::S; - case GDK_T: return Keyboard::Keycode::T; - case GDK_U: return Keyboard::Keycode::U; - case GDK_V: return Keyboard::Keycode::V; - case GDK_W: return Keyboard::Keycode::W; - case GDK_X: return Keyboard::Keycode::X; - case GDK_Y: return Keyboard::Keycode::Y; - case GDK_Z: return Keyboard::Keycode::Z; - - case GDK_a: return Keyboard::Keycode::a; - case GDK_b: return Keyboard::Keycode::b; - case GDK_c: return Keyboard::Keycode::c; - case GDK_d: return Keyboard::Keycode::d; - case GDK_e: return Keyboard::Keycode::e; - case GDK_f: return Keyboard::Keycode::f; - case GDK_g: return Keyboard::Keycode::g; - case GDK_h: return Keyboard::Keycode::h; - case GDK_i: return Keyboard::Keycode::i; - case GDK_j: return Keyboard::Keycode::j; - case GDK_k: return Keyboard::Keycode::k; - case GDK_l: return Keyboard::Keycode::l; - case GDK_m: return Keyboard::Keycode::m; - case GDK_n: return Keyboard::Keycode::n; - case GDK_o: return Keyboard::Keycode::o; - case GDK_p: return Keyboard::Keycode::p; - case GDK_q: return Keyboard::Keycode::q; - case GDK_r: return Keyboard::Keycode::r; - case GDK_s: return Keyboard::Keycode::s; - case GDK_t: return Keyboard::Keycode::t; - case GDK_u: return Keyboard::Keycode::u; - case GDK_v: return Keyboard::Keycode::v; - case GDK_w: return Keyboard::Keycode::w; - case GDK_x: return Keyboard::Keycode::x; - case GDK_y: return Keyboard::Keycode::y; - case GDK_z: return Keyboard::Keycode::z; - - case GDK_Num_Lock: return Keyboard::Keycode::NumLock; - case GDK_KP_Divide: return Keyboard::Keycode::Divide; - case GDK_KP_Multiply: return Keyboard::Keycode::Multiply; - case GDK_KP_Subtract: return Keyboard::Keycode::Subtract; - case GDK_KP_Add: return Keyboard::Keycode::Add; - case GDK_KP_Enter: return Keyboard::Keycode::Enter; - case GDK_KP_Decimal: return Keyboard::Keycode::Point; - - case GDK_KP_1: return Keyboard::Keycode::Keypad1; - case GDK_KP_2: return Keyboard::Keycode::Keypad2; - case GDK_KP_3: return Keyboard::Keycode::Keypad3; - case GDK_KP_4: return Keyboard::Keycode::Keypad4; - case GDK_KP_5: return Keyboard::Keycode::Keypad5; - case GDK_KP_6: return Keyboard::Keycode::Keypad6; - case GDK_KP_7: return Keyboard::Keycode::Keypad7; - case GDK_KP_8: return Keyboard::Keycode::Keypad8; - case GDK_KP_9: return Keyboard::Keycode::Keypad9; - case GDK_KP_0: return Keyboard::Keycode::Keypad0; - - case GDK_KP_Home: return Keyboard::Keycode::KeypadHome; - case GDK_KP_End: return Keyboard::Keycode::KeypadEnd; - case GDK_KP_Page_Up: return Keyboard::Keycode::KeypadPageUp; - case GDK_KP_Page_Down: return Keyboard::Keycode::KeypadPageDown; - case GDK_KP_Up: return Keyboard::Keycode::KeypadUp; - case GDK_KP_Down: return Keyboard::Keycode::KeypadDown; - case GDK_KP_Left: return Keyboard::Keycode::KeypadLeft; - case GDK_KP_Right: return Keyboard::Keycode::KeypadRight; - case GDK_KP_Begin: return Keyboard::Keycode::KeypadCenter; - case GDK_KP_Insert: return Keyboard::Keycode::KeypadInsert; - case GDK_KP_Delete: return Keyboard::Keycode::KeypadDelete; - } - return Keyboard::Keycode::None; -} - -} diff --git a/phoenix/gtk/widget/button.cpp b/phoenix/gtk/widget/button.cpp deleted file mode 100644 index 16e6bb37..00000000 --- a/phoenix/gtk/widget/button.cpp +++ /dev/null @@ -1,57 +0,0 @@ -namespace phoenix { - -static void Button_activate(Button* self) { - if(self->onActivate) self->onActivate(); -} - -Size pButton::minimumSize() { - Size size = pFont::size(widget.state.font, button.state.text); - - if(button.state.orientation == Orientation::Horizontal) { - size.width += button.state.image.width; - size.height = max(button.state.image.height, size.height); - } - - if(button.state.orientation == Orientation::Vertical) { - size.width = max(button.state.image.width, size.width); - size.height += button.state.image.height; - } - - return {size.width + 24, size.height + 12}; -} - -void pButton::setImage(const image& image, Orientation orientation) { - if(image.empty() == false) { - GtkImage* gtkImage = CreateImage(image); - gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); - } else { - gtk_button_set_image(GTK_BUTTON(gtkWidget), nullptr); - } - switch(orientation) { - case Orientation::Horizontal: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_LEFT); break; - case Orientation::Vertical: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_TOP); break; - } -} - -void pButton::setText(string text) { - gtk_button_set_label(GTK_BUTTON(gtkWidget), text); - setFont(widget.state.font); -} - -void pButton::constructor() { - gtkWidget = gtk_button_new(); - g_signal_connect_swapped(G_OBJECT(gtkWidget), "clicked", G_CALLBACK(Button_activate), (gpointer)&button); - - setText(button.state.text); -} - -void pButton::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pButton::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/canvas.cpp b/phoenix/gtk/widget/canvas.cpp deleted file mode 100644 index 4fad9909..00000000 --- a/phoenix/gtk/widget/canvas.cpp +++ /dev/null @@ -1,177 +0,0 @@ -namespace phoenix { - -static void Canvas_drop(GtkWidget* widget, GdkDragContext* context, signed x, signed y, -GtkSelectionData* data, unsigned type, unsigned timestamp, Canvas* canvas) { - if(!canvas->state.droppable) return; - lstring paths = DropPaths(data); - if(paths.empty()) return; - if(canvas->onDrop) canvas->onDrop(paths); -} - -static signed Canvas_expose(GtkWidget* widget, GdkEventExpose* event, Canvas* self) { - self->p.onExpose(event); - return true; -} - -static signed Canvas_mouseLeave(GtkWidget* widget, GdkEventButton* event, Canvas* self) { - if(self->onMouseLeave) self->onMouseLeave(); - return true; -} - -static signed Canvas_mouseMove(GtkWidget* widget, GdkEventButton* event, Canvas* self) { - if(self->onMouseMove) self->onMouseMove({(signed)event->x, (signed)event->y}); - return true; -} - -static signed Canvas_mousePress(GtkWidget* widget, GdkEventButton* event, Canvas* self) { - if(self->onMousePress) switch(event->button) { - case 1: self->onMousePress(Mouse::Button::Left); break; - case 2: self->onMousePress(Mouse::Button::Middle); break; - case 3: self->onMousePress(Mouse::Button::Right); break; - } - return true; -} - -static signed Canvas_mouseRelease(GtkWidget* widget, GdkEventButton* event, Canvas* self) { - if(self->onMouseRelease) switch(event->button) { - case 1: self->onMouseRelease(Mouse::Button::Left); break; - case 2: self->onMouseRelease(Mouse::Button::Middle); break; - case 3: self->onMouseRelease(Mouse::Button::Right); break; - } - return true; -} - -Size pCanvas::minimumSize() { - return {canvas.state.width, canvas.state.height}; -} - -void pCanvas::setDroppable(bool droppable) { - gtk_drag_dest_set(gtkWidget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY); - if(droppable) gtk_drag_dest_add_uri_targets(gtkWidget); -} - -void pCanvas::setGeometry(Geometry geometry) { - if(canvas.state.width == 0 || canvas.state.height == 0) rasterize(); - unsigned width = canvas.state.width; - unsigned height = canvas.state.height; - if(width == 0) width = widget.state.geometry.width; - if(height == 0) height = widget.state.geometry.height; - - if(width < geometry.width) { - geometry.x += (geometry.width - width) / 2; - geometry.width = width; - } - - if(height < geometry.height) { - geometry.y += (geometry.height - height) / 2; - geometry.height = height; - } - - pWidget::setGeometry(geometry); -} - -void pCanvas::setMode(Canvas::Mode mode) { - rasterize(), redraw(); -} - -void pCanvas::setSize(Size size) { - rasterize(), redraw(); -} - -void pCanvas::constructor() { - gtkWidget = gtk_drawing_area_new(); -//gtk_widget_set_double_buffered(gtkWidget, false); - gtk_widget_add_events(gtkWidget, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); - g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Canvas_mousePress), (gpointer)&canvas); - g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Canvas_mouseRelease), (gpointer)&canvas); - g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Canvas_drop), (gpointer)&canvas); - g_signal_connect(G_OBJECT(gtkWidget), "expose-event", G_CALLBACK(Canvas_expose), (gpointer)&canvas); - g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Canvas_mouseLeave), (gpointer)&canvas); - g_signal_connect(G_OBJECT(gtkWidget), "motion-notify-event", G_CALLBACK(Canvas_mouseMove), (gpointer)&canvas); - - setDroppable(canvas.state.droppable); - rasterize(), redraw(); -} - -void pCanvas::destructor() { - release(); - gtk_widget_destroy(gtkWidget); -} - -void pCanvas::orphan() { - destructor(); - constructor(); -} - -void pCanvas::onExpose(GdkEventExpose* expose) { - if(surface) gdk_draw_pixbuf(gtk_widget_get_window(gtkWidget), nullptr, surface, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0); -} - -void pCanvas::rasterize() { - unsigned width = canvas.state.width; - unsigned height = canvas.state.height; - if(width == 0) width = widget.state.geometry.width; - if(height == 0) height = widget.state.geometry.height; - - if(width != surfaceWidth || height != surfaceHeight) release(); - surfaceWidth = width; - surfaceHeight = height; - - if(width == 0 || height == 0) return; - - if(!surface) surface = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height); - uint32_t* buffer = (uint32_t*)gdk_pixbuf_get_pixels(surface); - - if(canvas.state.mode == Canvas::Mode::Color) { - uint32_t color = canvas.state.color.argb(); - for(unsigned n = 0; n < width * height; n++) buffer[n] = color; - } - - if(canvas.state.mode == Canvas::Mode::Gradient) { - nall::image image; - image.allocate(width, height); - image.gradient( - canvas.state.gradient[0].argb(), canvas.state.gradient[1].argb(), canvas.state.gradient[2].argb(), canvas.state.gradient[3].argb() - ); - memcpy(buffer, image.data, image.size); - } - - if(canvas.state.mode == Canvas::Mode::Image) { - nall::image image = canvas.state.image; - image.scale(width, height); - image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); - memcpy(buffer, image.data, image.size); - } - - if(canvas.state.mode == Canvas::Mode::Data) { - if(width == canvas.state.width && height == canvas.state.height) { - memcpy(buffer, canvas.state.data, width * height * sizeof(uint32_t)); - } else { - memset(buffer, 0x00, width * height * sizeof(uint32_t)); - } - } - - //ARGB -> ABGR conversion - for(unsigned n = 0; n < width * height; n++) { - uint32_t color = *buffer; - color = (color & 0xff00ff00) | ((color & 0xff0000) >> 16) | ((color & 0x0000ff) << 16); - *buffer++ = color; - } -} - -void pCanvas::redraw() { - if(gtk_widget_get_realized(gtkWidget)) { - gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), nullptr, true); - } -} - -void pCanvas::release() { - if(surface == nullptr) return; - g_object_unref(surface); - surface = nullptr; - surfaceWidth = 0; - surfaceHeight = 0; -} - -} diff --git a/phoenix/gtk/widget/check-button.cpp b/phoenix/gtk/widget/check-button.cpp deleted file mode 100644 index d72d91ff..00000000 --- a/phoenix/gtk/widget/check-button.cpp +++ /dev/null @@ -1,70 +0,0 @@ -namespace phoenix { - -static void CheckButton_toggle(GtkToggleButton* toggleButton, CheckButton* self) { - self->p.onToggle(); -} - -Size pCheckButton::minimumSize() { - Size size = pFont::size(widget.state.font, checkButton.state.text); - - if(checkButton.state.orientation == Orientation::Horizontal) { - size.width += checkButton.state.image.width; - size.height = max(checkButton.state.image.height, size.height); - } - - if(checkButton.state.orientation == Orientation::Vertical) { - size.width = max(checkButton.state.image.width, size.width); - size.height += checkButton.state.image.height; - } - - return {size.width + 24, size.height + 12}; -} - -void pCheckButton::setChecked(bool checked) { - locked = true; - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), checked); - locked = false; -} - -void pCheckButton::setImage(const image& image, Orientation orientation) { - if(image.empty() == false) { - GtkImage* gtkImage = CreateImage(image); - gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); - } else { - gtk_button_set_image(GTK_BUTTON(gtkWidget), nullptr); - } - switch(orientation) { - case Orientation::Horizontal: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_LEFT); break; - case Orientation::Vertical: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_TOP); break; - } -} - -void pCheckButton::setText(string text) { - gtk_button_set_label(GTK_BUTTON(gtkWidget), text); - setFont(widget.state.font); -} - -void pCheckButton::constructor() { - gtkWidget = gtk_toggle_button_new(); - g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(CheckButton_toggle), (gpointer)&checkButton); - - setChecked(checkButton.state.checked); - setText(checkButton.state.text); -} - -void pCheckButton::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pCheckButton::orphan() { - destructor(); - constructor(); -} - -void pCheckButton::onToggle() { - if(locked) return; - checkButton.state.checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkWidget)); - if(checkButton.onToggle) checkButton.onToggle(); -} - -} diff --git a/phoenix/gtk/widget/check-label.cpp b/phoenix/gtk/widget/check-label.cpp deleted file mode 100644 index 6e59fbd6..00000000 --- a/phoenix/gtk/widget/check-label.cpp +++ /dev/null @@ -1,40 +0,0 @@ -namespace phoenix { - -static void CheckLabel_toggle(GtkToggleButton* toggleButton, CheckLabel* self) { - self->state.checked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self->p.gtkWidget)); - if(!self->p.locked && self->onToggle) self->onToggle(); -} - -Size pCheckLabel::minimumSize() { - Size size = pFont::size(widget.state.font, checkLabel.state.text); - return {size.width + 28, size.height + 4}; -} - -void pCheckLabel::setChecked(bool checked) { - locked = true; - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), checked); - locked = false; -} - -void pCheckLabel::setText(string text) { - gtk_button_set_label(GTK_BUTTON(gtkWidget), text); -} - -void pCheckLabel::constructor() { - gtkWidget = gtk_check_button_new_with_label(""); - g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(CheckLabel_toggle), (gpointer)&checkLabel); - - setChecked(checkLabel.state.checked); - setText(checkLabel.state.text); -} - -void pCheckLabel::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pCheckLabel::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/combo-button.cpp b/phoenix/gtk/widget/combo-button.cpp deleted file mode 100644 index ed523f1a..00000000 --- a/phoenix/gtk/widget/combo-button.cpp +++ /dev/null @@ -1,74 +0,0 @@ -namespace phoenix { - -static void ComboButton_change(ComboButton* self) { - if(!self->p.locked) { - self->state.selection = gtk_combo_box_get_active(GTK_COMBO_BOX(self->p.gtkWidget)); - if(self->onChange) self->onChange(); - } -} - -void pComboButton::append(string text) { - gtk_combo_box_append_text(GTK_COMBO_BOX(gtkWidget), text); - if(itemCounter++ == 0) comboButton.setSelection(0); -} - -Size pComboButton::minimumSize() { - unsigned maximumWidth = 0; - for(auto& item : comboButton.state.text) maximumWidth = max(maximumWidth, pFont::size(widget.state.font, item).width); - - Size size = pFont::size(widget.state.font, " "); - return {maximumWidth + 44, size.height + 12}; -} - -void pComboButton::remove(unsigned selection) { - locked = true; - gtk_combo_box_remove_text(GTK_COMBO_BOX(gtkWidget), selection); - itemCounter--; - locked = false; - - //when removing the actively selected item, reset the selection to the first entry - if(selection == comboButton.state.selection) comboButton.setSelection(0); -} - -void pComboButton::reset() { - locked = true; - gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(gtkWidget)))); - itemCounter = 0; - locked = false; -} - -void pComboButton::setSelection(unsigned selection) { - locked = true; - gtk_combo_box_set_active(GTK_COMBO_BOX(gtkWidget), selection); - locked = false; -} - -void pComboButton::setText(unsigned selection, string text) { - locked = true; - gtk_combo_box_remove_text(GTK_COMBO_BOX(gtkWidget), selection); - gtk_combo_box_insert_text(GTK_COMBO_BOX(gtkWidget), selection, text); - gtk_combo_box_set_active(GTK_COMBO_BOX(gtkWidget), comboButton.state.selection); - locked = false; -} - -void pComboButton::constructor() { - itemCounter = 0; - gtkWidget = gtk_combo_box_new_text(); - g_signal_connect_swapped(G_OBJECT(gtkWidget), "changed", G_CALLBACK(ComboButton_change), (gpointer)&comboButton); - - locked = true; - for(auto& text : comboButton.state.text) append(text); - locked = false; - setSelection(comboButton.state.selection); -} - -void pComboButton::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pComboButton::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/frame.cpp b/phoenix/gtk/widget/frame.cpp deleted file mode 100644 index f41e1c3c..00000000 --- a/phoenix/gtk/widget/frame.cpp +++ /dev/null @@ -1,48 +0,0 @@ -namespace phoenix { - -GtkWidget* pFrame::container(Widget& widget) { - return gtk_widget_get_parent(gtkWidget); -} - -Position pFrame::containerOffset() { - return {0, 0}; -} - -void pFrame::setEnabled(bool enabled) { - if(frame.state.layout) frame.state.layout->setEnabled(frame.state.layout->enabled()); - pWidget::setEnabled(enabled); -} - -void pFrame::setGeometry(Geometry geometry) { - pWidget::setGeometry(geometry); - if(frame.state.layout == nullptr) return; - Size size = pFont::size(widget.state.font, frame.state.text); - if(frame.state.text.empty()) size.height = 8; - geometry.x += 2, geometry.width -= 5; - geometry.y += size.height - 1, geometry.height -= size.height + 2; - frame.state.layout->setGeometry(geometry); -} - -void pFrame::setText(string text) { - gtk_frame_set_label(GTK_FRAME(gtkWidget), text); -} - -void pFrame::setVisible(bool visible) { - if(frame.state.layout) frame.state.layout->setVisible(frame.state.layout->visible()); - pWidget::setVisible(visible); -} - -void pFrame::constructor() { - gtkWidget = gtk_frame_new(""); -} - -void pFrame::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pFrame::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/horizontal-scroller.cpp b/phoenix/gtk/widget/horizontal-scroller.cpp deleted file mode 100644 index 5a46879f..00000000 --- a/phoenix/gtk/widget/horizontal-scroller.cpp +++ /dev/null @@ -1,43 +0,0 @@ -namespace phoenix { - -static void HorizontalScroller_change(GtkRange* gtkRange, HorizontalScroller* self) { - unsigned position = (unsigned)gtk_range_get_value(gtkRange); - if(self->state.position == position) return; - self->state.position = position; - if(!self->p.locked && self->onChange) self->onChange(); -} - -Size pHorizontalScroller::minimumSize() { - return {0, 20}; -} - -void pHorizontalScroller::setLength(unsigned length) { - locked = true; - length += length == 0; - gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); - gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); - locked = false; -} - -void pHorizontalScroller::setPosition(unsigned position) { - gtk_range_set_value(GTK_RANGE(gtkWidget), position); -} - -void pHorizontalScroller::constructor() { - gtkWidget = gtk_hscrollbar_new(0); - g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalScroller_change), (gpointer)&horizontalScroller); - - setLength(horizontalScroller.state.length); - setPosition(horizontalScroller.state.position); -} - -void pHorizontalScroller::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pHorizontalScroller::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/horizontal-slider.cpp b/phoenix/gtk/widget/horizontal-slider.cpp deleted file mode 100644 index 2ef80d93..00000000 --- a/phoenix/gtk/widget/horizontal-slider.cpp +++ /dev/null @@ -1,42 +0,0 @@ -namespace phoenix { - -static void HorizontalSlider_change(GtkRange* gtkRange, HorizontalSlider* self) { - unsigned position = (unsigned)gtk_range_get_value(gtkRange); - if(self->state.position == position) return; - self->state.position = position; - if(self->onChange) self->onChange(); -} - -Size pHorizontalSlider::minimumSize() { - return {0, 20}; -} - -void pHorizontalSlider::setLength(unsigned length) { - length += length == 0; - gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); - gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); -} - -void pHorizontalSlider::setPosition(unsigned position) { - gtk_range_set_value(GTK_RANGE(gtkWidget), position); -} - -void pHorizontalSlider::constructor() { - gtkWidget = gtk_hscale_new_with_range(0, 100, 1); - gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); - g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)&horizontalSlider); - - setLength(horizontalSlider.state.length); - setPosition(horizontalSlider.state.position); -} - -void pHorizontalSlider::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pHorizontalSlider::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/label.cpp b/phoenix/gtk/widget/label.cpp deleted file mode 100644 index c484587b..00000000 --- a/phoenix/gtk/widget/label.cpp +++ /dev/null @@ -1,28 +0,0 @@ -namespace phoenix { - -Size pLabel::minimumSize() { - Size size = pFont::size(widget.state.font, label.state.text); - return {size.width, size.height}; -} - -void pLabel::setText(string text) { - gtk_label_set_text(GTK_LABEL(gtkWidget), text); -} - -void pLabel::constructor() { - gtkWidget = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(gtkWidget), 0.0, 0.5); - - setText(label.state.text); -} - -void pLabel::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pLabel::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/line-edit.cpp b/phoenix/gtk/widget/line-edit.cpp deleted file mode 100644 index 642e6936..00000000 --- a/phoenix/gtk/widget/line-edit.cpp +++ /dev/null @@ -1,59 +0,0 @@ -namespace phoenix { - -static void LineEdit_activate(LineEdit* self) { - if(self->onActivate) self->onActivate(); -} - -static void LineEdit_change(LineEdit* self) { - self->state.text = self->text(); - if(self->p.locked == false && self->onChange) self->onChange(); -} - -Size pLineEdit::minimumSize() { - Size size = pFont::size(widget.state.font, lineEdit.state.text); - return {size.width + 10, size.height + 10}; -} - -void pLineEdit::setBackgroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_base(gtkWidget, GTK_STATE_NORMAL, &gdkColor); -} - -void pLineEdit::setEditable(bool editable) { - gtk_editable_set_editable(GTK_EDITABLE(gtkWidget), editable); -} - -void pLineEdit::setForegroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_text(gtkWidget, GTK_STATE_NORMAL, &gdkColor); -} - -void pLineEdit::setText(string text) { - locked = true; - gtk_entry_set_text(GTK_ENTRY(gtkWidget), text); - locked = false; -} - -string pLineEdit::text() { - return gtk_entry_get_text(GTK_ENTRY(gtkWidget)); -} - -void pLineEdit::constructor() { - gtkWidget = gtk_entry_new(); - g_signal_connect_swapped(G_OBJECT(gtkWidget), "activate", G_CALLBACK(LineEdit_activate), (gpointer)&lineEdit); - g_signal_connect_swapped(G_OBJECT(gtkWidget), "changed", G_CALLBACK(LineEdit_change), (gpointer)&lineEdit); - - setEditable(lineEdit.state.editable); - setText(lineEdit.state.text); -} - -void pLineEdit::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pLineEdit::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/list-view.cpp b/phoenix/gtk/widget/list-view.cpp deleted file mode 100644 index 8fa77c6c..00000000 --- a/phoenix/gtk/widget/list-view.cpp +++ /dev/null @@ -1,216 +0,0 @@ -namespace phoenix { - -static void ListView_activate(GtkTreeView* treeView, GtkTreePath* path, GtkTreeViewColumn* column, ListView* self) { - char* pathname = gtk_tree_path_to_string(path); - unsigned selection = decimal(pathname); - g_free(pathname); - self->state.selection = selection; - if(self->onActivate) self->onActivate(); -} - -static void ListView_change(GtkTreeView* treeView, ListView* self) { - GtkTreeIter iter; - if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(treeView), 0, &iter)) return; //should not be possible - char* path = gtk_tree_model_get_string_from_iter(gtk_tree_view_get_model(treeView), &iter); - unsigned selection = decimal(path); - g_free(path); - - if(!self->state.selected || self->state.selection != selection) { - self->state.selected = true; - self->state.selection = selection; - if(self->onChange) self->onChange(); - } -} - -static void ListView_toggle(GtkCellRendererToggle* cell, gchar* path, ListView* self) { - unsigned selection = decimal(path); - self->setChecked(selection, !self->checked(selection)); - if(self->onToggle) self->onToggle(selection); -} - -void pListView::append(const lstring& text) { - GtkTreeIter iter; - gtk_list_store_append(store, &iter); - for(unsigned n = 0; n < text.size(); n++) { - gtk_list_store_set(store, &iter, 1 + n * 2 + 1, (const char*)text[n], -1); - } -} - -void pListView::autoSizeColumns() { - gtk_tree_view_columns_autosize(GTK_TREE_VIEW(subWidget)); -} - -bool pListView::focused() { - return GTK_WIDGET_HAS_FOCUS(subWidget); -} - -void pListView::remove(unsigned selection) { - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); - GtkTreeIter iter; - gtk_tree_model_get_iter_from_string(model, &iter, string(selection)); - gtk_list_store_remove(store, &iter); -} - -void pListView::reset() { - listView.state.selected = false; - listView.state.selection = 0; - gtk_list_store_clear(GTK_LIST_STORE(store)); - gtk_tree_view_set_model(GTK_TREE_VIEW(subWidget), GTK_TREE_MODEL(store)); - //reset gtk_scrolled_window scrollbar position to 0,0 (top-left), as ListView is now empty - gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(gtkWidget), 0); - gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(gtkWidget), 0); -} - -void pListView::setBackgroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, &gdkColor); -} - -void pListView::setCheckable(bool checkable) { - gtk_cell_renderer_set_visible(column(0).checkbutton, checkable); -} - -void pListView::setChecked(unsigned selection, bool checked) { - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); - GtkTreeIter iter; - gtk_tree_model_get_iter_from_string(model, &iter, string(selection)); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, checked, -1); -} - -void pListView::setForegroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, &gdkColor); -} - -void pListView::setHeaderText(const lstring& text) { - destructor(); - constructor(); -} - -void pListView::setHeaderVisible(bool visible) { - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(subWidget), visible); -} - -void pListView::setImage(unsigned selection, unsigned position, const image& image) { - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); - GtkTreeIter iter; - gtk_tree_model_get_iter_from_string(model, &iter, string(selection)); - if(image.empty() == false) { - GdkPixbuf* pixbuf = CreatePixbuf(image, true); - gtk_list_store_set(store, &iter, 1 + position * 2, pixbuf, -1); - } else { - gtk_list_store_set(store, &iter, 1 + position * 2, nullptr, -1); - } -} - -void pListView::setSelected(bool selected) { - if(selected == false) { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); - gtk_tree_selection_unselect_all(selection); - } else { - setSelection(listView.state.selection); - } -} - -void pListView::setSelection(unsigned selection) { - GtkTreeSelection* treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); - gtk_tree_selection_unselect_all(treeSelection); - GtkTreePath* path = gtk_tree_path_new_from_string(string{selection}); - gtk_tree_selection_select_path(treeSelection, path); - gtk_tree_view_set_cursor(GTK_TREE_VIEW(subWidget), path, nullptr, false); - gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(subWidget), path, nullptr, true, 0.5, 0.0); - gtk_tree_path_free(path); -} - -void pListView::setText(unsigned selection, unsigned position, string text) { - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); - GtkTreeIter iter; - gtk_tree_model_get_iter_from_string(model, &iter, string(selection)); - gtk_list_store_set(store, &iter, 1 + position * 2 + 1, (const char*)text, -1); -} - -void pListView::constructor() { - gtkWidget = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); - - lstring headerText = listView.state.headerText; - if(headerText.size() == 0) headerText.append(""); //ListView must have at least one column - - column.reset(); - vector gtype; - for(auto& text : headerText) { - GtkColumn cell; - cell.label = gtk_label_new(text); - cell.column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_resizable(cell.column, true); - gtk_tree_view_column_set_title(cell.column, ""); - - if(column.size() == 0) { //first column checkbutton - cell.checkbutton = gtk_cell_renderer_toggle_new(); - gtk_tree_view_column_pack_start(cell.column, cell.checkbutton, false); - gtk_tree_view_column_set_attributes(cell.column, cell.checkbutton, "active", gtype.size(), nullptr); - gtype.append(G_TYPE_BOOLEAN); - g_signal_connect(cell.checkbutton, "toggled", G_CALLBACK(ListView_toggle), (gpointer)&listView); - } - - cell.icon = gtk_cell_renderer_pixbuf_new(); - gtk_tree_view_column_pack_start(cell.column, cell.icon, false); - gtk_tree_view_column_set_attributes(cell.column, cell.icon, "pixbuf", gtype.size(), nullptr); - gtype.append(GDK_TYPE_PIXBUF); - - cell.text = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(cell.column, cell.text, false); - gtk_tree_view_column_set_attributes(cell.column, cell.text, "text", gtype.size(), nullptr); - gtype.append(G_TYPE_STRING); - - column.append(cell); - } - - store = gtk_list_store_newv(gtype.size(), gtype.data()); - subWidget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); - g_object_unref(G_OBJECT(store)); - - for(auto& cell : column) { - gtk_tree_view_column_set_widget(GTK_TREE_VIEW_COLUMN(cell.column), cell.label); - gtk_tree_view_append_column(GTK_TREE_VIEW(subWidget), cell.column); - gtk_widget_show(cell.label); - } - - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(subWidget), headerText.size() >= 2); //two or more columns + checkbutton column - gtk_tree_view_set_search_column(GTK_TREE_VIEW(subWidget), 2); - - g_signal_connect(G_OBJECT(subWidget), "cursor-changed", G_CALLBACK(ListView_change), (gpointer)&listView); - g_signal_connect(G_OBJECT(subWidget), "row-activated", G_CALLBACK(ListView_activate), (gpointer)&listView); - - gtk_widget_show(subWidget); - - setHeaderVisible(listView.state.headerVisible); - setCheckable(listView.state.checkable); - for(auto& text : listView.state.text) append(text); - for(unsigned n = 0; n < listView.state.checked.size(); n++) setChecked(n, listView.state.checked[n]); - if(listView.state.selected) setSelection(listView.state.selection); - autoSizeColumns(); -} - -void pListView::destructor() { - gtk_widget_destroy(subWidget); - gtk_widget_destroy(gtkWidget); -} - -void pListView::orphan() { - destructor(); - constructor(); -} - -void pListView::setFocused() { - gtk_widget_grab_focus(subWidget); -} - -void pListView::setFont(string font) { - pFont::setFont(gtkWidget, font); - for(auto& cell : column) pFont::setFont(cell.label, font); -} - -} diff --git a/phoenix/gtk/widget/progress-bar.cpp b/phoenix/gtk/widget/progress-bar.cpp deleted file mode 100644 index 7f4545a2..00000000 --- a/phoenix/gtk/widget/progress-bar.cpp +++ /dev/null @@ -1,27 +0,0 @@ -namespace phoenix { - -Size pProgressBar::minimumSize() { - return {0, 25}; -} - -void pProgressBar::setPosition(unsigned position) { - position = position <= 100 ? position : 0; - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkWidget), (double)position / 100.0); -} - -void pProgressBar::constructor() { - gtkWidget = gtk_progress_bar_new(); - - setPosition(progressBar.state.position); -} - -void pProgressBar::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pProgressBar::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/radio-button.cpp b/phoenix/gtk/widget/radio-button.cpp deleted file mode 100644 index ca10fc36..00000000 --- a/phoenix/gtk/widget/radio-button.cpp +++ /dev/null @@ -1,89 +0,0 @@ -namespace phoenix { - -static void RadioButton_activate(GtkToggleButton* toggleButton, RadioButton* self) { - self->p.onActivate(); -} - -Size pRadioButton::minimumSize() { - Size size = pFont::size(widget.state.font, radioButton.state.text); - - if(radioButton.state.orientation == Orientation::Horizontal) { - size.width += radioButton.state.image.width; - size.height = max(radioButton.state.image.height, size.height); - } - - if(radioButton.state.orientation == Orientation::Vertical) { - size.width = max(radioButton.state.image.width, size.width); - size.height += radioButton.state.image.height; - } - - return {size.width + 24, size.height + 12}; -} - -void pRadioButton::setChecked() { - parent().locked = true; - for(auto& item : radioButton.state.group) { - bool checked = &item == &radioButton; - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item.p.gtkWidget), item.state.checked = checked); - } - parent().locked = false; -} - -void pRadioButton::setGroup(const group& group) { - parent().locked = true; - for(auto& item : radioButton.state.group) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item.p.gtkWidget), item.state.checked); - } - parent().locked = false; -} - -void pRadioButton::setImage(const image& image, Orientation orientation) { - if(image.empty() == false) { - GtkImage* gtkImage = CreateImage(image); - gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); - } else { - gtk_button_set_image(GTK_BUTTON(gtkWidget), nullptr); - } - switch(orientation) { - case Orientation::Horizontal: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_LEFT); break; - case Orientation::Vertical: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_TOP); break; - } -} - -void pRadioButton::setText(string text) { - gtk_button_set_label(GTK_BUTTON(gtkWidget), text); - setFont(widget.state.font); -} - -void pRadioButton::constructor() { - gtkWidget = gtk_toggle_button_new(); - g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioButton_activate), (gpointer)&radioButton); - - setGroup(radioButton.state.group); - setText(radioButton.state.text); -} - -void pRadioButton::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pRadioButton::orphan() { - destructor(); - constructor(); -} - -void pRadioButton::onActivate() { - if(parent().locked) return; - bool wasChecked = radioButton.state.checked; - setChecked(); - if(!wasChecked) { - if(radioButton.onActivate) radioButton.onActivate(); - } -} - -pRadioButton& pRadioButton::parent() { - if(radioButton.state.group.size()) return radioButton.state.group.first().p; - return *this; -} - -} diff --git a/phoenix/gtk/widget/radio-label.cpp b/phoenix/gtk/widget/radio-label.cpp deleted file mode 100644 index 5e1b224d..00000000 --- a/phoenix/gtk/widget/radio-label.cpp +++ /dev/null @@ -1,69 +0,0 @@ -namespace phoenix { - -static void RadioLabel_activate(GtkToggleButton* toggleButton, RadioLabel* self) { - self->p.onActivate(); -} - -Size pRadioLabel::minimumSize() { - Size size = pFont::size(widget.state.font, radioLabel.state.text); - return {size.width + 28, size.height + 4}; -} - -void pRadioLabel::setChecked() { - parent().locked = true; - for(auto& item : radioLabel.state.group) item.state.checked = false; - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), radioLabel.state.checked = true); - parent().locked = false; -} - -void pRadioLabel::setGroup(const group& group) { - if(&parent() == this) return; - parent().locked = true; - gtk_radio_button_set_group( - GTK_RADIO_BUTTON(gtkWidget), - gtk_radio_button_get_group(GTK_RADIO_BUTTON(parent().gtkWidget)) - ); - for(auto& item : radioLabel.state.group) { - if(item.state.checked) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item.p.gtkWidget), true); - break; - } - } - parent().locked = false; -} - -void pRadioLabel::setText(string text) { - gtk_button_set_label(GTK_BUTTON(gtkWidget), text); -} - -void pRadioLabel::constructor() { - gtkWidget = gtk_radio_button_new_with_label(nullptr, ""); - g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioLabel_activate), (gpointer)&radioLabel); - - setGroup(radioLabel.state.group); - setText(radioLabel.state.text); -} - -void pRadioLabel::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pRadioLabel::orphan() { - destructor(); - constructor(); -} - -void pRadioLabel::onActivate() { - if(parent().locked) return; - bool wasChecked = radioLabel.state.checked; - setChecked(); - if(wasChecked) return; - if(radioLabel.onActivate) radioLabel.onActivate(); -} - -pRadioLabel& pRadioLabel::parent() { - if(radioLabel.state.group.size()) return radioLabel.state.group.first().p; - return *this; -} - -} diff --git a/phoenix/gtk/widget/tab-frame.cpp b/phoenix/gtk/widget/tab-frame.cpp deleted file mode 100644 index a9a3c562..00000000 --- a/phoenix/gtk/widget/tab-frame.cpp +++ /dev/null @@ -1,126 +0,0 @@ -namespace phoenix { - -static void TabFrame_change(GtkNotebook* notebook, GtkWidget* page, unsigned selection, TabFrame* self) { - self->state.selection = selection; - self->p.synchronizeLayout(); - if(!self->p.locked && self->onChange) self->onChange(); -} - -void pTabFrame::append(string text, const image& image) { - unsigned selection = tabFrame.state.text.size() - 1; - - Tab tab; - tab.child = gtk_fixed_new(); - tab.container = gtk_hbox_new(false, 0); - tab.image = gtk_image_new(); - tab.title = gtk_label_new(text); - tabs.append(tab); - - gtk_widget_show(tab.child); - gtk_widget_show(tab.container); - gtk_widget_show(tab.image); - gtk_widget_show(tab.title); - gtk_box_pack_start(GTK_BOX(tab.container), tab.image, false, false, 0); - gtk_box_pack_start(GTK_BOX(tab.container), tab.title, false, false, 2); - - gtk_notebook_append_page(GTK_NOTEBOOK(gtkWidget), tab.child, tab.container); - setFont(widget.state.font); - if(!image.empty()) setImage(selection, image); -} - -GtkWidget* pTabFrame::container(Widget& widget) { - Layout* widgetLayout = GetParentWidgetLayout(&widget); - unsigned selection = 0; - for(auto& layout : tabFrame.state.layout) { - if(layout == widgetLayout) return tabs[selection].child; - selection++; - } - return nullptr; -} - -Position pTabFrame::displacement() { - return {6, 31}; -} - -void pTabFrame::remove(unsigned selection) { - tabs.remove(selection); - gtk_notebook_remove_page(GTK_NOTEBOOK(gtkWidget), selection); -} - -void pTabFrame::setEnabled(bool enabled) { - for(auto& layout : tabFrame.state.layout) { - if(layout) layout->setEnabled(layout->enabled()); - } - pWidget::setEnabled(enabled); -} - -void pTabFrame::setGeometry(Geometry geometry) { - pWidget::setGeometry(geometry); - geometry.x += 1, geometry.width -= 5; - geometry.y += 26, geometry.height -= 31; - for(auto& layout : tabFrame.state.layout) { - if(layout) layout->setGeometry(geometry); - } - synchronizeLayout(); -} - -void pTabFrame::setImage(unsigned selection, const image& image) { - if(image.empty() == false) { - nall::image copy = image; - unsigned size = pFont::size(widget.state.font, " ").height; - copy.scale(size, size); - GdkPixbuf* pixbuf = CreatePixbuf(copy); - gtk_image_set_from_pixbuf(GTK_IMAGE(tabs[selection].image), pixbuf); - } else { - gtk_image_clear(GTK_IMAGE(tabs[selection].image)); - } -} - -void pTabFrame::setSelection(unsigned selection) { - locked = true; - gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkWidget), selection); - locked = false; -} - -void pTabFrame::setText(unsigned selection, string text) { - gtk_label_set_text(GTK_LABEL(tabs[selection].title), text); -} - -void pTabFrame::setVisible(bool visible) { - for(auto& layout : tabFrame.state.layout) { - if(layout) layout->setVisible(layout->visible()); - } - pWidget::setVisible(visible); -} - -void pTabFrame::constructor() { - gtkWidget = gtk_notebook_new(); - gtk_notebook_set_show_border(GTK_NOTEBOOK(gtkWidget), false); - gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkWidget), GTK_POS_TOP); - g_signal_connect(G_OBJECT(gtkWidget), "switch-page", G_CALLBACK(TabFrame_change), (gpointer)&tabFrame); - - setSelection(tabFrame.state.selection); -} - -void pTabFrame::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pTabFrame::orphan() { - destructor(); - constructor(); -} - -void pTabFrame::setFont(string font) { - for(auto& tab : tabs) pFont::setFont(tab.title, font); -} - -void pTabFrame::synchronizeLayout() { - unsigned selection = 0; - for(auto& layout : tabFrame.state.layout) { - if(layout) layout->setVisible(selection == tabFrame.state.selection); - selection++; - } -} - -} diff --git a/phoenix/gtk/widget/text-edit.cpp b/phoenix/gtk/widget/text-edit.cpp deleted file mode 100644 index 49ee4df7..00000000 --- a/phoenix/gtk/widget/text-edit.cpp +++ /dev/null @@ -1,88 +0,0 @@ -namespace phoenix { - -static void TextEdit_change(TextEdit* self) { - self->state.text = self->text(); - if(self->p.locked == false && self->onChange) self->onChange(); -} - -bool pTextEdit::focused() { - return GTK_WIDGET_HAS_FOCUS(subWidget); -} - -void pTextEdit::setBackgroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, &gdkColor); -} - -void pTextEdit::setCursorPosition(unsigned position) { - GtkTextMark* mark = gtk_text_buffer_get_mark(textBuffer, "insert"); - GtkTextIter iter; - gtk_text_buffer_get_end_iter(textBuffer, &iter); - gtk_text_iter_set_offset(&iter, min(position, gtk_text_iter_get_offset(&iter))); - gtk_text_buffer_place_cursor(textBuffer, &iter); - gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(subWidget), mark); -} - -void pTextEdit::setEditable(bool editable) { - gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), editable); -} - -void pTextEdit::setForegroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, &gdkColor); -} - -void pTextEdit::setText(string text) { - locked = true; - gtk_text_buffer_set_text(textBuffer, text, -1); - locked = false; -} - -void pTextEdit::setWordWrap(bool wordWrap) { - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), wordWrap ? GTK_WRAP_WORD_CHAR : GTK_WRAP_NONE); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), - wordWrap ? GTK_POLICY_NEVER : GTK_POLICY_ALWAYS, - GTK_POLICY_ALWAYS); -} - -string pTextEdit::text() { - GtkTextIter start, end; - gtk_text_buffer_get_start_iter(textBuffer, &start); - gtk_text_buffer_get_end_iter(textBuffer, &end); - char* temp = gtk_text_buffer_get_text(textBuffer, &start, &end, true); - string text = temp; - g_free(temp); - return text; -} - -void pTextEdit::constructor() { - gtkWidget = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN); - - subWidget = gtk_text_view_new(); - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_WORD_CHAR); - gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget); - - textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); - - g_signal_connect_swapped(G_OBJECT(textBuffer), "changed", G_CALLBACK(TextEdit_change), (gpointer)&textEdit); - - gtk_widget_show(subWidget); - - setEditable(textEdit.state.editable); - setText(textEdit.state.text); - setWordWrap(textEdit.state.wordWrap); -} - -void pTextEdit::destructor() { - gtk_widget_destroy(subWidget); - gtk_widget_destroy(gtkWidget); -} - -void pTextEdit::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/vertical-scroller.cpp b/phoenix/gtk/widget/vertical-scroller.cpp deleted file mode 100644 index 68928ce3..00000000 --- a/phoenix/gtk/widget/vertical-scroller.cpp +++ /dev/null @@ -1,43 +0,0 @@ -namespace phoenix { - -static void VerticalScroller_change(GtkRange* gtkRange, VerticalScroller* self) { - unsigned position = (unsigned)gtk_range_get_value(gtkRange); - if(self->state.position == position) return; - self->state.position = position; - if(!self->p.locked && self->onChange) self->onChange(); -} - -Size pVerticalScroller::minimumSize() { - return {20, 0}; -} - -void pVerticalScroller::setLength(unsigned length) { - locked = true; - length += length == 0; - gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); - gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); - locked = false; -} - -void pVerticalScroller::setPosition(unsigned position) { - gtk_range_set_value(GTK_RANGE(gtkWidget), position); -} - -void pVerticalScroller::constructor() { - gtkWidget = gtk_vscrollbar_new(0); - g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalScroller_change), (gpointer)&verticalScroller); - - setLength(verticalScroller.state.length); - setPosition(verticalScroller.state.position); -} - -void pVerticalScroller::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pVerticalScroller::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/vertical-slider.cpp b/phoenix/gtk/widget/vertical-slider.cpp deleted file mode 100644 index 102b5c44..00000000 --- a/phoenix/gtk/widget/vertical-slider.cpp +++ /dev/null @@ -1,42 +0,0 @@ -namespace phoenix { - -static void VerticalSlider_change(GtkRange* gtkRange, VerticalSlider* self) { - unsigned position = (unsigned)gtk_range_get_value(gtkRange); - if(self->state.position == position) return; - self->state.position = position; - if(self->onChange) self->onChange(); -} - -Size pVerticalSlider::minimumSize() { - return {20, 0}; -} - -void pVerticalSlider::setLength(unsigned length) { - length += length == 0; - gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1)); - gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3); -} - -void pVerticalSlider::setPosition(unsigned position) { - gtk_range_set_value(GTK_RANGE(gtkWidget), position); -} - -void pVerticalSlider::constructor() { - gtkWidget = gtk_vscale_new_with_range(0, 100, 1); - gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); - g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)&verticalSlider); - - setLength(verticalSlider.state.length); - setPosition(verticalSlider.state.position); -} - -void pVerticalSlider::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pVerticalSlider::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/viewport.cpp b/phoenix/gtk/widget/viewport.cpp deleted file mode 100644 index bc2474e6..00000000 --- a/phoenix/gtk/widget/viewport.cpp +++ /dev/null @@ -1,76 +0,0 @@ -namespace phoenix { - -static void Viewport_dropEvent(GtkWidget* widget, GdkDragContext* context, gint x, gint y, -GtkSelectionData* data, guint type, guint timestamp, Viewport* viewport) { - if(viewport->state.droppable == false) return; - lstring paths = DropPaths(data); - if(paths.empty()) return; - if(viewport->onDrop) viewport->onDrop(paths); -} - -static gboolean Viewport_mouseLeave(GtkWidget* widget, GdkEventButton* event, pViewport* self) { - if(self->viewport.onMouseLeave) self->viewport.onMouseLeave(); - return true; -} - -static gboolean Viewport_mouseMove(GtkWidget* widget, GdkEventButton* event, pViewport* self) { - if(self->viewport.onMouseMove) self->viewport.onMouseMove({(signed)event->x, (signed)event->y}); - return true; -} - -static gboolean Viewport_mousePress(GtkWidget* widget, GdkEventButton* event, pViewport* self) { - if(self->viewport.onMousePress) switch(event->button) { - case 1: self->viewport.onMousePress(Mouse::Button::Left); break; - case 2: self->viewport.onMousePress(Mouse::Button::Middle); break; - case 3: self->viewport.onMousePress(Mouse::Button::Right); break; - } - return true; -} - -static gboolean Viewport_mouseRelease(GtkWidget* widget, GdkEventButton* event, pViewport* self) { - if(self->viewport.onMouseRelease) switch(event->button) { - case 1: self->viewport.onMouseRelease(Mouse::Button::Left); break; - case 2: self->viewport.onMouseRelease(Mouse::Button::Middle); break; - case 3: self->viewport.onMouseRelease(Mouse::Button::Right); break; - } - return true; -} - -uintptr_t pViewport::handle() { - return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget)); -} - -void pViewport::setDroppable(bool droppable) { - gtk_drag_dest_set(gtkWidget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY); - if(droppable) gtk_drag_dest_add_uri_targets(gtkWidget); -} - -void pViewport::constructor() { - gtkWidget = gtk_drawing_area_new(); -//gtk_widget_set_double_buffered(gtkWidget, false); - gtk_widget_add_events(gtkWidget, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); - g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Viewport_dropEvent), (gpointer)&viewport); - g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Viewport_mousePress), (gpointer)this); - g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Viewport_mouseRelease), (gpointer)this); - g_signal_connect(G_OBJECT(gtkWidget), "leave-notify-event", G_CALLBACK(Viewport_mouseLeave), (gpointer)this); - g_signal_connect(G_OBJECT(gtkWidget), "motion-notify-event", G_CALLBACK(Viewport_mouseMove), (gpointer)this); - - GdkColor color; - color.pixel = 0; - color.red = 0; - color.green = 0; - color.blue = 0; - gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, &color); -} - -void pViewport::destructor() { - gtk_widget_destroy(gtkWidget); -} - -void pViewport::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/widget/widget.cpp b/phoenix/gtk/widget/widget.cpp deleted file mode 100644 index 1b834d32..00000000 --- a/phoenix/gtk/widget/widget.cpp +++ /dev/null @@ -1,62 +0,0 @@ -namespace phoenix { - -GtkWidget* pWidget::container(Widget& widget) { - return nullptr; -} - -bool pWidget::focused() { - return GTK_WIDGET_HAS_FOCUS(gtkWidget); -} - -Size pWidget::minimumSize() { - return {0, 0}; -} - -void pWidget::setEnabled(bool enabled) { - if(!widget.parent()) enabled = false; - if(widget.state.abstract) enabled = false; - if(!widget.enabledToAll()) enabled = false; - gtk_widget_set_sensitive(gtkWidget, enabled); -} - -void pWidget::setFocused() { - gtk_widget_grab_focus(gtkWidget); -} - -void pWidget::setFont(string font) { - pFont::setFont(gtkWidget, font); -} - -void pWidget::setGeometry(Geometry geometry) { - Position displacement = GetDisplacement(&widget); - geometry.x -= displacement.x; - geometry.y -= displacement.y; - - if(gtkParent) gtk_fixed_move(GTK_FIXED(gtkParent), gtkWidget, geometry.x, geometry.y); - unsigned width = (signed)geometry.width <= 0 ? 1u : geometry.width; - unsigned height = (signed)geometry.height <= 0 ? 1u : geometry.height; - gtk_widget_set_size_request(gtkWidget, width, height); - if(widget.onSize) widget.onSize(); -} - -void pWidget::setVisible(bool visible) { - if(!widget.parent()) visible = false; - if(widget.state.abstract) visible = false; - if(!widget.visibleToAll()) visible = false; - gtk_widget_set_visible(gtkWidget, visible); -} - -void pWidget::constructor() { - if(widget.state.abstract) gtkWidget = gtk_fixed_new(); -} - -void pWidget::destructor() { - if(widget.state.abstract) gtk_widget_destroy(gtkWidget); -} - -void pWidget::orphan() { - destructor(); - constructor(); -} - -} diff --git a/phoenix/gtk/window.cpp b/phoenix/gtk/window.cpp deleted file mode 100644 index 573972be..00000000 --- a/phoenix/gtk/window.cpp +++ /dev/null @@ -1,402 +0,0 @@ -namespace phoenix { - -static gint Window_close(GtkWidget* widget, GdkEvent* event, Window* window) { - if(window->onClose) window->onClose(); - else window->setVisible(false); - if(window->state.modal && !window->visible()) window->setModal(false); - return true; -} - -static gboolean Window_expose(GtkWidget* widget, GdkEvent* event, Window* window) { - if(window->state.backgroundColorOverride == false) return false; - cairo_t* context = gdk_cairo_create(widget->window); - - Color color = window->backgroundColor(); - double red = (double)color.red / 255.0; - double green = (double)color.green / 255.0; - double blue = (double)color.blue / 255.0; - double alpha = (double)color.alpha / 255.0; - - if(gdk_screen_is_composited(gdk_screen_get_default()) - && gdk_screen_get_rgba_colormap(gdk_screen_get_default()) - ) { - cairo_set_source_rgba(context, red, green, blue, alpha); - } else { - cairo_set_source_rgb(context, red, green, blue); - } - - cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); - cairo_paint(context); - cairo_destroy(context); - - return false; -} - -static gboolean Window_configure(GtkWidget* widget, GdkEvent* event, Window* window) { - if(gtk_widget_get_realized(window->p.widget) == false) return false; - if(window->visible() == false) return false; - GdkWindow *gdkWindow = gtk_widget_get_window(widget); - - GdkRectangle border, client; - gdk_window_get_frame_extents(gdkWindow, &border); - gdk_window_get_geometry(gdkWindow, nullptr, nullptr, &client.width, &client.height, nullptr); - gdk_window_get_origin(gdkWindow, &client.x, &client.y); - - if(window->state.fullScreen == false) { - //update geometry settings - settings->geometry.frameX = client.x - border.x; - settings->geometry.frameY = client.y - border.y; - settings->geometry.frameWidth = border.width - client.width; - settings->geometry.frameHeight = border.height - client.height; - if(window->state.backgroundColorOverride == false) { - GdkColor color = widget->style->bg[GTK_STATE_NORMAL]; - settings->window.backgroundColor - = ((uint8_t)(color.red >> 8) << 16) - + ((uint8_t)(color.green >> 8) << 8) - + ((uint8_t)(color.blue >> 8) << 0); - } - settings->save(); - } - - Geometry geometry = { - client.x, - client.y + window->p.menuHeight(), - client.width, - client.height - window->p.menuHeight() - window->p.statusHeight() - }; - - //move - if(geometry.x != window->state.geometry.x || geometry.y != window->state.geometry.y) { - if(window->state.fullScreen == false) { - window->state.geometry.x = geometry.x; - window->state.geometry.y = geometry.y; - } - if(window->p.locked == false && window->onMove) window->onMove(); - } - - //size - if(geometry.width != window->state.geometry.width || geometry.height != window->state.geometry.height) { - window->p.onSizePending = true; - } - - return false; -} - -static void Window_drop(GtkWidget* widget, GdkDragContext* context, gint x, gint y, -GtkSelectionData* data, guint type, guint timestamp, Window* window) { - if(window->state.droppable == false) return; - lstring paths = DropPaths(data); - if(paths.empty()) return; - if(window->onDrop) window->onDrop(paths); -} - -static gboolean Window_keyPress(GtkWidget* widget, GdkEventKey* event, Window* window) { - Keyboard::Keycode key = Keysym(event->keyval); - if(key != Keyboard::Keycode::None && window->onKeyPress) window->onKeyPress(key); - return false; -} - -static gboolean Window_keyRelease(GtkWidget* widget, GdkEventKey* event, Window* window) { - Keyboard::Keycode key = Keysym(event->keyval); - if(key != Keyboard::Keycode::None && window->onKeyRelease) window->onKeyRelease(key); - return false; -} - -static void Window_sizeAllocate(GtkWidget* widget, GtkAllocation* allocation, Window* window) { - //size-allocate sent from gtk_fixed_move(); detect if layout unchanged and return - if(allocation->width == window->p.lastAllocation.width - && allocation->height == window->p.lastAllocation.height) return; - - window->state.geometry.width = allocation->width; - window->state.geometry.height = allocation->height; - - for(auto& layout : window->state.layout) { - Geometry geometry = window->geometry(); - geometry.x = geometry.y = 0; - layout.setGeometry(geometry); - } - - if(window->p.onSizePending && window->p.locked == false && window->onSize) { - window->p.onSizePending = false; - window->onSize(); - } - - window->p.lastAllocation = *allocation; -} - -static void Window_sizeRequest(GtkWidget* widget, GtkRequisition* requisition, Window* window) { - requisition->width = window->state.geometry.width; - requisition->height = window->state.geometry.height; -} - -Window& pWindow::none() { - static Window* window = nullptr; - if(window == nullptr) window = new Window; - return *window; -} - -void pWindow::append(Layout& layout) { - Geometry geometry = this->geometry(); - geometry.x = geometry.y = 0; - layout.setGeometry(geometry); -} - -void pWindow::append(Menu& menu) { - if(window.state.menuFont) menu.p.setFont(window.state.menuFont); - else menu.p.setFont(Font::sans(8)); - gtk_menu_shell_append(GTK_MENU_SHELL(this->menu), menu.p.widget); - gtk_widget_show(menu.p.widget); -} - -void pWindow::append(Widget& widget) { - if(widget.font().empty() && !window.state.widgetFont.empty()) { - widget.setFont(window.state.widgetFont); - } - - if(GetParentWidget(&widget)) { - widget.p.gtkParent = GetParentWidget(&widget)->p.container(widget); - } else { - widget.p.gtkParent = formContainer; - } - - gtk_fixed_put(GTK_FIXED(widget.p.gtkParent), widget.p.gtkWidget, 0, 0); - if(widget.state.font) widget.p.setFont(widget.state.font); - else if(window.state.widgetFont) widget.p.setFont(window.state.widgetFont); - else widget.p.setFont(Font::sans(8)); - widget.setVisible(widget.visible()); -} - -Geometry pWindow::frameMargin() { - if(window.state.fullScreen) return { - 0, - menuHeight(), - 0, - menuHeight() + statusHeight() - }; - - return { - settings->geometry.frameX, - settings->geometry.frameY + menuHeight(), - settings->geometry.frameWidth, - settings->geometry.frameHeight + menuHeight() + statusHeight() - }; -} - -bool pWindow::focused() { - return gtk_window_is_active(GTK_WINDOW(widget)); -} - -Geometry pWindow::geometry() { - if(window.state.fullScreen) { - int x, y, width, height; - gtk_window_get_position(GTK_WINDOW(widget), &x, &y); - gtk_window_get_size(GTK_WINDOW(widget), &width, &height); - return {x, y + menuHeight(), width, height - menuHeight() - statusHeight()}; - } - return window.state.geometry; -} - -void pWindow::remove(Layout& layout) { -} - -void pWindow::remove(Menu& menu) { - menu.p.orphan(); -} - -void pWindow::remove(Widget& widget) { - widget.p.orphan(); -} - -void pWindow::setBackgroundColor(Color color) { - GdkColor gdkColor = CreateColor(color.red, color.green, color.blue); - gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &gdkColor); -} - -void pWindow::setDroppable(bool droppable) { - gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY); - if(droppable) gtk_drag_dest_add_uri_targets(widget); -} - -void pWindow::setFocused() { - gtk_window_present(GTK_WINDOW(widget)); -} - -void pWindow::setFullScreen(bool fullScreen) { - if(fullScreen == false) { - gtk_window_unfullscreen(GTK_WINDOW(widget)); - } else { - gtk_window_fullscreen(GTK_WINDOW(widget)); - /*unsigned monitor = gdk_screen_get_monitor_at_window(gdk_screen_get_default(), gtk_widget_get_window(widget)); - GdkRectangle rectangle = {0}; - gdk_screen_get_monitor_geometry(gdk_screen_get_default(), monitor, &rectangle); - gtk_window_set_decorated(GTK_WINDOW(widget), false); - gtk_window_move(GTK_WINDOW(widget), rectangle.x, rectangle.y); - gtk_window_resize(GTK_WINDOW(widget), rectangle.width, rectangle.height); - gtk_widget_set_size_request(formContainer, rectangle.width, rectangle.height);*/ - } -} - -void pWindow::setGeometry(Geometry geometry) { - Geometry margin = frameMargin(); - gtk_window_move(GTK_WINDOW(widget), geometry.x - margin.x, geometry.y - margin.y); - - GdkGeometry geom; - geom.min_width = window.state.resizable ? 1 : window.state.geometry.width; - geom.min_height = window.state.resizable ? 1 : window.state.geometry.height; - gtk_window_set_geometry_hints(GTK_WINDOW(widget), GTK_WIDGET(widget), &geom, GDK_HINT_MIN_SIZE); - -//gtk_window_set_policy(GTK_WINDOW(widget), true, true, false); - gtk_widget_set_size_request(formContainer, geometry.width, geometry.height); - gtk_window_resize(GTK_WINDOW(widget), geometry.width, geometry.height + menuHeight() + statusHeight()); - - for(auto& layout : window.state.layout) { - Geometry layoutGeometry = geometry; - layoutGeometry.x = layoutGeometry.y = 0; - layout.setGeometry(layoutGeometry); - } -} - -void pWindow::setMenuFont(string font) { - for(auto& item : window.state.menu) item.p.setFont(font); -} - -void pWindow::setMenuVisible(bool visible) { - gtk_widget_set_visible(menu, visible); -} - -void pWindow::setModal(bool modal) { - if(modal == true) { - gtk_window_set_modal(GTK_WINDOW(widget), true); - while(window.state.modal) { - Application::processEvents(); - usleep(20 * 1000); - } - gtk_window_set_modal(GTK_WINDOW(widget), false); - } -} - -void pWindow::setResizable(bool resizable) { - gtk_window_set_resizable(GTK_WINDOW(widget), resizable); - gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(status), resizable); -} - -void pWindow::setStatusFont(string font) { - pFont::setFont(status, font); -} - -void pWindow::setStatusText(string text) { - gtk_statusbar_pop(GTK_STATUSBAR(status), 1); - gtk_statusbar_push(GTK_STATUSBAR(status), 1, text); -} - -void pWindow::setStatusVisible(bool visible) { - gtk_widget_set_visible(status, visible); -} - -void pWindow::setTitle(string text) { - gtk_window_set_title(GTK_WINDOW(widget), text); -} - -void pWindow::setVisible(bool visible) { - gtk_widget_set_visible(widget, visible); - if(visible) { - if(gtk_widget_get_visible(menu)) { - GtkAllocation allocation; - gtk_widget_get_allocation(menu, &allocation); - settings->geometry.menuHeight = allocation.height; - } - - if(gtk_widget_get_visible(status)) { - GtkAllocation allocation; - gtk_widget_get_allocation(status, &allocation); - settings->geometry.statusHeight = allocation.height; - } - } -} - -void pWindow::setWidgetFont(string font) { -} - -void pWindow::constructor() { - lastAllocation.width = 0; - lastAllocation.height = 0; - onSizePending = false; - - widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); - - //if program was given a name, try and set the window taskbar icon from one of the pixmaps folders - if(applicationState.name.empty() == false) { - string filename = {"/usr/share/pixmaps/", applicationState.name, ".png"}; - if(!file::exists(filename)) filename = {"/usr/local/share/pixmaps/", applicationState.name, ".png"}; - if(file::exists(filename)) { - //maximum image size supported by GTK+ is 256x256; so we must scale larger images ourselves - nall::image icon(filename); - icon.scale(min(256u, icon.width), min(256u, icon.height), true); - GdkPixbuf* pixbuf = CreatePixbuf(icon); - gtk_window_set_icon(GTK_WINDOW(widget), pixbuf); - g_object_unref(G_OBJECT(pixbuf)); - } - } - - GdkColormap* colormap = gdk_screen_get_rgba_colormap(gdk_screen_get_default()); - if(!colormap) colormap = gdk_screen_get_rgb_colormap(gdk_screen_get_default()); - if(colormap) gtk_widget_set_colormap(widget, colormap); - - gtk_window_set_resizable(GTK_WINDOW(widget), true); - #if GTK_MAJOR_VERSION >= 3 - gtk_window_set_has_resize_grip(GTK_WINDOW(widget), false); - #endif - - gtk_widget_set_app_paintable(widget, true); - gtk_widget_add_events(widget, GDK_CONFIGURE); - - menuContainer = gtk_vbox_new(false, 0); - gtk_container_add(GTK_CONTAINER(widget), menuContainer); - gtk_widget_show(menuContainer); - - menu = gtk_menu_bar_new(); - gtk_box_pack_start(GTK_BOX(menuContainer), menu, false, false, 0); - - formContainer = gtk_fixed_new(); - gtk_box_pack_start(GTK_BOX(menuContainer), formContainer, true, true, 0); - gtk_widget_show(formContainer); - - statusContainer = gtk_event_box_new(); - status = gtk_statusbar_new(); - gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(status), true); - gtk_container_add(GTK_CONTAINER(statusContainer), status); - gtk_box_pack_start(GTK_BOX(menuContainer), statusContainer, false, false, 0); - gtk_widget_show(statusContainer); - - setTitle(""); - setResizable(window.state.resizable); - setGeometry(window.state.geometry); - setMenuFont(Font::sans(8)); - setStatusFont(Font::sans(8)); - - g_signal_connect(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)&window); - g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(Window_expose), (gpointer)&window); - g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window); - g_signal_connect(G_OBJECT(widget), "drag-data-received", G_CALLBACK(Window_drop), (gpointer)&window); - g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(Window_keyPress), (gpointer)&window); - g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(Window_keyPress), (gpointer)&window); - - g_signal_connect(G_OBJECT(formContainer), "size-allocate", G_CALLBACK(Window_sizeAllocate), (gpointer)&window); - g_signal_connect(G_OBJECT(formContainer), "size-request", G_CALLBACK(Window_sizeRequest), (gpointer)&window); - - window.state.backgroundColor = Color( - (uint8_t)(settings->window.backgroundColor >> 16), - (uint8_t)(settings->window.backgroundColor >> 8), - (uint8_t)(settings->window.backgroundColor >> 0) - ); -} - -unsigned pWindow::menuHeight() { - return window.state.menuVisible ? settings->geometry.menuHeight : 0; -} - -unsigned pWindow::statusHeight() { - return window.state.statusVisible ? settings->geometry.statusHeight : 0; -} - -} diff --git a/phoenix/phoenix.cpp b/phoenix/phoenix.cpp deleted file mode 100644 index 63041289..00000000 --- a/phoenix/phoenix.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PHOENIX_CPP -#define PHOENIX_CPP - -#include "core/core.cpp" - -#endif diff --git a/phoenix/phoenix.hpp b/phoenix/phoenix.hpp deleted file mode 100644 index 21e85af6..00000000 --- a/phoenix/phoenix.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef PHOENIX_HPP -#define PHOENIX_HPP - -#include "core/core.hpp" - -#endif diff --git a/phoenix/qt/keyboard.cpp b/phoenix/qt/keyboard.cpp deleted file mode 100644 index 17821076..00000000 --- a/phoenix/qt/keyboard.cpp +++ /dev/null @@ -1,149 +0,0 @@ -namespace phoenix { - -void pKeyboard::initialize() { - auto append = [](Keyboard::Scancode scancode, unsigned keysym) { - settings->keymap.insert(scancode, XKeysymToKeycode(pApplication::display, keysym)); - }; - - append(Keyboard::Scancode::Escape, XK_Escape); - append(Keyboard::Scancode::F1, XK_F1); - append(Keyboard::Scancode::F2, XK_F2); - append(Keyboard::Scancode::F3, XK_F3); - append(Keyboard::Scancode::F4, XK_F4); - append(Keyboard::Scancode::F5, XK_F5); - append(Keyboard::Scancode::F6, XK_F6); - append(Keyboard::Scancode::F7, XK_F7); - append(Keyboard::Scancode::F8, XK_F8); - append(Keyboard::Scancode::F9, XK_F9); - append(Keyboard::Scancode::F10, XK_F10); - append(Keyboard::Scancode::F11, XK_F11); - append(Keyboard::Scancode::F12, XK_F12); - - append(Keyboard::Scancode::PrintScreen, XK_Print); - append(Keyboard::Scancode::ScrollLock, XK_Scroll_Lock); - append(Keyboard::Scancode::Pause, XK_Pause); - - append(Keyboard::Scancode::Insert, XK_Insert); - append(Keyboard::Scancode::Delete, XK_Delete); - append(Keyboard::Scancode::Home, XK_Home); - append(Keyboard::Scancode::End, XK_End); - append(Keyboard::Scancode::PageUp, XK_Prior); - append(Keyboard::Scancode::PageDown, XK_Next); - - append(Keyboard::Scancode::Up, XK_Up); - append(Keyboard::Scancode::Down, XK_Down); - append(Keyboard::Scancode::Left, XK_Left); - append(Keyboard::Scancode::Right, XK_Right); - - append(Keyboard::Scancode::Grave, XK_asciitilde); - append(Keyboard::Scancode::Number1, XK_1); - append(Keyboard::Scancode::Number2, XK_2); - append(Keyboard::Scancode::Number3, XK_3); - append(Keyboard::Scancode::Number4, XK_4); - append(Keyboard::Scancode::Number5, XK_5); - append(Keyboard::Scancode::Number6, XK_6); - append(Keyboard::Scancode::Number7, XK_7); - append(Keyboard::Scancode::Number8, XK_8); - append(Keyboard::Scancode::Number9, XK_9); - append(Keyboard::Scancode::Number0, XK_0); - append(Keyboard::Scancode::Minus, XK_minus); - append(Keyboard::Scancode::Equal, XK_equal); - append(Keyboard::Scancode::Backspace, XK_BackSpace); - - append(Keyboard::Scancode::BracketLeft, XK_bracketleft); - append(Keyboard::Scancode::BracketRight, XK_bracketright); - append(Keyboard::Scancode::Backslash, XK_backslash); - append(Keyboard::Scancode::Semicolon, XK_semicolon); - append(Keyboard::Scancode::Apostrophe, XK_apostrophe); - append(Keyboard::Scancode::Comma, XK_comma); - append(Keyboard::Scancode::Period, XK_period); - append(Keyboard::Scancode::Slash, XK_slash); - - append(Keyboard::Scancode::Tab, XK_Tab); - append(Keyboard::Scancode::CapsLock, XK_Caps_Lock); - append(Keyboard::Scancode::Return, XK_Return); - append(Keyboard::Scancode::ShiftLeft, XK_Shift_L); - append(Keyboard::Scancode::ShiftRight, XK_Shift_R); - append(Keyboard::Scancode::ControlLeft, XK_Control_L); - append(Keyboard::Scancode::ControlRight, XK_Control_R); - append(Keyboard::Scancode::SuperLeft, XK_Super_L); - append(Keyboard::Scancode::SuperRight, XK_Super_R); - append(Keyboard::Scancode::AltLeft, XK_Alt_L); - append(Keyboard::Scancode::AltRight, XK_Alt_R); - append(Keyboard::Scancode::Space, XK_space); - append(Keyboard::Scancode::Menu, XK_Menu); - - append(Keyboard::Scancode::A, XK_A); - append(Keyboard::Scancode::B, XK_B); - append(Keyboard::Scancode::C, XK_C); - append(Keyboard::Scancode::D, XK_D); - append(Keyboard::Scancode::E, XK_E); - append(Keyboard::Scancode::F, XK_F); - append(Keyboard::Scancode::G, XK_G); - append(Keyboard::Scancode::H, XK_H); - append(Keyboard::Scancode::I, XK_I); - append(Keyboard::Scancode::J, XK_J); - append(Keyboard::Scancode::K, XK_K); - append(Keyboard::Scancode::L, XK_L); - append(Keyboard::Scancode::M, XK_M); - append(Keyboard::Scancode::N, XK_N); - append(Keyboard::Scancode::O, XK_O); - append(Keyboard::Scancode::P, XK_P); - append(Keyboard::Scancode::Q, XK_Q); - append(Keyboard::Scancode::R, XK_R); - append(Keyboard::Scancode::S, XK_S); - append(Keyboard::Scancode::T, XK_T); - append(Keyboard::Scancode::U, XK_U); - append(Keyboard::Scancode::V, XK_V); - append(Keyboard::Scancode::W, XK_W); - append(Keyboard::Scancode::X, XK_X); - append(Keyboard::Scancode::Y, XK_Y); - append(Keyboard::Scancode::Z, XK_Z); - - append(Keyboard::Scancode::NumLock, XK_Num_Lock); - append(Keyboard::Scancode::Divide, XK_KP_Divide); - append(Keyboard::Scancode::Multiply, XK_KP_Multiply); - append(Keyboard::Scancode::Subtract, XK_KP_Subtract); - append(Keyboard::Scancode::Add, XK_KP_Add); - append(Keyboard::Scancode::Enter, XK_KP_Enter); - append(Keyboard::Scancode::Point, XK_KP_Decimal); - - append(Keyboard::Scancode::Keypad1, XK_KP_1); - append(Keyboard::Scancode::Keypad2, XK_KP_2); - append(Keyboard::Scancode::Keypad3, XK_KP_3); - append(Keyboard::Scancode::Keypad4, XK_KP_4); - append(Keyboard::Scancode::Keypad5, XK_KP_5); - append(Keyboard::Scancode::Keypad6, XK_KP_6); - append(Keyboard::Scancode::Keypad7, XK_KP_7); - append(Keyboard::Scancode::Keypad8, XK_KP_8); - append(Keyboard::Scancode::Keypad9, XK_KP_9); - append(Keyboard::Scancode::Keypad0, XK_KP_0); -} - -bool pKeyboard::pressed(Keyboard::Scancode scancode) { - char state[256]; - XQueryKeymap(pApplication::display, state); - if(auto result = settings->keymap.find(scancode)) { - unsigned id = result(); - return state[id >> 3] & (1 << (id & 7)); - } - return false; -} - -vector pKeyboard::state() { - vector output; - output.resize((unsigned)Keyboard::Scancode::Limit); - for(auto& n : output) n = false; - - char state[256]; - XQueryKeymap(pApplication::display, state); - for(auto node : settings->keymap) { - if(state[node.value >> 3] & (1 << (node.value & 7))) { - output[(unsigned)node.key] = true; - } - } - - return output; -} - -} diff --git a/phoenix/qt/widget/list-view.cpp b/phoenix/qt/widget/list-view.cpp deleted file mode 100644 index 7d5fd5dc..00000000 --- a/phoenix/qt/widget/list-view.cpp +++ /dev/null @@ -1,156 +0,0 @@ -namespace phoenix { - -void pListView::append(const lstring& text) { - locked = true; - auto items = qtListView->findItems("", Qt::MatchContains); - QTreeWidgetItem* item = new QTreeWidgetItem(qtListView); - - item->setData(0, Qt::UserRole, (unsigned)items.size()); - if(listView.state.checkable) item->setCheckState(0, Qt::Unchecked); - for(unsigned position = 0; position < text.size(); position++) { - item->setText(position, QString::fromUtf8(text[position])); - } - locked = false; -} - -void pListView::autoSizeColumns() { - for(unsigned n = 0; n < listView.state.headerText.size(); n++) qtListView->resizeColumnToContents(n); -} - -void pListView::remove(unsigned selection) { - locked = true; - QTreeWidgetItem* item = qtListView->topLevelItem(selection); - if(item == nullptr) return; - delete item; - locked = false; -} - -void pListView::reset() { - qtListView->clear(); -} - -void pListView::setBackgroundColor(Color color) { -} - -void pListView::setCheckable(bool checkable) { - if(checkable) { - auto items = qtListView->findItems("", Qt::MatchContains); - for(unsigned n = 0; n < items.size(); n++) items[n]->setCheckState(0, Qt::Unchecked); - } -} - -void pListView::setChecked(unsigned selection, bool checked) { - locked = true; - QTreeWidgetItem* item = qtListView->topLevelItem(selection); - if(item) item->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked); - locked = false; -} - -void pListView::setForegroundColor(Color color) { -} - -void pListView::setHeaderText(const lstring& text) { - QStringList labels; - for(auto& column : text) labels << QString::fromUtf8(column); - - qtListView->setColumnCount(text.size()); - qtListView->setAlternatingRowColors(text.size() >= 2); - qtListView->setHeaderLabels(labels); - autoSizeColumns(); -} - -void pListView::setHeaderVisible(bool visible) { - qtListView->setHeaderHidden(!visible); - autoSizeColumns(); -} - -void pListView::setImage(unsigned selection, unsigned position, const nall::image& image) { - QTreeWidgetItem* item = qtListView->topLevelItem(selection); - if(item) { - if(image.empty() == 0) item->setIcon(position, CreateIcon(image)); - if(image.empty() == 1) item->setIcon(position, QIcon()); - } -} - -void pListView::setSelected(bool selected) { - QTreeWidgetItem* item = qtListView->currentItem(); - if(item) item->setSelected(selected); -} - -void pListView::setSelection(unsigned selection) { - locked = true; - QTreeWidgetItem* item = qtListView->currentItem(); - if(item) item->setSelected(false); - item = qtListView->topLevelItem(selection); - if(item) qtListView->setCurrentItem(item); - locked = false; -} - -void pListView::setText(unsigned selection, unsigned position, string text) { - locked = true; - QTreeWidgetItem* item = qtListView->topLevelItem(selection); - if(item) item->setText(position, QString::fromUtf8(text)); - locked = false; -} - -void pListView::constructor() { - qtWidget = qtListView = new QTreeWidget; - qtListView->setAllColumnsShowFocus(true); - qtListView->setRootIsDecorated(false); - - connect(qtListView, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate())); - connect(qtListView, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(onChange(QTreeWidgetItem*))); - connect(qtListView, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onToggle(QTreeWidgetItem*))); - - pWidget::synchronizeState(); - setCheckable(listView.state.checkable); - setHeaderText(listView.state.headerText.size() ? listView.state.headerText : lstring{ " " }); - setHeaderVisible(listView.state.headerVisible); - for(auto& row : listView.state.text) append(row); - if(listView.state.checkable) { - for(unsigned n = 0; n < listView.state.checked.size(); n++) { - setChecked(n, listView.state.checked[n]); - } - } - setSelected(listView.state.selected); - if(listView.state.selected) setSelection(listView.state.selection); - autoSizeColumns(); -} - -void pListView::destructor() { - delete qtListView; - qtWidget = qtListView = nullptr; -} - -void pListView::orphan() { - destructor(); - constructor(); -} - -void pListView::onActivate() { - if(locked == false && listView.onActivate) listView.onActivate(); -} - -void pListView::onChange(QTreeWidgetItem* item) { - bool selected = listView.state.selected; - unsigned selection = listView.state.selection; - if(item) { - item->setSelected(true); //Qt bug workaround: clicking items with mouse does not mark items as selected - listView.state.selected = true; - listView.state.selection = item->data(0, Qt::UserRole).toUInt(); - } else { - listView.state.selected = false; - listView.state.selection = 0; - } - if(selected != listView.state.selected || selection != listView.state.selection) { - if(!locked && listView.onChange) listView.onChange(); - } -} - -void pListView::onToggle(QTreeWidgetItem* item) { - unsigned selection = item->data(0, Qt::UserRole).toUInt(); - listView.state.checked[selection] = (item->checkState(0) == Qt::Checked); - if(!locked && listView.onToggle) listView.onToggle(selection); -} - -} diff --git a/processor/Makefile b/processor/GNUmakefile similarity index 100% rename from processor/Makefile rename to processor/GNUmakefile diff --git a/processor/arm/disassembler.cpp b/processor/arm/disassembler.cpp index eaf9a368..03e90679 100644 --- a/processor/arm/disassembler.cpp +++ b/processor/arm/disassembler.cpp @@ -408,7 +408,7 @@ string ARM::disassemble_arm_instruction(uint32 pc) { output.append(load ? "ldm" : "stm", conditions[condition], indices[index], " "); output.append(registers[rn], writeback ? "!" : "", ",{"); for(unsigned n = 0; n < 16; n++) if(list & (1 << n)) output.append(registers[n], ","); - output.rtrim<1>(","); + output.rtrim(","); output.append("}", s ? "^" : ""); return output; @@ -681,7 +681,7 @@ string ARM::disassemble_thumb_instruction(uint32 pc) { if(list & (1 << l)) output.append(registers[l], ","); } if(branch) output.append(load == 0 ? "lr," : "pc,"); - output.rtrim<1>(","); + output.rtrim(","); output.append("}"); return output; @@ -698,7 +698,7 @@ string ARM::disassemble_thumb_instruction(uint32 pc) { for(unsigned l = 0; l < 8; l++) { if(list & (1 << l)) output.append(registers[l], ","); } - output.rtrim<1>(","); + output.rtrim(","); output.append("}"); return output; diff --git a/processor/lr35902/disassembler.cpp b/processor/lr35902/disassembler.cpp index 8929cf9a..9cf10036 100644 --- a/processor/lr35902/disassembler.cpp +++ b/processor/lr35902/disassembler.cpp @@ -12,9 +12,9 @@ string LR35902::disassemble(uint16 pc) { " SP:", hex<4>(r[SP]) }; - memcpy(output + 0, hex<4>(pc), 4); - memcpy(output + 6, opcode, opcode.length()); - memcpy(output + 23, registers, registers.length()); + memcpy(output + 0, hex<4>(pc).data(), 4); + memcpy(output + 6, opcode.data(), opcode.length()); + memcpy(output + 23, registers.data(), registers.length()); output[63] = 0; return output; } diff --git a/processor/r6502/disassembler.cpp b/processor/r6502/disassembler.cpp index 2537e063..40c7755e 100644 --- a/processor/r6502/disassembler.cpp +++ b/processor/r6502/disassembler.cpp @@ -182,7 +182,7 @@ string R6502::disassemble() { #undef op output.append(" "); - output[20] = 0; + output.resize(20); output.append( "A:", hex<2>(regs.a), " X:", hex<2>(regs.x), " Y:", hex<2>(regs.y), " S:", hex<2>(regs.s), " ", diff --git a/ruby/Makefile b/ruby/GNUmakefile similarity index 100% rename from ruby/Makefile rename to ruby/GNUmakefile diff --git a/ruby/ruby.cpp b/ruby/ruby.cpp index bdf091c9..5e03ebfb 100644 --- a/ruby/ruby.cpp +++ b/ruby/ruby.cpp @@ -1,5 +1,6 @@ #include +#undef deprecated #undef mkdir #undef usleep #include diff --git a/ruby/ruby.hpp b/ruby/ruby.hpp index ab421564..692cfe5c 100644 --- a/ruby/ruby.hpp +++ b/ruby/ruby.hpp @@ -1,8 +1,11 @@ -/* - ruby - version: 0.11 (2013-12-19) - license: public domain -*/ +/* ruby + * author: byuu + * license: ISC + * version: 0.11 (2013-12-19) + * + * ruby is a cross-platform hardware abstraction layer + * it provides a common interface to video, audio and input devices + */ #ifndef RUBY_H #define RUBY_H diff --git a/ruby/video/opengl/main.hpp b/ruby/video/opengl/main.hpp index 829fda6a..8b90ceff 100644 --- a/ruby/video/opengl/main.hpp +++ b/ruby/video/opengl/main.hpp @@ -28,11 +28,11 @@ void OpenGL::shader(const char* pathname) { for(auto& node : document["output"]) { string text = node.text(); if(node.name == "width") { - if(text.endsWith("%")) relativeWidth = real(text.rtrim<1>("%")) / 100.0; + if(text.endsWith("%")) relativeWidth = real(text.rtrim("%")) / 100.0; else absoluteWidth = decimal(text); } if(node.name == "height") { - if(text.endsWith("%")) relativeHeight = real(text.rtrim<1>("%")) / 100.0; + if(text.endsWith("%")) relativeHeight = real(text.rtrim("%")) / 100.0; else absoluteHeight = decimal(text); } } diff --git a/ruby/video/opengl/program.hpp b/ruby/video/opengl/program.hpp index 21950846..de127ccb 100644 --- a/ruby/video/opengl/program.hpp +++ b/ruby/video/opengl/program.hpp @@ -4,9 +4,9 @@ void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin modulo = glrModulo(node["modulo"].integer()); string w = node["width"].text(), h = node["height"].text(); - if(w.endsWith("%")) relativeWidth = real(w.rtrim<1>("%")) / 100.0; + if(w.endsWith("%")) relativeWidth = real(w.rtrim("%")) / 100.0; else absoluteWidth = decimal(w); - if(h.endsWith("%")) relativeHeight = real(h.rtrim<1>("%")) / 100.0; + if(h.endsWith("%")) relativeHeight = real(h.rtrim("%")) / 100.0; else absoluteHeight = decimal(h); format = glrFormat(node["format"].text()); @@ -78,7 +78,7 @@ void OpenGLProgram::parse(OpenGL* instance, string& source) { if(auto position = s.find("//")) s.resize(position()); //strip comments s.strip(); //remove extraneous whitespace if(s.match("#in ?*")) { - s.ltrim<1>("#in ").strip(); + s.ltrim("#in ").strip(); if(auto setting = instance->settings.find({s})) { line = {"#define ", setting().name, " ", setting().value}; } else { diff --git a/ruby/video/sdl.cpp b/ruby/video/sdl.cpp index 0079f87d..4c63d237 100644 --- a/ruby/video/sdl.cpp +++ b/ruby/video/sdl.cpp @@ -109,6 +109,7 @@ struct pVideoSDL { bool init() { display = XOpenDisplay(0); + //todo: this causes a segfault inside SDL_SetVideoMode on FreeBSD (works under Linux) char env[512]; sprintf(env, "SDL_WINDOWID=%ld", (long int)settings.handle); putenv(env); diff --git a/ruby/video/xshm.cpp b/ruby/video/xshm.cpp index ef1552a8..f1592218 100644 --- a/ruby/video/xshm.cpp +++ b/ruby/video/xshm.cpp @@ -1,3 +1,10 @@ +//XShm driver for Xorg + +//Note that on composited displays, the alpha bits will allow translucency underneath the active window +//As this is not a feature of ruby, this driver must always set the alpha bits on clear() and refresh() + +//Linear interpolation is only applied horizontally for performance reasons, although Nearest is still much faster + #include #include @@ -18,30 +25,22 @@ struct pVideoXShm { } device; struct Settings { - uintptr_t handle; - unsigned depth = 24; + uintptr_t handle = 0; + unsigned filter = Video::FilterLinear; uint32_t* buffer = nullptr; unsigned width, height; } settings; - struct Color { - unsigned depth; - unsigned shift; - - unsigned idepth; - unsigned ishift; - } red, green, blue; - bool cap(const string& name) { if(name == Video::Handle) return true; - if(name == Video::Depth) return true; + if(name == Video::Filter) return true; return false; } any get(const string& name) { if(name == Video::Handle) return settings.handle; - if(name == Video::Depth) return settings.depth; + if(name == Video::Filter) return settings.filter; return false; } @@ -50,8 +49,9 @@ struct pVideoXShm { settings.handle = any_cast(value); return true; } - if(name == Video::Depth) { - return setDepth(any_cast(value)); + if(name == Video::Filter) { + settings.filter = any_cast(value); + return true; } return false; } @@ -60,7 +60,7 @@ struct pVideoXShm { if(settings.buffer == nullptr || settings.width != width || settings.height != height) { if(settings.buffer) delete[] settings.buffer; settings.width = width, settings.height = height; - settings.buffer = new uint32_t[width * height](); + settings.buffer = new uint32_t[width * height + 16]; //+16 is padding for linear interpolation } data = settings.buffer; @@ -73,7 +73,9 @@ struct pVideoXShm { void clear() { if(settings.buffer == nullptr) return; - memset(settings.buffer, 0, settings.width * settings.height * sizeof(uint32_t)); + uint32_t* dp = settings.buffer; + unsigned length = settings.width * settings.height; + while(length--) *dp++ = (255u << 24); refresh(); } @@ -81,23 +83,27 @@ struct pVideoXShm { if(settings.buffer == nullptr) return; size(); - float xRatio = (float)settings.width / (float)device.width; - float yRatio = (float)settings.height / (float)device.height; - float yStep = 0; + float xratio = (float)settings.width / (float)device.width; + float yratio = (float)settings.height / (float)device.height; + + #pragma omp parallel for for(unsigned y = 0; y < device.height; y++) { - uint32_t* sp = settings.buffer + (unsigned)yStep * settings.width; + float ystep = y * yratio; + float xstep = 0; + + uint32_t* sp = settings.buffer + (unsigned)ystep * settings.width; uint32_t* dp = device.buffer + y * device.width; - yStep += yRatio; - float xStep = 0; - for(unsigned x = 0; x < device.width; x++) { - uint32_t color = sp[(unsigned)xStep]; - xStep += xRatio; - unsigned r = (color >> red.ishift ) & ((1 << red.idepth ) - 1); - unsigned g = (color >> green.ishift) & ((1 << green.idepth) - 1); - unsigned b = (color >> blue.ishift ) & ((1 << blue.idepth ) - 1); - *dp++ = image::normalize(r, red.idepth, red.depth ) << red.shift - | image::normalize(g, green.idepth, green.depth) << green.shift - | image::normalize(b, blue.idepth, blue.depth ) << blue.shift; + + if(settings.filter == Video::FilterNearest) { + for(unsigned x = 0; x < device.width; x++) { + *dp++ = (255u << 24) | sp[(unsigned)xstep]; + xstep += xratio; + } + } else { //settings.filter == Video::FilterLinear + for(unsigned x = 0; x < device.width; x++) { + *dp++ = (255u << 24) | interpolate(xstep - (unsigned)xstep, sp[(unsigned)xstep], sp[(unsigned)xstep + 1]); + xstep += xratio; + } } } @@ -118,24 +124,12 @@ struct pVideoXShm { XGetWindowAttributes(device.display, (Window)settings.handle, &getAttributes); device.depth = getAttributes.depth; device.visual = getAttributes.visual; - unsigned visualID = XVisualIDFromVisual(device.visual); - - XVisualInfo visualTemplate = {0}; - visualTemplate.screen = device.screen; - visualTemplate.depth = device.depth; - int visualsMatched = 0; - XVisualInfo* visualList = XGetVisualInfo(device.display, VisualScreenMask | VisualDepthMask, &visualTemplate, &visualsMatched); - for(unsigned n = 0; n < visualsMatched; n++) { - auto& v = visualList[n]; - if(v.visualid == visualID) { - red.depth = bit::count(v.red_mask), red.shift = bit::first(v.red_mask); - green.depth = bit::count(v.green_mask), green.shift = bit::first(v.green_mask); - blue.depth = bit::count(v.blue_mask), blue.shift = bit::first(v.blue_mask); - break; - } + //driver only supports 32-bit pixels + //note that even on 15-bit and 16-bit displays, the window visual's depth should be 32 + if(device.depth < 24 || device.depth > 32) { + free(); + return false; } - XFree(visualList); - setDepth(settings.depth); XSetWindowAttributes setAttributes = {0}; setAttributes.border_pixel = 0; @@ -168,26 +162,6 @@ struct pVideoXShm { } //internal: - bool setDepth(unsigned depth) { - if(depth == 24) { - settings.depth = 24; - red.idepth = 8, red.ishift = 16; - green.idepth = 8, green.ishift = 8; - blue.idepth = 8, blue.ishift = 0; - return true; - } - - if(depth == 30) { - settings.depth = 30; - red.idepth = 10, red.ishift = 20; - green.idepth = 10, green.ishift = 10; - blue.idepth = 10, blue.ishift = 0; - return true; - } - - return false; - } - bool size() { XWindowAttributes windowAttributes; XGetWindowAttributes(device.display, settings.handle, &windowAttributes); @@ -197,7 +171,6 @@ struct pVideoXShm { XResizeWindow(device.display, device.window, device.width, device.height); free(); - //create device.shmInfo.shmid = shmget(IPC_PRIVATE, device.width * device.height * sizeof(uint32_t), IPC_CREAT | 0777); if(device.shmInfo.shmid < 0) return false; @@ -220,6 +193,15 @@ struct pVideoXShm { shmdt(device.shmInfo.shmaddr); shmctl(device.shmInfo.shmid, IPC_RMID, 0); } + + alwaysinline uint32_t interpolate(float mu, uint32_t a, uint32_t b) { + uint8_t ar = (a >> 16), ag = (a >> 8), ab = (a >> 0); + uint8_t br = (b >> 16), bg = (b >> 8), bb = (b >> 0); + uint8_t cr = ar * (1.0 - mu) + br * mu; + uint8_t cg = ag * (1.0 - mu) + bg * mu; + uint8_t cb = ab * (1.0 - mu) + bb * mu; + return (cr << 16) | (cg << 8) | (cb << 0); + } }; DeclareVideo(XShm) diff --git a/sfc/Makefile b/sfc/GNUmakefile similarity index 100% rename from sfc/Makefile rename to sfc/GNUmakefile diff --git a/sfc/cartridge/cartridge.cpp b/sfc/cartridge/cartridge.cpp index 4a599991..c9bd946e 100644 --- a/sfc/cartridge/cartridge.cpp +++ b/sfc/cartridge/cartridge.cpp @@ -66,56 +66,44 @@ void Cartridge::load() { //Super Game Boy if(cartridge.has_gb_slot()) { - sha256 = nall::sha256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize); + sha256 = Hash::SHA256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize).digest(); } //Broadcast Satellaview else if(cartridge.has_bs_cart() && cartridge.has_bs_slot()) { - sha256 = nall::sha256(satellaviewcartridge.memory.data(), satellaviewcartridge.memory.size()); + sha256 = Hash::SHA256(satellaviewcartridge.memory.data(), satellaviewcartridge.memory.size()).digest(); } //Sufami Turbo else if(cartridge.has_st_slots()) { - sha256_ctx sha; - uint8_t hash[32]; - sha256_init(&sha); - sha256_chunk(&sha, sufamiturboA.rom.data(), sufamiturboA.rom.size()); - sha256_chunk(&sha, sufamiturboB.rom.data(), sufamiturboB.rom.size()); - sha256_final(&sha); - sha256_hash(&sha, hash); - string result; - for(auto& byte : hash) result.append(hex<2>(byte)); - sha256 = result; + Hash::SHA256 sha; + sha.data(sufamiturboA.rom.data(), sufamiturboA.rom.size()); + sha.data(sufamiturboB.rom.data(), sufamiturboB.rom.size()); + sha256 = sha.digest(); } //Super Famicom else { - sha256_ctx sha; - uint8_t hash[32]; - vector buffer; - sha256_init(&sha); + Hash::SHA256 sha; //hash each ROM image that exists; any with size() == 0 is ignored by sha256_chunk() - sha256_chunk(&sha, rom.data(), rom.size()); - sha256_chunk(&sha, bsxcartridge.rom.data(), bsxcartridge.rom.size()); - sha256_chunk(&sha, sa1.rom.data(), sa1.rom.size()); - sha256_chunk(&sha, superfx.rom.data(), superfx.rom.size()); - sha256_chunk(&sha, hitachidsp.rom.data(), hitachidsp.rom.size()); - sha256_chunk(&sha, spc7110.prom.data(), spc7110.prom.size()); - sha256_chunk(&sha, spc7110.drom.data(), spc7110.drom.size()); - sha256_chunk(&sha, sdd1.rom.data(), sdd1.rom.size()); + sha.data(rom.data(), rom.size()); + sha.data(bsxcartridge.rom.data(), bsxcartridge.rom.size()); + sha.data(sa1.rom.data(), sa1.rom.size()); + sha.data(superfx.rom.data(), superfx.rom.size()); + sha.data(hitachidsp.rom.data(), hitachidsp.rom.size()); + sha.data(spc7110.prom.data(), spc7110.prom.size()); + sha.data(spc7110.drom.data(), spc7110.drom.size()); + sha.data(sdd1.rom.data(), sdd1.rom.size()); //hash all firmware that exists + vector buffer; buffer = armdsp.firmware(); - sha256_chunk(&sha, buffer.data(), buffer.size()); + sha.data(buffer.data(), buffer.size()); buffer = hitachidsp.firmware(); - sha256_chunk(&sha, buffer.data(), buffer.size()); + sha.data(buffer.data(), buffer.size()); buffer = necdsp.firmware(); - sha256_chunk(&sha, buffer.data(), buffer.size()); + sha.data(buffer.data(), buffer.size()); //finalize hash - sha256_final(&sha); - sha256_hash(&sha, hash); - string result; - for(auto& byte : hash) result.append(hex<2>(byte)); - sha256 = result; + sha256 = sha.digest(); } rom.write_protect(true); diff --git a/sfc/chip/event/event.cpp b/sfc/chip/event/event.cpp index b7276295..5ffae110 100644 --- a/sfc/chip/event/event.cpp +++ b/sfc/chip/event/event.cpp @@ -63,7 +63,7 @@ void Event::submitScore() { lstring side = interface->server().split<1>("@"); string username = side(0).split<1>(":")(0); string password = side(0).split<1>(":")(1); - side(1).ltrim<1>("http://"); + side(1).ltrim("http://"); string hostname = side(1).split<1>("/")(0); string hostpath = side(1).split<1>("/")(1); side = hostname.split<1>(":"); @@ -71,7 +71,7 @@ void Event::submitScore() { string hostport = side(1); if(hostport.empty()) hostport = "80"; - http server; +/*http server; if(server.connect(hostname, decimal(hostport))) { string content = { "username:", username, "\n", @@ -92,7 +92,7 @@ void Event::submitScore() { }; server.send(packet); server.disconnect(); - } + }*/ } void Event::init() { diff --git a/sfc/chip/hsu1/hsu1.cpp b/sfc/chip/hsu1/hsu1.cpp index 5feaebf3..6cf06d63 100644 --- a/sfc/chip/hsu1/hsu1.cpp +++ b/sfc/chip/hsu1/hsu1.cpp @@ -55,7 +55,7 @@ void HSU1::write(unsigned addr, uint8 data) { lstring side = interface->server().split<1>("@"); string username = side(0).split<1>(":")(0); string password = side(0).split<1>(":")(1); - side(1).ltrim<1>("http://"); + side(1).ltrim("http://"); string hostname = side(1).split<1>("/")(0); string hostpath = side(1).split<1>("/")(1); side = hostname.split<1>(":"); @@ -63,7 +63,7 @@ void HSU1::write(unsigned addr, uint8 data) { string hostport = side(1); if(hostport.empty()) hostport = "80"; - http server; + /*http server; if(server.connect(hostname, decimal(hostport))) { string header { "username:", username, "\n", @@ -97,7 +97,7 @@ void HSU1::write(unsigned addr, uint8 data) { free(data); server.disconnect(); - } + }*/ } txlatch = latch; } diff --git a/sfc/system/serialization.cpp b/sfc/system/serialization.cpp index a29a9eeb..3c68e902 100644 --- a/sfc/system/serialization.cpp +++ b/sfc/system/serialization.cpp @@ -8,7 +8,7 @@ serializer System::serialize() { memcpy(&hash, (const char*)cartridge.sha256(), 64); memset(&description, 0, sizeof description); memset(&profile, 0, sizeof profile); - strmcpy(profile, Emulator::Profile, sizeof profile); + strcpy(profile, Emulator::Profile); s.integer(signature); s.integer(version); diff --git a/target-higan/GNUmakefile b/target-higan/GNUmakefile new file mode 100644 index 00000000..2f741edc --- /dev/null +++ b/target-higan/GNUmakefile @@ -0,0 +1,53 @@ +name := higan + +processors := arm gsu hg51b lr35902 r6502 r65816 spc700 upd96050 +include processor/GNUmakefile +include fc/GNUmakefile +include sfc/GNUmakefile +include gb/GNUmakefile +include gba/GNUmakefile + +ui_objects := ui-higan +ui_objects += ruby hiro + +# platform +ifeq ($(platform),windows) +else ifeq ($(platform),macosx) +else ifeq ($(platform),linux) +else ifeq ($(platform),bsd) + ruby := video.glx video.xshm + ruby += audio.openal audio.oss + ruby += input.xlib +endif + +# ruby +include ruby/GNUmakefile +link += $(rubylink) + +# hiro +include hiro/GNUmakefile +link += $(hirolink) + +# rules +objects := $(ui_objects) $(objects) +objects := $(patsubst %,obj/%.o,$(objects)) + +obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/) + $(compiler) $(rubyflags) -c $< -o $@ + +obj/hiro.o: hiro/hiro.cpp $(call rwildcard,hiro/) + $(compiler) $(hiroflags) -c $< -o $@ + +obj/ui-higan.o: $(ui)/higan.cpp $(call rwildcard,$(ui)/) + +# build +build: $(objects) + $(strip $(compiler) -o out/$(name) $(objects) $(link)) + +install: + cp out/$(name) $(prefix)/bin/$(name) + cp data/higan.png $(prefix)/share/icons/higan.png + +uninstall: + if [ -f $(prefix)/bin/$(name) ]; then rm $(prefix)/bin/$(name); fi + if [ -f $(prefix)/share/icons/higan.png ]; then rm $(prefix)/share/icons/higan.png diff --git a/target-higan/Makefile b/target-higan/Makefile deleted file mode 100644 index 6e726ce5..00000000 --- a/target-higan/Makefile +++ /dev/null @@ -1,117 +0,0 @@ -name := higan - -processors := arm gsu hg51b lr35902 r6502 r65816 spc700 upd96050 -include processor/Makefile - -include fc/Makefile -include sfc/Makefile -include gb/Makefile -include gba/Makefile - -ui_objects := ui-higan ui-configuration ui-interface ui-utility -ui_objects += ui-input ui-window ui-general ui-settings ui-tools -ui_objects += phoenix ruby -ui_objects += $(if $(call streq,$(platform),windows),resource) - -# platform -ifeq ($(platform),windows) - ruby := video.direct3d video.wgl video.directdraw video.gdi - ruby += audio.directsound audio.xaudio2 - ruby += input.windows -else ifeq ($(platform),macosx) - ruby := video.cgl - ruby += audio.openal - ruby += input.carbon -else ifeq ($(platform),linux) - ruby := video.glx video.xv video.xshm video.sdl - ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao - ruby += input.udev input.sdl input.xlib -else ifeq ($(platform),bsd) - ruby := video.glx - ruby += audio.openal audio.oss - ruby += input.xlib -endif - -# phoenix -include phoenix/Makefile -link += $(phoenixlink) - -# ruby -include ruby/Makefile -link += $(rubylink) - -# rules -objects := $(ui_objects) $(objects) -objects := $(patsubst %,obj/%.o,$(objects)) - -obj/ui-higan.o: $(ui)/higan.cpp $(call rwildcard,$(ui)/) -obj/ui-configuration.o: $(ui)/configuration/configuration.cpp $(call rwildcard,$(ui)/) -obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/) -obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/) -obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/) -obj/ui-window.o: $(ui)/window/window.cpp $(call rwildcard,$(ui)/) -obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/) -obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/) -obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/) - -obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/) - $(compiler) $(rubyflags) -c $< -o $@ - -obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/) - $(compiler) $(phoenixflags) -c $< -o $@ - -obj/resource.o: $(ui)/resource.rc -ifeq ($(arch),win32) - windres --target=pe-i386 $(ui)/resource.rc obj/resource.o -else - windres $(ui)/resource.rc obj/resource.o -endif - -# targets -build: $(objects) -ifeq ($(platform),windows) - $(strip $(compiler) -shared -o out/phoenix.dll obj/phoenix.o $(phoenixlink)) - $(strip $(compiler) -o out/$(name) $(subst obj/phoenix.o,,$(objects)) $(link) -Lout -lphoenix) -else ifeq ($(platform),macosx) - if [ -d out/$(name).app ]; then rm -r out/$(name).app; fi - mkdir out/$(name).app - mkdir out/$(name).app/Contents - mkdir out/$(name).app/Contents/MacOS - mkdir out/$(name).app/Contents/Resources - cp data/Info.plist out/$(name).app/Contents/Info.plist - sips -s format icns data/higan.png --out out/$(name).app/Contents/Resources/higan.icns - $(strip $(compiler) -o out/$(name).app/Contents/MacOS/$(name) $(objects) $(link)) -else - $(strip $(compiler) -o out/$(name) $(objects) $(link)) -endif - -resource: - sourcery $(ui)/resource/resource.bml $(ui)/resource/resource.cpp $(ui)/resource/resource.hpp - -install: -ifneq ($(shell id -un),root) - $(error "make install must be run as root") -else ifeq ($(platform),windows) -else ifeq ($(platform),macosx) - mkdir -p /Library/Application\ Support/$(name) - cp -R profile/* /Library/Application\ Support/$(name) - cp data/cheats.bml /Library/Application\ Support/$(name)/cheats.bml - chmod -R 777 /Library/Application\ Support/$(name) -else - cp out/$(name) $(prefix)/bin/$(name) - cp data/$(name).png $(prefix)/share/pixmaps/$(name).png - cp data/$(name).desktop $(prefix)/share/applications/$(name).desktop - mkdir -p /usr/share/$(name) - cp -R profile/* /usr/share/$(name) - cp data/cheats.bml /usr/share/$(name)/cheats.bml - chmod -R 777 /usr/share/$(name) -endif - -uninstall: -ifneq ($(shell id -un),root) - $(error "make uninstall must be run as root") -else ifeq ($(platform),windows) -else ifeq ($(platform),macosx) -else - rm $(prefix)/bin/$(name) -endif diff --git a/target-higan/bootstrap.cpp b/target-higan/bootstrap.cpp deleted file mode 100644 index 5b14e25e..00000000 --- a/target-higan/bootstrap.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include -#include - -void Program::bootstrap() { - interface = new Interface; - - emulator.append(new Famicom::Interface); - emulator.append(new SuperFamicom::Interface); - emulator.append(new GameBoy::Interface); - emulator.append(new GameBoyAdvance::Interface); - - for(auto& system : emulator) system->bind = interface; -} diff --git a/target-higan/configuration/configuration.cpp b/target-higan/configuration/configuration.cpp deleted file mode 100644 index 612f1bfc..00000000 --- a/target-higan/configuration/configuration.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "../higan.hpp" -ConfigurationSettings* config = nullptr; - -ConfigurationSettings::ConfigurationSettings() { - video.append(video.driver = ruby::video.optimalDriver(), "Driver"); - video.append(video.synchronize = false, "Synchronize"); - video.append(video.shader = "Blur", "Shader"); - video.append(video.scaleMode = 0, "ScaleMode"); - video.append(video.aspectCorrection = true, "AspectCorrection"); - video.append(video.colorEmulation = true, "ColorEmulation"); - video.maskOverscan.assign(video.maskOverscan.enable = false); - video.maskOverscan.append(video.maskOverscan.horizontal = 8, "Horizontal"); - video.maskOverscan.append(video.maskOverscan.vertical = 8, "Vertical"); - video.append(video.maskOverscan, "MaskOverscan"); - video.append(video.saturation = 100, "Saturation"); - video.append(video.gamma = 100, "Gamma"); - video.append(video.luminance = 100, "Luminance"); - video.append(video.startFullScreen = false, "StartFullScreen"); - append(video, "Video"); - - audio.append(audio.driver = ruby::audio.optimalDriver(), "Driver"); - audio.append(audio.synchronize = true, "Synchronize"); - audio.append(audio.frequency = 48000, "Frequency"); - audio.append(audio.latency = 60, "Latency"); - audio.append(audio.resampler = 2, "Resampler"); - audio.append(audio.volume = 100, "Volume"); - audio.append(audio.mute = false, "Mute"); - append(audio, "Audio"); - - input.append(input.driver = ruby::input.optimalDriver(), "Driver"); - input.focus.append(input.focus.pause = false, "Pause"); - input.focus.append(input.focus.allow = false, "AllowInput"); - input.append(input.focus, "Focus"); - append(input, "Input"); - - timing.append(timing.video = 60.0, "Video"); - timing.append(timing.audio = 48000.0, "Audio"); - append(timing, "Timing"); - - server.append(server.hostname = "", "Hostname"); - server.append(server.username = "", "Username"); - server.append(server.password = "", "Password"); - append(server, "Server"); - - library.append(library.selection = -1, "Selection"); - library.append(library.mediaMode = 0, "MediaMode"); - library.append(library.showOnStartup = true, "ShowOnStartup"); - append(library, "Library"); - - load(); -} - -void ConfigurationSettings::load() { - Configuration::Document::load(program->path("settings.bml")); - save(); //creates file if it does not exist -} - -void ConfigurationSettings::save() { - Configuration::Document::save(program->path("settings.bml")); -} diff --git a/target-higan/configuration/configuration.hpp b/target-higan/configuration/configuration.hpp deleted file mode 100644 index 9591669c..00000000 --- a/target-higan/configuration/configuration.hpp +++ /dev/null @@ -1,60 +0,0 @@ -struct ConfigurationSettings : Configuration::Document { - struct Video : Configuration::Node { - string driver; - bool synchronize; - string shader; - unsigned scaleMode; - bool aspectCorrection; - bool colorEmulation; - struct MaskOverscan : Configuration::Node { - bool enable; - unsigned horizontal; - unsigned vertical; - } maskOverscan; - unsigned saturation; - unsigned gamma; - unsigned luminance; - bool startFullScreen; - } video; - - struct Audio : Configuration::Node { - string driver; - bool synchronize; - unsigned frequency; - unsigned latency; - unsigned resampler; - unsigned volume; - bool mute; - } audio; - - struct Input : Configuration::Node { - string driver; - struct Focus : Configuration::Node { - bool pause; - bool allow; - } focus; - } input; - - struct Timing : Configuration::Node { - double video; - double audio; - } timing; - - struct Server : Configuration::Node { - string hostname; - string username; - string password; - } server; - - struct Library : Configuration::Node { - signed selection; - unsigned mediaMode; - bool showOnStartup; - } library; - - void load(); - void save(); - ConfigurationSettings(); -}; - -extern ConfigurationSettings* config; diff --git a/target-higan/general/dip-switches.cpp b/target-higan/general/dip-switches.cpp deleted file mode 100644 index 2734daaa..00000000 --- a/target-higan/general/dip-switches.cpp +++ /dev/null @@ -1,66 +0,0 @@ -DipSwitches* dipSwitches = nullptr; - -DipSwitch::DipSwitch() { - append(name, {100, 0}, 5); - append(value, {~0, 0}); -} - -DipSwitches::DipSwitches() { - setTitle("DIP Switches"); - layout.setMargin(5); - accept.setText("Accept"); - - append(layout); - for(auto& dipItem : dip) layout.append(dipItem, {~0, 0}, 5); - layout.append(controlLayout, {~0, 0}); - controlLayout.append(spacer, {~0, 0}); - controlLayout.append(accept, {80, 0}); - - setGeometry({128, 128, 250, layout.minimumSize().height}); - windowManager->append(this, "DipSwitches"); - - onClose = accept.onActivate = [&] { - setModal(false); - setVisible(false); - }; -} - -unsigned DipSwitches::run(const Markup::Node& node) { - for(auto& dipItem : dip) { - dipItem.name.setEnabled(false); - dipItem.name.setText("(empty)"); - dipItem.value.setEnabled(false); - dipItem.value.reset(); - dipItem.values.reset(); - } - - unsigned index = 0; - for(auto& setting : node) { - if(setting.name != "setting") continue; - dip[index].name.setEnabled(); - dip[index].name.setText(setting["name"].data); - dip[index].value.setEnabled(); - for(auto& option : setting) { - if(option.name != "option") continue; - if(auto result = Eval::integer(option["value"].data)) { - dip[index].value.append(option["name"].data); - dip[index].values.append(result()); - } - } - - if(++index >= Slots) break; - } - - setVisible(); - accept.setFocused(); - - audio.clear(); - setModal(); - - unsigned result = 0; - for(auto& dipItem : dip) { - if(dipItem.value.enabled() == false) continue; - result |= dipItem.values[dipItem.value.selection()]; - } - return result; -} diff --git a/target-higan/general/dip-switches.hpp b/target-higan/general/dip-switches.hpp deleted file mode 100644 index 0b25b73d..00000000 --- a/target-higan/general/dip-switches.hpp +++ /dev/null @@ -1,22 +0,0 @@ -struct DipSwitch : HorizontalLayout { - Label name; - ComboButton value; - vector values; - - DipSwitch(); -}; - -struct DipSwitches : Window { - enum : unsigned { Slots = 8 }; - - VerticalLayout layout; - DipSwitch dip[Slots]; - HorizontalLayout controlLayout; - Widget spacer; - Button accept; - - unsigned run(const Markup::Node& node); - DipSwitches(); -}; - -extern DipSwitches* dipSwitches; diff --git a/target-higan/general/general.cpp b/target-higan/general/general.cpp deleted file mode 100644 index fd34b8fa..00000000 --- a/target-higan/general/general.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "../higan.hpp" -#include "library.cpp" -#include "presentation.cpp" -#include "dip-switches.cpp" diff --git a/target-higan/general/general.hpp b/target-higan/general/general.hpp deleted file mode 100644 index 4e612af2..00000000 --- a/target-higan/general/general.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "library.hpp" -#include "presentation.hpp" -#include "dip-switches.hpp" diff --git a/target-higan/general/library.cpp b/target-higan/general/library.cpp deleted file mode 100644 index 3ce67235..00000000 --- a/target-higan/general/library.cpp +++ /dev/null @@ -1,298 +0,0 @@ -LibraryManager* libraryManager = nullptr; - -LibraryBrowser::LibraryBrowser(Emulator::Interface& emulator) : emulator(emulator) { - setMargin(5); - - informationType.setText({ - "Title:\n", - "Serial:" - }); - - for(auto& media : emulator.media) { - mediaMode.append(media.name); - } - - unsigned height = Font::size(program->normalFont, " ").height; - - append(folders, {~0, ~0}, 5); - append(informationLayout, {~0, 0}); - informationLayout.append(informationType, {0, height * 2}, 5); - informationLayout.append(information, {~0, height * 2}, 5); - informationLayout.append(mediaMode, {0, 0}); - - folders.onActivate = {&LibraryBrowser::onActivate, this}; - folders.onChange = {&LibraryBrowser::onChange, this}; - mediaMode.onChange = {&LibraryBrowser::setMode, this}; -} - -void LibraryBrowser::onActivate() { - if(folders.selected() == false) return; - if(libraryManager->loadButton.enabled() == false) return; - - unsigned selection = folders.selection(); - string pathname = {this->pathname, folders.text(selection, 0), typeSuffix}; - - libraryManager->loaded.append(folders.text(selection, 0)); - libraryManager->setInformation(false); - - if(libraryManager->slotLoad == false) { - utility->loadMedia(pathname); - } else { - libraryManager->loadPathname = pathname; - libraryManager->setModal(false); - } -} - -void LibraryBrowser::onChange() { - if(folders.selected() == false) return information.setText(""); - - string manifest = {pathname, folders.text(folders.selection(), 0), typeSuffix, "manifest.bml"}; - auto document = Markup::Document(file::read(manifest)); - - information.setText({ - document["information/title"].text(), "\n", - document["information/serial"].text() - }); -} - -void LibraryBrowser::refresh() { - folders.reset(); - lstring pathnames = directory::ifolders(pathname, typeMask); - unsigned selection = 0; - for(auto& pathname : pathnames) { - folders.append(string{pathname}.rtrim<1>(typeSuffix)); - folders.setImage(selection++, 0, {resource::game, sizeof resource::game}); - } - folders.setSelection(0); - onChange(); -} - -void LibraryBrowser::setMode() { - config->library.mediaMode = mediaMode.selection(); - auto& media = emulator.media[mediaMode.selection()]; - - pathname = {utility->libraryPath(), media.name, "/"}; - type = media.type; - typeMask = {"*.", type}; - typeSuffix = {".", type, "/"}; - - refresh(); - folders.setFocused(); - libraryManager->synchronize(); -} - -LibraryImport::LibraryImport() { - setMargin(5); - information.setText({ - "higan manages games in a library. To play a game, you must first import the game.\n" - "After doing so, the game will appear inside your library, and can then be loaded and played." - }); - importButton.setText("Import Game ..."); - append(information, {~0, 0}, 5); - append(importButton, {0, 0}); - - importButton.onActivate = {&LibraryImport::onImportActivate, this}; -} - -void LibraryImport::onImportActivate() { - if(program->ananke.open() == false) { - MessageWindow().setText("ananke must be installed to use this feature").warning(); - return; - } - function browse = program->ananke.sym("ananke_browse"); - if(!browse) return; - audio.clear(); //ananke's browser is modal - string pathname = browse(); - pathname.rtrim<1>("/"); - if(pathname.empty()) return; - - //after importing game, take user to the relevant game list to show the newly imported title - string type = extension(pathname); - for(signed bootable = 1; bootable >= 0; bootable--) { - unsigned selection = 0; - for(auto& browser : libraryManager->browsers) { - unsigned mode = 0; - for(auto& media : browser->emulator.media) { - if(type == media.type && media.bootable == bootable) { - browser->mediaMode.setSelection(mode); - libraryManager->libraryFrame.setSelection(selection); - libraryManager->onChange(); - - //find game in list and select it - string name = notdir(nall::basename(pathname)); - for(unsigned n = 0; n < browser->folders.rows(); n++) { - if(browser->folders.text(n, 0) == name) { - browser->folders.setSelection(n); - browser->onChange(); - break; - } - } - - return; - } - mode++; - } - selection++; - } - } -} - -LibraryManager::LibraryManager() { - libraryManager = this; - - setTitle("Game Library"); - setGeometry({128, 128, 640, 680}); - windowManager->append(this, "LibraryManager"); - - layout.setMargin(5); - bootstrap(); - libraryFrame.append("Import"); - libraryFrame.setLayout(browsers.size(), libraryImport); - loadButton.setText("Load"); - - unsigned height = Font::size(program->normalFont, " ").height; - - append(layout); - layout.append(libraryFrame, {~0, ~0}, 5); - layout.append(informationLayout, {~0, 0}); - informationLayout.append(information, {~0, height * 3}, 5); - informationLayout.append(skipButton, {80, 0}, 5); - informationLayout.append(loadButton, {80, 0}); - - onClose = skipButton.onActivate = [&] { - setModal(false); - setVisible(false); - }; - - libraryFrame.onChange = {&LibraryManager::onChange, this}; - loadButton.onActivate = {&LibraryManager::onLoad, this}; - - //initial config value of -1 defaults to import tab on first launch of higan - if(config->library.selection < 0) config->library.selection = browsers.size(); - libraryFrame.setSelection(config->library.selection); - - if(libraryFrame.selection() < browsers.size()) { - browsers[libraryFrame.selection()]->mediaMode.setSelection(config->library.mediaMode); - browsers[libraryFrame.selection()]->setMode(); - } -} - -void LibraryManager::bootstrap() { - unsigned selection = 0; - for(auto& emulator : program->emulator) { - LibraryBrowser* browser = new LibraryBrowser(*emulator); - libraryFrame.append(emulator->information.name); - libraryFrame.setLayout(selection++, *browser); - browsers.append(browser); - } -} - -string LibraryManager::load(const string& type) { - requestedLoadType = type; - unsigned selection = 0; - for(auto& browser : browsers) { - unsigned mode = 0; - for(auto& media : browser->emulator.media) { - if(type == media.type && media.bootable == false) { - libraryFrame.setSelection(selection); - browser->mediaMode.setSelection(mode); - browser->setMode(); - - slotLoad = true; - loadPathname = ""; - show(); - setModal(); - slotLoad = false; - browser->mediaMode.setSelection(config->library.mediaMode = 0); - return loadPathname; - } - mode++; - } - selection++; - } - return ""; //should never occur -} - -void LibraryManager::onChange() { - unsigned selection = libraryFrame.selection(); - config->library.selection = selection; - if(selection < browsers.size()) { - browsers[selection]->setMode(); - } else { - loadButton.setEnabled(false); - } -} - -void LibraryManager::onLoad() { - unsigned selection = libraryFrame.selection(); - if(selection < browsers.size()) browsers[selection]->onActivate(); -} - -void LibraryManager::setInformation(bool load) { - string text; - if(loaded.size() == 0) { - text = {" \nPlease select a game to load ...\n "}; - } else if(loaded.size() == 1 && load == false) { - text = {" \n", loaded[0], "\n "}; - } else if(loaded.size() == 1 && load == true) { - text = {loaded[0], " \nPlease select a slot game to load ...\n "}; - } else if(loaded.size() == 2 && load == false) { - text = {loaded[0], "\n", loaded[1], "\n "}; - } else if(loaded.size() == 2 && load == true) { - text = {loaded[0], "\n", loaded[1], "\nPlease select a slot game to load ..."}; - } else if(loaded.size() == 3) { - text = {loaded[0], "\n", loaded[1], "\n", loaded[2]}; - } - information.setText(text); -} - -void LibraryManager::show() { - if(slotLoad == false) { - loaded.reset(); - requestedLoadType.reset(); - skipButton.setText("Cancel"); - } else { - skipButton.setText("Skip"); - } - - setInformation(true); - setVisible(); - setFocused(); - onChange(); -} - -//set library to show a specific media type, and then show the library -void LibraryManager::show(const string& type) { - unsigned selection = 0; - for(auto& browser : browsers) { - unsigned mode = 0; - for(auto& media : browser->emulator.media) { - if(media.bootable && media.type == type) { - libraryFrame.setSelection(selection); - browser->mediaMode.setSelection(mode); - browser->setMode(); - return show(); - } - mode++; - } - selection++; - } -} - -void LibraryManager::synchronize() { - if(libraryFrame.selection() < browsers.size()) { - auto& emulator = browsers[libraryFrame.selection()]->emulator; - auto& media = emulator.media[browsers[libraryFrame.selection()]->mediaMode.selection()]; - - if(requestedLoadType.empty()) { - loadButton.setEnabled(media.bootable); - } else { - bool enabled = (requestedLoadType == media.type); - //allow Super Game Boy to load Game Boy Color games - if(requestedLoadType == "gb" && loaded.size() == 1 && media.type == "gbc") enabled = true; - loadButton.setEnabled(enabled); - } - } else { - loadButton.setEnabled(false); - } -} diff --git a/target-higan/general/library.hpp b/target-higan/general/library.hpp deleted file mode 100644 index 7d93f4c9..00000000 --- a/target-higan/general/library.hpp +++ /dev/null @@ -1,55 +0,0 @@ -struct LibraryBrowser : VerticalLayout { - ListView folders; - HorizontalLayout informationLayout; - Label informationType; - Label information; - ComboButton mediaMode; - - LibraryBrowser(Emulator::Interface& emulator); - void onActivate(); - void onChange(); - void refresh(); - void setMode(); - - Emulator::Interface& emulator; - string pathname; - string type; - string typeMask; - string typeSuffix; -}; - -struct LibraryImport : VerticalLayout { - Label information; - Button importButton; - - LibraryImport(); - void onImportActivate(); -}; - -struct LibraryManager : Window { - VerticalLayout layout; - TabFrame libraryFrame; - vector browsers; - LibraryImport libraryImport; - HorizontalLayout informationLayout; - Label information; - Button skipButton; - Button loadButton; - - LibraryManager(); - void bootstrap(); - string load(const string& type); - void onChange(); - void onLoad(); - void setInformation(bool load); - void show(); - void show(const string& type); - void synchronize(); - - lstring loaded; - string requestedLoadType; - bool slotLoad = false; - string loadPathname; -}; - -extern LibraryManager* libraryManager; diff --git a/target-higan/general/presentation.cpp b/target-higan/general/presentation.cpp deleted file mode 100644 index 651a11ac..00000000 --- a/target-higan/general/presentation.cpp +++ /dev/null @@ -1,257 +0,0 @@ -Presentation* presentation = nullptr; - -void Presentation::synchronize() { - for(auto& emulator : emulatorList) emulator->menu.setVisible(false); - for(auto& emulator : emulatorList) { - if(emulator->interface == program->active) { - active = emulator; - emulator->menu.setVisible(true); - } - } - - shaderNone.setChecked(); - if(config->video.shader == "None") shaderNone.setChecked(); - if(config->video.shader == "Blur") shaderBlur.setChecked(); - if(config->video.shader == "Display Emulation") shaderEmulation.setChecked(); - for(auto& shader : shaderList) { - string name = notdir(config->video.shader.split<1>(".shader/")(0)); - if(name == shader->text()) shader->setChecked(); - } - - switch(config->video.scaleMode) { - case 0: centerVideo.setChecked(); break; - case 1: scaleVideo.setChecked(); break; - case 2: stretchVideo.setChecked(); break; - } - aspectCorrection.setChecked(config->video.aspectCorrection); - maskOverscan.setChecked(config->video.maskOverscan.enable); - synchronizeVideo.setChecked(config->video.synchronize); - synchronizeAudio.setChecked(config->audio.synchronize); - muteAudio.setChecked(config->audio.mute); - - if(program->active == nullptr) { - toolsMenu.setVisible(false); - } else { - toolsMenu.setVisible(true); - saveStateMenu.setVisible(system().information.capability.states); - loadStateMenu.setVisible(system().information.capability.states); - stateMenuSeparator.setVisible(system().information.capability.states); - resizeWindow.setVisible(config->video.scaleMode != 2); - stateManager.setVisible(system().information.capability.states); - cheatEditor.setVisible(system().information.capability.cheats); - synchronizeTime.setVisible(system().rtc()); - } -} - -void Presentation::setSystemName(string name) { - if(active) active->menu.setText(systemName = name); -} - -Presentation::Presentation() { - bootstrap(); - loadShaders(); - setGeometry({256, 256, 720, 480}); - windowManager->append(this, "Presentation"); - - setTitle({::Emulator::Name, " v", ::Emulator::Version}); - setBackgroundColor({0, 0, 0}); - setMenuVisible(); - setStatusVisible(); - - setDroppable(); - viewport.setDroppable(); - - loadMenu.setText("Library"); - settingsMenu.setText("Settings"); - videoMenu.setText("Video"); - centerVideo.setText("Center"); - scaleVideo.setText("Scale"); - stretchVideo.setText("Stretch"); - RadioItem::group(centerVideo, scaleVideo, stretchVideo); - aspectCorrection.setText("Aspect Correction"); - maskOverscan.setText("Mask Overscan"); - shaderMenu.setText("Shader"); - shaderNone.setText("None"); - shaderBlur.setText("Blur"); - shaderEmulation.setText("Display Emulation"); - synchronizeVideo.setText("Synchronize Video"); - synchronizeAudio.setText("Synchronize Audio"); - muteAudio.setText("Mute Audio"); - configurationSettings.setText("Configuration ..."); - toolsMenu.setText("Tools"); - saveStateMenu.setText("Save State"); - for(unsigned n = 0; n < 5; n++) saveStateItem[n].setText({"Slot ", 1 + n}); - loadStateMenu.setText("Load State"); - for(unsigned n = 0; n < 5; n++) loadStateItem[n].setText({"Slot ", 1 + n}); - resizeWindow.setText("Resize Window"); - stateManager.setText("State Manager"); - cheatEditor.setText("Cheat Editor"); - synchronizeTime.setText("Synchronize Time"); - - append(loadMenu); - for(auto& item : loadBootableMedia) loadMenu.append(*item); - for(auto& systemItem : emulatorList) append(systemItem->menu); - append(settingsMenu); - settingsMenu.append(videoMenu); - videoMenu.append(centerVideo); - videoMenu.append(scaleVideo); - videoMenu.append(stretchVideo); - videoMenu.append(*new Separator); - videoMenu.append(aspectCorrection); - videoMenu.append(maskOverscan); - settingsMenu.append(shaderMenu); - shaderMenu.append(shaderNone); - shaderMenu.append(shaderBlur); - if(config->video.driver == "OpenGL") shaderMenu.append(shaderEmulation); - if(shaderList.size() > 0) { - shaderMenu.append(*new Separator); - for(auto& shader : shaderList) shaderMenu.append(*shader); - } - settingsMenu.append(*new Separator); - settingsMenu.append(synchronizeVideo); - settingsMenu.append(synchronizeAudio); - settingsMenu.append(muteAudio); - if(Intrinsics::platform() != Intrinsics::Platform::MacOSX) { - settingsMenu.append(*new Separator); - settingsMenu.append(configurationSettings); - } - append(toolsMenu); - toolsMenu.append(saveStateMenu); - for(unsigned n = 0; n < 5; n++) saveStateMenu.append(saveStateItem[n]); - toolsMenu.append(loadStateMenu); - for(unsigned n = 0; n < 5; n++) loadStateMenu.append(loadStateItem[n]); - toolsMenu.append(stateMenuSeparator); - toolsMenu.append(resizeWindow); - toolsMenu.append(stateManager); - toolsMenu.append(cheatEditor); - toolsMenu.append(synchronizeTime); - - append(layout); - layout.append(viewport, {0, 0, 1, 1}); - - onDrop = viewport.onDrop = [&](lstring paths) { - if(paths.size() && directory::exists(paths[0])) { - utility->loadMedia(paths[0]); - setFocused(); - } - }; - - onSize = [&] { - utility->resize(); - }; - - onClose = [&] { - setVisible(false); - if(Intrinsics::platform() == Intrinsics::Platform::MacOSX) { - utility->unload(); - } else { - Application::quit(); - } - }; - - shaderNone.onActivate = [&] { config->video.shader = "None"; utility->updateShader(); }; - shaderBlur.onActivate = [&] { config->video.shader = "Blur"; utility->updateShader(); }; - shaderEmulation.onActivate = [&] { config->video.shader = "Display Emulation"; utility->updateShader(); }; - centerVideo.onActivate = [&] { config->video.scaleMode = 0; utility->resize(); }; - scaleVideo.onActivate = [&] { config->video.scaleMode = 1; utility->resize(); }; - stretchVideo.onActivate = [&] { config->video.scaleMode = 2; utility->resize(); }; - aspectCorrection.onToggle = [&] { config->video.aspectCorrection = aspectCorrection.checked(); utility->resize(); }; - maskOverscan.onToggle = [&] { config->video.maskOverscan.enable = maskOverscan.checked(); }; - synchronizeVideo.onToggle = [&] { config->video.synchronize = synchronizeVideo.checked(); utility->synchronizeRuby(); }; - synchronizeAudio.onToggle = [&] { config->audio.synchronize = synchronizeAudio.checked(); utility->synchronizeRuby(); }; - muteAudio.onToggle = [&] { config->audio.mute = muteAudio.checked(); utility->synchronizeRuby(); }; - configurationSettings.onActivate = [&] { settings->setVisible(); }; - for(unsigned n = 0; n < 5; n++) saveStateItem[n].onActivate = [=] { utility->saveState(1 + n); }; - for(unsigned n = 0; n < 5; n++) loadStateItem[n].onActivate = [=] { utility->loadState(1 + n); }; - resizeWindow.onActivate = [&] { utility->resize(true); }; - stateManager.onActivate = [&] { tools->panels.setSelection(1); tools->setVisible(); }; - cheatEditor.onActivate = [&] { tools->panels.setSelection(0); tools->setVisible(); }; - synchronizeTime.onActivate = [&] { system().rtcsync(); }; - - synchronize(); -} - -void Presentation::bootstrap() { - for(auto& emulator : program->emulator) { - for(auto& media : emulator->media) { - if(media.bootable == false) continue; - Item* item = new Item; - item->setText({media.name, " ..."}); - item->onActivate = [=] { libraryManager->show(media.type); }; - loadBootableMedia.append(item); - } - } - - for(auto& emulator : program->emulator) { - auto iEmulator = new Emulator; - iEmulator->interface = emulator; - - iEmulator->menu.setText(emulator->information.name); - iEmulator->power.setText("Power"); - iEmulator->reset.setText("Reset"); - iEmulator->unload.setText("Unload"); - - for(auto& port : emulator->port) { - auto iPort = new Emulator::Port; - iPort->menu.setText(port.name); - iEmulator->port.append(iPort); - - for(auto& device : port.device) { - auto iDevice = new RadioItem; - iDevice->setText(device.name); - iDevice->onActivate = [=] { utility->connect(port.id, device.id); }; - iPort->group.append(*iDevice); - iPort->device.append(iDevice); - } - - RadioItem::group(iPort->group); - } - - iEmulator->menu.append(iEmulator->power); - if(emulator->information.resettable) - iEmulator->menu.append(iEmulator->reset); - iEmulator->menu.append(*new Separator); - unsigned visiblePorts = 0; - for(auto& iPort : iEmulator->port) { - iEmulator->menu.append(iPort->menu); - if(iPort->device.size() <= 1) iPort->menu.setVisible(false); - else visiblePorts++; - for(auto& iDevice : iPort->device) { - iPort->menu.append(*iDevice); - } - } - iEmulator->menu.append(iEmulator->controllerSeparator); - if(visiblePorts == 0) iEmulator->controllerSeparator.setVisible(false); - iEmulator->menu.append(iEmulator->unload); - - iEmulator->power.onActivate = {&Utility::power, utility}; - iEmulator->reset.onActivate = {&Utility::reset, utility}; - iEmulator->unload.onActivate = {&Utility::unload, utility}; - - emulatorList.append(iEmulator); - } -} - -void Presentation::loadShaders() { - //only the OpenGL driver has video shader support - if(config->video.driver == "OpenGL") { - string pathname = program->path("Video Shaders/"); - lstring shaders = directory::folders(pathname, "*.shader"); - for(auto& name : shaders) { - auto shader = new RadioItem; - shader->setText(name.split<1>(".shader/")(0)); - shader->onActivate = [=] { - config->video.shader = {pathname, name}; - utility->updateShader(); - }; - shaderList.append(shader); - } - } - - nall::group group; - group.append(shaderNone); - group.append(shaderBlur); - group.append(shaderEmulation); - for(auto& shader : shaderList) group.append(*shader); - RadioItem::group(group); -} diff --git a/target-higan/general/presentation.hpp b/target-higan/general/presentation.hpp deleted file mode 100644 index 7bc83326..00000000 --- a/target-higan/general/presentation.hpp +++ /dev/null @@ -1,63 +0,0 @@ -struct Presentation : Window { - FixedLayout layout; - Viewport viewport; - - struct Emulator { - ::Emulator::Interface* interface; - - Menu menu; - Item power; - Item reset; - Item unload; - Separator controllerSeparator; - struct Port { - Menu menu; - nall::group group; - vector device; - }; - vector port; - function callback; - }; - vector emulatorList; - Emulator* active = nullptr; - - Menu loadMenu; - vector loadBootableMedia; - Menu settingsMenu; - Menu videoMenu; - RadioItem centerVideo; - RadioItem scaleVideo; - RadioItem stretchVideo; - CheckItem aspectCorrection; - CheckItem maskOverscan; - Menu shaderMenu; - RadioItem shaderNone; - RadioItem shaderBlur; - RadioItem shaderEmulation; - vector shaderList; - CheckItem synchronizeVideo; - CheckItem synchronizeAudio; - CheckItem muteAudio; - Item configurationSettings; - Menu toolsMenu; - Menu saveStateMenu; - Item saveStateItem[5]; - Menu loadStateMenu; - Item loadStateItem[5]; - Separator stateMenuSeparator; - Item resizeWindow; - Item stateManager; - Item cheatEditor; - Item synchronizeTime; - - void synchronize(); - void setSystemName(string name); - void loadShaders(); - void bootstrap(); - Presentation(); - -//internal: - string systemName; -}; - -extern Presentation* presentation; diff --git a/target-higan/higan.cpp b/target-higan/higan.cpp index 0d8fce73..ee967a88 100644 --- a/target-higan/higan.cpp +++ b/target-higan/higan.cpp @@ -1,164 +1,25 @@ #include "higan.hpp" -#include "bootstrap.cpp" -#include "resource/resource.cpp" -Program* program = nullptr; -DSP dspaudio; +struct Presentation : Window { + MenuBar menuBar{this}; + Menu menuSystem{&menuBar}; + StatusBar statusBar{this}; -Emulator::Interface& system() { - if(program->active == nullptr) throw; - return *program->active; -} + Presentation() { + menuSystem.setText("System"); + onClose(&Application::quit); -bool Program::focused() { - return config->input.focus.allow || presentation->focused(); -} - -string Program::path(string name) { - string path = {basepath, name}; - if(file::exists(path) || directory::exists(path)) return path; - path = {userpath, name}; - if(file::exists(path) || directory::exists(path)) return path; - path = {sharedpath, name}; - if(file::exists(path) || directory::exists(path)) return path; - return {userpath, name}; -} - -void Program::main() { - inputManager->poll(); - utility->updateStatus(); - autopause = config->input.focus.pause && presentation->focused() == false; - - if(active == nullptr || system().loaded() == false || pause || autopause) { - audio.clear(); - usleep(20 * 1000); - return; + setBackgroundColor({0, 0, 0}); + setTitle({Emulator::Name, " v", Emulator::Version}); + setSize({640, 480}); + setCentered(); + setVisible(); } +}; - system().run(); -} - -Program::Program(int argc, char** argv) { - ananke.open("ananke"); - - program = this; - pause = false; - autopause = false; - - basepath = nall::programpath(); - userpath = {nall::configpath(), "higan/"}; - sharedpath = {nall::sharedpath(), "higan/"}; - directory::create(userpath); - - bootstrap(); - active = nullptr; - - normalFont = Font::sans(8); - boldFont = Font::sans(8, "Bold"); - titleFont = Font::sans(16, "Bold"); - monospaceFont = Font::monospace(8); - - config = new ConfigurationSettings; - video.driver(config->video.driver); - audio.driver(config->audio.driver); - input.driver(config->input.driver); - - utility = new Utility; - inputManager = new InputManager; - windowManager = new WindowManager; - libraryManager = new LibraryManager; - presentation = new Presentation; - dipSwitches = new DipSwitches; - videoSettings = new VideoSettings; - audioSettings = new AudioSettings; - inputSettings = new InputSettings; - hotkeySettings = new HotkeySettings; - timingSettings = new TimingSettings; - serverSettings = new ServerSettings; - advancedSettings = new AdvancedSettings; - settings = new Settings; - cheatDatabase = new CheatDatabase; - cheatEditor = new CheatEditor; - stateManager = new StateManager; - tools = new Tools; - windowManager->loadGeometry(); - presentation->setVisible(); - utility->resize(); - - if(argc == 1 && config->library.showOnStartup) libraryManager->show(); - - video.set(Video::Handle, presentation->viewport.handle()); - if(!video.cap(Video::Depth) || !video.set(Video::Depth, depth = 30u)) { - video.set(Video::Depth, depth = 24u); - } - if(video.init() == false) { video.driver("None"); video.init(); } - - audio.set(Audio::Handle, presentation->viewport.handle()); - if(audio.init() == false) { audio.driver("None"); audio.init(); } - - input.set(Input::Handle, presentation->viewport.handle()); - if(input.init() == false) { input.driver("None"); input.init(); } - - dspaudio.setPrecision(16); - dspaudio.setBalance(0.0); - dspaudio.setFrequency(96000); - - utility->synchronizeRuby(); - utility->updateShader(); - - if(config->video.startFullScreen && argc >= 2) utility->toggleFullScreen(); - Application::processEvents(); - - if(argc >= 2) utility->loadMedia(argv[1]); - - Application::main = {&Program::main, this}; - Application::run(); - - utility->unload(); - config->save(); - inputManager->saveConfiguration(); - windowManager->saveGeometry(); - - ananke.close(); -} - -int main(int argc, char** argv) { - #if defined(PLATFORM_WINDOWS) - utf8_args(argc, argv); - #endif - +#include +auto nall::main(lstring args) -> void { Application::setName("higan"); - - Application::Windows::onModalBegin = [&] { - audio.clear(); - }; - - Application::Cocoa::onActivate = [&] { - presentation->setVisible(); - }; - - Application::Cocoa::onAbout = [&] { - MessageWindow() - .setTitle({"About ", Emulator::Name}) - .setText({ - Emulator::Name, " v", Emulator::Version, "\n", - Emulator::Profile, " Profile\n", - "Author: ", Emulator::Author, "\n", - "License: ", Emulator::License, "\n", - "Website: ", Emulator::Website - }) - .information(); - }; - - Application::Cocoa::onPreferences = [&] { - settings->setVisible(); - }; - - Application::Cocoa::onQuit = [&] { - Application::quit(); - }; - - new Program(argc, argv); - delete program; - return 0; + new Presentation; + Application::run(); } diff --git a/target-higan/higan.hpp b/target-higan/higan.hpp index b9b9a22d..97b63a1f 100644 --- a/target-higan/higan.hpp +++ b/target-higan/higan.hpp @@ -1,59 +1,8 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -using namespace nall; - -#include -using namespace phoenix; - +#include #include +#include +using namespace nall; using namespace ruby; - -#include "configuration/configuration.hpp" -#include "interface/interface.hpp" -#include "utility/utility.hpp" -#include "input/input.hpp" -#include "window/window.hpp" -#include "general/general.hpp" -#include "settings/settings.hpp" -#include "tools/tools.hpp" -#include "resource/resource.hpp" - -Emulator::Interface& system(); - -struct Program { - vector emulator; - Emulator::Interface* active = nullptr; - library ananke; - - bool pause; - bool autopause; - unsigned depth; //color depth; 24(bpp) or 30(bpp) - - string basepath; - string userpath; - string sharedpath; - - string normalFont; - string boldFont; - string titleFont; - string monospaceFont; - - bool focused(); - string path(string filename); - void main(); - void bootstrap(); - Program(int argc, char** argv); -}; - -extern Program* program; -extern DSP dspaudio; +using namespace hiro; diff --git a/target-higan/input/hotkeys.cpp b/target-higan/input/hotkeys.cpp deleted file mode 100644 index 0df72552..00000000 --- a/target-higan/input/hotkeys.cpp +++ /dev/null @@ -1,146 +0,0 @@ -void InputManager::appendHotkeys() { - { - auto hotkey = new HotkeyInput; - hotkey->name = "Toggle Fullscreen Mode"; - hotkey->mapping = "1/Button/F11"; - - hotkey->press = [] { - utility->toggleFullScreen(); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Toggle Mouse Capture"; - hotkey->mapping = "1/Button/F12"; - - hotkey->press = [] { - input.acquired() ? input.unacquire() : input.acquire(); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Show Library"; - hotkey->mapping = "1/Button/L"; - - hotkey->press = [] { - libraryManager->show(); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Pause Emulation"; - hotkey->mapping = "1/Button/P"; - - hotkey->press = [] { - program->pause = !program->pause; - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Fast Forward"; - hotkey->mapping = "1/Button/Tilde"; - - hotkey->press = [] { - video.set(Video::Synchronize, false); - audio.set(Audio::Synchronize, false); - }; - - hotkey->release = [] { - video.set(Video::Synchronize, ::config->video.synchronize); - audio.set(Audio::Synchronize, ::config->audio.synchronize); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Power Cycle"; - hotkey->mapping = "None"; - - hotkey->press = [] { - utility->power(); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Soft Reset"; - hotkey->mapping = "None"; - - hotkey->press = [] { - utility->reset(); - }; - } - - static unsigned activeSlot = 1; - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Save State"; - hotkey->mapping = "1/Button/F5"; - - hotkey->press = [&] { - utility->saveState(activeSlot); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Load State"; - hotkey->mapping = "1/Button/F7"; - - hotkey->press = [&] { - utility->loadState(activeSlot); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Decrement Slot"; - hotkey->mapping = "1/Button/F6"; - - hotkey->press = [&] { - if(--activeSlot == 0) activeSlot = 5; - utility->showMessage({"Selected slot ", activeSlot}); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Increment Slot"; - hotkey->mapping = "1/Button/F8"; - - hotkey->press = [&] { - if(++activeSlot == 6) activeSlot = 1; - utility->showMessage({"Selected slot ", activeSlot}); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Close Emulator"; - hotkey->mapping = "None"; - - hotkey->press = [] { - Application::quit(); - }; - } - - Configuration::Node node; - for(auto& hotkey : hotkeyMap) { - node.append(hotkey->mapping, string{hotkey->name}.replace(" ", "")); - } - config.append(node, "Hotkey"); -} - -void InputManager::pollHotkeys() { - for(auto& hotkey : hotkeyMap) { - bool state = hotkey->poll(); - if(hotkey->state == 0 && state == 1) if(hotkey->press) hotkey->press(); - if(hotkey->state == 1 && state == 0) if(hotkey->release) hotkey->release(); - hotkey->state = state; - } -} diff --git a/target-higan/input/input.cpp b/target-higan/input/input.cpp deleted file mode 100644 index bc0083c1..00000000 --- a/target-higan/input/input.cpp +++ /dev/null @@ -1,294 +0,0 @@ -#include "../higan.hpp" -#include "hotkeys.cpp" -InputManager* inputManager = nullptr; -HID::Null hidNull; - -void AbstractInput::bind() { - inputList.reset(); - lstring list = mapping.split(","); - - for(auto& mapping : list) { - lstring values = mapping.split("/"); - if(values.size() == 1) continue; //skip "None" mapping - - uint64_t id = hex(values[0]); - string group = values(1, ""); - string input = values(2, ""); - string qualifier = values(3, ""); - - Input item; - for(auto device : inputManager->devices) { - if(id != device->id) continue; - if(group == "Rumble") { - item.device = device; - item.id = id; - item.group = 0; - item.input = 0; - break; - } - if(auto groupID = device->find(group)) { - if(auto inputID = device->group[groupID()].find(input)) { - item.device = device; - item.id = id; - item.group = groupID(); - item.input = inputID(); - item.qualifier = Input::Qualifier::None; - if(qualifier == "Lo") item.qualifier = Input::Qualifier::Lo; - if(qualifier == "Hi") item.qualifier = Input::Qualifier::Hi; - break; - } - } - } - if(item.device == nullptr) continue; - - inputList.append(item); - } -} - -bool AbstractInput::append(string encode) { - lstring mappings = mapping.split(","); - if(mappings.find(encode)) return true; //mapping already bound - if(mapping.empty() || mapping == "None") mapping = encode; //remove "None" - else mapping.append(",", encode); //add to existing mapping list - bind(); - return true; -} - -// - -bool DigitalInput::bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) { - if(device.isNull() || (device.isKeyboard() && device.group[group].input[input].name == "Escape")) { - inputList.reset(); - mapping = "None"; - return true; - } - - string encode = {hex(device.id), "/", device.group[group].name, "/", device.group[group].input[input].name}; - - if((device.isKeyboard() && group == HID::Keyboard::GroupID::Button) - || (device.isMouse() && group == HID::Mouse::GroupID::Button) - || (device.isJoypad() && group == HID::Joypad::GroupID::Button) - ) { - if(newValue != 0) return append(encode); - } - - if((device.isJoypad() && group == HID::Joypad::GroupID::Axis) - || (device.isJoypad() && group == HID::Joypad::GroupID::Hat) - ) { - if(newValue < -16384) return append({encode, "/Lo"}); - if(newValue > +16384) return append({encode, "/Hi"}); - } - - return false; -} - -int16_t DigitalInput::poll() { - if(program->focused() == false) return 0; - if(inputList.size() == 0) return 0; - bool result = logic; - - for(auto& item : inputList) { - HID::Device& device = *(item.device); - int16_t value = device.group[item.group].input[item.input].value; - bool output = logic; - if((device.isKeyboard() && item.group == HID::Keyboard::GroupID::Button) - || (device.isMouse() && item.group == HID::Mouse::GroupID::Button) - || (device.isJoypad() && item.group == HID::Joypad::GroupID::Button) - ) { - output = value; - } - if((device.isJoypad() && item.group == HID::Joypad::GroupID::Axis) - || (device.isJoypad() && item.group == HID::Joypad::GroupID::Hat) - ) { - if(item.qualifier == Input::Qualifier::Lo) output = value < -16384; - if(item.qualifier == Input::Qualifier::Hi) output = value > +16384; - } - if(logic == 0) result |= output; - if(logic == 1) result &= output; - } - - return result; -} - -// - -bool RelativeInput::bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) { - if(device.isNull() || (device.isKeyboard() && device.group[group].input[input].name == "Escape")) { - inputList.reset(); - mapping = "None"; - return true; - } - - string encode = {hex(device.id), "/", device.group[group].name, "/", device.group[group].input[input].name}; - - if((device.isMouse() && group == HID::Mouse::GroupID::Axis) - || (device.isJoypad() && group == HID::Joypad::GroupID::Axis) - || (device.isJoypad() && group == HID::Joypad::GroupID::Hat) - ) { - if(newValue < -16384) return append(encode); - if(newValue > +16384) return append(encode); - } - - return false; -} - -int16_t RelativeInput::poll() { - if(program->focused() == false) return 0; - if(inputList.size() == 0) return 0; - int16_t result = 0; - - for(auto& item : inputList) { - HID::Device& device = *(item.device); - int16_t value = device.group[item.group].input[item.input].value; - if(device.isJoypad() && item.group == HID::Joypad::GroupID::Axis) value >>= 8; - if(device.isJoypad() && item.group == HID::Joypad::GroupID::Hat) value = (value < 0 ? -1 : value > 0 ? + 1 : 0); - if(device.isMouse() && input.acquired() == false) value = 0; - result += value; - } - - return result; -} - -// - -bool RumbleInput::bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) { - if(device.isNull() || (device.isKeyboard() && device.group[group].input[input].name == "Escape")) { - inputList.reset(); - mapping = "None"; - return true; - } - - string encode = {hex(device.id), "/Rumble"}; - - if(device.isJoypad() && group == HID::Joypad::GroupID::Button) { - if(newValue != 0) return append(encode); - } - - return false; -} - -void RumbleInput::rumble(bool enable) { - if(program->focused() == false) return; - if(inputList.size() == 0) return; - - for(auto& item : inputList) { - input.rumble(item.id, enable); - } -} - -// - -HotkeyInput::HotkeyInput() { - logic = 1; //AND - inputManager->hotkeyMap.append(this); -} - -// - -//convert an input mapping string to a more human-readable form for the UI -string InputManager::sanitize(string mapping, string concatenate) const { - lstring values = mapping.split(","); - for(auto& value : values) { - lstring part = value.split("/"); - if(part.size() < 2) continue; //skip "None" mapping - if(part[0] == "1") part[0] = "Keyboard"; - else if(part[0] == "2") part[0] = "Mouse"; - else part[0] = {"Joypad(", part[0].slice(0, 3), ")"}; - value = part.merge("."); - } - return values.merge(concatenate); -} - -void InputManager::onChange(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) { - if(settings->focused()) { - inputSettings->inputEvent(device, group, input, oldValue, newValue); - hotkeySettings->inputEvent(device, group, input, oldValue, newValue); - } -} - -HID::Device* InputManager::findMouse() { - for(auto device : devices) { - if(device->isMouse()) return device; - } - return nullptr; -} - -void InputManager::bind() { - for(auto& input : inputMap) input->bind(); - for(auto& input : hotkeyMap) input->bind(); -} - -void InputManager::poll() { - auto devices = input.poll(); - bool changed = devices.size() != this->devices.size(); - if(changed == false) { - for(unsigned n = 0; n < devices.size(); n++) { - changed = devices[n] != this->devices[n]; - if(changed) break; - } - } - if(changed == true) { - this->devices = devices; - bind(); - } - - if(presentation->focused()) pollHotkeys(); -} - -void InputManager::saveConfiguration() { - config.save(program->path("input.bml")); -} - -InputManager::InputManager() { - inputManager = this; - bootstrap(); - - input.onChange = {&InputManager::onChange, this}; -} - -void InputManager::bootstrap() { - unsigned guid = 0; - for(auto& emulator : program->emulator) { - Configuration::Node emulatorNode; - - for(auto& port : emulator->port) { - Configuration::Node portNode; - - for(auto& device : port.device) { - Configuration::Node deviceNode; - - for(auto& number : device.order) { - auto& input = device.input[number]; - - AbstractInput* abstract = nullptr; - if(input.type == 0) abstract = new DigitalInput; - if(input.type == 1) abstract = new RelativeInput; - if(input.type == 2) abstract = new RumbleInput; - if(abstract == nullptr) continue; - - abstract->name = string{input.name}.replace(" ", ""); - abstract->mapping = "None"; - abstract->logic = 0; //OR - - input.guid = guid++; - inputMap.append(abstract); - - deviceNode.append(abstract->mapping, abstract->name); - } - - portNode.append(deviceNode, string{device.name}.replace(" ", "")); - } - - emulatorNode.append(portNode, string{port.name}.replace(" ", "")); - } - - config.append(emulatorNode, string{emulator->information.name}.replace(" ", "")); - } - - appendHotkeys(); - - config.load(program->path("input.bml")); - config.save(program->path("input.bml")); - - bind(); -} diff --git a/target-higan/input/input.hpp b/target-higan/input/input.hpp deleted file mode 100644 index 7466b5a2..00000000 --- a/target-higan/input/input.hpp +++ /dev/null @@ -1,71 +0,0 @@ -extern HID::Null hidNull; - -struct AbstractInput { - string name; - string mapping; - bool logic = 0; //0 = OR, 1 = AND - bool state = 0; - - struct Input { - HID::Device* device = nullptr; - uint64_t id = 0; - unsigned group = 0; - unsigned input = 0; - enum class Qualifier : unsigned { None, Lo, Hi } qualifier; - }; - vector inputList; - - void bind(); - bool append(string mapping); - virtual bool bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) { return false; } - virtual int16_t poll() { return 0; } - virtual void rumble(bool enable) {} -}; - -struct DigitalInput : AbstractInput { - using AbstractInput::bind; - bool bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue); - int16_t poll(); -}; - -struct RelativeInput : AbstractInput { - using AbstractInput::bind; - bool bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue); - int16_t poll(); -}; - -struct RumbleInput : AbstractInput { - using AbstractInput::bind; - bool bind(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue); - void rumble(bool enable); -}; - -struct HotkeyInput : DigitalInput { - function press; - function release; - HotkeyInput(); -}; - -struct InputManager { - vector devices; - vector inputMap; - vector hotkeyMap; - - string sanitize(string mapping, string concatenate) const; - void onChange(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue); - HID::Device* findMouse(); - void bind(); - void poll(); - void saveConfiguration(); - void bootstrap(); - InputManager(); - - //hotkeys.cpp - void appendHotkeys(); - void pollHotkeys(); - -private: - Configuration::Document config; -}; - -extern InputManager* inputManager; diff --git a/target-higan/interface/interface.cpp b/target-higan/interface/interface.cpp deleted file mode 100644 index c48e7f96..00000000 --- a/target-higan/interface/interface.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "../higan.hpp" -Interface* interface = nullptr; - -void Interface::loadRequest(unsigned id, string name, string type) { - return utility->loadRequest(id, name, type); -} - -void Interface::loadRequest(unsigned id, string path) { - return utility->loadRequest(id, path); -} - -void Interface::saveRequest(unsigned id, string path) { - return utility->saveRequest(id, path); -} - -uint32_t Interface::videoColor(unsigned source, uint16_t a, uint16_t r, uint16_t g, uint16_t b) { - if(config->video.shader != "Display Emulation") { - if(config->video.saturation != 100) { - uint16_t grayscale = uclamp<16>((r + g + b) / 3); - double saturation = config->video.saturation * 0.01; - double inverse = max(0.0, 1.0 - saturation); - r = uclamp<16>(r * saturation + grayscale * inverse); - g = uclamp<16>(g * saturation + grayscale * inverse); - b = uclamp<16>(b * saturation + grayscale * inverse); - } - - if(config->video.gamma != 100) { - double exponent = config->video.gamma * 0.01; - double reciprocal = 1.0 / 32767.0; - r = r > 32767 ? r : 32767 * pow(r * reciprocal, exponent); - g = g > 32767 ? g : 32767 * pow(g * reciprocal, exponent); - b = b > 32767 ? b : 32767 * pow(b * reciprocal, exponent); - } - - if(config->video.luminance != 100) { - double luminance = config->video.luminance * 0.01; - r = r * luminance; - g = g * luminance; - b = b * luminance; - } - } - - if(program->depth == 30) { - a >>= 14, r >>= 6, g >>= 6, b >>= 6; - return a << 30 | r << 20 | g << 10 | b << 0; - } - - if(program->depth == 24) { - a >>= 8, r >>= 8, g >>= 8, b >>= 8; - return a << 24 | r << 16 | g << 8 | b << 0; - } - - return 0u; -} - -void Interface::videoRefresh(const uint32_t* palette, const uint32_t* data, unsigned pitch, unsigned width, unsigned height) { - uint32_t* output; - unsigned outputPitch; - - if(video.lock(output, outputPitch, width, height)) { - pitch >>= 2, outputPitch >>= 2; - - for(unsigned y = 0; y < height; y++) { - const uint32_t* sp = data + y * pitch; - uint32_t* dp = output + y * outputPitch; - for(unsigned x = 0; x < width; x++) { - *dp++ = palette[*sp++]; - } - } - - if(system().information.overscan && config->video.maskOverscan.enable) { - unsigned h = config->video.maskOverscan.horizontal; - unsigned v = config->video.maskOverscan.vertical; - - if(h) for(unsigned y = 0; y < height; y++) { - memset(output + y * outputPitch, 0, 4 * h); - memset(output + y * outputPitch + (width - h), 0, 4 * h); - } - - if(v) for(unsigned y = 0; y < v; y++) { - memset(output + y * outputPitch, 0, 4 * width); - memset(output + (height - 1 - y) * outputPitch, 0, 4 * width); - } - } - - video.unlock(); - video.refresh(); - } - - static unsigned frameCounter = 0; - static time_t previous, current; - frameCounter++; - - time(¤t); - if(current != previous) { - previous = current; - utility->setStatusText({"FPS: ", frameCounter}); - frameCounter = 0; - } -} - -void Interface::audioSample(int16_t lsample, int16_t rsample) { - signed samples[] = {lsample, rsample}; - dspaudio.sample(samples); - while(dspaudio.pending()) { - dspaudio.read(samples); - audio.sample(samples[0], samples[1]); - } -} - -int16_t Interface::inputPoll(unsigned port, unsigned device, unsigned input) { - unsigned guid = system().port[port].device[device].input[input].guid; - return inputManager->inputMap[guid]->poll(); -} - -void Interface::inputRumble(unsigned port, unsigned device, unsigned input, bool enable) { - unsigned guid = system().port[port].device[device].input[input].guid; - return inputManager->inputMap[guid]->rumble(enable); -} - -unsigned Interface::dipSettings(const Markup::Node& node) { - return dipSwitches->run(node); -} - -string Interface::path(unsigned group) { - return utility->path(group); -} - -string Interface::server() { - return { - config->server.username, ":", - config->server.password, "@", - config->server.hostname - }; -} - -void Interface::notify(string text) { - MessageWindow().setParent(*presentation).setText(text).information(); -} diff --git a/target-higan/interface/interface.hpp b/target-higan/interface/interface.hpp deleted file mode 100644 index 485c831f..00000000 --- a/target-higan/interface/interface.hpp +++ /dev/null @@ -1,16 +0,0 @@ -struct Interface : Emulator::Interface::Bind { - void loadRequest(unsigned id, string name, string type); - void loadRequest(unsigned id, string path); - void saveRequest(unsigned id, string path); - uint32_t videoColor(unsigned source, uint16_t alpha, uint16_t red, uint16_t green, uint16_t blue); - void videoRefresh(const uint32_t* palette, const uint32_t* data, unsigned pitch, unsigned width, unsigned height); - void audioSample(int16_t lsample, int16_t rsample); - int16_t inputPoll(unsigned port, unsigned device, unsigned input); - void inputRumble(unsigned port, unsigned device, unsigned input, bool enable); - unsigned dipSettings(const Markup::Node& node); - string path(unsigned group); - string server(); - void notify(string text); -}; - -extern Interface* interface; diff --git a/target-higan/resource.rc b/target-higan/resource.rc deleted file mode 100644 index 49441758..00000000 --- a/target-higan/resource.rc +++ /dev/null @@ -1,2 +0,0 @@ -1 24 "../data/higan.Manifest" -2 ICON DISCARDABLE "../data/higan.ico" diff --git a/target-higan/resource/cheat-editor.png b/target-higan/resource/cheat-editor.png deleted file mode 100644 index c8d899cff2a5d6cfabb70db4cc39c300914069ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 937 zcmV;a16KTrP)~s5J7JDPHfNEe|jA6@tsBpG4bKa)0S=9 zi&w|44DR@szZ%UP>gnwRaObh`%K*OK1t_J=d-JpW#PPl!rPO`^7{2tyE79g?q*&Tu zTI=qra698-k}=`g1#r$w3k(0iGz?ZQm*ZE*t_(^kuf<|9tUOrJTI>1ku*HSA-qHPO zPgozywY?U5?v&{kC!yU90FMFAo=N=1IsbNcE~P`E5Hb%k zL`37y*C(Fxcx%shb`SX7(ljbti_ppjh`_1=6XEcvOLWrB=S{dSo(?x5O?oqU(DuG? zX+TQ8hGOmp4AX=+^agJKlu!ZyCL)o+BbCbaPRr^J2_cnosq8wa3)HYi)9@I}CjWJK z3ZBLsvRii%YHR}cwqy1F&%}R>M&EUExuMQ*SkEjiT`O#DI{Cr|_Z`+PLNfeomr#hA zXm6-TGBJnzltjgGpxrVE1nxS{@V?eoN-Zy6IHpu@t?5(3=TnWZ^Y8!8tRNT+ApT_o z@-MBqd!rF5-taX=fWPX+>)JyM#&Lcwpf9|%3W2Y!;cH}n_G zSGOb>FyrPtSATz4FqXT-w&T0C?39fNZZjD{y+MC*`V$Re99;E`7$ zK5`JgNDM>_j~@O>tm;Ab0l3AOG==m#00BhXQ`$W>?bJk2%J%&S5vFrO$L{Z{00000 LNkvXXu0mjfs=~K$ diff --git a/target-higan/resource/folder.png b/target-higan/resource/folder.png deleted file mode 100644 index 472484f11279c3e37a20ddcc8277c516ad246115..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1176 zcmV;J1ZVq+P)1yxd$0C6kuV7bR+PdY00{*lQ*M=l z8i@j0IzB)oK0r!@M1^RfLrAAU7s-kOiqb{G#>6NV#`n5+-j|u38H#(!I(Lo}a#ASx zOOJMTcK3OH^E@-NyCMujUZ>=1js9N%@BwbzxZx|Mem2IuchLhvh}>HH`NM|~zg!tW znx z&Mh?nAq1P7oB6@P!AHRDl>lh1(=5xxrAr$aW3bkq30%yC5Q1v8T0cBI{9=21`_`;~ znVfUlTKn$b$Z5|!&XdlVufDtg z{_MP%0o`cSt6FQ+AChLZ%>LhFqBx(7Z0TsvBM}Qt0W>N;D$@u-XLfnM6&qu8zdxYc z?Gk5}dbNZ#lN;pJ!Lx=t&)ie96SLNlWQH`$!HM|>RxCkQsRXoIEixmh1tqLgcycwb zi*cG$Z~BaeIo7%-3jleZt0)@L?+?)C4XS~Ua}H0Qo97pkgHfu{xh3!=ajLB``OyM^ zF(xaQOH`X1tkudmKnk(E_%A5q9HUf|TZiWfg0jbHk|`m?$pV12HXDt`91j%h^-Jj7 zzS8J3ZHY4jPT)`dls(DlRON!Fldzb9)c1Y7AfQQ^OxX*AOy-!wy2(Ca?8H=Vm#s*g zgTW}ZxpRvE*4kt|9@824R9a=CM3d?1O9;q~MH`3CExDO)%P*OgL>Y$T#1qn6T7pyv zfeadyNs60>X%$s}D(4*iBtcj^SO93Z+hS*D$3(GWaO(K; zWQgp(;tse($HzmPB*O>0?RG5;!*~t=cu^Gn^vj|6Os(Vpw*Sf>yJzIU0$80M96$Ks z>*6&r`!#E~+s$BY?af-y+H^Q6g8x)+GM1_(Nr{gdepj+bg-;!Hp8!ZtGP zkKPl6+^slId#p6YR?a5#8>U?U>+ktE^J21=v zZ_|sGk^UCh3$LI=qm)94CVSx({Do<9>GgpVd-?8s>dwo7Y%e>sFyL=|!IqXTiW3(= zYXrFc;Q`#6qo6^HBAMQdIX+C)#p6X0wk3bgYqQm!(}6%-2C@%qw7rH_N)s0mKtvD` z%tT$_f}v0Xxy!HPHnfpXud}u0@LW#J>Odr(e$@6;%Rsw0jcY-mG=7f!^^^Fy&!=9{ zI!FkK)^3dP5vne|Ija*D9mw{uU5gCl((7zL^;Pnt|3tg_sB=Fv28D^B`zQ=VDU=BL zD@XAfmXU9N#1^FDPTUb7+rxHWE2!VhIA_@^fDPu;csSFgZ9>ZJM zLbk2bsRZ#QfU1YzVKe znQZGCM=3cRhll|5ODNz_vA)q}$=4~2oepf5sri~U&4@_oLI5JA$*I{#Sz%aJSoIw! z!wQ`E>>bntk5Q;u?1)S)WCS2D;p4N-p7^9F*WSTtS`!r%Q5eZZC_9OWpmXEo-rYy; z-G2Pc^+?>X643~Znx!mQz8$l+1u;w#E!{Y|49@NU6t$k(g=r&5{))c|`umCDGez^p zb?nA(Aj(9P!d|p`>IB@pjL3A$&FUr+4?TmGT8>%Wh?QE72qZeTP}}uW5>z24`is8j zKT-Wljzo>$=@evo*@no0V*6U#Pc`A+xI|+0Zj|AG2*vY%M(4(ZaYU_HIIDJ}CG1IS zG@ud<=#e4x@&1zb+{feM6#=F}q&sbE#a2|J0ST@^C{E&j{05*gYCG`8-@{nag{tic zg*9l9s(SS35dN_{i_Z#BhR~>ks{46MEnS1oe-U;q_%|;?;U;F|TC~iiKwpRe%jt0nV@AV)V&XTu5cE zZSlz%W^*U_Zg4b_NW3)I=f3}``}BkT90kl!qkP=I1X2mW0-Txg+cRAGb{m(QbHm?} zMIDB!UxxTDSV{bmAxeXN?$KfQN8K-TEGAwCPy~*LTUr^w2m$O^L=Z2Zpl)Mt?Ro5xYIjv@p6rsv!2)UUw6hoYYF#9e*gdg07*qoM6N<$f+&dEi2wiq diff --git a/target-higan/resource/resource.bml b/target-higan/resource/resource.bml deleted file mode 100644 index e9a78611..00000000 --- a/target-higan/resource/resource.bml +++ /dev/null @@ -1,15 +0,0 @@ -resource name=resource - binary id=advanced name=advanced.png - binary id=audio name=audio.png - binary id=cheatEditor name=cheat-editor.png - binary id=folder name=folder.png - binary id=game name=game.png - binary id=home name=home.png - binary id=hotkeys name=hotkeys.png - binary id=input name=input.png - binary id=server name=server.png - binary id=stateManager name=state-manager.png - binary id=timing name=timing.png - binary id=unverified name=unverified.png - binary id=up name=up.png - binary id=video name=video.png diff --git a/target-higan/resource/resource.cpp b/target-higan/resource/resource.cpp deleted file mode 100644 index 1f84fc61..00000000 --- a/target-higan/resource/resource.cpp +++ /dev/null @@ -1,411 +0,0 @@ -namespace resource { - -const uint8_t advanced[611] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, - 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,9,26,12,19,57,139,99,194,72,0,0,1,240,73, - 68,65,84,56,203,165,146,75,104,19,97,20,133,191,153,248,76,138,77,20,10,130,74,176,204,198,133,182,221,69,172,46, - 52,20,98,102,235,66,112,33,84,164,168,181,45,18,82,2,21,3,67,66,160,107,65,116,101,64,138,226,194,137,141,208, - 98,87,130,210,54,137,73,23,21,130,85,105,211,151,134,32,68,68,58,51,110,102,134,49,29,235,194,179,251,185,231,156, - 123,239,185,63,252,39,4,231,35,157,81,162,128,10,200,241,88,34,247,23,77,52,157,81,108,142,216,82,84,251,175,246, - 3,168,166,153,171,248,250,181,1,205,108,180,29,233,140,98,52,26,117,35,157,81,12,247,90,195,170,69,1,196,116,70, - 137,90,100,171,171,215,219,230,102,28,5,120,240,240,62,241,88,66,6,114,0,34,160,14,222,28,50,158,62,155,48,0, - 245,246,173,17,54,215,215,144,58,37,234,245,175,247,90,179,137,221,25,21,44,49,128,96,21,111,12,12,26,154,182,37, - 232,186,110,232,186,70,97,126,78,40,188,47,2,200,59,5,43,180,116,176,17,233,187,72,185,82,97,185,246,5,32,25, - 143,37,238,254,243,140,78,188,202,191,52,74,149,18,221,39,123,40,150,11,152,19,76,2,186,171,65,48,146,58,12,212, - 172,247,149,144,78,215,9,137,163,71,142,209,108,54,121,55,247,22,183,53,60,78,241,248,112,152,190,80,39,29,1,47, - 217,153,77,142,183,127,75,46,125,94,58,215,125,170,135,128,63,192,74,109,249,242,133,240,249,249,233,169,215,85,192,0, - 16,131,145,84,23,80,123,52,38,51,91,94,100,182,188,72,199,65,31,0,230,222,114,46,255,2,73,146,56,123,186,215, - 250,100,118,30,34,80,28,31,14,51,245,166,196,150,166,35,238,243,179,81,111,218,35,154,35,203,217,39,143,57,208,238, - 231,76,168,23,96,204,105,0,192,238,93,30,246,248,14,241,243,199,47,178,249,5,128,112,171,73,46,175,82,253,88,253, - 35,108,17,96,101,227,59,251,125,1,218,246,122,120,62,243,1,32,252,105,114,116,218,73,52,77,146,107,235,171,11,64, - 210,190,66,48,146,186,4,76,56,184,219,196,59,225,55,55,226,213,246,234,188,84,188,0,0,0,0,73,69,78,68,174, - 66,96,130, -}; - -const uint8_t audio[592] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, - 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,1,226,73,68,65,84,56,141, - 165,147,191,79,83,81,20,199,63,231,246,245,165,68,168,3,193,201,63,64,99,66,4,139,128,113,100,241,71,88,40,88, - 162,46,36,242,106,58,233,0,127,132,49,93,173,12,13,137,160,169,105,2,196,133,196,168,131,131,137,16,23,69,172,147, - 58,176,184,152,247,76,244,93,222,61,14,198,218,22,140,65,191,227,57,159,156,123,190,223,123,175,168,42,255,35,243,167, - 70,126,58,159,11,130,32,253,79,3,10,133,137,193,20,242,56,142,227,212,129,7,20,10,19,131,105,63,243,84,85,179, - 173,245,161,224,94,112,122,118,121,172,147,247,46,77,79,134,64,198,243,188,175,168,222,73,251,153,235,51,51,51,217,202, - 221,74,210,10,58,167,239,141,104,53,23,60,236,223,168,76,126,105,110,32,72,166,124,187,236,205,207,205,31,86,152,43, - 149,74,217,209,145,51,120,158,7,64,110,118,169,56,114,109,233,232,230,194,213,39,10,235,104,124,179,205,130,162,244,245, - 29,225,248,177,19,168,170,12,156,60,69,38,211,133,136,0,32,66,111,34,148,1,68,101,69,144,209,61,25,188,217,122, - 205,187,198,91,0,26,141,109,182,183,183,176,214,2,144,114,44,2,99,34,136,26,247,10,116,72,4,105,102,0,16,134, - 97,115,101,187,107,81,126,191,141,93,163,137,168,164,0,172,209,196,79,164,45,120,3,16,70,33,97,20,162,170,216,216, - 98,99,219,4,4,83,64,244,153,42,234,37,169,1,96,83,91,78,48,0,81,20,177,179,179,3,192,135,79,31,137,109, - 220,26,191,167,164,111,252,132,245,130,194,139,182,107,84,85,173,215,235,137,136,88,35,102,113,117,117,229,242,248,197,241, - 238,95,192,203,133,43,183,0,134,139,247,71,129,60,98,250,59,45,244,168,106,183,115,174,123,121,233,65,209,126,79,206, - 173,61,90,139,156,115,109,94,93,226,134,65,139,27,149,233,207,173,117,217,239,51,77,77,77,157,197,184,245,67,93,61, - 189,213,106,245,219,30,160,51,196,78,213,106,181,231,56,115,222,247,253,100,191,254,95,55,56,136,126,0,228,148,200,42, - 201,231,90,24,0,0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t cheatEditor[937] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0, - 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,11,28,23,56,34,56,174,182,224,0,0,3,54,73, - 68,65,84,56,203,93,147,75,76,92,117,20,198,191,255,99,230,222,121,128,115,65,96,102,128,162,19,4,154,73,83,19, - 23,197,87,221,24,74,210,141,169,85,27,31,171,54,193,84,107,213,210,102,72,67,26,98,162,13,148,88,155,52,172,76, - 136,143,133,27,92,17,18,187,168,166,52,93,24,181,117,12,29,168,52,242,152,41,101,24,198,14,51,112,231,206,253,255, - 143,27,192,73,191,213,57,223,201,247,203,73,78,14,195,182,70,70,47,246,2,248,206,52,205,135,167,62,248,56,142,42, - 141,140,94,28,147,82,190,245,201,233,254,186,106,127,122,28,239,241,157,70,8,49,241,225,201,211,150,109,219,139,87,199, - 174,12,238,248,151,191,26,205,28,234,233,237,3,112,231,177,240,203,0,190,222,5,40,165,204,123,243,179,252,196,241,190, - 30,165,212,126,0,24,190,244,197,43,209,230,104,164,88,218,96,90,235,238,170,112,59,227,98,146,49,225,217,5,112,206, - 75,11,11,255,192,52,12,86,46,151,227,87,199,174,12,74,41,175,197,98,49,172,60,88,209,90,235,249,237,176,197,133, - 184,222,209,253,105,80,120,106,84,245,6,61,169,84,10,203,233,37,118,226,120,95,167,109,219,239,119,117,117,121,24,56, - 230,239,207,3,192,15,211,227,240,112,33,166,90,227,71,155,234,90,14,49,0,216,5,156,235,31,184,197,57,95,156,155, - 155,133,105,152,204,10,89,81,210,64,118,109,85,3,152,60,123,38,241,25,23,98,188,190,249,192,254,104,199,155,30,80, - 9,68,244,63,0,0,180,214,71,102,238,206,208,234,234,10,92,229,98,99,163,128,100,50,233,0,24,186,249,13,63,239, - 15,181,189,22,123,238,148,233,22,39,161,221,13,0,143,1,206,158,73,252,198,57,255,118,118,46,165,67,161,16,50,15, - 50,68,68,227,207,215,39,158,242,120,107,207,119,118,15,248,221,210,52,42,91,139,208,202,6,136,192,170,1,19,225,240, - 168,75,116,210,205,231,77,184,46,158,14,55,33,77,122,51,120,208,246,190,112,105,64,74,190,134,98,238,6,12,211,132, - 55,244,6,110,255,148,80,2,0,38,34,145,193,35,149,202,245,78,203,234,14,9,33,149,114,169,236,58,168,11,212,176, - 70,211,240,24,203,38,255,117,120,10,158,198,28,178,91,119,17,106,108,2,247,182,99,245,254,207,196,127,140,70,223,117, - 114,185,161,206,112,88,207,44,45,93,43,108,109,58,249,194,6,247,29,214,45,66,50,252,107,151,80,136,153,104,111,168, - 71,50,49,135,252,148,68,197,113,160,221,50,8,4,238,58,206,240,190,214,86,74,45,47,95,56,166,84,111,173,233,83, - 194,231,83,141,175,243,239,255,206,172,32,24,12,32,254,101,3,242,47,173,185,123,163,17,42,222,240,66,85,42,112,221, - 77,128,8,28,229,114,189,227,56,234,152,82,159,79,6,2,151,61,82,154,194,66,193,111,181,31,8,61,187,7,126,146, - 184,55,244,23,204,87,183,36,24,49,93,208,112,29,7,170,178,9,128,32,225,245,102,130,126,255,158,219,109,109,101,173, - 181,156,89,75,23,155,47,60,225,111,217,123,212,8,156,251,5,201,143,254,64,199,157,48,42,191,215,64,107,130,172,149, - 80,218,221,6,0,226,109,203,202,165,215,215,95,92,119,28,153,103,196,194,253,90,60,115,248,29,131,115,15,140,134,39, - 97,68,235,144,94,200,34,155,45,224,145,87,33,62,114,16,190,72,12,68,12,143,30,254,73,172,234,65,246,1,184,197, - 152,52,133,244,59,0,1,68,219,83,218,61,53,237,212,68,80,202,246,253,7,17,166,115,66,199,238,239,170,0,0,0, - 0,73,69,78,68,174,66,96,130, -}; - -const uint8_t folder[1176] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122, - 244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, - 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, - 97,112,101,46,111,114,103,155,238,60,26,0,0,4,21,73,68,65,84,88,133,237,151,61,111,28,69,24,199,127,51,187, - 119,123,175,246,57,145,48,9,5,86,148,194,31,0,9,5,33,83,110,149,130,26,137,2,90,58,62,64,36,62,64,74, - 132,68,133,104,161,67,72,167,64,23,201,138,2,138,210,69,194,198,196,40,22,198,247,186,119,222,151,153,157,25,138,123, - 201,58,119,142,19,114,82,40,248,75,143,118,118,118,247,121,126,243,60,51,179,187,34,12,67,94,167,228,107,141,254,95, - 0,240,1,110,220,184,225,43,165,126,54,198,188,119,209,3,66,136,220,90,251,249,195,135,15,191,92,25,64,154,166,91, - 149,74,229,157,155,55,111,250,73,146,224,156,3,192,90,11,48,63,159,182,253,59,119,238,220,222,222,222,254,254,209,163, - 71,199,43,1,80,74,101,213,106,213,29,29,29,209,233,116,112,206,45,53,0,33,4,155,155,155,249,193,193,193,71,192, - 237,149,0,104,173,211,44,203,196,165,75,27,24,99,176,214,158,9,92,204,132,16,130,106,181,90,63,60,60,252,98,123, - 123,251,214,172,127,153,156,115,218,90,251,241,222,222,222,143,207,5,0,178,44,203,188,78,167,75,167,211,153,3,204,142, - 179,32,197,64,91,91,91,245,70,163,65,179,217,68,8,129,16,2,0,41,229,188,29,69,17,247,238,221,187,5,60,31, - 224,242,229,203,105,191,223,247,54,54,90,104,173,23,0,150,149,98,166,56,142,1,230,16,69,139,227,24,99,76,237,188, - 224,115,128,221,221,93,117,237,218,53,217,235,245,230,25,0,150,130,204,178,81,212,108,196,197,224,82,202,25,64,229,66, - 0,0,99,140,109,54,215,100,154,102,220,63,180,220,221,63,27,228,188,58,63,171,25,204,228,153,22,206,93,185,206,219, - 31,232,226,61,158,39,190,93,255,253,155,79,206,0,56,231,116,183,219,245,187,221,46,143,59,13,62,253,240,93,174,191, - 181,81,112,54,61,62,47,250,18,200,105,207,60,206,147,206,152,175,190,187,255,254,236,188,152,1,221,104,212,171,90,107, - 212,31,146,102,181,204,254,223,99,162,56,159,140,108,233,104,207,35,17,11,77,1,52,42,62,42,211,8,65,103,118,121, - 190,21,27,99,116,191,63,160,219,237,18,103,150,122,181,132,53,147,27,228,212,193,179,134,59,207,220,83,179,19,179,214, - 145,100,134,52,203,193,137,249,6,86,44,65,86,169,4,180,90,45,50,35,168,5,37,172,83,120,114,53,175,139,113,154, - 83,111,250,140,134,57,214,186,39,11,0,121,158,171,40,26,209,239,15,208,230,13,170,129,143,115,14,79,158,155,231,23, - 147,131,81,170,209,185,37,240,37,113,170,173,49,249,209,2,128,49,38,43,151,75,84,155,27,172,213,202,56,64,10,177, - 188,248,47,40,227,28,163,84,147,91,135,231,9,130,178,199,105,146,41,33,196,201,2,128,181,54,27,141,198,28,15,20, - 235,245,75,232,220,190,210,232,51,109,137,51,3,78,224,79,253,148,61,201,232,84,229,130,167,147,176,152,129,212,247,125, - 188,32,160,73,153,76,217,11,131,76,230,152,195,186,201,62,97,236,196,84,110,151,173,72,156,131,193,40,181,185,115,139, - 0,214,218,100,60,30,211,25,248,84,90,101,162,68,147,233,233,75,8,200,141,69,27,135,206,45,185,153,110,203,47,153, - 149,68,25,134,227,196,19,210,91,90,130,84,8,129,12,26,148,74,62,163,68,19,37,154,84,25,148,182,47,29,108,153, - 226,44,231,52,209,62,231,148,32,142,227,83,122,81,133,74,13,30,159,196,12,99,189,212,209,191,145,0,134,177,66,25, - 83,250,245,234,94,47,124,252,12,128,181,54,6,129,245,107,100,185,37,138,53,74,95,60,15,94,84,82,10,78,134,9, - 82,200,56,220,221,157,59,62,51,7,146,36,33,74,12,87,175,4,84,3,143,160,188,186,111,86,41,4,105,170,144,82, - 12,139,253,197,18,36,0,154,18,235,85,143,122,105,21,85,127,42,231,28,253,36,65,88,59,88,0,104,183,219,98,103, - 103,199,68,177,98,112,234,248,243,100,136,236,190,226,14,184,68,199,199,67,155,36,195,7,187,237,118,45,12,195,120,14, - 0,120,81,20,253,244,203,161,248,76,173,227,255,182,255,202,31,187,103,228,192,2,88,157,30,28,63,248,225,235,226,53, - 49,251,53,107,183,219,205,96,109,237,205,90,208,218,116,56,41,133,92,201,18,200,141,49,42,75,107,185,16,121,62,58, - 233,1,127,133,97,216,91,0,152,66,72,32,96,146,153,124,21,0,83,5,64,10,168,48,12,207,44,45,241,255,207,233, - 235,6,248,7,188,50,165,151,203,8,55,43,0,0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t game[1490] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122, - 244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,5,137,73,68,65,84,88,133,237,150,91,108,20, - 231,21,199,127,231,155,155,151,181,124,89,3,181,113,193,183,13,16,81,82,21,225,52,50,1,132,91,53,20,212,132,155, - 212,84,149,18,161,40,82,213,151,72,68,81,108,212,74,121,168,122,81,165,190,24,171,125,141,218,226,66,171,66,91,37, - 65,145,82,225,2,9,6,148,132,40,73,9,55,219,4,112,146,58,49,23,239,125,102,190,62,204,236,120,236,176,182,1, - 169,79,29,233,232,236,203,156,255,239,252,207,249,190,29,248,255,115,31,79,182,135,157,153,94,116,102,47,91,239,181,134, - 186,31,113,173,216,159,173,249,10,90,243,215,76,47,91,254,103,0,217,30,118,106,225,143,183,219,215,219,250,225,103,201, - 180,173,179,53,28,186,23,136,187,6,8,58,151,253,147,233,13,142,151,106,97,226,76,63,238,194,54,50,237,143,222,19, - 132,220,173,56,134,57,144,95,243,3,43,111,8,147,31,253,3,180,7,98,80,189,226,123,152,159,95,102,193,197,227,69, - 129,237,201,95,240,234,124,106,206,219,129,108,47,59,48,204,1,111,211,139,150,145,254,22,217,11,175,160,68,163,148,66, - 137,38,123,225,21,252,133,105,114,233,245,129,19,123,249,238,124,234,206,203,129,108,47,59,180,48,224,111,124,193,150,150, - 46,138,19,23,64,107,4,184,253,225,1,220,155,163,160,65,139,34,153,222,140,57,62,76,213,197,227,69,17,182,37,127, - 206,107,179,213,158,211,129,64,92,6,178,15,108,180,189,134,86,74,19,23,17,64,68,16,17,204,68,93,224,130,161,80, - 2,185,203,175,227,54,180,145,79,175,179,181,230,240,92,78,204,234,64,36,158,126,212,246,83,203,64,187,56,141,107,65, - 160,52,126,142,252,245,147,248,185,207,167,94,208,58,72,8,137,214,110,140,241,17,170,46,189,57,171,19,21,29,200,246, - 176,93,139,12,228,210,235,108,63,245,85,242,163,255,68,187,249,168,115,63,51,6,133,137,160,251,40,12,68,41,148,8, - 249,43,71,241,26,150,145,111,127,196,22,164,226,78,220,17,32,219,195,118,95,228,79,217,116,151,237,213,53,147,191,50, - 136,8,129,128,8,34,10,17,65,41,99,70,168,169,12,20,174,30,195,91,216,66,182,173,211,169,4,241,37,128,178,120, - 174,227,17,219,175,91,66,225,234,49,20,160,68,161,172,5,80,158,125,205,82,204,228,226,105,226,18,101,21,65,20,175, - 158,192,75,45,37,219,182,214,17,228,208,100,15,155,43,2,100,122,217,22,136,63,108,251,117,77,20,174,190,137,8,72, - 185,168,83,27,117,111,47,92,73,242,107,79,97,47,94,61,189,243,16,72,194,113,136,64,113,108,8,175,174,153,108,235, - 26,71,41,57,28,135,136,0,244,75,40,224,80,177,190,209,102,201,215,41,140,157,14,108,151,169,249,154,53,205,136,72, - 232,66,0,34,165,201,169,217,71,89,97,88,85,88,245,29,40,195,10,156,248,236,29,212,3,143,81,168,89,236,136,76, - 45,100,4,32,47,225,227,179,205,158,248,164,40,215,222,193,105,90,19,21,20,81,24,201,69,40,59,137,136,160,115,227, - 228,222,221,71,238,221,126,252,204,245,72,220,176,18,209,8,140,154,165,44,88,190,29,179,182,5,49,76,18,45,221,56, - 185,12,206,237,255,20,181,158,218,133,105,35,72,254,138,191,9,250,251,137,225,51,69,243,198,117,236,198,111,32,202,68, - 148,194,94,180,122,234,4,220,188,140,200,116,203,205,234,38,18,15,61,131,149,90,142,89,221,136,149,90,142,8,36,58, - 182,80,219,245,83,18,84,33,39,250,139,190,231,63,81,253,75,142,68,141,223,233,20,100,122,217,134,200,129,98,251,90, - 219,79,53,225,223,184,68,98,245,110,148,225,128,8,197,243,127,70,231,198,131,113,68,173,88,56,171,118,163,37,236,73, - 107,52,160,18,13,232,145,33,244,241,254,146,246,220,199,227,226,21,1,166,65,164,59,109,107,197,86,84,162,1,9,174, - 64,40,78,226,126,252,6,160,49,106,59,240,198,223,195,88,210,133,170,237,8,133,53,104,144,170,122,244,232,16,254,177, - 59,139,207,10,80,134,208,168,131,170,251,121,75,45,93,131,206,127,17,118,45,248,55,47,66,225,38,102,227,90,180,214, - 81,169,224,183,6,39,20,255,215,190,138,226,115,2,64,120,47,24,230,65,99,211,30,83,39,171,241,174,31,199,168,107, - 71,223,56,15,94,1,107,229,15,65,153,83,215,176,214,96,215,161,71,79,226,205,33,62,47,128,50,132,54,140,3,254, - 242,78,75,234,27,17,237,66,241,22,214,146,46,164,174,131,80,25,173,65,236,26,252,209,33,188,193,190,146,214,238,19, - 115,253,27,206,247,131,196,248,108,15,59,146,85,242,7,86,126,211,182,59,127,140,246,242,168,240,78,40,3,96,85,227, - 141,156,194,27,236,43,77,228,220,93,205,191,225,53,192,3,252,138,133,103,17,85,128,13,84,1,206,175,223,98,244,201, - 85,92,72,101,174,109,241,201,24,102,115,39,248,110,112,52,145,72,188,52,216,231,190,255,169,251,244,131,253,28,5,204, - 80,163,124,220,191,4,82,9,192,2,156,153,241,219,51,92,249,118,27,151,155,115,195,223,145,69,29,134,170,95,134,248, - 46,88,73,252,145,33,74,131,125,238,209,97,247,71,221,47,115,44,38,94,6,80,4,142,135,91,90,25,192,8,1,236, - 88,68,16,47,159,229,90,103,147,30,110,187,117,170,91,26,90,149,212,183,226,143,156,164,56,216,231,30,254,183,187,103, - 215,65,222,10,197,227,162,241,81,107,130,177,204,10,96,134,16,102,8,80,6,114,0,231,192,7,140,173,72,249,87,86, - 76,158,218,160,111,127,170,74,111,255,197,251,253,89,247,39,207,252,157,211,49,209,184,160,31,134,23,203,21,1,252,24, - 189,17,203,101,48,3,176,14,159,99,172,165,198,191,182,218,26,89,255,187,51,254,207,158,59,194,233,25,66,238,140,40, - 197,34,26,193,108,167,160,188,7,118,44,199,195,138,1,150,187,44,11,20,103,68,33,150,167,45,226,124,142,97,121,28, - 54,211,71,83,22,143,47,150,23,235,62,14,51,173,235,187,5,184,211,59,113,241,114,141,153,179,158,215,243,95,119,198, - 63,107,9,247,71,127,0,0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t home[606] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, - 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,10,14,20,37,19,83,42,210,59,0,0,1,235,73, - 68,65,84,56,203,149,147,191,107,83,81,20,128,191,123,251,222,75,211,64,242,36,160,85,135,100,81,123,19,104,85,172, - 17,92,28,140,66,19,167,135,212,74,39,145,162,163,24,92,58,180,110,193,169,254,24,234,212,37,139,245,199,96,19,240, - 15,240,63,16,121,91,92,196,90,219,240,98,81,137,33,121,215,33,246,217,151,80,33,103,186,92,206,247,221,115,14,231, - 194,1,225,41,85,172,128,174,128,246,148,122,200,48,177,7,123,74,105,79,169,61,73,113,104,120,177,56,163,203,55,111, - 252,87,34,250,225,154,235,110,20,148,98,253,220,89,182,39,78,113,228,240,56,39,188,38,83,107,107,212,92,151,130,82, - 215,14,185,110,117,64,176,31,126,83,156,97,247,248,49,148,202,50,22,141,210,106,181,24,219,252,74,182,92,30,144,136, - 126,184,122,251,22,157,100,146,116,42,77,42,149,2,64,107,104,183,219,236,214,235,156,44,149,66,18,177,31,126,247,160, - 68,199,48,201,229,46,96,219,118,208,154,214,26,0,223,247,249,185,181,69,114,110,46,144,136,10,232,130,82,188,127,84, - 198,107,54,57,63,157,35,30,143,35,132,8,9,124,223,15,206,134,16,140,230,243,212,92,23,3,184,3,172,78,157,62, - 195,253,210,61,54,170,111,3,240,201,202,51,86,30,63,69,139,17,116,167,133,48,70,209,221,223,44,47,45,209,238,165, - 204,202,121,120,190,48,153,33,17,79,0,160,212,4,153,140,34,155,205,244,94,20,146,145,244,149,222,196,83,121,144,22, - 90,107,22,38,51,204,195,186,236,239,211,178,44,76,211,196,48,140,224,254,75,227,7,0,31,234,59,116,187,126,144,11, - 48,32,144,82,34,165,196,146,159,1,232,96,241,241,83,3,128,111,222,47,58,34,18,90,36,99,96,179,254,14,207,231, - 40,0,151,46,78,115,53,26,67,234,113,46,75,147,237,77,66,21,24,253,21,252,155,126,239,165,239,222,14,162,217,56, - 112,245,3,65,36,18,193,182,109,18,137,4,2,137,16,16,139,197,112,28,103,0,178,44,43,252,23,174,207,58,175,0, - 135,225,98,245,229,139,215,119,255,0,86,248,213,163,133,187,128,26,0,0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t hotkeys[587] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, - 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, - 97,112,101,46,111,114,103,155,238,60,26,0,0,1,200,73,68,65,84,56,141,181,146,177,107,83,81,20,198,127,247,222, - 115,95,95,8,73,159,136,180,209,38,177,21,7,165,21,26,16,204,228,34,102,8,8,34,212,168,127,72,193,191,160,131, - 45,174,29,178,184,180,116,17,212,12,25,4,23,137,32,168,56,85,227,146,162,85,112,145,212,190,151,52,125,185,14,109, - 53,29,164,193,226,7,151,115,46,231,124,223,189,231,240,169,82,169,196,113,160,15,146,122,189,174,142,37,48,191,48,159, - 30,134,80,169,84,252,193,187,58,24,161,88,156,157,242,60,223,3,239,187,136,216,100,210,88,99,196,199,152,139,190,245, - 175,2,87,28,76,3,30,74,189,72,38,82,229,106,181,26,203,31,45,127,195,57,123,201,250,186,108,69,143,59,103,50, - 32,99,86,108,216,239,179,174,148,187,15,242,174,213,106,253,204,159,157,104,110,111,255,40,0,175,127,11,52,26,141,93, - 224,205,254,249,219,247,131,252,228,196,50,142,157,173,173,206,251,67,59,56,10,115,119,230,174,163,226,183,202,169,200,104, - 175,80,171,213,186,0,114,20,113,239,229,91,151,193,61,82,112,111,101,101,237,249,96,77,45,173,45,37,78,118,131,166, - 159,24,57,163,181,70,27,141,86,123,209,104,131,214,10,173,13,206,57,0,246,123,94,61,88,120,88,4,144,157,86,120, - 45,83,184,112,106,102,122,6,107,61,68,4,43,22,99,4,173,13,56,71,223,245,137,162,136,48,10,49,90,211,104,188, - 156,173,84,110,158,95,93,125,220,20,17,239,118,144,62,225,133,97,135,205,175,159,72,37,211,160,0,20,74,41,218,237, - 54,249,92,142,56,142,249,178,249,153,108,54,79,106,52,144,245,15,31,111,0,139,98,180,46,7,65,0,206,145,61,157, - 99,183,31,31,154,127,52,157,166,215,235,1,138,169,201,115,116,186,93,50,99,227,102,196,179,119,129,69,137,227,120,227, - 233,179,39,90,169,225,157,236,156,3,199,55,24,112,226,191,98,104,31,252,55,129,95,252,113,137,228,164,151,154,151,0, - 0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t input[812] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,6,98,75,71,68,0,172,0,77,0,0,52,214,215,123,0,0,0,9,112,72,89,115,0,0,11,19,0, - 0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,213,4,7,15,10,39,178,201,163,153,0,0,0,140,116, - 69,88,116,67,111,109,109,101,110,116,0,77,101,110,117,45,115,105,122,101,100,32,105,99,111,110,10,61,61,61,61,61, - 61,61,61,61,61,10,10,40,99,41,32,50,48,48,51,32,74,97,107,117,98,32,39,106,105,109,109,97,99,39,32,83, - 116,101,105,110,101,114,44,32,10,104,116,116,112,58,47,47,106,105,109,109,97,99,46,109,117,115,105,99,104,97,108,108, - 46,99,122,10,10,99,114,101,97,116,101,100,32,119,105,116,104,32,116,104,101,32,71,73,77,80,44,10,104,116,116,112, - 58,47,47,119,119,119,46,103,105,109,112,46,111,114,103,103,138,199,71,0,0,2,33,73,68,65,84,56,203,149,146,203, - 107,83,65,20,198,127,147,220,228,38,214,210,164,177,54,245,209,135,160,184,73,176,20,255,130,130,123,17,138,136,130,168, - 32,88,8,193,133,173,15,180,221,136,46,68,10,10,130,72,22,93,213,186,19,68,208,133,187,34,84,179,19,68,20,42, - 21,53,53,183,105,244,230,117,111,230,184,184,105,154,66,178,232,129,3,195,240,205,55,191,249,230,40,58,212,199,179,132, - 255,170,221,51,97,41,95,2,124,235,42,178,96,80,191,58,62,95,40,181,234,84,167,195,117,124,223,250,14,237,141,27, - 225,16,162,53,142,93,102,237,251,186,181,161,122,6,79,204,231,237,77,173,175,157,129,70,165,99,67,177,184,175,43,140, - 235,247,99,21,107,216,174,143,129,35,253,189,192,253,86,173,175,195,11,82,129,93,97,252,166,137,17,12,16,12,26,252, - 94,181,136,14,198,137,200,198,153,86,161,145,74,79,206,0,119,90,55,203,86,6,167,84,193,202,217,116,71,187,40,230, - 255,225,214,28,220,170,67,69,153,209,84,250,178,52,164,179,42,149,158,148,185,135,143,182,93,255,235,229,61,170,203,115, - 88,185,34,249,181,18,162,96,223,240,30,162,177,46,234,135,47,112,240,212,109,108,219,230,198,173,41,12,0,173,53,133, - 66,97,11,235,248,57,114,111,30,211,63,212,199,200,104,15,134,25,160,248,243,15,185,85,135,3,231,47,98,89,22,65, - 51,184,149,129,104,241,90,188,86,129,16,3,215,151,88,212,167,249,186,244,133,207,239,62,241,170,52,206,254,155,239,81, - 129,16,34,2,141,71,120,4,162,209,34,32,226,125,172,0,134,137,27,234,101,228,193,42,43,43,43,228,223,190,134,128, - 137,214,26,192,51,105,18,136,96,189,184,198,143,233,97,214,23,167,26,68,26,183,238,182,36,35,72,93,35,186,209,13, - 3,163,153,252,242,2,82,43,81,90,94,160,251,228,93,0,142,37,71,121,250,236,73,115,93,23,221,68,111,230,181,25, - 98,104,108,130,202,135,231,132,198,38,208,90,163,68,72,36,146,36,18,73,68,20,74,137,135,223,48,216,70,96,154,38, - 71,175,100,128,76,219,169,178,109,111,114,203,229,50,0,149,74,101,59,65,54,155,197,117,93,118,82,74,169,45,131,72, - 36,210,68,2,168,86,171,0,212,106,181,142,6,142,227,120,70,237,70,121,7,53,251,31,168,192,0,159,97,230,172,204, - 0,0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t server[408] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,11,18,0, - 0,11,18,1,210,221,126,252,0,0,0,7,116,73,77,69,7,214,2,16,22,3,20,11,54,9,17,0,0,1,37,73, - 68,65,84,56,203,157,146,61,75,195,80,20,134,159,155,92,242,63,164,46,221,2,226,238,32,226,38,82,255,131,17,10, - 34,56,74,196,42,232,228,80,63,210,95,32,4,99,5,255,134,131,110,46,130,56,152,22,170,129,214,170,225,82,18,7, - 13,26,242,97,240,29,207,121,207,203,121,206,189,130,2,181,246,182,61,160,65,185,58,178,164,217,88,152,95,164,86,55, - 115,155,131,167,7,188,174,107,149,5,80,171,155,44,55,47,48,140,180,77,169,9,87,206,10,0,165,1,66,8,12,67, - 98,206,78,3,49,32,0,184,189,190,39,138,190,60,178,140,245,180,189,207,220,20,168,151,30,143,98,134,247,15,197,235, - 56,76,121,100,69,86,122,207,111,223,21,29,128,56,142,127,16,170,176,70,163,97,170,254,123,131,74,172,238,225,82,102, - 179,204,17,117,93,163,63,24,231,178,58,71,7,121,132,118,42,224,230,174,15,177,200,101,93,91,109,166,38,53,77,227, - 196,105,183,100,98,82,106,130,49,28,101,110,144,40,8,130,220,35,203,132,231,242,184,81,248,10,0,238,249,89,97,64, - 199,235,186,214,31,127,222,182,183,118,118,139,2,172,141,245,77,194,48,204,157,76,88,129,194,0,124,223,231,191,146,101, - 124,85,244,9,241,192,132,130,214,14,135,66,0,0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t stateManager[378] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, - 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,6,16,18,41,48,44,67,93,90,0,0,1,7,73, - 68,65,84,56,203,189,146,189,74,3,65,28,196,127,251,145,69,177,176,73,44,124,128,128,207,225,19,8,130,136,31,129, - 136,104,37,34,104,173,32,10,130,181,165,112,6,242,20,190,78,138,120,8,90,104,178,183,123,107,17,15,205,37,94,238, - 82,56,229,252,255,59,179,179,179,226,168,221,4,216,19,130,136,10,8,129,125,224,73,103,135,175,78,46,73,146,1,225, - 123,90,4,33,36,215,15,183,81,8,32,142,15,154,225,188,125,138,148,211,151,245,48,198,153,250,4,175,134,49,55,157, - 14,58,35,30,163,59,250,214,148,186,254,138,177,180,118,47,70,6,25,217,183,134,237,213,151,82,2,221,94,131,193,231, - 59,90,215,144,204,9,169,70,222,114,150,83,183,215,40,20,210,191,115,253,181,156,231,151,148,35,245,14,231,146,31,129, - 245,250,219,92,81,52,128,181,31,60,199,203,149,90,216,202,71,168,218,130,79,253,236,71,44,213,6,64,234,221,255,182, - 48,33,96,236,43,155,27,135,99,131,212,123,164,82,164,222,231,62,208,56,39,90,59,107,247,139,11,254,76,235,218,84, - 7,231,146,194,8,95,134,90,101,183,231,143,210,134,0,0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t timing[897] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,6,98,75,71,68,0,0,0,0,0,0,249,67,187,127,0,0,0,9,112,72,89,115,0,0,13,215,0, - 0,13,215,1,66,40,155,120,0,0,0,7,116,73,77,69,7,213,9,15,8,58,5,128,132,46,85,0,0,3,14,73, - 68,65,84,56,203,101,146,75,76,92,101,28,197,127,223,119,239,188,152,185,119,96,34,8,210,202,35,88,29,108,48,150, - 190,226,162,177,59,220,152,138,193,186,32,26,54,38,68,87,181,53,38,44,77,99,26,31,137,198,68,77,172,53,177,139, - 62,240,17,77,76,163,46,176,5,77,85,40,5,58,88,43,218,17,233,76,167,204,12,195,204,189,195,12,119,190,207,141, - 109,40,158,228,236,206,57,255,71,142,96,19,142,28,24,25,210,146,23,5,226,97,148,14,8,67,122,90,138,27,85,181, - 126,230,157,207,94,127,101,179,94,108,48,246,104,248,116,247,190,71,123,182,247,198,9,71,194,8,1,90,67,113,181,196, - 204,84,130,75,151,230,211,131,195,231,142,245,60,146,10,34,117,146,80,242,180,185,193,124,97,112,120,192,46,27,138,85, - 159,131,40,190,118,103,138,221,113,140,120,224,65,26,59,83,205,141,205,149,55,61,189,115,213,208,191,172,8,183,93,73, - 0,141,62,62,56,60,96,223,88,43,208,254,80,136,104,245,237,187,214,180,235,45,182,110,107,161,119,111,142,104,195,46, - 131,192,187,13,200,167,163,192,14,121,228,192,200,208,238,125,59,118,150,180,71,91,87,35,45,91,226,155,207,68,74,137, - 16,2,51,16,67,178,68,165,116,2,167,52,19,4,253,131,4,6,182,247,198,89,46,103,105,109,109,166,144,255,135,248, - 227,167,72,103,125,119,63,75,8,42,94,31,158,232,39,149,172,114,242,195,7,170,120,242,156,169,209,123,194,145,48,150, - 23,66,41,133,207,103,81,118,139,132,234,44,70,94,218,134,223,222,203,115,109,57,108,219,66,200,24,210,127,16,195,187, - 201,194,212,199,209,161,23,250,131,18,168,23,2,154,154,26,200,23,242,40,165,168,41,141,227,20,57,250,222,239,68,98, - 221,76,76,76,160,148,66,107,133,97,26,152,134,4,165,5,208,101,2,43,90,19,43,187,85,58,58,218,169,84,214,80, - 74,81,44,22,233,238,238,230,229,195,175,114,237,218,85,106,181,26,82,74,180,82,104,13,72,52,176,32,5,226,162,83, - 114,88,252,59,141,82,10,207,243,240,60,143,67,135,14,147,72,36,200,100,210,88,150,69,173,86,195,178,108,202,110,25, - 167,228,128,207,112,63,57,253,150,35,129,179,115,147,243,216,134,133,83,114,241,249,252,140,141,141,49,58,58,74,42,181, - 116,39,48,28,142,160,53,44,95,207,50,55,57,79,133,218,12,128,124,227,203,163,39,126,62,63,53,217,24,182,25,255, - 254,87,180,214,244,245,61,65,58,157,98,173,82,65,107,77,32,16,192,52,77,242,153,28,238,178,203,197,31,167,171,95, - 77,156,121,6,192,0,232,188,183,107,110,97,54,249,236,254,253,143,249,255,252,99,145,92,33,207,253,109,91,8,6,130, - 4,131,33,252,190,0,55,255,202,144,191,190,194,201,15,206,234,217,165,217,247,167,230,127,154,3,178,6,192,76,114,58, - 239,55,253,87,150,174,102,246,52,53,196,162,109,45,173,120,69,143,74,126,141,114,182,204,173,228,45,46,143,207,242,245, - 231,223,174,143,255,118,225,248,249,233,239,190,1,210,64,78,108,232,74,61,208,249,228,174,254,231,239,187,103,235,83,117, - 254,186,22,41,164,169,209,202,93,119,139,233,66,58,241,197,248,169,143,128,20,112,5,88,4,180,224,255,136,252,23,118, - 155,26,40,3,171,64,22,40,0,234,182,248,95,201,36,100,6,22,194,54,223,0,0,0,0,73,69,78,68,174,66,96, - 130, -}; - -const uint8_t unverified[1675] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122, - 244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,6,66,73,68,65,84,88,133,229,151,217,115,84, - 85,30,199,191,231,119,238,146,78,210,183,59,107,147,116,167,151,132,152,72,132,208,128,27,13,9,104,160,28,202,146,161, - 3,79,83,214,164,242,52,207,62,251,224,195,252,13,62,88,53,37,102,134,69,12,250,162,165,14,58,162,65,81,17,179, - 66,7,59,91,111,233,108,244,96,210,33,73,247,237,123,231,161,23,110,98,2,1,103,158,230,86,253,234,156,170,123,239, - 249,124,206,249,253,234,87,117,128,255,247,135,253,158,159,143,118,116,119,106,76,239,37,157,94,253,234,139,191,125,242,36, - 107,208,239,129,103,152,126,94,177,213,32,67,218,135,109,199,186,78,60,201,58,252,73,225,26,99,231,188,190,131,242,169, - 147,29,88,211,56,159,137,70,207,184,234,247,254,28,154,24,8,254,79,5,142,118,116,119,106,132,243,222,67,62,217,225, - 170,195,59,189,223,224,224,179,45,40,85,20,30,143,68,30,91,226,177,4,142,118,116,119,130,211,133,87,94,123,69,42, - 171,182,225,131,43,55,161,105,192,157,169,89,28,122,174,5,102,197,194,167,195,225,199,146,216,182,64,91,71,151,159,56, - 191,248,122,215,105,241,233,150,167,240,246,197,175,0,157,65,32,2,17,67,48,52,7,223,129,93,48,91,44,60,22,10, - 159,113,55,236,187,25,26,239,31,251,175,8,180,117,116,249,193,232,194,159,94,247,75,45,45,77,24,15,207,195,251,180, - 19,7,118,185,112,247,94,18,43,171,105,16,99,24,11,207,227,57,111,19,20,139,149,71,67,83,219,146,120,164,64,91, - 71,151,159,49,186,112,224,240,33,105,207,158,102,68,226,255,6,24,64,44,187,243,249,68,18,139,75,171,16,56,129,24, - 195,100,100,1,251,91,159,202,74,132,31,45,241,80,129,60,124,223,33,159,84,235,172,67,96,124,6,85,21,102,16,17, - 194,211,119,241,237,207,227,152,187,187,4,129,19,4,226,16,136,192,115,239,188,187,119,66,177,150,241,72,40,116,198,221, - 224,221,82,98,203,62,208,126,172,251,20,35,186,224,245,249,164,29,14,59,62,191,54,130,180,154,1,39,2,103,12,137, - 123,247,113,127,37,5,81,224,16,57,135,40,80,97,78,68,184,118,115,12,110,143,27,190,246,118,137,129,125,212,126,188, - 251,15,219,22,104,63,214,125,10,76,191,232,61,152,133,255,235,251,81,112,70,133,99,38,202,206,69,158,135,103,71,129, - 19,132,220,156,51,194,15,131,147,112,215,123,224,59,210,38,211,22,18,191,73,65,30,190,247,69,159,84,227,112,224,155, - 159,126,1,129,65,224,4,119,109,5,170,203,205,32,98,208,52,29,43,43,41,168,25,173,112,244,198,84,8,156,192,25, - 97,110,97,17,187,154,60,80,172,86,33,58,21,58,237,118,183,254,52,53,57,48,182,169,192,145,227,93,127,4,195,251, - 173,47,100,119,254,93,255,120,1,46,16,161,209,85,13,171,82,12,98,12,101,74,49,26,221,54,164,83,42,150,150,215, - 10,223,100,225,188,48,231,68,88,72,36,209,220,232,130,181,204,42,132,67,225,51,70,137,7,41,120,235,45,210,117,246, - 81,149,221,37,181,182,54,227,198,208,36,56,123,144,87,145,115,216,42,20,112,198,178,117,64,12,196,24,86,83,234,186, - 111,178,115,130,73,22,81,91,109,133,44,8,224,140,16,28,159,197,97,223,126,212,185,93,178,78,236,211,223,158,192,213, - 171,122,125,189,119,96,121,121,209,207,4,19,111,110,116,98,62,177,84,200,125,185,165,4,205,245,59,64,68,88,76,174, - 224,202,181,0,198,166,230,145,74,169,133,221,154,100,17,12,217,230,100,171,84,240,236,30,55,146,203,107,72,165,51,216, - 183,219,133,196,92,28,125,125,215,83,200,104,175,230,79,96,93,10,166,38,6,238,120,26,90,71,102,98,81,191,217,98, - 229,77,13,78,220,189,151,4,39,194,174,134,26,84,150,149,130,17,67,40,150,192,226,210,202,131,156,115,66,133,181,4, - 109,207,55,98,109,85,133,36,114,212,213,150,67,49,155,80,93,105,198,254,221,78,68,67,97,156,59,255,97,42,147,86, - 79,94,253,242,236,103,91,22,225,212,248,192,168,167,161,117,36,30,139,250,45,214,50,190,211,227,192,210,242,26,246,63, - 227,130,32,16,136,17,130,147,179,80,85,173,80,108,2,113,232,58,208,224,172,66,173,205,10,103,109,5,44,102,19,136, - 8,149,229,165,24,25,30,197,63,206,93,78,111,132,111,42,96,148,152,142,70,252,86,107,57,63,122,112,55,100,89,0, - 67,182,251,217,42,21,36,147,107,40,41,150,80,95,87,133,213,149,20,158,105,178,67,49,155,10,29,146,136,80,102,41, - 198,224,208,109,244,252,253,114,58,147,86,95,219,8,223,82,96,189,68,180,179,185,201,195,157,142,26,164,83,42,136,8, - 178,40,64,18,57,100,81,64,131,179,26,110,71,37,148,210,34,16,35,176,28,220,170,152,48,56,20,64,79,207,229,116, - 38,157,222,20,254,80,129,188,132,171,222,59,50,60,28,232,116,56,106,72,42,50,97,240,86,12,153,140,134,88,252,30, - 150,146,171,112,218,203,193,11,13,42,11,87,204,121,120,239,67,225,143,20,0,128,208,68,255,168,211,179,119,100,104,232, - 182,159,139,197,188,178,170,28,247,151,83,80,211,26,154,118,238,128,82,106,2,203,117,71,34,6,115,105,81,246,216,123, - 122,211,170,150,57,249,245,23,239,110,9,223,150,64,78,34,104,119,182,4,98,145,200,201,138,138,42,254,114,219,30,216, - 119,88,97,46,41,42,180,102,34,134,210,146,34,12,15,7,240,94,79,111,122,117,109,229,116,223,151,239,253,51,183,132, - 254,36,2,4,64,2,80,4,64,14,79,14,133,170,108,158,224,108,60,126,130,139,37,188,169,209,9,77,211,11,69,87, - 82,44,99,104,56,128,119,123,46,169,139,191,46,252,249,135,190,75,87,1,8,57,70,190,225,105,219,21,16,1,200,27, - 99,58,18,8,91,202,107,39,98,177,217,227,110,151,157,219,107,170,161,105,58,138,77,89,248,217,158,75,234,194,124,244, - 47,253,63,126,220,103,128,231,5,8,217,107,128,110,60,145,205,4,120,78,64,50,68,65,98,102,58,24,43,85,42,38, - 127,25,139,190,228,114,216,169,206,97,195,224,208,109,156,237,185,164,198,167,39,222,24,233,191,114,61,7,55,66,141,247, - 15,29,64,230,81,2,66,78,66,200,9,228,133,100,0,242,220,204,68,188,200,100,14,7,39,166,219,18,137,69,250,248, - 211,43,153,104,248,206,155,163,195,95,223,48,64,141,64,45,23,25,195,184,165,128,102,176,231,134,49,47,198,1,136,11, - 115,161,184,44,149,196,18,191,174,30,142,132,110,253,53,24,184,126,99,3,72,221,16,105,67,20,82,240,176,171,89,190, - 14,36,195,104,12,209,32,152,223,101,30,144,218,16,107,134,113,93,33,110,231,110,152,79,135,132,245,169,201,195,141,133, - 149,49,236,222,40,179,110,215,143,43,176,217,63,70,120,126,141,141,185,222,214,243,31,50,77,124,34,176,20,164,223,0, - 0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t up[652] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114, - 101,0,119,119,119,46,105,110,107,115,99,97,112,101,46,111,114,103,155,238,60,26,0,0,2,30,73,68,65,84,56,141, - 149,147,79,104,19,65,20,198,191,55,187,51,217,141,133,122,104,76,255,209,130,4,237,193,64,42,168,208,213,138,104,68, - 98,69,45,20,114,107,74,201,73,144,98,22,193,171,199,82,145,160,23,15,69,79,30,165,66,241,226,77,42,94,68,80, - 208,67,41,180,42,149,148,52,137,166,154,38,217,217,25,15,81,172,33,169,246,29,223,251,230,199,124,223,155,33,173,53, - 218,213,201,155,124,30,0,150,102,189,233,118,26,214,110,224,184,60,221,223,21,73,246,117,29,76,58,46,79,239,9,224, - 184,60,26,16,251,178,87,206,76,6,199,70,147,193,128,8,102,29,151,71,255,11,224,184,188,3,132,197,137,115,211,214, - 150,151,199,150,183,137,248,200,37,11,132,69,199,229,29,255,4,16,225,209,232,112,162,167,55,52,72,159,75,31,240,177, - 244,30,157,157,157,20,27,58,209,13,194,195,93,1,142,203,211,253,7,34,137,179,71,199,249,74,254,13,12,198,97,50, - 142,87,107,11,136,13,29,23,161,253,61,137,230,60,216,142,195,81,193,237,108,42,225,218,235,229,101,104,242,32,132,137, - 58,125,199,54,21,241,46,255,28,23,78,95,13,154,166,248,43,15,182,211,247,212,88,198,82,228,161,34,75,16,1,1, - 30,224,40,203,117,8,219,64,65,174,162,168,86,113,254,212,69,139,216,159,60,216,111,223,241,99,227,221,135,250,98,148, - 175,172,193,228,6,56,55,80,81,5,84,141,175,16,54,131,176,25,150,191,189,64,184,55,68,71,14,15,135,137,53,242, - 160,145,140,153,30,232,142,100,111,76,220,177,5,15,64,65,194,135,135,215,185,5,188,45,60,131,100,21,16,35,36,6, - 50,208,90,67,41,160,94,175,225,241,211,249,74,177,180,57,99,18,67,234,83,110,197,158,185,119,185,225,137,163,122,247, - 250,19,171,44,115,240,141,109,112,193,192,76,130,193,9,115,15,110,87,101,77,91,191,236,7,137,33,101,46,205,122,78, - 211,38,180,214,10,165,250,23,48,131,96,112,6,30,104,64,100,77,91,47,231,60,218,245,29,0,128,210,62,126,212,139, - 141,43,251,26,178,174,160,85,235,63,99,182,106,250,74,162,90,219,134,50,53,160,21,124,73,240,189,61,0,164,47,17, - 31,188,6,98,0,49,2,17,246,0,32,108,220,186,63,25,110,37,38,194,70,115,239,39,48,247,197,219,182,208,154,34, - 0,0,0,0,73,69,78,68,174,66,96,130, -}; - -const uint8_t video[662] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255, - 97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13, - 215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99, - 97,112,101,46,111,114,103,155,238,60,26,0,0,2,19,73,68,65,84,56,141,165,147,203,106,20,65,20,134,191,83,85, - 115,109,72,50,32,6,98,18,35,38,11,183,222,54,186,112,99,6,29,240,25,124,4,55,130,184,81,80,4,241,49,124, - 131,108,92,8,9,17,34,226,222,96,188,129,38,16,131,97,72,156,233,234,233,158,238,58,46,58,17,19,3,65,60,155, - 42,170,234,255,207,119,206,161,164,221,110,243,63,225,58,157,206,29,17,121,168,170,181,127,17,138,136,87,213,187,78,85, - 31,183,111,92,143,154,141,38,121,174,199,103,116,130,181,134,110,183,91,95,90,124,245,196,169,106,109,116,116,132,249,155, - 207,73,233,3,160,122,132,209,222,81,77,34,94,190,184,205,200,232,40,64,195,237,223,167,161,207,133,171,99,136,200,30, - 34,128,148,171,0,90,238,223,44,111,179,250,238,61,83,83,147,37,81,154,166,128,160,226,136,211,80,10,20,68,228,128, - 73,54,204,217,238,254,4,28,103,103,103,49,18,74,3,239,61,33,20,24,99,24,228,82,102,43,155,4,148,194,205,31, - 59,196,62,5,160,97,90,124,88,91,99,122,122,146,36,73,112,73,146,80,20,1,140,35,201,203,108,138,32,64,156,164, - 236,244,18,84,29,149,250,94,181,137,101,122,230,52,21,103,240,222,227,226,56,70,131,98,76,133,65,112,251,0,36,233, - 144,108,104,112,181,232,224,248,172,229,243,199,79,204,205,205,210,239,247,75,2,69,17,107,73,131,3,5,69,81,107,169, - 216,35,134,97,135,76,156,154,192,24,202,18,188,247,0,24,227,176,213,232,111,197,161,24,154,62,69,81,160,8,113,28, - 227,66,40,187,217,106,56,178,205,193,177,6,81,213,33,70,49,34,37,129,115,174,183,254,109,163,245,236,209,249,99,197, - 191,41,210,156,245,245,13,128,29,233,116,58,183,106,181,218,3,17,141,64,12,48,83,169,56,87,169,86,197,26,3,64, - 17,2,89,150,105,62,204,135,192,87,208,160,202,174,247,201,125,151,231,249,66,158,231,11,0,170,26,181,78,140,189,157, - 111,183,207,93,186,120,153,241,147,227,168,42,91,91,223,89,121,189,162,75,203,75,171,73,111,112,37,203,50,191,79,35, - 135,191,179,49,102,164,222,172,63,109,70,205,107,214,154,51,128,22,161,248,50,240,131,197,222,110,255,158,136,196,127,190, - 255,5,119,143,242,70,185,147,13,30,0,0,0,0,73,69,78,68,174,66,96,130, -}; - -}; diff --git a/target-higan/resource/resource.hpp b/target-higan/resource/resource.hpp deleted file mode 100644 index 8a518946..00000000 --- a/target-higan/resource/resource.hpp +++ /dev/null @@ -1,16 +0,0 @@ -namespace resource { - extern const uint8_t advanced[611]; - extern const uint8_t audio[592]; - extern const uint8_t cheatEditor[937]; - extern const uint8_t folder[1176]; - extern const uint8_t game[1490]; - extern const uint8_t home[606]; - extern const uint8_t hotkeys[587]; - extern const uint8_t input[812]; - extern const uint8_t server[408]; - extern const uint8_t stateManager[378]; - extern const uint8_t timing[897]; - extern const uint8_t unverified[1675]; - extern const uint8_t up[652]; - extern const uint8_t video[662]; -}; diff --git a/target-higan/resource/unverified.png b/target-higan/resource/unverified.png deleted file mode 100644 index 8a150b847114e2468c61b01cf0119c7fbca15f11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1675 zcmV;626Xv}P)hA?9>>4uckYr-(ziQnlXRz-gqTQ#(105a322}k%95c2 zPgB;U@-)vr`{2X;4L(>kC1!?24Emy_4mzSiQ4zC32RmDD>1_01(jiIr?R)2;7j9w# z0cW1(R{iRns(bJGe9rm(>Q{Au|M!Reo}Z6)ba!e@?j~n0{Wd z)gVLKhi%8YPCUsv{7K;&W9PiSgYv199az&ipNU4#xa#-*9GVyi{!aytc64`Yg!A4* zKH1@_!#lm-;NY_@C{+|5k3=3@;;{sdc64`w(}h=Fdqpa%w&8;-H=$|3ovB$Idaea# z#lok<;m4BLwm@4)m!CMl_zPJb#(c`=)#{~_e(7;O&AZ)!~3)o2X?t|_g)e!t7#Bp7z@wiId2mbi#Rdydg!|1jGBSFJyQAUH^CiE)b#7RSm0B z3}OsrN--MUHl$N3mX_BF-(=yuFy};ANF>qR=z_J(DuhGfGe(IADR}EG(slMxmE9$^ zwl?F&&?Go}kXMm&*eVoo#@a!HplFMsIr8C&K+l9nj9DRM)Q^;tq=1*W<3Z^Co?sytnM`mJCzu98t zO$|=my_WDu@WOC_oZ9WKlqavl?zkC6v-45F@Z0+^U!`I21rn&*gL`o!%7w zP=UOJtKK^@JRInBIBG~LGGXvm44I6ESo|KAlB;mq%fSl`DhpT4d3f(b;g1vmfY3z$ zsME7|WN7HNpNqx3vZ@^Sms3#F8k%ds-bB*icMMg*`7=4!hG~E{Xc%(XMpDg z2-$0ZZak6A1b9wBGDJaQW;z%vRVpTb8H>K;a@eWPVZ-3iZJh17q{gQw-Wch>ayrrQ#UMf&*DE178c&YPpdU*9l5jX*6I z8N;}xfM&4ghA}V30f-B8p|~uS#1g-*9*%@={WTc4eq#ej-4JO*6jJc8t69DdB*SP7 z(IA-LWgd{)5Nn2UT_JAgZkSJpg!QS(!;OWNG3?$bvu@XqE3nx=MtFXWjk(^|^B*!z Vd?K(Eq~8Dl002ovPDHLkV1lXf8uI`E diff --git a/target-higan/settings/advanced.cpp b/target-higan/settings/advanced.cpp deleted file mode 100644 index 508c11a9..00000000 --- a/target-higan/settings/advanced.cpp +++ /dev/null @@ -1,81 +0,0 @@ -AdvancedSettings* advancedSettings = nullptr; - -AdvancedSettings::AdvancedSettings() { - driverTitle.setFont(program->boldFont); - driverTitle.setText("Driver Selection:"); - videoLabel.setText("Video:"); - audioLabel.setText("Audio:"); - inputLabel.setText("Input:"); - libraryTitle.setFont(program->boldFont); - libraryTitle.setText("Game Library:"); - libraryLabel.setText("Path:"); - libraryPath.setEditable(false); - libraryPath.setText(utility->libraryPath()); - libraryBrowse.setText("Browse ..."); - libraryShowOnStartup.setChecked(config->library.showOnStartup); - libraryShowOnStartup.setText("Show game library on program start"); - information.setText("Note: changing advanced settings requires program restart to take effect."); - infoLabel.setFont(program->boldFont); - infoLabel.setText({ - Emulator::Name, " v", Emulator::Version, "\n", - " ", Emulator::Profile, " Profile\n", - " Author: ", Emulator::Author, "\n", - " License: ", Emulator::License, "\n", - " Website: ", Emulator::Website - }); - - lstring list; - - list.split(";", video.availableDrivers()); - for(unsigned n = 0; n < list.size(); n++) { - videoDriver.append(list[n]); - if(list[n] == config->video.driver) videoDriver.setSelection(n); - } - - list.split(";", audio.availableDrivers()); - for(unsigned n = 0; n < list.size(); n++) { - audioDriver.append(list[n]); - if(list[n] == config->audio.driver) audioDriver.setSelection(n); - } - - list.split(";", input.availableDrivers()); - for(unsigned n = 0; n < list.size(); n++) { - inputDriver.append(list[n]); - if(list[n] == config->input.driver) inputDriver.setSelection(n); - } - - append(driverTitle, {~0, 0}); - append(driverLayout, {~0, 0}, 15); - driverLayout.append(videoLabel, {0, 0}, 5); - driverLayout.append(videoDriver, {~0, 0}, 5); - driverLayout.append(audioLabel, {0, 0}, 5); - driverLayout.append(audioDriver, {~0, 0}, 5); - driverLayout.append(inputLabel, {0, 0}, 5); - driverLayout.append(inputDriver, {~0, 0}); - append(libraryTitle, {~0, 0}); - append(libraryLayout, {~0, 0}); - libraryLayout.append(libraryLabel, {0, 0}, 5); - libraryLayout.append(libraryPath, {~0, 0}, 5); - libraryLayout.append(libraryBrowse, {80, 0}); - append(libraryShowOnStartup, {~0, 0}, 15); - append(information, {~0, 0}, 15); - if(Intrinsics::platform() != Intrinsics::Platform::MacOSX) { - append(spacer, {~0, ~0}); - append(infoLabel, {~0, 0}); - } - - videoDriver.onChange = [&] { config->video.driver = videoDriver.text(); }; - audioDriver.onChange = [&] { config->audio.driver = audioDriver.text(); }; - inputDriver.onChange = [&] { config->input.driver = inputDriver.text(); }; - - libraryBrowse.onActivate = [&] { - string path = BrowserWindow().setParent(*settings).setPath(userpath()).directory(); - if(path.empty()) return; - file::write({configpath(), "higan/library.bml"}, {"Path: ", path, "\n"}); - libraryPath.setText(path); - }; - - libraryShowOnStartup.onToggle = [&] { - config->library.showOnStartup = libraryShowOnStartup.checked(); - }; -} diff --git a/target-higan/settings/advanced.hpp b/target-higan/settings/advanced.hpp deleted file mode 100644 index eaf0041a..00000000 --- a/target-higan/settings/advanced.hpp +++ /dev/null @@ -1,26 +0,0 @@ -struct AdvancedSettings : SettingsLayout { - Label driverTitle; - HorizontalLayout driverLayout; - Label videoLabel; - ComboButton videoDriver; - Label audioLabel; - ComboButton audioDriver; - Label inputLabel; - ComboButton inputDriver; - - Label libraryTitle; - HorizontalLayout libraryLayout; - Label libraryLabel; - LineEdit libraryPath; - Button libraryBrowse; - CheckLabel libraryShowOnStartup; - - Label information; - - Widget spacer; - Label infoLabel; - - AdvancedSettings(); -}; - -extern AdvancedSettings* advancedSettings; diff --git a/target-higan/settings/audio.cpp b/target-higan/settings/audio.cpp deleted file mode 100644 index 6059576c..00000000 --- a/target-higan/settings/audio.cpp +++ /dev/null @@ -1,79 +0,0 @@ -AudioSettings* audioSettings = nullptr; - -AudioSlider::AudioSlider() { - append(name, {75, 0}); - append(value, {75, 0}); - append(slider, {~0, 0}); -} - -AudioSettings::AudioSettings() { - frequencyLabel.setText("Frequency:"); - frequency.append("32000hz"); - frequency.append("44100hz"); - frequency.append("48000hz"); - frequency.append("96000hz"); - latencyLabel.setText("Latency:"); - latency.append("20ms"); - latency.append("40ms"); - latency.append("60ms"); - latency.append("80ms"); - latency.append("100ms"); - resamplerLabel.setText("Resampler:"); - resampler.append("Linear"); - resampler.append("Hermite"); - resampler.append("Sinc"); - volume.name.setText("Volume:"); - volume.slider.setLength(201); - - append(controlLayout, {~0, 0}, 5); - controlLayout.append(frequencyLabel, {0, 0}, 5); - controlLayout.append(frequency, {~0, 0}, 5); - controlLayout.append(latencyLabel, {0, 0}, 5); - controlLayout.append(latency, {~0, 0}, 5); - controlLayout.append(resamplerLabel, {0, 0}, 5); - controlLayout.append(resampler, {~0, 0}); - append(volume, {~0, 0}); - - switch(config->audio.frequency) { default: - case 32000: frequency.setSelection(0); break; - case 44100: frequency.setSelection(1); break; - case 48000: frequency.setSelection(2); break; - case 96000: frequency.setSelection(3); break; - } - switch(config->audio.latency) { default: - case 20: latency.setSelection(0); break; - case 40: latency.setSelection(1); break; - case 60: latency.setSelection(2); break; - case 80: latency.setSelection(3); break; - case 100: latency.setSelection(4); break; - } - resampler.setSelection(config->audio.resampler); - volume.slider.setPosition(config->audio.volume); - - frequency.onChange = latency.onChange = resampler.onChange = volume.slider.onChange = - {&AudioSettings::synchronize, this}; - - synchronize(); -} - -void AudioSettings::synchronize() { - switch(frequency.selection()) { - case 0: config->audio.frequency = 32000; break; - case 1: config->audio.frequency = 44100; break; - case 2: config->audio.frequency = 48000; break; - case 3: config->audio.frequency = 96000; break; - } - switch(latency.selection()) { - case 0: config->audio.latency = 20; break; - case 1: config->audio.latency = 40; break; - case 2: config->audio.latency = 60; break; - case 3: config->audio.latency = 80; break; - case 4: config->audio.latency = 100; break; - } - config->audio.resampler = resampler.selection(); - config->audio.volume = volume.slider.position(); - - volume.value.setText({config->audio.volume, "%"}); - - utility->synchronizeRuby(); -} diff --git a/target-higan/settings/audio.hpp b/target-higan/settings/audio.hpp deleted file mode 100644 index d27fcfc8..00000000 --- a/target-higan/settings/audio.hpp +++ /dev/null @@ -1,23 +0,0 @@ -struct AudioSlider : HorizontalLayout { - Label name; - Label value; - HorizontalSlider slider; - - AudioSlider(); -}; - -struct AudioSettings : SettingsLayout { - HorizontalLayout controlLayout; - Label frequencyLabel; - ComboButton frequency; - Label latencyLabel; - ComboButton latency; - Label resamplerLabel; - ComboButton resampler; - AudioSlider volume; - - void synchronize(); - AudioSettings(); -}; - -extern AudioSettings* audioSettings; diff --git a/target-higan/settings/hotkey.cpp b/target-higan/settings/hotkey.cpp deleted file mode 100644 index e5ec041e..00000000 --- a/target-higan/settings/hotkey.cpp +++ /dev/null @@ -1,58 +0,0 @@ -HotkeySettings* hotkeySettings = nullptr; - -HotkeySettings::HotkeySettings() { - inputList.setHeaderText({"Name", "Mapping"}); - inputList.setHeaderVisible(); - eraseButton.setText("Erase"); - - append(inputList, {~0, ~0}, 5); - append(controlLayout, {~0, 0}); - controlLayout.append(spacer, {~0, 0}); - controlLayout.append(eraseButton, {80, 0}); - - inputList.onChange = {&HotkeySettings::synchronize, this}; - inputList.onActivate = {&HotkeySettings::assignInput, this}; - eraseButton.onActivate = {&HotkeySettings::eraseInput, this}; - - for(auto& hotkey : inputManager->hotkeyMap) inputList.append({"", ""}); - refresh(); -} - -void HotkeySettings::synchronize() { - eraseButton.setEnabled(inputList.selected()); -} - -void HotkeySettings::refresh() { - unsigned index = 0; - for(auto& hotkey : inputManager->hotkeyMap) { - string mapping = inputManager->sanitize(hotkey->mapping, " and "); - inputList.setText(index++, {hotkey->name, mapping}); - } - synchronize(); -} - -void HotkeySettings::eraseInput() { - activeInput = inputManager->hotkeyMap[inputList.selection()]; - inputEvent(hidNull, 0, 0, 0, 1); -} - -void HotkeySettings::assignInput() { - activeInput = inputManager->hotkeyMap[inputList.selection()]; - - settings->setStatusText({"Set assignment for [", activeInput->name, "] ..."}); - settings->layout.setEnabled(false); - setEnabled(false); -} - -void HotkeySettings::inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) { - if(activeInput == nullptr) return; - if(device.isMouse()) return; - if(device.isJoypad() && group == HID::Joypad::GroupID::Axis) return; - if(activeInput->bind(device, group, input, oldValue, newValue) == false) return; - - activeInput = nullptr; - settings->setStatusText(""); - settings->layout.setEnabled(true); - setEnabled(true); - refresh(); -} diff --git a/target-higan/settings/hotkey.hpp b/target-higan/settings/hotkey.hpp deleted file mode 100644 index c254df73..00000000 --- a/target-higan/settings/hotkey.hpp +++ /dev/null @@ -1,18 +0,0 @@ -struct HotkeySettings : SettingsLayout { - ListView inputList; - HorizontalLayout controlLayout; - Widget spacer; - Button eraseButton; - - void synchronize(); - void refresh(); - void eraseInput(); - void assignInput(); - void inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue); - HotkeySettings(); - -private: - HotkeyInput* activeInput = nullptr; -}; - -extern HotkeySettings* hotkeySettings; diff --git a/target-higan/settings/input.cpp b/target-higan/settings/input.cpp deleted file mode 100644 index b720524c..00000000 --- a/target-higan/settings/input.cpp +++ /dev/null @@ -1,187 +0,0 @@ -InputSettings* inputSettings = nullptr; - -InputSettings::InputSettings() { - focusLabel.setText("When Focus is Lost:"); - focusPause.setText("Pause Emulation"); - focusAllow.setText("Allow Input"); - inputList.setHeaderText({"Name", "Mapping"}); - inputList.setHeaderVisible(); - resetButton.setText("Reset"); - eraseButton.setText("Erase"); - - append(focusLayout, {~0, 0}, 5); - focusLayout.append(focusLabel, {0, 0}, 5); - focusLayout.append(focusPause, {0, 0}, 5); - focusLayout.append(focusAllow, {0, 0}); - append(selectionLayout, {~0, 0}, 5); - selectionLayout.append(systemList, {~0, 0}, 5); - selectionLayout.append(portList, {~0, 0}, 5); - selectionLayout.append(deviceList, {~0, 0}); - append(inputList, {~0, ~0}, 5); - append(controlLayout, {~0, 0}); - controlLayout.append(assign[0], {100, 0}, 5); - controlLayout.append(assign[1], {100, 0}, 5); - controlLayout.append(assign[2], {100, 0}, 5); - controlLayout.append(spacer, {~0, 0}); - controlLayout.append(resetButton, {80, 0}, 5); - controlLayout.append(eraseButton, {80, 0}); - - for(auto& emulator : program->emulator) { - systemList.append(emulator->information.name); - } - - focusPause.setChecked(config->input.focus.pause); - focusAllow.setChecked(config->input.focus.allow); - focusAllow.setEnabled(!config->input.focus.pause); - - focusPause.onToggle = [&] { config->input.focus.pause = focusPause.checked(); focusAllow.setEnabled(!focusPause.checked()); }; - focusAllow.onToggle = [&] { config->input.focus.allow = focusAllow.checked(); }; - systemList.onChange = {&InputSettings::systemChanged, this}; - portList.onChange = {&InputSettings::portChanged, this}; - deviceList.onChange = {&InputSettings::deviceChanged, this}; - inputList.onChange = {&InputSettings::synchronize, this}; - inputList.onActivate = {&InputSettings::assignInput, this}; - assign[0].onActivate = [&] { assignMouseInput(0); }; - assign[1].onActivate = [&] { assignMouseInput(1); }; - assign[2].onActivate = [&] { assignMouseInput(2); }; - resetButton.onActivate = {&InputSettings::resetInput, this}; - eraseButton.onActivate = {&InputSettings::eraseInput, this}; - - systemChanged(); -} - -void InputSettings::synchronize() { - if(inputList.selected() == false) { - assign[0].setVisible(false); - assign[1].setVisible(false); - assign[2].setVisible(false); - } else { - unsigned number = activeDevice().order[inputList.selection()]; - auto& input = activeDevice().input[number]; - auto selectedInput = inputManager->inputMap[input.guid]; - - if(dynamic_cast(selectedInput)) { - assign[0].setText("Mouse Left"); - assign[1].setText("Mouse Middle"); - assign[2].setText("Mouse Right"); - assign[0].setVisible(true); - assign[1].setVisible(true); - assign[2].setVisible(true); - } - - if(dynamic_cast(selectedInput)) { - assign[0].setText("Mouse X-axis"); - assign[1].setText("Mouse Y-axis"); - assign[0].setVisible(true); - assign[1].setVisible(true); - assign[2].setVisible(false); - } - } - - eraseButton.setEnabled(inputList.selected()); -} - -Emulator::Interface& InputSettings::activeSystem() { - return *program->emulator[systemList.selection()]; -} - -Emulator::Interface::Port& InputSettings::activePort() { - return activeSystem().port[portList.selection()]; -} - -Emulator::Interface::Device& InputSettings::activeDevice() { - return activePort().device[deviceList.selection()]; -} - -void InputSettings::systemChanged() { - portList.reset(); - for(auto& port : activeSystem().port) { - portList.append(port.name); - } - portChanged(); -} - -void InputSettings::portChanged() { - deviceList.reset(); - for(auto& device : activePort().device) { - deviceList.append(device.name); - } - deviceChanged(); -} - -void InputSettings::deviceChanged() { - inputList.reset(); - for(unsigned number : activeDevice().order) inputList.append({"", ""}); - inputChanged(); - synchronize(); -} - -void InputSettings::inputChanged() { - unsigned index = 0; - for(unsigned number : activeDevice().order) { - auto& input = activeDevice().input[number]; - auto abstract = inputManager->inputMap(input.guid); - string mapping = inputManager->sanitize(abstract->mapping, " or "); - inputList.setText(index++, {input.name, mapping}); - } -} - -void InputSettings::resetInput() { - if(MessageWindow().setParent(*settings).setText("All inputs will be erased. Are you sure you want to do this?") - .question() == MessageWindow::Response::No) return; - - auto& device = activeDevice(); - unsigned length = device.input.size(); - for(unsigned n = 0; n < length; n++) { - activeInput = inputManager->inputMap[device.input[n].guid]; - inputEvent(hidNull, 0, 0, 0, 1); - } -} - -void InputSettings::eraseInput() { - unsigned number = activeDevice().order[inputList.selection()]; - auto& input = activeDevice().input[number]; - activeInput = inputManager->inputMap[input.guid]; - inputEvent(hidNull, 0, 0, 0, 1); -} - -void InputSettings::assignInput() { - unsigned number = activeDevice().order[inputList.selection()]; - auto& input = activeDevice().input[number]; - activeInput = inputManager->inputMap[input.guid]; - - settings->setStatusText({"Set assignment for [", activeDevice().name, "::", input.name, "] ..."}); - settings->layout.setEnabled(false); - setEnabled(false); -} - -void InputSettings::assignMouseInput(unsigned n) { - unsigned number = activeDevice().order[inputList.selection()]; - auto& input = activeDevice().input[number]; - activeInput = inputManager->inputMap[input.guid]; - - if(dynamic_cast(activeInput)) { - if(auto hidMouse = inputManager->findMouse()) { - return inputEvent(*hidMouse, HID::Mouse::GroupID::Button, n, 0, 1, true); - } - } - - if(dynamic_cast(activeInput)) { - if(auto hidMouse = inputManager->findMouse()) { - return inputEvent(*hidMouse, HID::Mouse::GroupID::Axis, n, 0, +32767, true); - } - } -} - -void InputSettings::inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue, bool allowMouseInput) { - if(activeInput == nullptr) return; - if(allowMouseInput == false && device.isMouse()) return; - if(activeInput->bind(device, group, input, oldValue, newValue) == false) return; - - activeInput = nullptr; - inputChanged(); - settings->setStatusText(""); - settings->layout.setEnabled(true); - setEnabled(true); - synchronize(); -} diff --git a/target-higan/settings/input.hpp b/target-higan/settings/input.hpp deleted file mode 100644 index 20a505f3..00000000 --- a/target-higan/settings/input.hpp +++ /dev/null @@ -1,38 +0,0 @@ -struct InputSettings : SettingsLayout { - HorizontalLayout focusLayout; - Label focusLabel; - CheckLabel focusPause; - CheckLabel focusAllow; - HorizontalLayout selectionLayout; - ComboButton systemList; - ComboButton portList; - ComboButton deviceList; - ListView inputList; - HorizontalLayout controlLayout; - Button assign[3]; - Widget spacer; - Button resetButton; - Button eraseButton; - - void synchronize(); - - Emulator::Interface& activeSystem(); - Emulator::Interface::Port& activePort(); - Emulator::Interface::Device& activeDevice(); - - void systemChanged(); - void portChanged(); - void deviceChanged(); - void inputChanged(); - void resetInput(); - void eraseInput(); - void assignInput(); - void assignMouseInput(unsigned n); - void inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue, bool allowMouseInput = false); - InputSettings(); - -private: - AbstractInput* activeInput = nullptr; -}; - -extern InputSettings* inputSettings; diff --git a/target-higan/settings/server.cpp b/target-higan/settings/server.cpp deleted file mode 100644 index 44e4fd1a..00000000 --- a/target-higan/settings/server.cpp +++ /dev/null @@ -1,29 +0,0 @@ -ServerSettings* serverSettings = nullptr; - -ServerSettings::ServerSettings() { - hostLabel.setText("Hostname:"); - userLabel.setText("Username:"); - passLabel.setText("Password:"); - - unsigned width = min( - Font::size(program->normalFont, "Hostname:").width, - Font::size(program->normalFont, "Username:").width - ); - - append(hostLayout, {~0, 0}, 5); - hostLayout.append(hostLabel, {width, 0}, 5); - hostLayout.append(hostEdit, {~0, 0}); - append(userLayout, {~0, 0}); - userLayout.append(userLabel, {width, 0}, 5); - userLayout.append(userEdit, {~0, 0}, 5); - userLayout.append(passLabel, {0, 0}, 5); - userLayout.append(passEdit, {~0, 0}); - - hostEdit.setText(config->server.hostname); - userEdit.setText(config->server.username); - passEdit.setText(config->server.password); - - hostEdit.onChange = [&] { config->server.hostname = hostEdit.text(); }; - userEdit.onChange = [&] { config->server.username = userEdit.text(); }; - passEdit.onChange = [&] { config->server.password = passEdit.text(); }; -} diff --git a/target-higan/settings/server.hpp b/target-higan/settings/server.hpp deleted file mode 100644 index 617c49c2..00000000 --- a/target-higan/settings/server.hpp +++ /dev/null @@ -1,14 +0,0 @@ -struct ServerSettings : SettingsLayout { - HorizontalLayout hostLayout; - Label hostLabel; - LineEdit hostEdit; - HorizontalLayout userLayout; - Label userLabel; - LineEdit userEdit; - Label passLabel; - LineEdit passEdit; - - ServerSettings(); -}; - -extern ServerSettings* serverSettings; diff --git a/target-higan/settings/settings.cpp b/target-higan/settings/settings.cpp deleted file mode 100644 index b9be5910..00000000 --- a/target-higan/settings/settings.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "../higan.hpp" -#include "video.cpp" -#include "audio.cpp" -#include "input.cpp" -#include "hotkey.cpp" -#include "timing.cpp" -#include "server.cpp" -#include "advanced.cpp" -Settings* settings = nullptr; - -SettingsLayout::SettingsLayout() { - setMargin(5); -} - -Settings::Settings() { - setGeometry({128, 128, 640, 360}); - windowManager->append(this, "Settings"); - - setTitle("Configuration Settings"); - setStatusVisible(); - - layout.setMargin(5); - panels.append("Video", {resource::video, sizeof resource::video}); - panels.append("Audio", {resource::audio, sizeof resource::audio}); - panels.append("Input", {resource::input, sizeof resource::input}); - panels.append("Hotkeys", {resource::hotkeys, sizeof resource::hotkeys}); - panels.append("Timing", {resource::timing, sizeof resource::timing}); - panels.append("Server", {resource::server, sizeof resource::server}); - panels.append("Advanced", {resource::advanced, sizeof resource::advanced}); - panels.setLayout(0, *videoSettings); - panels.setLayout(1, *audioSettings); - panels.setLayout(2, *inputSettings); - panels.setLayout(3, *hotkeySettings); - panels.setLayout(4, *timingSettings); - panels.setLayout(5, *serverSettings); - panels.setLayout(6, *advancedSettings); - panels.setSelection(2); - - append(layout); - layout.append(panels, {~0, ~0}); - - onClose = [&] { - timingSettings->analysis.stop = true; - setVisible(false); - }; -} diff --git a/target-higan/settings/settings.hpp b/target-higan/settings/settings.hpp deleted file mode 100644 index db3e8235..00000000 --- a/target-higan/settings/settings.hpp +++ /dev/null @@ -1,20 +0,0 @@ -struct SettingsLayout : VerticalLayout { - SettingsLayout(); -}; - -#include "video.hpp" -#include "audio.hpp" -#include "input.hpp" -#include "hotkey.hpp" -#include "timing.hpp" -#include "server.hpp" -#include "advanced.hpp" - -struct Settings : Window { - VerticalLayout layout; - TabFrame panels; - - Settings(); -}; - -extern Settings* settings; diff --git a/target-higan/settings/timing.cpp b/target-higan/settings/timing.cpp deleted file mode 100644 index 3fdc0c36..00000000 --- a/target-higan/settings/timing.cpp +++ /dev/null @@ -1,126 +0,0 @@ -TimingSettings* timingSettings = nullptr; - -TimingAdjustment::TimingAdjustment() { - assign.setEnabled(false); - assign.setText("Assign"); - analyze.setText("Analyze"); - stop.setEnabled(false); - stop.setText("Stop"); - - append(name, {40, 0}); - append(value, {100, 0}, 5); - append(assign, {80, 0}, 5); - append(spacer, {~0, 0}); - append(analyze, {80, 0}, 5); - append(stop, {80, 0}); -} - -TimingSettings::TimingSettings() { - videoAdjust.name.setText("Video:"); - videoAdjust.value.setText({config->timing.video}); - audioAdjust.name.setText("Audio:"); - audioAdjust.value.setText({config->timing.audio}); - - append(videoAdjust, {~0, 0}, 5); - append(audioAdjust, {~0, 0}, 5); - - videoAdjust.value.onChange = [&] { videoAdjust.assign.setEnabled(true); }; - audioAdjust.value.onChange = [&] { audioAdjust.assign.setEnabled(true); }; - videoAdjust.assign.onActivate = [&] { - config->timing.video = atof(videoAdjust.value.text()); - videoAdjust.value.setText({config->timing.video}); - videoAdjust.assign.setEnabled(false); - utility->synchronizeDSP(); - }; - audioAdjust.assign.onActivate = [&] { - config->timing.audio = atof(audioAdjust.value.text()); - audioAdjust.value.setText({config->timing.audio}); - audioAdjust.assign.setEnabled(false); - utility->synchronizeDSP(); - }; - videoAdjust.analyze.onActivate = {&TimingSettings::analyzeVideoFrequency, this}; - audioAdjust.analyze.onActivate = {&TimingSettings::analyzeAudioFrequency, this}; - videoAdjust.stop.onActivate = audioAdjust.stop.onActivate = [&] { analysis.stop = true; }; -} - -void TimingSettings::analyzeVideoFrequency() { - video.set(Video::Synchronize, true); - audio.set(Audio::Synchronize, false); - videoAdjust.stop.setEnabled(true); - analyzeStart(); - do { - uint32_t* output; - unsigned pitch; - if(video.lock(output, pitch, 16, 16)) { - pitch >>= 2; - for(unsigned y = 0; y < 16; y++) memset(output + y * pitch, 0, 4 * 16); - video.unlock(); - video.refresh(); - } - } while(analyzeTick("Video")); - analyzeStop(); -} - -void TimingSettings::analyzeAudioFrequency() { - video.set(Video::Synchronize, false); - audio.set(Audio::Synchronize, true); - audioAdjust.stop.setEnabled(true); - analyzeStart(); - do { - audio.sample(0, 0); - } while(analyzeTick("Audio")); - analyzeStop(); -} - -void TimingSettings::analyzeStart() { - audio.clear(); - -//settings->panels.setEnabled(false); - videoAdjust.analyze.setEnabled(false); - audioAdjust.analyze.setEnabled(false); - settings->setStatusText("Initializing ..."); - Application::processEvents(); - - analysis.stop = false; - analysis.seconds = 0; - analysis.counter = 0; - analysis.sample.reset(); - analysis.systemTime = time(0); -} - -bool TimingSettings::analyzeTick(string type) { - analysis.counter++; - - time_t systemTime = time(0); - if(systemTime > analysis.systemTime) { - analysis.systemTime = systemTime; - Application::processEvents(); - - if(analysis.seconds < 3) { - analysis.seconds++; - } else { - analysis.sample.append(analysis.counter); - uintmax_t sum = 0; - for(auto& point : analysis.sample) sum += point; - settings->setStatusText({ - type, " sample rate: ", (double)sum / analysis.sample.size(), "hz", - " (", analysis.sample.size(), " sample points)" - }); - } - - analysis.counter = 0; - } - - return !analysis.stop; -} - -void TimingSettings::analyzeStop() { - video.set(Video::Synchronize, config->video.synchronize); - audio.set(Audio::Synchronize, config->audio.synchronize); - -//settings->panels.setEnabled(true); - videoAdjust.analyze.setEnabled(true); - audioAdjust.analyze.setEnabled(true); - videoAdjust.stop.setEnabled(false); - audioAdjust.stop.setEnabled(false); -} diff --git a/target-higan/settings/timing.hpp b/target-higan/settings/timing.hpp deleted file mode 100644 index 8c89cc9b..00000000 --- a/target-higan/settings/timing.hpp +++ /dev/null @@ -1,34 +0,0 @@ -struct TimingAdjustment : HorizontalLayout { - Label name; - LineEdit value; - Button assign; - Widget spacer; - Button analyze; - Button stop; - - TimingAdjustment(); -}; - -struct TimingSettings : SettingsLayout { - TimingAdjustment videoAdjust; - TimingAdjustment audioAdjust; - - void analyzeVideoFrequency(); - void analyzeAudioFrequency(); - - void analyzeStart(); - bool analyzeTick(string type); - void analyzeStop(); - - TimingSettings(); - - struct Analysis { - bool stop; - unsigned seconds; - unsigned counter; - vector sample; - time_t systemTime; - } analysis; -}; - -extern TimingSettings* timingSettings; diff --git a/target-higan/settings/video.cpp b/target-higan/settings/video.cpp deleted file mode 100644 index 6d33aadf..00000000 --- a/target-higan/settings/video.cpp +++ /dev/null @@ -1,64 +0,0 @@ -VideoSettings* videoSettings = nullptr; - -VideoSlider::VideoSlider() { - append(name, {75, 0}); - append(value, {75, 0}); - append(slider, {~0, 0}); -} - -VideoSettings::VideoSettings() { - colorAdjustment.setFont(program->boldFont); - colorAdjustment.setText("Color adjustment:"); - saturation.name.setText("Saturation:"); - saturation.slider.setLength(201); - gamma.name.setText("Gamma:"); - gamma.slider.setLength(101); - luminance.name.setText("Luminance:"); - luminance.slider.setLength(101); - colorEmulation.setText("Color emulation"); - overscanAdjustment.setFont(program->boldFont); - overscanAdjustment.setText("Overscan mask:"); - overscanHorizontal.name.setText("Horizontal:"); - overscanHorizontal.slider.setLength(17); - overscanVertical.name.setText("Vertical:"); - overscanVertical.slider.setLength(17); - - append(colorAdjustment, {~0, 0}); - append(saturation, {~0, 0}); - append(gamma, {~0, 0}); - append(luminance, {~0, 0}); - append(colorEmulation, {~0, 0}, 5); - append(overscanAdjustment, {~0, 0}); - append(overscanHorizontal, {~0, 0}); - append(overscanVertical, {~0, 0}, 5); - - colorEmulation.setChecked(config->video.colorEmulation); - saturation.slider.setPosition(config->video.saturation); - gamma.slider.setPosition(config->video.gamma - 100); - luminance.slider.setPosition(config->video.luminance); - overscanHorizontal.slider.setPosition(config->video.maskOverscan.horizontal); - overscanVertical.slider.setPosition(config->video.maskOverscan.vertical); - - synchronize(); - - saturation.slider.onChange = gamma.slider.onChange = luminance.slider.onChange = colorEmulation.onToggle = - overscanHorizontal.slider.onChange = overscanVertical.slider.onChange = - {&VideoSettings::synchronize, this}; -} - -void VideoSettings::synchronize() { - config->video.saturation = saturation.slider.position(); - config->video.gamma = 100 + gamma.slider.position(); - config->video.luminance = luminance.slider.position(); - config->video.colorEmulation = colorEmulation.checked(); - config->video.maskOverscan.horizontal = overscanHorizontal.slider.position(); - config->video.maskOverscan.vertical = overscanVertical.slider.position(); - - saturation.value.setText({config->video.saturation, "%"}); - gamma.value.setText({config->video.gamma, "%"}); - luminance.value.setText({config->video.luminance, "%"}); - overscanHorizontal.value.setText({config->video.maskOverscan.horizontal, "px"}); - overscanVertical.value.setText({config->video.maskOverscan.vertical, "px"}); - - utility->updatePalette(); -} diff --git a/target-higan/settings/video.hpp b/target-higan/settings/video.hpp deleted file mode 100644 index 3e47f882..00000000 --- a/target-higan/settings/video.hpp +++ /dev/null @@ -1,23 +0,0 @@ -struct VideoSlider : HorizontalLayout { - Label name; - Label value; - HorizontalSlider slider; - - VideoSlider(); -}; - -struct VideoSettings : SettingsLayout { - Label colorAdjustment; - VideoSlider saturation; - VideoSlider gamma; - VideoSlider luminance; - CheckLabel colorEmulation; - Label overscanAdjustment; - VideoSlider overscanHorizontal; - VideoSlider overscanVertical; - - void synchronize(); - VideoSettings(); -}; - -extern VideoSettings* videoSettings; diff --git a/target-higan/tools/cheat-database.cpp b/target-higan/tools/cheat-database.cpp deleted file mode 100644 index 5063188a..00000000 --- a/target-higan/tools/cheat-database.cpp +++ /dev/null @@ -1,68 +0,0 @@ -CheatDatabase* cheatDatabase = nullptr; - -CheatDatabase::CheatDatabase() { - setGeometry({256, 256, 600, 360}); - windowManager->append(this, "CheatDatabase"); - - layout.setMargin(5); - cheatList.setCheckable(); - selectAllButton.setText("Select All"); - unselectAllButton.setText("Unselect All"); - acceptButton.setText("Add Codes"); - - append(layout); - layout.append(cheatList, {~0, ~0}, 5); - layout.append(controlLayout, {~0, 0}); - controlLayout.append(selectAllButton, {100, 0}, 5); - controlLayout.append(unselectAllButton, {100, 0}, 5); - controlLayout.append(spacer, {~0, 0}); - controlLayout.append(acceptButton, {80, 0}); - - selectAllButton.onActivate = [&] { - for(unsigned n = 0; n < cheat.size(); n++) cheatList.setChecked(n, true); - }; - - unselectAllButton.onActivate = [&] { - for(unsigned n = 0; n < cheat.size(); n++) cheatList.setChecked(n, false); - }; - - acceptButton.onActivate = {&CheatDatabase::addCodes, this}; -} - -void CheatDatabase::findCodes() { - const string sha256 = system().sha256(); - cheatList.reset(); - cheat.reset(); - - auto document = Markup::Document(string::read(program->path("cheats.bml"))); - for(auto& node : document) { - if(node.name != "cartridge") continue; - if(node["sha256"].text() != sha256) continue; - - setTitle(node["name"].text()); - for(auto& cheat : node) { - if(cheat.name != "cheat") continue; - cheatList.append(cheat["description"].text()); - this->cheat.append({cheat["code"].text(), cheat["description"].text()}); - } - - setVisible(); - return; - } - - MessageWindow().setParent(*tools).setText("Sorry, no cheat codes were found.").information(); -} - -void CheatDatabase::addCodes() { - for(unsigned n = 0; n < cheat.size(); n++) { - if(cheatList.checked(n) == false) continue; - if(cheatEditor->import(cheat[n].code, cheat[n].desc) == false) { - MessageWindow().setParent(*this).setText("Ran out of empty slots for cheat codes.\nNot all cheat codes were added.").warning(); - break; - } - } - - setVisible(false); - cheatEditor->synchronize(); - cheatEditor->refresh(); -} diff --git a/target-higan/tools/cheat-database.hpp b/target-higan/tools/cheat-database.hpp deleted file mode 100644 index 3d0ea5d1..00000000 --- a/target-higan/tools/cheat-database.hpp +++ /dev/null @@ -1,22 +0,0 @@ -struct CheatDatabase : Window { - VerticalLayout layout; - ListView cheatList; - HorizontalLayout controlLayout; - Button selectAllButton; - Button unselectAllButton; - Widget spacer; - Button acceptButton; - - void findCodes(); - void addCodes(); - CheatDatabase(); - -private: - struct Cheat { - string code; - string desc; - }; - vector cheat; -}; - -extern CheatDatabase* cheatDatabase; diff --git a/target-higan/tools/cheat-editor.cpp b/target-higan/tools/cheat-editor.cpp deleted file mode 100644 index 010b8da8..00000000 --- a/target-higan/tools/cheat-editor.cpp +++ /dev/null @@ -1,178 +0,0 @@ -CheatEditor* cheatEditor = nullptr; - -CheatEditor::CheatEditor() { - cheatList.setHeaderText({"Slot", "Code", "Description"}); - cheatList.setHeaderVisible(); - cheatList.setCheckable(); - for(unsigned n = 0; n < Codes; n++) cheatList.append({"", "", ""}); - codeLabel.setText("Code(s):"); - descLabel.setText("Description:"); - findButton.setText("Find Codes ..."); - resetButton.setText("Reset"); - eraseButton.setText("Erase"); - unsigned width = max( - Font::size(program->normalFont, "Codes(s)" ).width, - Font::size(program->normalFont, "Description:").width - ); - - append(cheatList, {~0, ~0}, 5); - append(codeLayout, {~0, 0}, 5); - codeLayout.append(codeLabel, {width, 0}, 5); - codeLayout.append(codeEdit, {~0, 0}); - append(descLayout, {~0, 0}, 5); - descLayout.append(descLabel, {width, 0}, 5); - descLayout.append(descEdit, {~0, 0}); - append(controlLayout, {~0, 0}); - controlLayout.append(findButton, {0, 0}, 5); - controlLayout.append(spacer, {~0, 0}); - controlLayout.append(resetButton, {80, 0}, 5); - controlLayout.append(eraseButton, {80, 0}); - - cheatList.onChange = {&CheatEditor::synchronize, this}; - cheatList.onToggle = [&](unsigned) { update(); }; - codeEdit.onChange = {&CheatEditor::updateCode, this}; - descEdit.onChange = {&CheatEditor::updateDesc, this}; - findButton.onActivate = {&CheatDatabase::findCodes, cheatDatabase}; - resetButton.onActivate = [&] { - if(MessageWindow().setParent(*tools).setText("All codes will be erased. Are you sure you want to do this?") - .question() == MessageWindow::Response::Yes) reset(); - }; - eraseButton.onActivate = {&CheatEditor::erase, this}; - - cheatList.setSelection(0); - synchronize(); -} - -void CheatEditor::synchronize() { - setEnabled(program->active); - - if(cheatList.selected()) { - unsigned n = cheatList.selection(); - codeEdit.setText(cheat[n].code); - descEdit.setText(cheat[n].desc); - codeEdit.setEnabled(true); - descEdit.setEnabled(true); - eraseButton.setEnabled(true); - } else { - codeEdit.setText(""); - descEdit.setText(""); - codeEdit.setEnabled(false); - descEdit.setEnabled(false); - eraseButton.setEnabled(false); - } -} - -void CheatEditor::refresh() { - for(unsigned n = 0; n < Codes; n++) { - string code = cheat[n].code; - string desc = cheat[n].code.empty() && cheat[n].desc.empty() ? "(empty)" : cheat[n].desc; - lstring codes = code.split("+"); - if(codes.size() > 1) code = {codes[0], "+..."}; - cheatList.setText(n, {format<3>(1 + n), code, desc}); - } - cheatList.autoSizeColumns(); -} - -void CheatEditor::update() { - lstring codes; - for(unsigned n = 0; n < Codes; n++) { - string code = cheat[n].code; - if(cheatList.checked(n) && !code.empty()) codes.append(code); - } - system().cheatSet(codes); -} - -void CheatEditor::reset() { - for(unsigned n = 0; n < Codes; n++) { - cheatList.setChecked(n, false); - cheat[n].code = ""; - cheat[n].desc = ""; - } - codeEdit.setText(""); - descEdit.setText(""); - refresh(); - update(); -} - -void CheatEditor::erase() { - unsigned n = cheatList.selection(); - cheatList.setChecked(n, false); - cheat[n].code = ""; - cheat[n].desc = ""; - codeEdit.setText(""); - descEdit.setText(""); - refresh(); - update(); -} - -void CheatEditor::updateCode() { - unsigned n = cheatList.selection(); - cheat[n].code = codeEdit.text(); - refresh(); - update(); -} - -void CheatEditor::updateDesc() { - unsigned n = cheatList.selection(); - cheat[n].desc = descEdit.text(); - refresh(); -} - -bool CheatEditor::load(string filename) { - string data = string::read(filename); - if(data.empty()) return false; - - unsigned n = 0; - auto document = Markup::Document(data); - for(auto& node : document["cartridge"]) { - if(node.name != "cheat") continue; - cheatList.setChecked(n, node["enabled"].exists()); - cheat[n].code = node["code"].text(); - cheat[n].desc = node["description"].text(); - if(++n >= Codes) break; - } - - refresh(); - update(); - return true; -} - -bool CheatEditor::save(string filename) { - signed lastSave = -1; - for(signed n = 127; n >= 0; n--) { - if(!cheat[n].code.empty() || !cheat[n].desc.empty()) { - lastSave = n; - break; - } - } - - if(lastSave == -1) { - file::remove(filename); - return true; - } - - file fp; - if(fp.open(filename, file::mode::write) == false) return false; - - fp.print("cartridge sha256:", system().sha256(), "\n"); - for(unsigned n = 0; n <= lastSave; n++) { - fp.print(" cheat", cheatList.checked(n) ? " enabled\n" : "\n"); - fp.print(" description:", cheat[n].desc, "\n"); - fp.print(" code:", cheat[n].code, "\n"); - } - fp.close(); - - return true; -} - -bool CheatEditor::import(string code, string desc) { - for(unsigned n = 0; n < Codes; n++) { - if(cheat[n].code.empty() && cheat[n].desc.empty()) { - cheatList.setChecked(n, false); - cheat[n].code = code; - cheat[n].desc = desc; - return true; - } - } - return false; -} diff --git a/target-higan/tools/cheat-editor.hpp b/target-higan/tools/cheat-editor.hpp deleted file mode 100644 index 0a35317c..00000000 --- a/target-higan/tools/cheat-editor.hpp +++ /dev/null @@ -1,38 +0,0 @@ -struct CheatEditor : ToolsLayout { - ListView cheatList; - HorizontalLayout codeLayout; - Label codeLabel; - LineEdit codeEdit; - HorizontalLayout descLayout; - Label descLabel; - LineEdit descEdit; - HorizontalLayout controlLayout; - Button findButton; - Widget spacer; - Button resetButton; - Button eraseButton; - - void reset(); - void erase(); - void updateCode(); - void updateDesc(); - - bool load(string filename); - bool save(string filename); - bool import(string code, string desc); - - void update(); - void refresh(); - void synchronize(); - CheatEditor(); - -private: - enum : unsigned { Codes = 128 }; - struct Cheat { - string code; - string desc; - }; - Cheat cheat[Codes]; -}; - -extern CheatEditor* cheatEditor; diff --git a/target-higan/tools/state-manager.cpp b/target-higan/tools/state-manager.cpp deleted file mode 100644 index fde3cb96..00000000 --- a/target-higan/tools/state-manager.cpp +++ /dev/null @@ -1,153 +0,0 @@ -StateManager* stateManager = nullptr; - -StateManager::StateManager() { - stateList.setHeaderText({"Slot", "Description"}); - stateList.setHeaderVisible(); - for(unsigned n = 0; n < Slots; n++) stateList.append({format<2>(1 + n), "(empty)"}); - stateList.autoSizeColumns(); - descLabel.setText("Description:"); - saveButton.setText("Save"); - loadButton.setText("Load"); - resetButton.setText("Reset"); - eraseButton.setText("Erase"); - - append(stateList, {~0, ~0}, 5); - append(descLayout, {~0, 0}, 5); - descLayout.append(descLabel, {0, 0}, 5); - descLayout.append(descEdit, {~0, 0}); - append(controlLayout, {~0, 0}); - controlLayout.append(saveButton, {80, 0}, 5); - controlLayout.append(loadButton, {80, 0}, 5); - controlLayout.append(spacer, {~0, 0}); - controlLayout.append(resetButton, {80, 0}, 5); - controlLayout.append(eraseButton, {80, 0}); - - stateList.onChange = {&StateManager::synchronize, this}; - stateList.onActivate = {&StateManager::slotLoad, this}; - descEdit.onChange = {&StateManager::slotSaveDescription, this}; - saveButton.onActivate = {&StateManager::slotSave, this}; - loadButton.onActivate = {&StateManager::slotLoad, this}; - resetButton.onActivate = [&] { - if(MessageWindow().setParent(*tools).setText("All states will be erased. Are you sure you want to do this?") - .question() == MessageWindow::Response::Yes) reset(); - }; - eraseButton.onActivate = {&StateManager::slotErase, this}; - - stateList.setSelection(0); - synchronize(); -} - -void StateManager::synchronize() { - setEnabled(program->active); - - descEdit.setText(""); - descEdit.setEnabled(false); - controlLayout.setEnabled(stateList.selected()); - if(stateList.selected() == false) return; - - if(slot[stateList.selection()].capacity() > 0) { - descEdit.setText(slotLoadDescription(stateList.selection())); - descEdit.setEnabled(true); - } -} - -void StateManager::refresh() { - for(unsigned n = 0; n < Slots; n++) { - stateList.setText(n, {format<2>(1 + n), slotLoadDescription(n)}); - } - stateList.autoSizeColumns(); -} - -void StateManager::reset() { - for(auto& slot : this->slot) slot = serializer(); - synchronize(); - refresh(); -} - -bool StateManager::load(string filename, unsigned revision) { - for(auto& slot : this->slot) slot = serializer(); - synchronize(); - - file fp; - if(fp.open(filename, file::mode::read) == false) return false; - - if(fp.readl(4) == 0x31415342 /* 'BSA1' */ && fp.readl(4) == revision) { - for(auto &slot : this->slot) { - if(fp.read() == false) continue; //slot is empty - unsigned size = fp.readl(4); - uint8_t* data = new uint8_t[size]; - fp.read(data, size); - slot = serializer(data, size); - delete[] data; - } - } - - refresh(); - synchronize(); - return true; -} - -bool StateManager::save(string filename, unsigned revision) { - bool hasSave = false; - for(auto& slot : this->slot) hasSave |= slot.capacity() > 0; - if(hasSave == false) { - file::remove(filename); - return true; - } - - directory::create(dir(filename)); - - file fp; - if(fp.open(filename, file::mode::write) == false) return false; - - fp.writel(0x31415342, 4); //'BSA1' - fp.writel(revision, 4); - for(auto& slot : this->slot) { - fp.write(slot.capacity() > 0); - if(slot.capacity()) { - fp.writel(slot.capacity(), 4); - fp.write(slot.data(), slot.capacity()); - } - } - - return true; -} - -void StateManager::slotLoad() { - if(stateList.selected() == false) return; - serializer s(slot[stateList.selection()].data(), slot[stateList.selection()].capacity()); - system().unserialize(s); -} - -void StateManager::slotSave() { - if(stateList.selected()) { - slot[stateList.selection()] = system().serialize(); - } - refresh(); - synchronize(); - descEdit.setFocused(); -} - -void StateManager::slotErase() { - if(stateList.selected()) { - slot[stateList.selection()] = serializer(); - } - refresh(); - synchronize(); -} - -string StateManager::slotLoadDescription(unsigned id) { - if(slot[id].capacity() == 0) return "(empty)"; - char text[DescriptionLength]; - strmcpy(text, (const char*)slot[id].data() + HeaderLength, DescriptionLength); - return text; -} - -void StateManager::slotSaveDescription() { - if(stateList.selected() == false) return; - string text = descEdit.text(); - if(slot[stateList.selection()].capacity() > 0) { - strmcpy((char*)slot[stateList.selection()].data() + HeaderLength, (const char*)text, DescriptionLength); - } - refresh(); -} diff --git a/target-higan/tools/state-manager.hpp b/target-higan/tools/state-manager.hpp deleted file mode 100644 index daf06001..00000000 --- a/target-higan/tools/state-manager.hpp +++ /dev/null @@ -1,36 +0,0 @@ -struct StateManager : ToolsLayout { - ListView stateList; - HorizontalLayout descLayout; - Label descLabel; - LineEdit descEdit; - HorizontalLayout controlLayout; - Button saveButton; - Button loadButton; - Widget spacer; - Button resetButton; - Button eraseButton; - - void reset(); - bool load(string filename, unsigned revision); - bool save(string filename, unsigned revision); - - void slotLoad(); - void slotSave(); - void slotErase(); - string slotLoadDescription(unsigned id); - void slotSaveDescription(); - - void refresh(); - void synchronize(); - StateManager(); - -private: - enum : unsigned { - Slots = 32, - HeaderLength = 72, - DescriptionLength = 512, - }; - serializer slot[Slots]; -}; - -extern StateManager* stateManager; diff --git a/target-higan/tools/tools.cpp b/target-higan/tools/tools.cpp deleted file mode 100644 index 894b7d9b..00000000 --- a/target-higan/tools/tools.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "../higan.hpp" -#include "cheat-database.cpp" -#include "cheat-editor.cpp" -#include "state-manager.cpp" -Tools* tools = nullptr; - -ToolsLayout::ToolsLayout() { - setMargin(5); -} - -Tools::Tools() { - setGeometry({128, 128, 640, 360}); - windowManager->append(this, "Tools"); - - setTitle("Tools"); - - layout.setMargin(5); - panels.append("Cheat Editor", {resource::cheatEditor, sizeof resource::cheatEditor}); - panels.append("State Manager", {resource::stateManager, sizeof resource::stateManager}); - panels.setLayout(0, *cheatEditor); - panels.setLayout(1, *stateManager); - - append(layout); - layout.append(panels, {~0, ~0}); -} diff --git a/target-higan/tools/tools.hpp b/target-higan/tools/tools.hpp deleted file mode 100644 index 06680369..00000000 --- a/target-higan/tools/tools.hpp +++ /dev/null @@ -1,16 +0,0 @@ -struct ToolsLayout : VerticalLayout { - ToolsLayout(); -}; - -#include "cheat-database.hpp" -#include "cheat-editor.hpp" -#include "state-manager.hpp" - -struct Tools : Window { - VerticalLayout layout; - TabFrame panels; - - Tools(); -}; - -extern Tools* tools; diff --git a/target-higan/utility/utility.cpp b/target-higan/utility/utility.cpp deleted file mode 100644 index 2645092a..00000000 --- a/target-higan/utility/utility.cpp +++ /dev/null @@ -1,314 +0,0 @@ -#include "../higan.hpp" - -Utility* utility = nullptr; - -void Utility::setInterface(Emulator::Interface* emulator) { - program->active = emulator; - presentation->synchronize(); -} - -//load from command-line, etc -void Utility::loadMedia(string pathname) { - pathname.transform("\\", "/"); - if(pathname.endsWith("/")) pathname.rtrim("/"); - - if(!directory::exists(pathname)) return; - string type = extension(pathname); - - //determine type by comparing extension against all emulation cores - for(auto& emulator : program->emulator) { - for(auto& media : emulator->media) { - if(media.bootable == false) continue; - if(type != media.type) continue; - loadMedia(emulator, media, {pathname, "/"}); - libraryManager->setVisible(false); - return; - } - } - - MessageWindow().setText("Unable to determine media type.").warning(); -} - -//load base cartridge -void Utility::loadMedia(Emulator::Interface* emulator, Emulator::Interface::Media& media, string pathname) { - unload(); - setInterface(emulator); - path(0) = program->path({media.name, ".sys/"}); - path(media.id) = pathname; - this->pathname.append(pathname); - - system().load(media.id); - system().power(); - - presentation->setSystemName(media.name); - presentation->setVisible(); - load(); -} - -//request from emulation core to load non-volatile media folder -void Utility::loadRequest(unsigned id, string name, string type) { - string pathname = libraryManager->load(type); - if(pathname.empty()) return; - path(id) = pathname; - this->pathname.append(pathname); - - system().load(id); -} - -//request from emulation core to load non-volatile media file -void Utility::loadRequest(unsigned id, string path) { - string pathname = {this->path(system().group(id)), path}; - if(file::exists(pathname) == false) return; - mmapstream stream(pathname); - return system().load(id, stream); -} - -//request from emulation core to save non-volatile media file -void Utility::saveRequest(unsigned id, string path) { - string pathname = {this->path(system().group(id)), path}; - filestream stream(pathname, file::mode::write); - return system().save(id, stream); -} - -void Utility::connect(unsigned port, unsigned device) { - if(program->active == nullptr) return; - system().connect(port, device); -} - -void Utility::power() { - if(program->active == nullptr) return; - system().power(); -} - -void Utility::reset() { - if(program->active == nullptr) return; - system().reset(); -} - -void Utility::load() { - presentation->setTitle(system().title()); - - cheatEditor->load({pathname[0], "cheats.bml"}); - stateManager->load({pathname[0], "higan/states.bsa"}, 1); - - synchronizeDSP(); - - resize(); - updateShader(); - cheatEditor->synchronize(); - cheatEditor->refresh(); -} - -void Utility::unload() { - if(program->active == nullptr) return; - - cheatEditor->save({pathname[0], "cheats.bml"}); - stateManager->save({pathname[0], "higan/states.bsa"}, 1); - - system().unload(); - path.reset(); - pathname.reset(); - cheatEditor->reset(); - stateManager->reset(); - setInterface(nullptr); - - video.clear(); - audio.clear(); - presentation->setTitle({Emulator::Name, " v", Emulator::Version}); - cheatDatabase->setVisible(false); - cheatEditor->setVisible(false); - stateManager->setVisible(false); -} - -void Utility::saveState(unsigned slot) { - if(program->active == nullptr) return; - serializer s = system().serialize(); - if(s.size() == 0) return; - directory::create({pathname[0], "higan/"}); - if(file::write({pathname[0], "higan/state-", slot, ".bsa"}, s.data(), s.size()) == false); - showMessage({"Saved to slot ", slot}); -} - -void Utility::loadState(unsigned slot) { - if(program->active == nullptr) return; - auto memory = file::read({pathname[0], "higan/state-", slot, ".bsa"}); - if(memory.size() == 0) return showMessage({"Unable to locate slot ", slot, " state"}); - serializer s(memory.data(), memory.size()); - if(system().unserialize(s) == false) return showMessage({"Slot ", slot, " state incompatible"}); - showMessage({"Loaded from slot ", slot}); -} - -void Utility::synchronizeDSP() { - if(program->active == nullptr) return; - - if(config->video.synchronize == false) { - return dspaudio.setFrequency(system().audioFrequency()); - } - - double inputRatio = system().audioFrequency() / system().videoFrequency(); - double outputRatio = config->timing.audio / config->timing.video; - double frequency = inputRatio / outputRatio * config->audio.frequency; - - dspaudio.setFrequency(frequency); -} - -void Utility::synchronizeRuby() { - video.set(Video::Synchronize, config->video.synchronize); - audio.set(Audio::Synchronize, config->audio.synchronize); - audio.set(Audio::Frequency, config->audio.frequency); - audio.set(Audio::Latency, config->audio.latency); - - switch(config->audio.resampler) { - case 0: dspaudio.setResampler(DSP::ResampleEngine::Linear); break; - case 1: dspaudio.setResampler(DSP::ResampleEngine::Hermite); break; - case 2: dspaudio.setResampler(DSP::ResampleEngine::Sinc); break; - } - dspaudio.setResamplerFrequency(config->audio.frequency); - dspaudio.setVolume(config->audio.mute ? 0.0 : config->audio.volume * 0.01); - synchronizeDSP(); -} - -void Utility::updatePalette() { - if(program->active == nullptr) return; - - if(config->video.shader == "Display Emulation" && config->video.driver == "OpenGL") { - system().paletteUpdate(Emulator::Interface::PaletteMode::Channel); - } else if(config->video.colorEmulation) { - system().paletteUpdate(Emulator::Interface::PaletteMode::Emulation); - } else { - system().paletteUpdate(Emulator::Interface::PaletteMode::Standard); - } -} - -void Utility::updateShader() { - if(config->video.shader == "None") { - video.set(Video::Shader, (const char*)""); - video.set(Video::Filter, Video::FilterNearest); - } else if(config->video.shader == "Blur") { - video.set(Video::Shader, (const char*)""); - video.set(Video::Filter, Video::FilterLinear); - } else if(config->video.shader == "Display Emulation" && config->video.driver != "OpenGL") { - video.set(Video::Shader, (const char*)""); - video.set(Video::Filter, Video::FilterLinear); - } else if(config->video.shader == "Display Emulation") { - if(program->active) { - string pathname = program->path("Video Shaders/"); - pathname.append("Display Emulation/"); - pathname.append(presentation->systemName, ".shader/"); - if(directory::exists(pathname)) { - video.set(Video::Shader, (const char*)pathname); - } else { - video.set(Video::Shader, (const char*)""); - video.set(Video::Filter, Video::FilterLinear); - } - } else { - video.set(Video::Shader, (const char*)""); - video.set(Video::Filter, Video::FilterLinear); - } - } else { - video.set(Video::Shader, (const char*)config->video.shader); - } - updatePalette(); -} - -void Utility::resize(bool resizeWindow) { - if(program->active == nullptr) { - auto geometry = presentation->geometry(); - presentation->viewport.setGeometry({0, 0, geometry.width, geometry.height}); - return; - } - - Geometry geometry = presentation->geometry(); - unsigned width = system().information.width; - unsigned height = system().information.height; - - unsigned scaledWidth = geometry.width / width; - unsigned scaledHeight = geometry.height / height; - unsigned multiplier = max(1u, min(scaledWidth, scaledHeight)); - - if(config->video.aspectCorrection) { - width *= system().information.aspectRatio; - } - - width *= multiplier; - height *= multiplier; - - unsigned scaleMode = 0; - - if(config->video.scaleMode == 1) { - width = (double)width * ((double)geometry.height / height); - height = geometry.height; - } - - if(config->video.scaleMode == 2) { - width = geometry.width; - height = geometry.height; - } - - if(resizeWindow == false) { - if(geometry.width < width ) width = geometry.width; - if(geometry.height < height) height = geometry.height; - - presentation->viewport.setGeometry({ - (geometry.width - width) / 2, (geometry.height - height) / 2, width, height - }); - } else { - presentation->setGeometry({geometry.x, geometry.y, width, height}); - presentation->viewport.setGeometry({0, 0, width, height}); - } - - presentation->synchronize(); -} - -void Utility::toggleFullScreen() { - static Geometry geometry; - - if(presentation->fullScreen() == false) { - geometry = presentation->geometry(); - presentation->setMenuVisible(false); - presentation->setStatusVisible(false); - presentation->setFullScreen(true); - input.acquire(); - } else { - input.unacquire(); - presentation->setMenuVisible(true); - presentation->setStatusVisible(true); - presentation->setFullScreen(false); - presentation->setGeometry(geometry); - } - - resize(); -} - -void Utility::updateStatus() { - time_t currentTime = time(0); - string text; - if((currentTime - statusTime) <= 2) { - text = statusMessage; - } else if(program->active == nullptr) { - text = "No cartridge loaded"; - } else if(program->pause || program->autopause) { - text = "Paused"; - } else { - text = statusText; - } - if(text != presentation->statusText()) { - presentation->setStatusText(text); - } -} - -void Utility::setStatusText(string text) { - statusText = text; -} - -void Utility::showMessage(string message) { - statusTime = time(0); - statusMessage = message; -} - -string Utility::libraryPath() { - string path = string::read({configpath(), "higan/library.bml"}).strip().ltrim<1>("Path: ").transform("\\", "/"); - if(path.empty()) path = {userpath(), "Emulation/"}; - if(path.endsWith("/") == false) path.append("/"); - return path; -} diff --git a/target-higan/utility/utility.hpp b/target-higan/utility/utility.hpp deleted file mode 100644 index 5b3fb92c..00000000 --- a/target-higan/utility/utility.hpp +++ /dev/null @@ -1,42 +0,0 @@ -struct Utility { - void setInterface(Emulator::Interface* emulator); - - void loadMedia(string pathname); - void loadMedia(Emulator::Interface* emulator, Emulator::Interface::Media& media, string pathname); - - void loadRequest(unsigned id, string name, string type); - void loadRequest(unsigned id, string path); - void saveRequest(unsigned id, string path); - - void connect(unsigned port, unsigned device); - void power(); - void reset(); - void load(); - void unload(); - - void saveState(unsigned slot); - void loadState(unsigned slot); - - void synchronizeDSP(); - void synchronizeRuby(); - void updatePalette(); - void updateShader(); - void resize(bool resizeWindow = false); - void toggleFullScreen(); - - void updateStatus(); - void setStatusText(string text); - void showMessage(string message); - - string libraryPath(); - - lstring path; - lstring pathname; - -private: - string statusText; - string statusMessage; - time_t statusTime = 0; -}; - -extern Utility* utility; diff --git a/target-higan/window/window.cpp b/target-higan/window/window.cpp deleted file mode 100644 index 582f3817..00000000 --- a/target-higan/window/window.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "../higan.hpp" -WindowManager* windowManager = nullptr; - -void WindowManager::append(Window* window, string name) { - window->setMenuFont(program->normalFont); - window->setWidgetFont(program->normalFont); - window->setStatusFont(program->boldFont); - windowList.append({window, name, window->geometry().text()}); -} - -void WindowManager::loadGeometry() { - static bool initialized = false; - if(initialized == false) { - initialized = true; - Configuration::Node geometry; - for(auto& window : windowList) { - geometry.append(window.geometry, window.name); - } - config.append(geometry, "Geometry"); - } - config.load(program->path("geometry.bml")); - config.save(program->path("geometry.bml")); - for(auto& window : windowList) { - window.window->setGeometry(window.geometry); - } -} - -void WindowManager::saveGeometry() { - for(auto& window : windowList) { - window.geometry = window.window->geometry().text(); - } - config.save(program->path("geometry.bml")); -} - -void WindowManager::hideAll() { - for(auto& window : windowList) { - window.window->setVisible(false); - } -} diff --git a/target-higan/window/window.hpp b/target-higan/window/window.hpp deleted file mode 100644 index caa81e5d..00000000 --- a/target-higan/window/window.hpp +++ /dev/null @@ -1,18 +0,0 @@ -struct WindowManager { - struct WindowList { - Window* window; - string name; - string geometry; - }; - vector windowList; - - void append(Window* window, string name); - void loadGeometry(); - void saveGeometry(); - void hideAll(); - -private: - Configuration::Document config; -}; - -extern WindowManager* windowManager; diff --git a/target-loki/Makefile b/target-loki/Makefile deleted file mode 100644 index 28b9d9be..00000000 --- a/target-loki/Makefile +++ /dev/null @@ -1,96 +0,0 @@ -name := loki - -processors := arm gsu hg51b lr35902 r65816 spc700 upd96050 -include processor/Makefile - -include sfc/Makefile -include gb/Makefile - -ui_objects := ui-loki ui-settings ui-input -ui_objects += ui-interface ui-debugger -ui_objects += ui-presentation ui-terminal -ui_objects += ruby phoenix -ui_objects += $(if $(call streq,$(platform),windows),resource) - -ifeq ($(platform),windows) - ruby := video.wgl audio.xaudio2 input.windows -else ifeq ($(platform),macosx) - ruby := video.cgl audio.openal input.carbon -else ifeq ($(platform),linux) - ruby := video.glx audio.alsa input.udev -else ifeq ($(platform),bsd) - ruby := video.glx audio.openal input.x -endif - -include ruby/Makefile -link += $(rubylink) - -include phoenix/Makefile -link += $(phoenixlink) - -objects := $(ui_objects) $(objects) -objects := $(patsubst %,obj/%.o,$(objects)) - -obj/ui-loki.o: $(ui)/loki.cpp $(call rwildcard,$(ui)/) -obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/) -obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/) -obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/) -obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(call rwildcard,$(ui)/) -obj/ui-presentation.o: $(ui)/presentation/presentation.cpp $(call rwildcard,$(ui)/) -obj/ui-terminal.o: $(ui)/terminal/terminal.cpp $(call rwildcard,$(ui)/) - -obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/) - $(compiler) $(rubyflags) -c $< -o $@ - -obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/) - $(compiler) $(phoenixflags) -c $< -o $@ - -obj/resource.o: $(ui)/resource.rc -ifeq ($(arch),win32) - windres --target=pe-i386 $(ui)/resource.rc obj/resource.o -else - windres $(ui)/resource.rc obj/resource.o -endif - -build: $(objects) -ifeq ($(platform),windows) - $(strip $(compiler) -shared -o out/phoenix.dll obj/phoenix.o $(phoenixlink)) - $(strip $(compiler) -o out/$(name) $(subst obj/phoenix.o,,$(objects)) $(link) -Lout -lphoenix) -else ifeq ($(platform),macosx) - if [ -d out/$(name).app ]; then rm -r out/$(name).app; fi - mkdir out/$(name).app - mkdir out/$(name).app/Contents - mkdir out/$(name).app/Contents/MacOS - mkdir out/$(name).app/Contents/Resources - cp data/Info.plist out/$(name).app/Contents/Info.plist - $(strip $(compiler) -o out/$(name).app/Contents/MacOS/$(name) $(objects) $(link)) -else - $(strip $(compiler) -o out/$(name) $(objects) $(link)) -endif - -resource: - sourcery $(ui)/resource/resource.bml $(ui)/resource/resource.cpp $(ui)/resource/resource.hpp - -install: -ifneq ($(shell id -un),root) - $(error "make install must be run as root") -else ifeq ($(platform),windows) -else ifeq ($(platform),macosx) - mkdir -p /Library/Application\ Support/$(name) - cp -R profile/* /Library/Application\ Support/$(name) - chmod -R 777 /Library/Application\ Support/$(name) -else - cp out/$(name) $(prefix)/bin/$(name) - mkdir -p /usr/share/$(name) - cp -R profile/* /usr/share/$(name) - chmod -R 777 /usr/share/$(name) -endif - -uninstall: -ifneq ($(shell id -un),root) - $(error "make uninstall must be run as root") -else ifeq ($(platform),windows) -else ifeq ($(platform),macosx) -else - rm $(prefix)/bin/$(name) -endif diff --git a/target-loki/debugger/debugger.cpp b/target-loki/debugger/debugger.cpp deleted file mode 100644 index 200681fa..00000000 --- a/target-loki/debugger/debugger.cpp +++ /dev/null @@ -1,479 +0,0 @@ -#include "../loki.hpp" -Debugger* debugger = nullptr; - -Debugger::Debugger() { - debugger = this; - SFC::cpu.debugger.op_exec = {&Debugger::cpuExec, this}; - SFC::cpu.debugger.op_read = {&Debugger::cpuRead, this}; - SFC::cpu.debugger.op_write = {&Debugger::cpuWrite, this}; - SFC::smp.debugger.op_exec = {&Debugger::smpExec, this}; - SFC::smp.debugger.op_read = {&Debugger::smpRead, this}; - SFC::smp.debugger.op_write = {&Debugger::smpWrite, this}; - SFC::ppu.debugger.vram_read = {&Debugger::ppuVramRead, this}; - SFC::ppu.debugger.vram_write = {&Debugger::ppuVramWrite, this}; - SFC::ppu.debugger.oam_read = {&Debugger::ppuOamRead, this}; - SFC::ppu.debugger.oam_write = {&Debugger::ppuOamWrite, this}; - SFC::ppu.debugger.cgram_read = {&Debugger::ppuCgramRead, this}; - SFC::ppu.debugger.cgram_write = {&Debugger::ppuCgramWrite, this}; -} - -void Debugger::load() { - directory::create({interface->pathname, "loki/"}); - - cpuUsage = new uint8[0x1000000](); - apuUsage = new uint8[0x10000](); - file fp; - - if(fp.open({interface->pathname, "loki/cpu.usage.map"}, file::mode::read)) { - if(fp.size() == 0x1000000) fp.read(cpuUsage, 0x1000000); - fp.close(); - } - - if(fp.open({interface->pathname, "loki/apu.usage.map"}, file::mode::read)) { - if(fp.size() == 0x10000) fp.read(apuUsage, 0x10000); - fp.close(); - } -} - -void Debugger::unload() { - if(cpuTracerFile.open()) cpuTracerFile.close(); - if(smpTracerFile.open()) smpTracerFile.close(); - file::write({interface->pathname, "loki/cpu.usage.map"}, cpuUsage, 0x1000000); - file::write({interface->pathname, "loki/apu.usage.map"}, apuUsage, 0x10000); - delete[] cpuUsage; - delete[] apuUsage; - cpuUsage = nullptr; - apuUsage = nullptr; -} - -void Debugger::main() { - if(running == false) { - usleep(20 * 1000); - return; - } - - emulator->run(); -} - -void Debugger::run() { - running = true; -} - -void Debugger::stop() { - running = false; - cpuRunFor = nothing; - cpuRunTo = nothing; - cpuStepFor = nothing; - cpuStepTo = nothing; - smpRunFor = nothing; - smpRunTo = nothing; - smpStepFor = nothing; - smpStepTo = nothing; -} - -void Debugger::leave() { - stop(); - SFC::scheduler.debug(); -} - -bool Debugger::breakpointTest(Source source, Breakpoint::Mode mode, unsigned addr, uint8 data) { - if(savingState) return false; - for(unsigned n = 0; n < breakpoints.size(); n++) { - auto& bp = breakpoints[n]; - if(bp.source != source) continue; - if(bp.mode != mode) continue; - if(bp.addr != addr) continue; - if(bp.mode != Breakpoint::Mode::Execute && bp.data && bp.data() != data) continue; - string output = {"Breakpoint #", n, " hit"}; - if(bp.mode == Breakpoint::Mode::Read ) output.append("; read ", hex<2>(data)); - if(bp.mode == Breakpoint::Mode::Write) output.append("; wrote ", hex<2>(data)); - output.append("; triggered: ", ++bp.triggered); - echo(output, "\n"); - return true; - } - return false; -} - -string Debugger::cpuDisassemble() { - char text[4096]; - SFC::cpu.disassemble_opcode(text); - return {text, " F:", (unsigned)SFC::cpu.field(), " V:", format<3>(SFC::cpu.vcounter()), " H:", format<4>(SFC::cpu.hcounter())}; -} - -string Debugger::cpuDisassemble(unsigned addr, bool e, bool m, bool x) { - char text[4096]; - SFC::cpu.disassemble_opcode(text, addr, e, m, x); - return {text, " F:", (unsigned)SFC::cpu.field(), " V:", format<3>(SFC::cpu.vcounter()), " H:", format<4>(SFC::cpu.hcounter())}; -} - -void Debugger::cpuExec(uint24 addr) { - cpuUsage[addr] |= Usage::Execute; - if(SFC::cpu.regs.e == 0) cpuUsage[addr] &= ~Usage::FlagE; - if(SFC::cpu.regs.p.m == 0) cpuUsage[addr] &= ~Usage::FlagM; - if(SFC::cpu.regs.p.x == 0) cpuUsage[addr] &= ~Usage::FlagX; - if(SFC::cpu.regs.e == 1) cpuUsage[addr] |= Usage::FlagE; - if(SFC::cpu.regs.p.m == 1) cpuUsage[addr] |= Usage::FlagM; - if(SFC::cpu.regs.p.x == 1) cpuUsage[addr] |= Usage::FlagX; - - cpuInstructionCounter++; - - if(cpuTracerFile.open()) { - if(!cpuTracerMask || cpuTracerMask[addr] == false) { - if(cpuTracerMask) cpuTracerMask[addr] = true; - cpuTracerFile.print(cpuDisassemble(), "\n"); - } - } - - if(savingState) return; - - if(breakpointTest(Source::CPU, Breakpoint::Mode::Execute, addr)) { - echo(cpuDisassemble(), "\n"); - return leave(); - } - - if(cpuRunFor) { - if(--cpuRunFor() == 0) { - echo(cpuDisassemble(), "\n"); - return leave(); - } - } - - if(cpuRunTo) { - if(addr == cpuRunTo()) { - echo(cpuDisassemble(), "\n"); - return leave(); - } - } - - if(cpuStepFor) { - echo(cpuDisassemble(), "\n"); - if(--cpuStepFor() == 0) return leave(); - } - - if(cpuStepTo) { - echo(cpuDisassemble(), "\n"); - if(addr == cpuStepTo()) return leave(); - } -} - -void Debugger::cpuRead(uint24 addr, uint8 data) { - cpuUsage[addr] |= Usage::Read; - if(breakpointTest(Source::CPU, Breakpoint::Mode::Read, addr, data)) leave(); -} - -void Debugger::cpuWrite(uint24 addr, uint8 data) { - cpuUsage[addr] |= Usage::Write; - if(breakpointTest(Source::CPU, Breakpoint::Mode::Write, addr, data)) leave(); -} - -void Debugger::echoBreakpoints() { - if(breakpoints.size() == 0) return; - echo("# source type addr data triggered\n"); - echo("--- ------ -------- ------ ---- ---------\n"); - for(unsigned n = 0; n < breakpoints.size(); n++) { - auto& bp = breakpoints[n]; - string output = {format<-3>(n), " "}; - output.append(format<-6>(sourceName(bp.source)), " "); - if(bp.mode == Breakpoint::Mode::Disabled) output.append("disabled "); - if(bp.mode == Breakpoint::Mode::Read ) output.append("read "); - if(bp.mode == Breakpoint::Mode::Write ) output.append("write "); - if(bp.mode == Breakpoint::Mode::Execute ) output.append("execute "); - output.append(hex<6>(bp.addr), " "); - output.append(bp.data ? hex<2>(bp.data()) : " ", " "); - output.append(format<-9>(bp.triggered)); - echo(output, "\n"); - } -} - -void Debugger::echoDisassemble(Source source, unsigned addr, signed size) { - if(source != Source::CPU && source != Source::SMP) return; - const unsigned maximumDisplacement = (source == Source::CPU ? 5 : 4); //maximum opcode length - uint8* usage = (source == Source::CPU ? cpuUsage : apuUsage); - if(!(usage[addr] & Usage::Execute)) return echo("No usage data available for ", sourceName(source), "/", hex<6>(addr), "\n"); - - while(size > 0) { - string text; - if(source == Source::CPU) { - text = cpuDisassemble(addr, usage[addr] & Usage::FlagE, usage[addr] & Usage::FlagM, usage[addr] & Usage::FlagX); - } - if(source == Source::SMP) { - text = smpDisassemble(addr, usage[addr] & Usage::FlagP); - } - text.resize(20); //remove register information - echo(text, "\n"); - if(--size <= 0) break; - - unsigned displacement = 1; - while(displacement < maximumDisplacement) { //maximum opcode length is four bytes - if(usage[addr + displacement] & Usage::Execute) break; - displacement++; - } - if(displacement >= maximumDisplacement) { - echo("...\n"); - return; - } - addr += displacement; - } -} - -void Debugger::echoHex(Source source, unsigned addr, signed size) { - if(memorySize(source) == 0) return; //not a valid memory pool - while(size > 0) { - string hexdata, asciidata; - for(unsigned n = 0; n < 16; n++) { - unsigned offset = addr; - if(source == Source::CPU && ((offset & 0x40e000) == 0x002000 || (offset & 0x40e000) == 0x004000)) { - //$00-3f,80-bf:2000-5fff - //reading MMIO registers can negatively impact emulation, so disallow these reads - hexdata.append("?? "); - asciidata.append("?"); - } else { - uint8 byte = memoryRead(source, addr + n); - hexdata.append(hex<2>(byte), " "); - asciidata.append(byte >= 0x20 && byte <= 0x7e ? (char)byte : '.'); - } - } - echo(hex<6>(addr % memorySize(source)), " [ ", hexdata, "] ", asciidata, "\n"); - addr += 16, size -= 16; - } -} - -void Debugger::memoryExport(Source source, string filename) { - file fp; - if(fp.open(filename, file::mode::write)) { - unsigned size = memorySize(source); - for(unsigned addr = 0; addr < size; addr++) { - fp.write(memoryRead(source, addr)); - } - echo("Exported memory to ", notdir(filename), "\n"); - } -} - -uint8 Debugger::memoryRead(Source source, unsigned addr) { - if(source == Source::CPU) { - return SFC::bus.read(addr & 0xffffff); - } - - if(source == Source::APU) { - return SFC::smp.apuram[addr & 0xffff]; - } - - if(source == Source::WRAM) { - return SFC::cpu.wram[addr & 0x1ffff]; - } - - if(source == Source::VRAM) { - return SFC::ppu.vram[addr & 0xffff]; - } - - if(source == Source::OAM) { - return SFC::ppu.oam[addr % 544]; - } - - if(source == Source::CGRAM) { - return SFC::ppu.cgram[addr & 511]; - } - - return 0x00; -} - -unsigned Debugger::memorySize(Source source) { - switch(source) { - case Source::CPU: return 0x1000000; - case Source::APU: return 0x10000; - case Source::WRAM: return 0x20000; - case Source::VRAM: return 0x10000; - case Source::OAM: return 544; - case Source::CGRAM: return 512; - } - return 0; -} - -void Debugger::memoryWrite(Source source, unsigned addr, uint8 data) { - if(source == Source::CPU) { - SFC::bus.write(addr & 0xffffff, data); - return; - } - - if(source == Source::APU) { - SFC::smp.apuram[addr & 0xffff] = data; - return; - } - - if(source == Source::WRAM) { - SFC::cpu.wram[addr & 0x1ffff] = data; - return; - } - - if(source == Source::VRAM) { - SFC::ppu.vram[addr & 0xffff] = data; - return; - } - - if(source == Source::OAM) { - SFC::ppu.oam[addr % 544] = data; - SFC::ppu.sprite.update(addr % 544, data); - return; - } - - if(source == Source::CGRAM) { - if(addr & 1) data &= 0x7f; - SFC::ppu.cgram[addr] = data; - return; - } -} - -void Debugger::ppuCgramRead(uint16 addr, uint8 data) { - if(breakpointTest(Source::CGRAM, Breakpoint::Mode::Read, addr, data)) leave(); -} - -void Debugger::ppuCgramWrite(uint16 addr, uint8 data) { - if(breakpointTest(Source::CGRAM, Breakpoint::Mode::Write, addr, data)) leave(); -} - -void Debugger::ppuOamRead(uint16 addr, uint8 data) { - if(breakpointTest(Source::OAM, Breakpoint::Mode::Read, addr, data)) leave(); -} - -void Debugger::ppuOamWrite(uint16 addr, uint8 data) { - if(breakpointTest(Source::OAM, Breakpoint::Mode::Write, addr, data)) leave(); -} - -void Debugger::ppuVramRead(uint16 addr, uint8 data) { - if(breakpointTest(Source::VRAM, Breakpoint::Mode::Read, addr, data)) leave(); -} - -void Debugger::ppuVramWrite(uint16 addr, uint8 data) { - if(breakpointTest(Source::VRAM, Breakpoint::Mode::Write, addr, data)) leave(); -} - -string Debugger::smpDisassemble() { - return SFC::smp.disassemble_opcode(SFC::smp.regs.pc, SFC::smp.regs.p.p); -} - -string Debugger::smpDisassemble(uint16 addr, bool p) { - return SFC::smp.disassemble_opcode(addr, p); -} - -void Debugger::smpExec(uint16 addr) { - apuUsage[addr] |= Usage::Execute; - if(SFC::smp.regs.p.p == 0) apuUsage[addr] &= ~Usage::FlagP; - if(SFC::smp.regs.p.p == 1) apuUsage[addr] |= Usage::FlagP; - - smpInstructionCounter++; - - if(smpTracerFile.open()) { - if(!smpTracerMask || smpTracerMask[addr] == false) { - if(smpTracerMask) smpTracerMask[addr] = true; - smpTracerFile.print(smpDisassemble(), "\n"); - } - } - - if(savingState) return; - - if(breakpointTest(Source::SMP, Breakpoint::Mode::Execute, addr)) { - echo(smpDisassemble(), "\n"); - return leave(); - } - - if(smpRunFor) { - if(--smpRunFor() == 0) { - echo(smpDisassemble(), "\n"); - return leave(); - } - } - - if(smpRunTo) { - if(addr == smpRunTo()) { - echo(smpDisassemble(), "\n"); - return leave(); - } - } - - if(smpStepFor) { - echo(smpDisassemble(), "\n"); - if(--smpStepFor() == 0) return leave(); - } - - if(smpStepTo) { - echo(smpDisassemble(), "\n"); - if(addr == smpStepTo()) return leave(); - } -} - -void Debugger::smpRead(uint16 addr, uint8 data) { - apuUsage[addr] |= Usage::Read; - if(breakpointTest(Source::SMP, Breakpoint::Mode::Read, addr, data)) leave(); - if(breakpointTest(Source::APU, Breakpoint::Mode::Read, addr, data)) leave(); -} - -void Debugger::smpWrite(uint16 addr, uint8 data) { - apuUsage[addr] |= Usage::Write; - if(breakpointTest(Source::SMP, Breakpoint::Mode::Write, addr, data)) leave(); - if(breakpointTest(Source::APU, Breakpoint::Mode::Write, addr, data)) leave(); -} - -string Debugger::sourceName(Source source) { - switch(source) { - case Source::CPU: return "cpu"; - case Source::SMP: return "smp"; - case Source::PPU: return "ppu"; - case Source::DSP: return "dsp"; - case Source::APU: return "apu"; - case Source::WRAM: return "wram"; - case Source::VRAM: return "vram"; - case Source::OAM: return "oam"; - case Source::CGRAM: return "cgram"; - } - return "none"; -} - -void Debugger::stateLoad(string filename) { - auto memory = file::read(filename); - if(memory.size() == 0) return echo("Error: state file ", notdir(filename), " not found\n"); - serializer s(memory.data(), memory.size()); - if(emulator->unserialize(s) == false) return echo("Error: failed to unserialize state from ", notdir(filename), "\n"); - echo("State loaded from ", notdir(filename), "\n"); -} - -void Debugger::stateSave(string filename) { - savingState = true; - serializer s = emulator->serialize(); - if(file::write(filename, s.data(), s.size())) { - echo("State saved to ", notdir(filename), "\n"); - } - savingState = false; -} - -void Debugger::tracerDisable(Source source) { - if(source != Source::CPU && source != Source::SMP) return; - file& tracerFile = (source == Source::CPU ? cpuTracerFile : smpTracerFile); - if(tracerFile.open() == false) return; - tracerFile.close(); - echo(sourceName(source).upper(), " tracer disabled\n"); -} - -void Debugger::tracerEnable(Source source, string filename) { - if(source != Source::CPU && source != Source::SMP) return; - file& tracerFile = (source == Source::CPU ? cpuTracerFile : smpTracerFile); - if(tracerFile.open() == true) return; - if(tracerFile.open(filename, file::mode::write)) { - echo(sourceName(source).upper(), " tracer enabled\n"); - } -} - -void Debugger::tracerMaskDisable(Source source) { - if(source != Source::CPU && source != Source::SMP) return; - bitvector& tracerMask = (source == Source::CPU ? cpuTracerMask : smpTracerMask); - tracerMask.reset(); - echo(sourceName(source).upper(), " tracer mask disabled\n"); -} - -void Debugger::tracerMaskEnable(Source source) { - if(source != Source::CPU && source != Source::SMP) return; - bitvector& tracerMask = (source == Source::CPU ? cpuTracerMask : smpTracerMask); - unsigned size = (source == Source::CPU ? 0x1000000 : 0x10000); - tracerMask.resize(size); - tracerMask.clear(); - echo(sourceName(source).upper(), " tracer mask enabled\n"); -} diff --git a/target-loki/debugger/debugger.hpp b/target-loki/debugger/debugger.hpp deleted file mode 100644 index 3ed978cb..00000000 --- a/target-loki/debugger/debugger.hpp +++ /dev/null @@ -1,92 +0,0 @@ -struct Debugger { - enum class Source : unsigned { CPU, SMP, PPU, DSP, APU, WRAM, VRAM, OAM, CGRAM }; - - struct Breakpoint { - Source source = Source::CPU; - enum class Mode : unsigned { Disabled, Read, Write, Execute } mode = Mode::Disabled; - unsigned addr = 0; - maybe data; - unsigned triggered = 0; //counter for number of times breakpoint was hit - }; - - struct Usage { - enum : unsigned { - Read = 0x01, - Write = 0x02, - Execute = 0x04, - //CPU - FlagE = 0x08, - FlagM = 0x10, - FlagX = 0x20, - //APU - FlagP = 0x08, - DspRead = 0x10, - DspWrite = 0x20, - }; - }; - - Debugger(); - - void load(); - void unload(); - void main(); - - void run(); - void stop(); - void leave(); - - bool breakpointTest(Source source, Breakpoint::Mode mode, unsigned addr, uint8 data = 0x00); - string cpuDisassemble(); - string cpuDisassemble(unsigned addr, bool e, bool m, bool x); - void cpuExec(uint24 addr); - void cpuRead(uint24 addr, uint8 data); - void cpuWrite(uint24 addr, uint8 data); - void echoBreakpoints(); - void echoDisassemble(Source source, unsigned addr, signed size); - void echoHex(Source source, unsigned addr, signed size); - void memoryExport(Source source, string filename); - uint8 memoryRead(Source source, unsigned addr); - unsigned memorySize(Source source); - void memoryWrite(Source source, unsigned addr, uint8 data); - void ppuCgramRead(uint16 addr, uint8 data); - void ppuCgramWrite(uint16 addr, uint8 data); - void ppuOamRead(uint16 addr, uint8 data); - void ppuOamWrite(uint16 addr, uint8 data); - void ppuVramRead(uint16 addr, uint8 data); - void ppuVramWrite(uint16 addr, uint8 data); - string smpDisassemble(); - string smpDisassemble(uint16 addr, bool p); - void smpExec(uint16 addr); - void smpRead(uint16 addr, uint8 data); - void smpWrite(uint16 addr, uint8 data); - string sourceName(Source source); - void stateLoad(string filename); - void stateSave(string filename); - void tracerDisable(Source source); - void tracerEnable(Source source, string filename); - void tracerMaskDisable(Source source); - void tracerMaskEnable(Source source); - - bool running = false; //emulation runs asynchronously (cooperatively) to terminal commands - bool savingState = false; //suppresses all break events to allow state to be captured synchronously - - uint8* apuUsage = nullptr; - vector breakpoints; - unsigned cpuInstructionCounter = 0; - maybe cpuRunFor; - maybe cpuRunTo; - maybe cpuStepFor; - maybe cpuStepTo; - file cpuTracerFile; - bitvector cpuTracerMask; - uint8* cpuUsage = nullptr; - unsigned smpInstructionCounter = 0; - maybe smpRunFor; - maybe smpRunTo; - maybe smpStepFor; - maybe smpStepTo; - file smpTracerFile; - bitvector smpTracerMask; -}; - -extern Debugger* debugger; diff --git a/target-loki/input/input.cpp b/target-loki/input/input.cpp deleted file mode 100644 index a45105a4..00000000 --- a/target-loki/input/input.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "../loki.hpp" -InputManager* inputManager = nullptr; - -void AbstractInput::bind() { - for(auto device : inputManager->devices) { - if(device->isKeyboard() == false) continue; - if(auto group = device->find("Button")) { - if(auto input = device->group[group()].find(mapping)) { - this->device = device; - this->group = group(); - this->input = input(); - break; - } - } - } -} - -int16_t AbstractInput::poll() { - if(device == nullptr) return 0; - return device->group[group].input[input].value; -} - -InputManager::InputManager() { - inputManager = this; -} - -void InputManager::load() { - unsigned guid = 0; - Configuration::Node emulatorNode; - - for(auto& port : emulator->port) { - Configuration::Node portNode; - - for(auto& device : port.device) { - Configuration::Node deviceNode; - - for(auto& number : device.order) { - auto& input = device.input[number]; - input.guid = guid++; - - auto abstract = new AbstractInput; - abstract->name = string{input.name}.replace(" ", ""); - abstract->mapping = "None"; - inputMap.append(abstract); - - deviceNode.append(abstract->mapping, abstract->name); - } - - portNode.append(deviceNode, string{device.name}.replace(" ", "")); - } - - emulatorNode.append(portNode, string{port.name}.replace(" ", "")); - } - - append(emulatorNode, "SuperFamicom"); - - Configuration::Document::load(program->path("input.bml")); - Configuration::Document::save(program->path("input.bml")); -} - -void InputManager::unload() { - Configuration::Document::save(program->path("input.bml")); -} - -void InputManager::bind() { - for(auto input : inputMap) input->bind(); -} - -void InputManager::poll() { - auto devices = input.poll(); - bool changed = devices.size() != this->devices.size(); - if(changed == false) { - for(unsigned n = 0; n < devices.size(); n++) { - changed = devices[n] != this->devices[n]; - if(changed) break; - } - } - if(changed == true) { - this->devices = devices; - bind(); - } -} diff --git a/target-loki/input/input.hpp b/target-loki/input/input.hpp deleted file mode 100644 index d8b84a87..00000000 --- a/target-loki/input/input.hpp +++ /dev/null @@ -1,25 +0,0 @@ -struct AbstractInput { - void bind(); - int16_t poll(); - - string name; - string mapping; - - HID::Device* device = nullptr; - unsigned group = 0; - unsigned input = 0; -}; - -struct InputManager : Configuration::Document { - InputManager(); - void load(); - void unload(); - - void bind(); - void poll(); - - vector devices; - vector inputMap; -}; - -extern InputManager* inputManager; diff --git a/target-loki/interface/interface.cpp b/target-loki/interface/interface.cpp deleted file mode 100644 index 388b30db..00000000 --- a/target-loki/interface/interface.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "../loki.hpp" -Interface* interface = nullptr; -SuperFamicom::Interface* emulator = nullptr; - -Interface::Interface() { - interface = this; - emulator = new SuperFamicom::Interface; - emulator->bind = this; -} - -bool Interface::load(string pathname) { - pathname.transform("\\", "/").rtrim("/"); - if(!directory::exists(pathname)) return false; - - string type = extension(pathname); - - for(auto& media : emulator->media) { - if(media.bootable == false) continue; - if(type != media.type) continue; - - this->pathname = pathname.append("/"); - pathnames.reset(); - pathnames(0) = program->path({media.name, ".sys/"}); - pathnames(media.id) = pathname; - echo("Loaded ", pathname, "\n"); - - emulator->load(media.id); - emulator->paletteUpdate(Emulator::Interface::PaletteMode::Standard); - emulator->power(); - presentation->setTitle(emulator->title()); - - return true; - } - - return false; -} - -void Interface::unload() { - emulator->unload(); -} - -//bindings - -void Interface::loadRequest(unsigned id, string name, string type) { -} - -void Interface::loadRequest(unsigned id, string path) { - string pathname = {pathnames(emulator->group(id)), path}; - if(file::exists(pathname) == false) return; - mmapstream stream(pathname); - emulator->load(id, stream); - echo("Loaded ", path, "\n"); -} - -void Interface::saveRequest(unsigned id, string path) { - string pathname = {pathnames(emulator->group(id)), path}; - filestream stream(pathname, file::mode::write); - emulator->save(id, stream); - echo("Saved ", path, "\n"); -} - -uint32_t Interface::videoColor(unsigned source, uint16_t alpha, uint16_t red, uint16_t green, uint16_t blue) { - return ((alpha >> 8) << 24) | ((red >> 8) << 16) | ((green >> 8) << 8) | ((blue >> 8) << 0); -} - -void Interface::videoRefresh(const uint32_t* palette, const uint32_t* data, unsigned pitch, unsigned width, unsigned height) { - uint32_t* output; - unsigned outputPitch; - - if(video.lock(output, outputPitch, width, height)) { - pitch >>= 2, outputPitch >>= 2; - - for(unsigned y = 0; y < height; y++) { - const uint32_t* sp = data + y * pitch; - uint32_t* dp = output + y * outputPitch; - for(unsigned x = 0; x < width; x++) { - *dp++ = palette[*sp++]; - } - } - - video.unlock(); - video.refresh(); - } -} - -void Interface::audioSample(int16_t lsample, int16_t rsample) { - if(settings->audio.mute) lsample = 0, rsample = 0; - signed samples[] = {lsample, rsample}; - dspaudio.sample(samples); - while(dspaudio.pending()) { - dspaudio.read(samples); - audio.sample(samples[0], samples[1]); - } -} - -int16_t Interface::inputPoll(unsigned port, unsigned device, unsigned input) { - unsigned guid = emulator->port[port].device[device].input[input].guid; - return inputManager->inputMap[guid]->poll(); -} - -void Interface::inputRumble(unsigned port, unsigned device, unsigned input, bool enable) { -} - -unsigned Interface::dipSettings(const Markup::Node& node) { - return 0; -} - -string Interface::path(unsigned group) { - return pathnames(group); -} - -string Interface::server() { - return ""; -} - -void Interface::notify(string text) { -} diff --git a/target-loki/interface/interface.hpp b/target-loki/interface/interface.hpp deleted file mode 100644 index 1438075e..00000000 --- a/target-loki/interface/interface.hpp +++ /dev/null @@ -1,25 +0,0 @@ -struct Interface : Emulator::Interface::Bind { - Interface(); - bool load(string pathname); - void unload(); - - //bindings - void loadRequest(unsigned id, string name, string type); - void loadRequest(unsigned id, string path); - void saveRequest(unsigned id, string path); - uint32_t videoColor(unsigned source, uint16_t alpha, uint16_t red, uint16_t green, uint16_t blue); - void videoRefresh(const uint32_t* palette, const uint32_t* data, unsigned pitch, unsigned width, unsigned height); - void audioSample(int16_t lsample, int16_t rsample); - int16_t inputPoll(unsigned port, unsigned device, unsigned input); - void inputRumble(unsigned port, unsigned device, unsigned input, bool enable); - unsigned dipSettings(const Markup::Node& node); - string path(unsigned group); - string server(); - void notify(string text); - - string pathname; //path to game folder - lstring pathnames; -}; - -extern Interface* interface; -extern SuperFamicom::Interface* emulator; diff --git a/target-loki/loki.cpp b/target-loki/loki.cpp deleted file mode 100644 index 26232e1c..00000000 --- a/target-loki/loki.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "loki.hpp" -#include "resource/resource.cpp" - -Program* program = nullptr; -DSP dspaudio; - -string Program::path(string name) { - string path = {basepath, name}; - if(file::exists(path) || directory::exists(path)) return path; - path = {userpath, name}; - if(file::exists(path) || directory::exists(path)) return path; - path = {sharedpath, name}; - if(file::exists(path) || directory::exists(path)) return path; - return {userpath, name}; -} - -void Program::main() { - inputManager->poll(); - debugger->main(); -} - -Program::Program(string pathname) { - program = this; - - basepath = nall::programpath(); - userpath = {nall::configpath(), "loki/"}; - sharedpath = {nall::sharedpath(), "loki/"}; - directory::create(userpath); - - new Settings; - new InputManager; - new Interface; - new Debugger; - new Presentation; - new Terminal; - - presentation->setVisible(); - terminal->setVisible(); - Application::processEvents(); - - video.driver(settings->video.driver); - video.set(Video::Handle, presentation->viewport.handle()); - video.set(Video::Synchronize, settings->video.synchronize); - video.set(Video::Filter, Video::FilterNearest); - if(video.init() == false) { video.driver("None"); video.init(); } - - audio.driver(settings->audio.driver); - audio.set(Audio::Handle, presentation->viewport.handle()); - audio.set(Audio::Synchronize, settings->audio.synchronize); - audio.set(Audio::Frequency, 48000u); - if(audio.init() == false) { audio.driver("None"); audio.init(); } - - input.driver(settings->input.driver); - input.set(Input::Handle, presentation->viewport.handle()); - if(input.init() == false) { input.driver("None"); input.init(); } - input.onChange = {&Terminal::inputEvent, terminal}; - - dspaudio.setPrecision(16); - dspaudio.setBalance(0.0); - dspaudio.setFrequency(32000); - dspaudio.setResampler(DSP::ResampleEngine::Hermite); - dspaudio.setResamplerFrequency(48000); - - presentation->showSplash(); - - inputManager->load(); - interface->load(pathname); - debugger->load(); - terminal->load(); - - Application::main = {&Program::main, this}; - Application::run(); - - terminal->unload(); - debugger->unload(); - interface->unload(); - inputManager->unload(); - settings->unload(); -} - -int main(int argc, char** argv) { - #if defined(PLATFORM_WINDOWS) - utf8_args(argc, argv); - #endif - - if(argc != 2 || !directory::exists(argv[1])) { - print("loki v", Emulator::Version, "\n"); - print("usage: loki /path/game.sfc/\n"); - return 0; - } - - Application::setName("loki"); - new Program(argv[1]); - delete program; - - return 0; -} diff --git a/target-loki/loki.hpp b/target-loki/loki.hpp deleted file mode 100644 index 293b21ea..00000000 --- a/target-loki/loki.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -namespace SFC = SuperFamicom; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -using namespace nall; - -#include -using namespace ruby; - -#include -using namespace phoenix; - -#include "settings/settings.hpp" -#include "input/input.hpp" -#include "interface/interface.hpp" -#include "debugger/debugger.hpp" -#include "presentation/presentation.hpp" -#include "terminal/terminal.hpp" -#include "resource/resource.hpp" - -struct Program { - string basepath; - string userpath; - string sharedpath; - - string path(string name); - void main(); - Program(string pathname); -}; - -template void echo(Args&&... args) { - terminal->print({std::forward(args)...}); -} - -extern Program* program; -extern DSP dspaudio; diff --git a/target-loki/presentation/presentation.cpp b/target-loki/presentation/presentation.cpp deleted file mode 100644 index 00a85862..00000000 --- a/target-loki/presentation/presentation.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "../loki.hpp" -Presentation* presentation = nullptr; - -Presentation::Presentation() { - presentation = this; - if(settings->geometry.presentation.empty()) { - settings->geometry.presentation = "64,64,512,480"; - } - - setTitle({"loki v", Emulator::Version}); - setGeometry(settings->geometry.presentation); - setResizable(false); - - layout.append(viewport, {0, 0, 512, 480}); - append(layout); - - onClose = &Application::quit; - - splash.allocate(512, 480); - splash.verticalGradient(0xff00005f, 0xff000000, 512, 480, 256, 0); - nall::image floor; - floor.allocate(512, 480); - floor.radialGradient(0xffff0000, 0x00000000, 384, 240, 256, 415); - splash.impose(image::blend::sourceAlpha, 0, 0, floor, 0, 0, floor.width, floor.height); - nall::image loki(resource::loki, sizeof resource::loki); - splash.impose(image::blend::sourceAlpha, (512 - loki.width) / 2, (480 - loki.height) / 2, loki, 0, 0, loki.width, loki.height); -} - -void Presentation::showSplash() { - uint32_t* data; - unsigned pitch; - if(video.lock(data, pitch, 512, 480)) { - for(unsigned y = 0; y < 480; y++) { - memcpy((uint8_t*)data + y * pitch, splash.data + y * splash.pitch, 512 * sizeof(uint32_t)); - } - video.unlock(); - video.refresh(); - } -} diff --git a/target-loki/presentation/presentation.hpp b/target-loki/presentation/presentation.hpp deleted file mode 100644 index f5094b11..00000000 --- a/target-loki/presentation/presentation.hpp +++ /dev/null @@ -1,11 +0,0 @@ -struct Presentation : Window { - Presentation(); - void showSplash(); - - FixedLayout layout; - Viewport viewport; - - nall::image splash; -}; - -extern Presentation* presentation; diff --git a/target-loki/resource/loki.png b/target-loki/resource/loki.png deleted file mode 100644 index 7b031d9ccf3f06aa8bf33ee480dd12fa0292175b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121905 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 KMNUMnLSTY{54ukP diff --git a/target-loki/resource/resource.bml b/target-loki/resource/resource.bml deleted file mode 100644 index 9d8482c8..00000000 --- a/target-loki/resource/resource.bml +++ /dev/null @@ -1,2 +0,0 @@ -resource name=resource - binary id=loki name=loki.png diff --git a/target-loki/resource/resource.cpp b/target-loki/resource/resource.cpp deleted file mode 100644 index 5f8cffbf..00000000 --- a/target-loki/resource/resource.cpp +++ /dev/null @@ -1,3816 +0,0 @@ -namespace resource { - -const uint8_t loki[121905] = { - 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,1,32,0,0,1,104,8,6,0,0,0,247,136,38, - 129,0,0,0,9,112,72,89,115,0,0,11,19,0,0,11,19,1,0,154,156,24,0,0,0,4,103,65,77,65,0,0, - 177,142,124,251,81,147,0,0,0,32,99,72,82,77,0,0,122,37,0,0,128,131,0,0,249,255,0,0,128,233,0,0, - 117,48,0,0,234,96,0,0,58,152,0,0,23,111,146,95,197,70,0,1,219,167,73,68,65,84,120,218,236,253,119,152, - 100,215,117,222,11,255,246,62,161,114,85,231,220,51,61,57,103,12,114,14,36,2,193,28,36,81,129,162,2,149,124,229, - 251,73,150,174,172,123,45,75,126,244,93,203,178,37,75,178,44,90,209,164,40,81,34,197,12,18,32,0,34,199,193,0, - 147,83,247,116,206,93,93,93,185,234,196,189,239,31,85,51,24,128,32,197,128,72,246,122,158,126,122,166,186,234,156,83, - 59,188,123,173,119,37,81,187,239,125,188,26,98,10,137,18,146,55,131,68,226,22,255,242,224,4,31,248,143,79,240,86, - 144,255,1,244,0,255,127,224,111,129,191,4,54,3,231,129,63,251,46,175,245,21,96,14,56,2,124,28,24,5,2,224, - 52,176,23,184,23,216,222,252,187,15,104,192,0,20,208,14,180,129,184,14,228,81,48,218,65,100,33,92,128,160,23,184, - 237,251,252,158,117,96,6,216,4,252,28,176,3,200,1,78,243,153,126,5,168,189,9,231,231,131,192,6,192,2,126,23, - 248,123,224,16,240,54,32,211,124,246,231,154,99,56,12,172,109,142,101,25,120,7,112,79,115,156,199,128,46,96,13,112, - 13,240,123,205,107,143,0,133,230,56,76,0,235,128,241,230,123,119,1,207,3,155,119,238,163,239,193,23,48,61,221,188, - 218,171,35,251,6,223,216,61,107,178,42,63,116,34,155,160,147,105,44,0,209,9,134,9,118,20,226,2,18,199,32,19, - 129,214,18,200,24,44,118,73,57,211,166,84,185,38,132,54,163,81,64,124,119,55,20,2,195,247,80,190,191,58,248,171, - 178,10,64,63,140,18,54,79,216,13,64,43,24,123,192,182,32,17,66,26,104,23,141,3,183,79,66,111,20,186,93,41, - 123,124,132,182,85,248,76,196,180,239,245,60,231,220,161,214,142,96,241,255,248,61,116,52,14,74,125,199,247,246,147,105, - 54,223,251,207,180,220,251,25,172,213,169,88,149,85,0,250,225,17,221,52,125,210,32,135,193,238,128,84,30,58,5,244, - 43,88,35,97,16,24,112,160,191,98,199,122,150,251,250,187,138,61,93,169,83,139,179,241,3,83,51,179,59,96,26,207, - 137,152,169,140,40,253,135,255,73,213,144,72,253,237,77,0,45,4,82,26,152,145,40,174,214,4,158,71,128,32,4,236, - 213,41,89,149,85,0,250,225,208,120,2,96,17,140,50,36,98,66,116,197,96,77,168,245,6,27,54,123,66,110,204,167, - 50,107,179,241,84,231,98,212,200,208,149,78,248,29,237,178,218,213,75,110,100,148,173,217,229,153,29,97,248,152,128,103, - 77,88,52,93,39,236,125,236,107,44,93,125,27,202,52,17,175,0,66,66,26,24,177,56,218,169,81,203,103,25,57,252, - 56,239,172,85,120,252,208,163,164,42,165,213,73,89,149,85,0,250,65,151,0,72,0,187,64,62,6,113,3,250,226,176, - 205,210,122,47,66,236,200,153,246,186,137,150,206,129,165,77,27,90,229,186,158,72,58,41,201,196,124,124,43,198,145,227, - 211,180,125,249,158,218,187,87,138,103,58,225,17,15,30,76,194,177,9,88,238,242,92,117,205,125,159,229,212,229,55,224, - 89,54,232,240,2,234,16,88,54,88,22,193,242,2,147,143,126,149,59,206,30,69,140,156,226,241,192,167,79,107,20,223, - 53,107,180,42,171,0,180,42,111,69,137,3,62,216,87,64,187,11,59,12,184,218,133,203,207,39,90,182,77,172,219,208, - 163,183,15,196,90,59,99,162,95,57,224,148,136,138,12,211,101,120,254,201,231,184,250,220,248,220,53,120,135,52,60,236, - 193,83,14,140,236,129,242,28,168,218,37,54,157,22,2,109,152,4,150,141,85,175,48,116,234,24,222,217,227,44,31,126, - 156,133,82,30,5,92,160,170,245,234,148,172,202,42,0,189,53,197,6,142,211,112,237,14,54,205,42,247,95,209,38,34, - 96,172,129,30,23,110,0,110,155,138,197,47,159,61,112,217,218,112,109,38,154,76,199,241,125,77,101,113,133,186,116,137, - 181,165,152,40,20,201,62,252,130,247,225,197,236,240,32,250,81,23,30,52,225,72,20,22,142,129,59,1,108,107,242,72, - 8,129,147,72,129,20,36,10,57,182,61,245,32,226,241,175,179,185,94,229,108,224,147,93,213,116,94,19,209,128,48,4, - 58,13,162,40,208,1,160,245,42,0,173,202,107,43,17,224,33,94,140,141,201,1,7,128,202,183,249,140,4,211,131,117, - 26,222,54,223,59,240,54,245,193,187,186,230,74,211,20,231,75,164,242,138,164,89,39,19,9,49,91,211,156,154,205,211, - 245,240,243,249,31,175,212,143,217,240,144,11,143,104,56,101,64,241,147,16,246,53,65,79,92,0,22,207,101,207,3,159, - 167,115,252,28,189,195,39,48,125,143,17,173,145,171,83,245,154,138,0,188,153,25,236,143,255,111,130,187,62,128,221,26, - 193,180,77,188,10,232,239,194,27,249,102,148,213,181,243,22,56,33,82,64,43,141,128,181,86,96,99,83,43,217,242,178, - 159,237,64,6,12,5,9,7,186,23,174,189,188,99,232,186,253,144,93,166,152,155,39,52,107,36,45,73,38,222,206,241, - 51,203,36,30,58,154,191,171,82,127,214,128,127,9,224,115,2,158,47,65,254,72,3,119,88,15,172,0,109,205,251,77, - 250,30,251,191,242,15,12,158,60,140,233,185,63,48,167,240,91,1,128,252,220,18,230,191,251,57,190,116,160,151,242,47, - 254,12,143,254,237,39,8,125,7,157,150,72,67,34,132,120,203,174,239,85,121,139,136,75,35,58,186,11,56,215,60,61, - 76,26,241,61,23,248,150,24,4,109,144,79,9,57,91,59,114,186,242,84,127,75,250,221,239,184,150,165,130,199,225,179, - 227,100,11,101,142,141,47,208,114,236,92,237,71,235,181,243,62,60,166,225,97,31,70,226,224,215,155,38,223,94,224,102, - 160,175,105,126,117,94,48,195,86,229,141,3,162,48,192,171,148,153,253,220,39,121,254,115,159,164,255,207,126,159,53,191, - 252,127,225,190,227,131,136,182,40,182,48,9,235,26,241,22,98,222,86,53,160,183,152,186,42,129,98,243,255,123,155,192, - 240,110,224,110,224,125,192,65,240,21,76,249,90,61,125,197,244,228,11,149,39,143,120,231,23,114,244,36,76,126,241,253, - 239,226,224,109,55,48,93,46,176,195,169,123,166,82,10,48,52,100,108,104,53,33,214,6,70,6,68,186,121,143,36,141, - 20,3,86,249,157,55,149,214,96,2,245,241,17,82,191,249,49,126,251,178,62,30,252,185,159,36,56,122,146,72,82,144, - 202,72,132,148,171,0,180,42,175,157,74,158,108,114,67,135,155,154,143,251,162,137,166,5,100,5,60,17,117,235,95,217, - 255,252,137,231,22,159,92,116,203,50,202,217,51,79,115,249,222,65,62,241,55,255,133,142,159,252,137,248,145,84,219,80, - 5,110,143,194,135,37,188,199,129,235,99,176,235,122,232,235,130,68,30,228,170,145,245,230,20,125,225,64,10,3,170,149, - 50,222,151,62,77,225,206,3,212,126,238,39,249,235,191,250,59,148,91,195,72,75,120,147,155,103,171,0,244,22,151,11, - 218,201,2,112,31,240,32,240,0,120,45,48,234,194,215,59,85,240,249,29,223,120,248,208,241,7,158,115,236,161,29,76, - 61,51,130,63,126,158,119,255,231,143,217,87,63,248,143,221,227,63,242,227,151,63,148,234,254,192,188,48,63,22,192,47, - 75,248,185,24,124,64,194,117,243,176,201,129,54,7,236,101,16,106,117,184,223,212,27,217,242,61,114,159,251,123,254,224, - 215,63,202,115,55,239,162,246,241,191,68,151,43,184,118,136,142,201,55,165,14,187,10,64,63,64,11,48,108,254,30,2, - 178,224,250,66,140,251,82,62,210,165,220,175,111,250,242,163,39,31,253,187,111,248,201,29,219,8,85,129,83,247,126,134, - 193,190,8,63,251,233,63,177,14,124,246,239,186,30,185,237,242,125,159,217,216,241,246,175,182,118,254,200,73,97,253,156, - 134,159,181,225,199,21,220,169,224,178,121,88,51,3,153,115,13,48,146,149,75,78,226,87,55,63,123,85,190,31,205,248, - 2,196,20,39,199,168,254,246,47,51,117,112,128,23,126,225,35,116,29,59,73,152,20,68,51,18,195,120,243,108,251,85, - 18,250,45,174,130,155,52,74,92,196,64,238,132,72,28,98,123,32,82,6,43,166,117,2,104,245,161,214,175,130,197,200, - 215,190,158,251,219,185,185,204,109,191,241,145,216,181,155,54,51,253,220,33,18,99,51,188,237,230,183,113,217,13,255,204, - 3,95,254,188,125,254,145,39,218,78,141,140,183,77,14,207,173,237,158,205,30,88,27,250,51,105,56,111,194,176,130,241, - 89,152,93,128,101,160,96,66,197,6,119,1,130,16,148,209,220,0,171,154,210,155,3,140,172,48,192,43,23,73,126,225, - 31,232,187,231,179,100,223,249,35,28,186,246,22,54,189,235,3,116,181,197,168,85,87,1,104,85,190,7,147,75,52,249, - 31,11,228,46,136,204,67,70,65,71,10,122,5,12,248,208,158,128,24,208,82,211,186,199,133,78,29,141,13,4,134,109, - 4,147,11,222,63,255,201,39,98,238,237,215,176,251,250,189,200,184,201,233,71,191,64,207,192,90,62,116,199,157,204,95, - 113,37,199,159,57,204,212,11,47,36,138,249,108,226,212,236,210,96,231,124,97,103,219,124,33,107,46,101,23,98,42,156, - 181,27,152,55,227,55,126,22,134,97,217,130,194,58,168,70,192,115,33,176,65,201,85,205,232,205,35,190,71,199,231,62, - 201,103,63,247,73,158,250,147,255,196,47,125,236,215,121,215,135,126,178,113,116,173,2,208,170,124,167,38,86,20,164,15, - 86,39,196,103,161,43,6,131,186,81,227,107,115,29,134,10,210,30,200,71,51,173,37,83,70,74,17,25,9,186,59,147, - 173,67,221,150,238,50,69,44,147,17,59,77,67,72,175,74,110,250,12,167,31,94,161,119,247,78,118,92,125,3,238,204, - 56,179,11,103,176,218,58,185,226,242,13,108,90,223,203,244,240,56,194,194,240,188,82,139,151,93,105,145,217,202,250,197, - 147,147,110,253,228,104,41,62,183,180,210,230,123,75,9,21,206,217,48,19,194,76,0,179,157,176,16,192,130,3,203,239, - 132,90,5,130,55,39,251,240,195,107,162,229,39,206,243,251,191,245,11,124,226,227,127,200,244,196,249,85,0,90,149,111, - 109,102,105,26,9,166,221,192,187,32,102,67,151,128,53,26,214,89,13,208,217,90,74,36,55,102,215,172,233,245,183,108, - 204,68,55,14,68,186,134,58,89,159,18,152,182,65,38,145,36,21,73,160,113,241,106,101,242,217,34,147,19,243,20,125, - 65,247,224,6,218,163,54,165,209,195,164,59,123,145,145,78,170,217,5,170,179,11,88,118,11,194,173,48,57,50,77,204, - 142,99,72,65,203,134,30,99,199,85,59,227,66,136,120,113,33,219,179,112,122,118,235,194,185,37,71,143,206,151,219,114, - 139,185,120,105,101,49,230,121,51,17,24,14,224,76,59,140,45,193,220,46,40,218,224,85,65,197,86,167,245,77,35,51, - 147,163,171,38,216,170,124,235,211,202,1,118,131,116,32,146,131,150,40,108,240,225,160,134,253,158,97,172,243,182,111,31, - 140,220,124,85,231,186,171,46,139,237,219,181,149,174,222,86,18,134,143,187,188,64,173,176,66,189,158,167,90,46,82,90, - 89,96,113,198,225,252,200,12,11,139,115,84,42,21,52,154,186,231,113,199,157,55,35,60,147,249,177,73,2,165,145,94, - 72,173,92,226,212,233,103,57,121,102,129,68,42,131,45,43,172,223,48,196,145,103,198,153,158,157,97,227,166,245,108,220, - 188,150,125,119,94,38,115,55,86,226,227,243,115,241,220,66,177,123,102,198,223,102,78,228,170,241,231,143,45,117,230,151, - 198,82,112,86,192,169,8,156,155,131,73,96,73,64,77,129,10,87,167,120,85,86,1,232,205,169,245,132,52,106,68,239, - 130,104,4,186,13,88,175,97,91,8,251,253,100,122,175,185,127,199,154,246,119,95,149,105,191,249,114,187,189,187,7,83, - 24,248,65,141,218,114,142,114,177,74,173,152,101,121,113,145,233,137,44,83,19,5,242,185,2,158,23,224,123,62,8,69, - 123,71,59,123,246,110,231,236,185,83,204,206,76,49,48,48,64,16,212,241,157,58,197,124,141,83,167,39,152,153,207,99, - 24,6,61,61,25,182,110,216,134,38,228,236,240,89,234,53,135,177,225,57,166,207,205,146,157,88,162,163,43,142,116,86, - 216,56,48,128,215,37,197,226,166,174,100,112,195,254,228,236,249,197,65,253,204,11,187,219,199,206,78,119,248,222,176,132, - 19,33,28,43,193,185,71,96,97,23,212,98,205,162,30,171,230,217,42,0,173,202,155,68,106,192,187,193,176,26,209,201, - 155,3,184,50,132,203,107,241,196,22,174,61,56,212,255,222,107,91,218,247,14,200,120,103,154,170,227,178,56,126,26,171, - 226,227,107,147,92,169,192,252,248,20,115,99,43,44,47,151,240,3,23,173,3,12,35,74,166,37,138,97,71,232,237,237, - 225,178,131,251,104,105,73,176,148,27,101,165,48,75,60,33,72,216,38,181,98,153,51,39,167,153,157,171,98,88,38,187, - 246,13,176,255,192,46,38,207,45,114,236,216,57,240,99,152,34,32,244,53,169,68,146,241,51,227,84,115,109,184,190,75, - 118,230,44,67,27,6,8,22,179,184,161,195,208,149,91,173,232,29,63,222,85,24,47,116,142,223,255,220,38,243,201,39, - 246,245,122,245,51,54,28,10,225,153,235,225,204,52,228,98,16,60,191,10,66,171,0,180,42,111,172,214,163,128,61,64, - 90,136,72,0,253,66,235,253,2,110,168,152,230,149,165,131,187,55,164,223,182,163,165,123,231,128,72,102,98,84,150,179, - 20,23,75,132,118,18,95,105,130,208,34,59,49,202,244,217,17,148,19,16,141,9,6,7,44,42,53,240,189,24,169,84, - 146,104,90,209,183,166,151,173,155,119,83,173,214,153,158,158,102,112,112,128,149,149,121,226,49,73,173,84,228,236,153,9, - 102,23,92,214,172,31,228,186,27,119,208,213,157,230,228,145,179,156,56,122,14,161,109,148,167,48,36,40,237,17,232,50, - 209,152,65,177,178,140,101,69,113,106,117,70,199,203,236,217,188,159,82,54,207,241,7,159,164,173,183,155,129,157,59,197, - 246,95,123,111,122,225,3,55,167,143,127,254,145,181,173,143,62,188,121,200,247,54,85,225,145,78,120,110,16,166,179,80, - 75,128,94,117,223,175,2,208,170,188,1,18,0,189,192,207,64,52,167,245,122,19,110,242,17,111,31,235,235,61,160,110, - 220,215,53,176,175,203,108,77,197,17,37,141,99,69,209,173,237,76,230,28,202,203,130,173,125,157,84,230,158,69,85,23, - 88,55,216,70,185,88,162,144,175,83,42,7,152,81,73,215,64,156,150,76,43,155,182,109,32,153,206,48,62,58,207,83, - 79,29,2,2,238,120,251,245,12,116,247,18,4,46,163,99,203,100,75,1,7,175,219,205,101,151,239,161,179,35,201,241, - 231,143,112,234,216,73,146,169,52,197,66,158,100,44,192,13,20,117,87,19,104,137,176,99,8,229,35,76,77,75,164,21, - 237,4,76,143,143,113,229,213,87,209,222,223,201,161,67,71,88,122,228,41,226,137,35,108,220,185,143,107,255,175,95,138, - 21,127,244,253,219,167,254,248,127,116,182,157,60,54,152,130,161,50,60,121,13,156,42,195,202,213,224,63,180,186,28,86, - 1,104,85,94,63,105,7,182,130,140,66,186,10,155,13,184,169,140,184,227,252,229,59,47,107,185,110,107,162,45,29,65, - 40,73,45,189,134,192,202,4,167,142,79,250,247,62,241,141,232,141,7,47,19,63,241,206,43,200,207,60,71,57,59,73, - 107,122,144,220,92,153,153,233,105,12,43,164,107,160,157,68,107,154,150,246,46,246,236,217,137,235,132,60,245,196,17,158, - 63,124,140,82,185,204,174,93,27,105,107,109,165,94,54,120,225,217,51,44,45,213,185,233,174,119,48,56,212,74,123,71, - 23,99,167,71,120,254,217,23,216,180,126,13,249,124,157,82,14,82,137,54,42,110,133,114,181,130,10,45,76,51,130,37, - 192,182,21,137,136,6,83,226,122,112,236,244,121,174,184,230,50,2,35,224,244,209,83,184,229,128,83,79,61,195,209,67, - 207,178,227,170,155,197,158,63,255,175,93,147,159,250,236,53,211,159,248,68,255,160,231,110,240,225,27,54,60,245,23,48, - 245,235,224,127,101,117,89,172,2,208,170,188,246,210,10,252,21,200,86,104,173,194,126,19,222,158,179,172,155,231,110,56, - 176,99,224,170,117,182,169,29,202,178,133,149,160,63,116,62,243,76,221,120,224,193,194,76,44,94,252,240,31,254,135,77, - 63,118,215,94,251,196,67,95,66,121,154,109,91,110,225,241,71,30,36,191,56,67,166,61,195,192,218,181,40,203,164,115, - 160,143,189,7,14,50,63,183,192,151,63,127,63,227,195,83,248,65,72,58,147,226,186,27,174,194,176,52,167,78,159,32, - 183,92,226,246,119,223,141,213,210,202,82,193,67,137,26,143,63,246,48,251,118,239,197,64,114,238,236,51,248,129,139,20, - 96,154,2,165,60,16,17,194,208,37,147,180,137,89,18,97,10,68,194,64,59,117,202,245,5,206,159,63,198,222,93,187, - 112,75,101,150,230,178,8,105,83,118,2,158,254,250,151,24,31,57,205,59,126,225,23,227,139,183,222,180,237,153,127,247, - 219,157,187,167,198,58,99,144,88,129,111,252,58,76,206,128,119,100,117,121,172,2,208,91,215,166,81,12,245,167,248,104, - 204,36,94,15,222,116,143,39,104,212,245,249,40,200,53,208,86,134,131,6,188,103,50,154,184,173,240,174,221,107,217,176, - 70,156,158,245,48,74,34,104,157,122,161,218,57,242,47,225,96,62,111,44,173,221,144,254,137,191,253,179,142,157,87,174, - 181,135,31,252,2,169,100,23,117,87,241,141,175,63,64,177,176,196,174,45,107,104,233,236,166,26,73,17,177,108,118,221, - 120,51,185,5,135,251,62,251,48,147,19,179,8,13,65,205,231,170,59,111,97,243,229,87,240,232,87,63,67,33,183,192, - 141,31,248,8,166,213,201,99,143,223,199,187,127,228,102,14,223,243,5,246,93,117,128,181,93,67,60,248,185,127,33,12, - 67,236,72,132,13,59,58,41,29,117,113,67,129,182,5,161,31,96,96,99,199,45,132,37,136,89,54,150,105,226,4,62, - 197,133,25,178,109,105,182,236,187,140,74,253,49,98,65,149,221,215,220,196,218,66,200,163,159,249,60,255,244,7,255,149, - 219,126,226,131,226,214,207,252,69,231,151,127,241,223,95,183,239,200,243,86,43,24,2,30,252,67,152,248,3,112,31,88, - 221,159,171,0,244,86,20,215,11,217,179,181,141,191,89,147,134,115,43,111,202,103,60,2,194,133,150,50,92,110,192,123, - 78,183,244,222,185,242,246,253,125,139,97,9,239,203,71,195,93,203,197,149,205,229,106,37,89,173,24,85,116,98,106,203, - 118,251,170,79,252,81,116,211,238,1,49,124,228,27,196,218,7,153,31,30,231,200,83,143,97,101,210,92,119,235,53,152, - 134,137,136,167,73,122,16,198,147,212,42,240,249,79,124,146,233,233,81,226,210,100,185,234,209,218,155,228,250,119,222,206, - 204,244,34,217,51,103,185,250,182,187,17,45,29,252,239,63,249,115,222,255,225,119,49,125,242,24,27,247,236,102,104,112, - 3,15,127,249,171,204,231,107,24,74,210,217,155,34,149,72,160,252,0,219,180,16,66,161,209,4,174,70,9,69,58,147, - 33,168,58,180,102,146,172,84,106,24,210,96,126,126,129,237,3,91,217,188,125,43,51,195,39,153,62,119,148,93,55,125, - 16,251,125,119,243,240,61,247,242,197,191,254,43,110,184,253,38,222,243,201,191,74,125,237,55,126,239,234,161,123,191,104, - 12,128,136,195,253,127,14,19,191,10,222,189,172,22,183,95,5,160,183,160,8,165,121,108,99,43,75,231,86,136,190,137, - 22,176,160,209,147,61,6,86,20,54,90,240,246,231,83,233,183,141,92,182,182,79,59,14,137,35,147,206,221,83,211,167, - 19,232,9,5,201,10,172,29,219,185,43,115,197,159,255,135,104,95,166,34,150,142,61,65,88,79,241,220,11,143,48,55, - 114,130,205,219,46,99,221,206,109,84,107,53,226,189,27,33,48,56,126,232,16,55,223,125,19,159,251,248,167,152,25,61, - 135,21,53,113,11,62,90,187,236,58,120,45,86,75,154,35,159,253,59,118,238,191,150,68,219,102,254,244,79,255,148,157, - 251,182,210,158,12,9,173,14,98,177,56,227,195,167,153,60,55,73,24,104,122,6,51,244,182,165,113,156,0,29,64,196, - 18,72,20,66,8,66,109,162,181,162,165,189,29,199,42,35,181,207,218,129,126,22,151,22,49,172,24,11,51,227,108,222, - 190,147,234,202,50,209,120,148,51,71,30,229,192,141,119,80,169,228,152,57,113,130,35,143,60,70,53,95,227,93,127,242, - 159,18,255,24,56,87,69,30,184,79,117,128,154,129,7,126,23,38,62,2,254,111,209,232,171,190,42,171,0,244,150,17, - 165,225,234,15,110,229,239,31,158,98,164,230,191,105,190,104,72,131,120,222,3,182,11,253,121,196,174,177,173,91,7,172, - 84,20,207,180,216,92,115,22,82,232,23,60,152,171,192,238,225,237,91,219,238,252,227,255,51,221,221,150,19,249,108,157, - 225,163,11,44,156,58,139,142,150,185,250,237,55,210,187,102,19,179,217,58,235,182,239,167,88,11,249,234,151,191,200,93, - 239,126,39,143,124,241,203,204,158,62,135,29,143,147,207,175,32,137,144,110,177,184,230,230,59,152,124,246,16,118,44,32, - 185,237,0,255,248,231,159,33,29,137,112,249,21,91,177,35,9,102,22,230,233,145,146,179,199,39,88,41,86,24,90,223, - 67,166,45,74,87,111,23,83,99,203,24,40,44,41,8,3,31,35,158,64,99,128,14,8,8,73,182,183,82,93,154,39, - 157,78,81,172,214,73,36,227,148,139,203,184,129,199,250,237,91,25,31,27,167,191,191,155,147,207,61,206,45,239,125,39, - 15,212,139,36,39,22,88,56,241,12,45,189,157,252,236,223,254,89,236,239,223,247,225,203,15,28,58,164,18,16,58,112, - 95,15,204,232,102,141,234,55,242,208,88,149,85,0,250,174,68,123,33,230,134,22,254,231,250,22,14,159,204,190,169,158, - 109,29,240,73,16,6,68,235,66,196,172,142,148,236,137,39,24,173,72,10,94,24,24,96,215,97,221,83,91,215,94,254, - 142,255,250,163,157,29,93,54,197,34,60,241,224,163,228,38,230,24,236,235,224,218,155,238,68,117,116,48,182,82,99,247, - 238,93,228,230,10,124,225,239,255,137,107,111,189,129,201,225,97,78,28,122,148,68,36,66,177,6,181,186,65,34,226,178, - 102,251,110,162,49,201,137,227,135,216,115,203,29,124,233,11,159,167,184,56,201,157,239,127,39,61,237,157,140,13,79,48, - 122,234,44,108,217,196,137,23,70,24,92,219,199,198,109,189,136,48,164,88,113,153,95,88,70,10,69,212,50,241,116,136, - 52,37,94,224,227,7,26,215,169,211,223,223,15,78,21,45,52,107,214,111,96,102,114,148,254,158,118,102,103,103,89,179, - 115,43,177,229,28,137,68,27,197,106,141,220,194,20,215,188,251,71,120,232,111,254,28,195,142,114,254,169,199,25,220,188, - 133,31,255,244,223,165,255,238,166,187,46,191,126,106,162,106,64,54,132,242,255,128,149,95,162,145,203,241,70,200,157,192, - 41,88,237,107,191,10,64,223,165,248,154,63,248,217,221,124,242,183,30,37,246,38,33,163,3,26,133,222,45,208,30,4, - 150,86,126,88,169,106,217,153,18,118,232,144,174,149,45,31,118,63,188,161,171,247,186,255,240,190,238,205,61,67,148,115, - 33,247,221,251,56,243,147,75,92,181,111,43,123,174,28,162,158,238,97,97,185,194,222,77,67,76,159,25,231,51,159,254, - 10,67,107,186,104,75,68,120,226,203,247,97,9,15,55,2,249,233,10,145,120,10,83,21,184,236,178,131,76,15,31,98, - 253,238,237,28,125,126,134,217,23,142,177,123,215,102,246,237,219,193,82,110,153,227,143,62,66,186,173,155,71,30,121,1, - 133,98,223,101,123,8,205,26,38,146,167,159,126,26,161,37,201,148,77,213,115,41,87,20,194,0,67,132,40,213,208,130, - 34,81,155,84,71,23,245,90,149,206,174,62,140,120,130,120,58,195,114,190,64,93,197,24,216,186,157,217,99,103,216,116, - 217,181,28,125,242,235,92,255,142,237,236,184,253,29,156,190,231,11,68,8,121,244,179,127,207,135,126,245,223,115,213,199, - 255,180,229,217,119,126,224,224,245,129,59,173,97,54,1,199,174,3,231,93,52,26,47,190,94,230,180,160,209,2,105,8, - 56,182,138,21,171,0,244,93,147,209,126,200,205,7,123,137,189,237,114,106,247,188,64,50,116,222,112,46,72,52,65,168, - 42,68,96,65,190,69,235,101,39,183,236,22,183,182,69,141,88,192,11,102,44,49,220,18,111,217,245,203,239,200,28,88, - 183,153,226,66,137,175,127,229,81,102,22,23,185,226,170,131,236,191,238,50,220,120,156,249,133,49,54,246,244,50,117,102, - 152,47,125,238,33,12,13,151,95,125,5,79,220,255,16,94,165,66,36,146,96,58,183,130,17,51,8,252,26,157,131,189, - 180,24,14,11,229,34,210,90,195,243,247,127,129,174,182,118,174,185,237,42,234,213,37,14,61,248,32,182,25,99,114,106, - 150,243,227,243,188,253,230,27,105,233,109,69,136,62,190,113,207,131,228,203,30,189,157,237,40,175,68,60,22,197,205,150, - 145,134,36,26,19,4,190,34,172,215,240,92,151,100,71,55,70,97,9,199,41,211,187,102,136,82,181,72,111,79,47,185, - 185,101,54,238,216,72,177,99,28,183,84,99,219,142,203,24,126,225,105,118,222,240,46,102,78,30,71,207,12,163,170,121, - 30,254,204,95,243,206,95,253,247,156,254,165,159,239,27,255,211,63,187,122,8,198,235,144,253,29,152,52,32,124,130,70, - 195,198,215,235,176,24,4,54,208,168,185,157,92,197,139,85,0,250,174,57,151,186,199,169,107,174,71,143,57,140,158,120, - 1,255,77,96,211,251,192,101,90,251,235,96,62,2,19,3,211,139,165,178,179,62,26,139,216,60,222,25,239,248,137,15, - 94,203,173,91,118,144,159,94,228,254,135,30,165,180,156,103,247,142,141,92,113,235,1,114,126,146,194,236,50,157,145,8, - 165,185,105,238,255,234,19,44,231,86,184,235,125,111,103,122,114,150,236,204,50,118,36,194,74,197,195,175,128,142,249,216, - 150,205,150,13,107,169,150,230,232,236,216,194,3,247,61,142,233,229,217,125,219,173,88,173,157,60,125,207,61,88,245,34, - 185,178,199,212,76,158,206,84,156,43,174,222,67,188,175,135,67,247,60,196,249,115,211,180,175,93,71,166,205,164,152,45, - 227,122,53,66,101,82,173,213,24,236,238,164,82,244,33,240,241,156,58,118,75,15,201,150,12,142,227,144,238,236,98,170, - 88,160,181,163,139,252,228,28,245,250,38,122,182,236,99,250,244,17,6,247,188,141,153,153,5,170,217,105,246,222,113,39, - 135,254,106,132,104,194,98,105,250,28,71,238,253,28,63,250,91,255,70,254,229,211,207,109,237,125,238,153,27,44,152,172, - 192,202,151,160,240,31,223,0,243,235,83,171,56,177,10,64,223,215,151,172,85,57,115,203,173,76,207,79,161,151,151,223, - 112,0,114,128,187,33,148,141,190,127,83,221,229,242,242,241,115,11,93,253,253,107,185,243,134,237,28,216,219,207,92,174, - 192,177,195,231,153,155,42,177,123,247,102,246,94,127,13,243,139,57,168,101,145,229,28,178,179,147,251,31,58,198,236,82, - 137,221,7,54,211,221,191,134,175,252,195,23,176,67,240,112,112,235,62,166,157,164,84,175,208,219,31,37,29,171,98,70, - 58,56,127,106,140,194,236,18,173,3,61,108,220,212,205,217,135,31,32,63,151,101,197,181,152,207,151,241,116,145,187,110, - 123,15,61,59,246,113,244,249,195,28,127,238,24,101,4,87,239,219,128,63,49,73,162,127,55,231,166,142,18,143,72,44, - 21,18,79,39,41,151,74,88,126,26,211,55,128,16,51,211,69,186,93,18,250,54,237,221,189,148,36,116,173,233,39,63, - 55,204,224,222,91,137,45,230,41,85,86,216,182,107,23,147,135,159,102,251,29,31,160,99,215,30,166,158,123,142,142,214, - 22,142,63,253,36,155,118,109,225,154,223,253,88,114,228,67,35,251,118,149,115,35,37,24,91,7,181,35,224,101,120,125, - 88,105,5,44,241,237,59,209,174,202,42,0,253,235,11,73,107,34,134,201,71,15,94,206,173,247,126,237,77,241,76,115, - 192,104,3,132,252,65,100,125,238,244,233,176,163,199,54,222,113,240,6,220,162,195,217,137,19,140,156,153,103,253,166,126, - 54,31,220,199,82,190,68,220,180,152,31,155,96,221,224,32,207,29,58,66,118,49,71,34,30,227,134,235,175,225,209,71, - 159,32,168,87,144,134,164,232,128,235,75,66,29,176,156,93,228,178,45,173,88,145,24,133,178,203,201,99,47,96,9,159, - 3,187,247,48,123,126,130,241,241,25,10,165,144,133,114,13,79,5,220,176,239,74,174,121,251,141,204,204,143,243,212,231, - 239,35,87,118,233,93,59,64,202,148,4,153,52,35,51,57,188,208,37,149,177,80,190,38,29,79,82,107,113,209,66,35, - 180,194,150,6,134,48,201,116,247,176,188,84,33,221,217,141,31,84,105,27,218,74,233,228,11,248,165,69,186,55,239,101, - 114,244,20,235,55,109,66,159,51,88,26,61,78,255,182,45,204,140,156,34,148,146,238,246,14,158,253,210,61,92,251,225, - 31,99,226,195,239,238,47,126,252,111,174,72,192,153,93,48,119,24,178,255,9,72,188,198,243,83,5,222,9,252,6,171, - 49,72,171,0,244,42,240,46,132,33,19,93,221,124,218,178,89,241,189,55,172,29,136,15,220,14,44,131,169,160,219,132, - 161,69,51,222,150,234,77,27,87,237,90,131,95,90,98,97,197,229,204,232,44,169,22,131,45,91,215,177,82,45,210,158, - 106,225,220,11,71,88,191,110,29,163,99,83,156,59,55,73,221,117,185,254,198,107,40,23,74,204,143,76,96,138,144,58, - 154,92,197,64,72,141,83,89,161,45,105,145,140,154,216,137,14,142,157,28,70,121,21,134,134,122,49,60,135,83,103,207, - 145,173,4,148,28,73,221,115,88,219,222,198,53,183,221,130,39,3,30,253,199,127,162,92,172,178,88,169,112,199,193,189, - 212,22,166,168,213,234,156,159,24,39,17,129,84,202,164,86,242,177,132,69,91,103,148,122,177,142,48,4,182,52,49,13, - 139,74,185,142,176,162,216,81,129,87,168,33,19,29,116,12,109,165,180,56,78,251,142,107,73,183,117,224,84,43,172,217, - 178,141,133,201,115,180,68,147,108,234,236,97,120,108,134,190,129,77,172,20,203,44,12,31,103,237,135,111,52,143,125,249, - 129,173,87,207,77,237,43,194,209,1,200,223,7,129,249,26,3,67,216,156,171,202,235,0,118,171,0,244,67,32,86,24, - 144,235,238,230,119,58,58,152,155,159,123,67,159,229,19,192,46,200,4,176,51,64,238,249,106,202,236,187,226,134,237,36, - 133,65,185,230,113,106,116,158,122,32,217,185,103,16,39,8,232,203,100,152,30,25,37,98,88,168,80,113,246,236,56,97, - 40,73,38,227,108,217,184,134,71,30,126,12,225,73,66,9,139,213,34,136,86,68,80,98,176,39,131,16,73,218,59,186, - 40,149,92,150,231,150,104,111,73,16,77,70,56,59,60,74,97,217,165,162,13,102,23,151,232,73,89,236,220,187,145,68, - 87,146,199,62,255,53,102,39,150,88,88,42,177,101,221,26,218,18,154,211,249,5,230,151,125,156,74,157,222,182,56,134, - 45,201,86,28,234,46,116,244,180,177,232,47,162,77,11,165,13,34,241,20,147,75,43,180,246,174,193,76,216,216,174,139, - 87,117,137,247,108,36,91,88,193,173,20,72,181,245,81,201,205,211,214,222,67,108,126,138,154,83,198,111,73,18,233,74, - 113,100,248,40,151,93,113,45,165,185,57,182,239,216,197,147,59,55,181,85,231,166,182,153,176,81,192,120,59,20,186,94, - 7,243,235,12,171,29,62,86,1,232,85,18,13,104,165,249,191,59,58,152,158,159,123,67,120,160,0,216,12,108,4,171, - 2,67,17,184,242,1,219,220,25,63,56,24,217,209,217,142,19,106,78,141,44,49,53,190,200,190,131,67,4,129,164,22, - 132,196,80,120,133,34,93,93,253,156,56,113,22,215,215,84,42,21,174,223,127,128,153,233,41,230,103,22,64,167,240,13, - 73,197,201,97,186,43,108,93,147,36,157,73,178,82,170,210,218,217,199,185,115,19,68,132,198,178,34,228,235,30,11,203, - 53,2,199,96,62,159,197,196,101,215,206,77,236,186,124,43,39,158,121,146,177,211,147,76,45,215,48,165,224,138,141,189, - 44,206,156,97,227,101,59,89,250,198,8,218,13,72,153,54,75,69,151,137,133,89,10,117,197,134,76,55,42,12,48,19, - 73,132,29,199,136,165,176,18,6,161,17,39,146,72,224,213,92,66,167,140,76,117,17,233,88,71,80,88,38,210,190,6, - 59,209,142,178,76,82,109,93,248,229,28,6,81,58,18,9,86,86,86,24,30,59,203,229,251,47,35,234,4,180,29,92, - 99,14,63,104,108,220,171,194,221,10,142,157,134,210,92,35,214,244,53,3,159,12,141,70,0,171,230,215,42,0,189,106, - 98,75,193,51,155,55,243,201,19,199,223,176,103,248,101,96,7,100,52,236,42,10,246,159,236,74,116,95,181,126,19,117, - 223,228,204,236,44,99,83,89,118,109,92,79,151,105,83,93,41,83,143,39,201,23,138,132,74,51,183,144,37,183,82,161, - 238,134,196,226,22,107,215,246,243,252,115,207,163,148,137,231,43,166,150,151,209,166,77,198,172,115,235,53,151,115,242,236, - 44,126,42,201,66,54,79,49,151,39,110,71,112,125,200,45,85,169,249,38,78,221,163,176,178,194,205,215,238,98,231,190, - 173,76,143,141,115,252,133,147,12,143,45,163,3,147,104,218,192,165,68,79,87,15,78,32,25,29,31,165,163,163,133,72, - 36,205,212,217,19,244,118,181,81,169,215,137,39,186,112,131,58,50,30,131,104,156,192,138,16,104,159,194,74,145,129,238, - 22,108,211,196,115,202,68,188,58,177,76,59,70,190,138,174,150,136,165,219,81,161,67,44,213,66,224,213,105,233,236,97, - 246,204,89,34,194,102,105,108,146,197,158,33,182,116,247,179,255,170,45,252,195,96,186,123,247,100,126,187,9,131,117,152, - 106,17,56,81,33,94,19,13,69,105,152,209,154,204,42,62,172,2,208,247,203,253,24,198,75,207,48,17,188,113,1,137, - 221,192,219,32,226,55,58,90,92,118,38,30,223,52,176,111,187,140,26,38,103,198,102,153,43,58,164,50,22,173,29,38, - 132,146,114,121,133,206,53,3,228,242,14,133,74,149,192,119,240,85,132,82,117,145,171,175,216,69,185,88,100,97,33,71, - 46,95,197,247,171,140,77,76,33,77,155,15,254,232,213,180,183,218,228,75,30,118,42,206,202,194,28,6,224,32,169,150, - 92,28,79,224,7,146,185,236,60,91,54,12,178,117,219,58,68,16,48,114,102,154,231,207,205,19,81,81,76,229,208,215, - 213,70,251,230,13,68,35,113,30,252,204,3,216,194,161,103,176,143,177,209,60,166,17,161,167,53,73,110,57,139,136,167, - 177,220,4,177,136,69,44,147,38,16,26,21,106,178,243,51,208,151,193,10,125,180,1,97,117,9,51,22,129,104,2,183, - 84,37,154,105,69,105,133,178,227,84,61,159,214,181,189,56,118,43,149,165,9,16,130,211,39,78,209,51,212,199,230,129, - 94,50,87,110,139,205,77,62,53,216,7,107,210,112,52,121,93,143,211,241,43,219,161,250,42,207,103,212,192,123,122,137, - 194,159,158,186,216,131,109,85,222,34,0,36,66,31,180,70,232,111,61,115,90,74,180,52,95,23,240,177,45,197,83,195, - 105,230,10,54,166,161,241,124,159,161,161,117,252,175,206,78,98,217,236,235,110,223,39,128,118,104,9,97,79,89,136,253, - 75,67,67,157,3,125,61,156,30,31,70,210,78,61,95,98,235,254,65,60,81,198,140,183,80,203,105,100,80,103,110,170, - 140,235,9,28,207,163,238,64,34,149,102,211,230,33,158,125,242,41,234,53,143,68,186,149,192,119,217,180,113,136,233,233, - 28,189,61,173,148,42,69,66,34,40,165,241,74,43,24,34,77,222,245,169,187,33,102,96,145,93,92,32,22,179,217,180, - 174,159,84,58,198,217,115,195,156,56,54,131,242,19,24,17,131,206,76,72,207,218,78,90,218,123,120,232,75,223,96,126, - 126,133,158,158,40,21,191,200,200,194,18,59,214,246,210,106,249,148,242,5,202,158,75,34,221,2,97,128,157,138,227,4, - 33,137,104,140,229,233,89,156,245,157,4,202,193,204,164,240,43,57,68,221,71,71,186,112,148,32,82,93,70,91,22,102, - 44,129,246,125,132,25,167,111,231,65,206,31,57,73,172,59,73,189,144,229,196,11,135,232,28,90,207,142,45,59,152,146, - 207,244,174,81,106,75,21,186,71,94,200,21,150,126,227,185,240,33,165,95,213,192,68,71,10,150,170,62,31,1,188,85, - 124,120,139,105,64,226,146,51,67,235,111,77,198,188,142,224,115,255,137,86,44,67,53,74,58,104,141,25,137,112,109,95, - 31,219,179,175,111,126,152,6,38,192,156,134,62,19,246,12,183,182,110,180,183,247,202,217,233,69,164,72,115,108,228,60, - 107,122,227,180,91,9,92,55,68,91,130,48,208,120,245,144,229,165,44,210,202,80,174,130,235,20,217,190,181,135,202,74, - 129,226,138,75,36,146,34,48,67,178,185,34,61,241,24,187,175,218,198,99,207,159,100,239,182,1,234,94,29,101,36,16, - 50,66,185,28,195,49,60,108,51,32,87,9,169,73,159,125,235,186,233,236,78,115,234,220,4,199,143,156,163,94,49,216, - 50,180,150,120,220,199,169,251,108,221,188,145,83,135,142,114,250,244,52,233,214,20,157,61,93,156,56,57,65,95,107,134, - 84,139,32,29,137,145,155,206,147,43,213,105,221,49,72,117,105,5,225,25,216,82,147,72,26,212,202,5,74,249,25,44, - 11,12,67,16,202,40,166,246,9,107,115,196,226,105,38,199,102,105,235,233,38,38,77,210,153,36,243,231,79,179,118,235, - 62,156,76,27,178,90,163,61,109,176,60,91,162,183,31,114,97,157,195,241,72,251,213,149,250,78,19,182,234,138,63,251, - 217,138,95,252,143,175,193,92,221,13,68,86,1,232,117,17,249,90,236,126,45,5,136,55,70,121,125,37,240,145,151,60, - 74,8,28,217,188,229,117,127,174,57,96,188,193,253,108,211,49,123,215,242,166,13,237,174,136,178,130,226,232,124,141,137, - 185,101,54,111,28,196,169,214,136,69,18,228,139,53,234,174,67,97,165,132,33,13,180,8,8,117,29,116,141,193,254,78, - 74,249,2,201,88,6,169,35,184,149,0,165,5,151,239,31,226,206,107,215,83,171,133,140,205,150,9,181,135,246,3,74, - 85,143,26,101,12,195,162,80,87,228,114,69,214,36,91,217,186,126,128,74,81,113,228,217,89,170,213,40,123,47,223,192, - 238,61,237,84,75,33,189,131,59,89,200,213,121,230,217,83,164,18,146,189,123,214,178,176,156,39,8,108,90,210,22,201, - 136,164,88,83,76,46,174,176,48,51,71,186,181,3,35,18,199,173,86,241,106,14,241,168,137,227,212,88,94,92,194,173, - 150,168,151,114,104,183,138,10,61,138,217,5,76,29,176,56,61,205,242,236,12,97,173,68,52,18,165,86,40,99,20,231, - 233,104,109,161,230,133,132,190,198,201,151,88,158,93,228,150,107,246,225,108,236,140,157,128,173,54,28,4,214,108,7,235, - 5,26,197,221,134,95,133,159,49,224,126,26,45,145,86,193,231,45,206,1,105,41,26,10,145,126,125,253,8,134,161,191, - 37,248,0,72,165,112,98,49,78,89,22,117,223,127,221,80,190,4,166,108,104,63,251,167,6,82,91,11,67,182,204,21, - 10,248,85,55,44,158,56,231,236,218,191,62,222,22,141,9,207,169,32,140,56,213,186,143,101,155,132,94,136,129,196,113, - 107,4,94,157,246,182,4,17,203,96,33,191,66,168,20,129,22,44,231,74,68,146,130,237,155,187,232,138,105,134,122,186, - 153,205,86,17,134,133,143,166,226,107,204,168,71,224,184,104,124,210,41,69,87,123,134,207,63,114,152,145,169,42,217,108, - 137,116,91,138,150,13,67,140,207,140,210,155,137,17,181,202,28,121,106,4,203,15,184,249,166,61,228,10,75,44,47,231, - 73,164,186,104,77,43,80,146,217,229,58,21,108,38,70,70,160,126,43,201,76,6,191,94,129,168,73,128,160,173,53,73, - 110,49,75,210,110,35,84,154,168,22,141,14,32,245,58,181,220,50,150,10,88,30,31,165,51,38,48,149,34,157,105,97, - 242,204,11,108,236,111,103,228,228,9,90,99,157,196,82,6,227,231,206,49,184,161,143,95,251,141,159,230,19,191,249,103, - 131,3,211,43,87,167,97,100,16,150,214,193,98,203,171,56,87,47,52,181,159,85,239,215,15,0,9,253,189,130,80,163, - 135,245,119,175,65,89,134,230,252,82,140,175,31,111,197,54,191,25,124,0,204,32,96,182,171,151,199,110,184,140,205,76, - 17,190,150,124,148,33,16,121,23,255,153,121,52,216,41,24,148,182,177,109,177,61,222,94,10,125,188,154,230,170,195,167, - 244,181,42,112,39,135,122,35,97,221,51,237,136,77,165,230,80,119,5,145,168,141,82,26,83,154,132,174,34,12,13,58, - 90,218,169,151,235,56,117,15,199,245,89,42,20,81,166,207,186,53,93,156,58,125,142,53,215,237,166,61,29,50,53,94, - 71,102,58,200,57,117,164,97,163,188,24,78,221,99,219,150,1,114,115,115,36,99,146,122,201,32,105,11,118,95,213,133, - 165,5,143,127,245,97,202,150,73,255,80,146,222,169,4,235,162,105,222,127,215,78,18,241,20,71,142,157,37,145,76,98, - 133,1,177,136,77,190,92,35,87,241,137,198,50,44,205,44,82,92,204,17,239,104,195,117,106,16,106,194,32,164,163,53, - 69,118,120,140,206,140,32,40,231,105,109,15,176,35,49,34,82,80,90,156,167,51,19,227,228,209,179,248,67,29,132,190, - 166,165,181,149,233,169,97,34,134,69,111,58,205,226,114,137,100,87,27,237,49,131,211,207,31,231,234,155,174,226,182,95, - 125,159,253,248,127,252,196,142,187,43,222,213,30,156,125,26,10,55,128,27,127,149,166,44,191,10,62,63,56,0,244,61, - 129,144,10,27,149,114,190,23,11,78,128,231,55,62,40,191,205,231,181,227,211,122,199,229,220,114,211,32,248,175,97,76, - 116,212,132,99,89,170,207,204,243,28,68,4,116,85,226,86,207,76,44,98,230,243,130,203,207,12,115,192,113,228,61,109, - 233,84,34,106,154,245,114,133,68,50,73,174,92,197,215,6,81,105,162,128,192,15,81,74,18,4,10,195,20,184,174,71, - 185,226,178,82,113,8,12,131,206,238,65,182,236,220,197,220,169,231,169,215,61,44,83,35,13,131,154,235,226,6,130,56, - 54,149,165,69,174,189,241,0,43,203,51,100,90,90,153,93,206,210,27,85,252,232,29,87,115,195,45,123,120,250,201,163, - 12,182,230,241,80,140,206,79,115,126,120,153,229,214,58,219,74,91,145,211,231,169,121,33,65,8,237,209,128,90,5,38, - 22,11,84,93,69,75,170,149,236,66,145,243,231,199,217,158,138,160,188,42,166,157,34,116,125,210,9,155,145,92,158,226, - 114,156,72,202,194,169,228,81,161,143,82,38,197,66,133,150,142,54,234,149,2,203,217,44,173,201,4,182,109,2,22,174, - 87,34,211,102,227,87,163,76,205,231,88,187,111,3,229,92,150,217,153,37,174,62,176,149,133,15,94,219,62,241,183,15, - 237,29,130,189,192,248,121,152,223,253,166,229,36,86,229,13,5,160,151,130,144,250,215,193,231,251,229,128,196,119,130,93, - 2,225,121,80,246,112,188,215,112,201,121,33,86,205,191,48,208,73,9,221,217,184,108,61,47,163,12,78,140,115,121,174, - 160,179,160,139,29,29,70,171,52,241,132,192,215,6,78,40,240,131,0,132,65,168,160,230,6,248,210,34,212,14,97,88, - 193,113,13,20,49,140,88,130,236,236,28,207,158,56,204,87,30,120,150,119,223,184,19,66,133,34,69,16,113,240,189,50, - 86,24,163,86,169,113,112,111,134,158,78,205,200,249,42,158,105,176,88,45,242,254,219,182,113,227,141,251,120,228,248,56, - 71,79,77,144,136,117,82,43,215,56,184,125,11,191,245,43,123,89,88,28,231,190,135,143,112,236,252,18,189,3,253,12, - 181,37,136,69,5,147,179,37,114,249,18,177,84,138,68,196,162,88,23,12,159,27,103,243,246,117,84,86,150,200,152,38, - 129,231,19,248,46,149,98,157,165,133,101,50,97,28,211,180,0,19,203,142,224,212,139,4,142,133,20,33,203,75,203,196, - 227,54,34,8,233,78,119,49,154,205,163,18,96,135,17,90,204,8,139,75,75,108,221,190,133,236,114,129,254,181,29,92, - 125,231,205,60,246,208,185,245,3,19,179,151,197,225,248,60,228,55,128,243,253,164,76,132,77,243,107,21,128,126,0,1, - 232,69,16,18,175,41,248,124,199,167,156,212,20,170,38,165,186,137,149,146,4,175,209,178,211,9,139,200,87,38,200,129, - 225,67,91,28,6,71,205,68,107,109,46,199,205,139,133,170,173,9,231,77,17,9,123,218,109,223,13,81,82,80,115,53, - 1,6,86,196,32,12,21,1,10,95,73,28,213,232,187,5,18,199,215,56,129,96,38,91,224,200,240,24,185,66,25,37, - 35,60,118,124,152,95,184,235,50,42,85,240,80,132,161,70,121,117,218,146,46,215,223,114,61,95,252,234,97,42,53,147, - 66,121,158,171,118,173,231,242,61,219,152,61,63,193,200,211,199,137,201,22,150,75,5,122,6,91,120,247,123,222,70,123, - 52,164,191,67,163,61,77,189,22,97,114,102,153,254,116,130,106,96,144,47,231,233,110,73,163,109,139,154,83,197,83,154, - 209,243,147,120,181,18,94,181,128,114,91,49,16,212,42,21,220,80,83,173,56,196,226,38,97,50,164,232,172,16,73,196, - 80,126,29,191,90,34,30,143,145,95,46,210,217,213,142,235,86,137,69,34,8,211,192,182,18,232,160,206,192,96,55,11, - 217,9,178,133,42,81,203,98,108,100,134,13,219,183,179,233,67,55,181,204,252,193,167,246,12,193,30,15,198,70,27,90, - 208,247,108,61,105,26,9,168,171,113,63,63,160,0,212,0,33,121,33,39,226,101,127,120,125,173,110,83,106,22,10,17, - 62,127,184,135,247,113,156,104,169,134,146,175,1,8,69,12,196,112,158,42,88,26,186,149,45,215,140,214,189,212,45,181, - 122,169,191,234,157,243,193,46,180,199,214,183,116,219,17,199,113,176,19,54,78,45,192,247,3,220,48,192,22,22,142,227, - 161,100,148,98,65,81,200,149,184,108,219,16,229,98,141,108,190,196,249,169,41,234,129,203,109,119,221,198,35,79,62,195, - 120,182,192,216,146,162,82,171,98,40,31,29,196,112,41,243,158,119,30,96,41,95,226,252,116,1,167,88,227,198,171,215, - 178,119,251,58,254,215,23,159,64,27,22,182,52,153,95,158,227,224,181,59,184,237,214,171,201,196,77,202,203,115,56,85, - 56,125,122,150,182,182,24,109,109,235,89,90,92,97,37,167,217,176,113,13,182,97,51,54,91,160,98,40,180,33,41,172, - 20,88,158,159,195,112,107,204,207,205,146,238,237,195,148,146,88,52,69,177,148,39,98,67,220,78,96,199,99,148,253,2, - 58,244,41,23,86,144,192,226,252,50,155,214,15,225,84,170,24,177,4,117,215,33,226,219,40,167,128,163,11,116,117,118, - 50,61,58,207,198,93,235,88,156,89,198,52,206,177,229,109,123,197,99,95,124,118,157,119,110,228,50,27,142,47,195,74, - 245,251,208,130,70,128,5,126,112,34,115,47,180,251,190,180,163,136,15,108,7,10,64,180,249,218,109,66,80,3,254,127, - 64,43,200,19,64,7,176,95,32,42,32,109,13,69,208,25,96,14,212,156,144,106,141,148,220,22,190,10,1,160,90,191, - 1,227,45,52,66,135,47,49,135,244,27,112,238,216,166,98,44,151,160,240,143,231,25,92,124,237,146,83,235,192,50,68, - 109,232,94,50,69,111,143,172,235,43,115,225,41,87,115,196,132,181,174,157,88,23,137,199,168,20,115,152,106,128,114,169, - 140,138,40,100,16,226,25,18,169,34,248,182,197,220,202,40,145,192,71,134,1,110,16,16,218,138,80,123,220,125,235,205, - 12,172,93,207,195,135,158,192,117,66,166,86,106,212,61,129,210,38,117,127,133,91,175,92,199,182,141,235,248,155,207,60, - 207,242,138,195,205,151,247,115,231,141,59,8,48,145,113,139,231,78,206,177,110,176,139,247,189,255,26,246,31,216,141,54, - 193,119,92,12,51,198,244,226,18,115,139,85,140,68,18,148,79,38,99,114,228,236,57,118,238,186,3,175,84,197,50,12, - 240,192,50,4,150,116,152,157,203,179,169,51,197,236,196,4,177,182,86,132,147,37,244,28,150,43,144,72,24,20,202,117, - 218,13,16,150,73,40,12,106,78,128,169,161,88,88,161,144,207,34,157,18,113,101,131,39,241,66,80,210,164,156,119,88, - 211,27,67,198,45,10,181,10,45,221,105,38,78,158,101,115,75,130,214,247,92,223,58,247,159,71,246,174,133,61,53,24, - 27,129,185,189,223,163,22,228,208,112,189,191,85,0,72,240,205,137,178,33,141,96,215,43,105,148,253,213,96,244,129,92, - 0,121,4,44,31,34,239,1,227,253,52,98,133,47,92,39,214,32,223,77,31,34,151,131,84,160,115,166,140,251,82,38, - 2,95,99,106,37,114,90,7,49,33,150,93,59,146,141,168,176,74,248,253,171,13,226,141,31,239,55,6,124,46,136,101, - 194,211,251,246,96,222,55,135,255,26,45,18,191,177,80,82,22,244,22,44,187,115,171,171,151,173,192,59,18,192,88,96, - 136,181,180,167,109,173,4,146,8,190,239,98,68,108,44,219,100,114,97,146,245,29,237,248,41,201,161,83,195,108,236,234, - 197,162,68,169,236,82,117,52,245,42,172,233,105,227,238,187,174,227,239,62,251,69,214,12,117,147,27,89,96,169,84,66, - 186,62,158,27,210,55,144,225,166,171,247,144,205,213,120,250,216,48,91,182,36,121,239,59,118,33,148,197,3,143,156,96, - 102,106,137,24,54,43,139,33,209,222,237,24,9,69,80,145,232,48,192,208,14,51,195,141,54,207,74,91,72,71,34,173, - 50,251,247,108,98,97,106,12,167,226,35,147,73,132,43,81,94,149,164,29,101,102,114,142,205,125,187,201,231,87,200,228, - 86,136,25,38,90,249,56,1,84,29,15,179,34,136,26,130,138,227,208,209,223,141,31,56,104,173,240,253,144,66,161,72, - 92,56,216,118,128,16,6,85,167,2,72,42,101,7,217,103,82,173,46,51,20,31,228,233,51,227,108,90,51,200,233,103, - 159,99,205,174,203,121,114,99,223,134,129,243,115,7,34,112,44,7,185,58,56,177,239,97,174,14,243,230,46,187,161,94, - 166,221,12,2,105,16,43,96,252,58,136,182,6,125,21,5,236,63,7,233,131,229,8,50,129,38,213,9,209,18,180,216, - 208,33,26,101,181,69,243,154,34,124,209,244,180,37,196,107,96,9,80,218,87,41,80,45,102,195,159,35,45,112,208,250, - 240,86,207,125,112,9,38,254,30,130,239,119,231,254,248,27,11,64,111,44,248,64,195,37,63,190,117,59,127,240,252,243, - 156,207,46,189,234,93,15,170,192,31,129,56,8,137,58,244,120,97,16,27,10,229,168,15,167,36,132,117,73,138,76,204, - 244,157,0,219,74,162,148,196,138,25,60,125,122,150,106,181,196,250,193,54,74,51,211,129,59,54,73,164,175,197,172,59, - 121,132,53,128,227,135,204,78,101,121,231,59,175,35,26,79,226,155,9,182,110,106,103,206,181,176,45,3,223,146,4,58, - 228,142,155,174,34,30,143,113,232,244,56,233,4,252,244,135,175,198,204,68,121,232,171,243,140,158,90,226,230,245,189,108, - 218,210,199,200,82,158,175,125,250,51,56,239,184,145,253,251,215,32,178,14,245,108,141,137,169,105,100,50,129,17,212,49, - 227,81,106,142,230,242,29,107,89,219,187,158,143,255,229,103,136,217,22,130,8,17,4,81,108,166,70,39,152,223,182,6, - 43,26,101,250,220,8,109,49,147,88,196,98,178,94,161,221,183,136,56,6,21,17,48,187,148,195,76,164,72,196,37,10, - 141,109,90,44,45,46,211,223,17,197,245,92,164,105,226,251,1,166,105,224,120,14,110,208,56,221,205,192,97,118,116,78, - 205,44,150,197,157,7,7,197,194,232,4,246,149,187,83,203,231,231,118,117,195,182,16,206,253,41,56,135,248,206,235,70, - 95,168,251,220,10,108,105,254,255,205,96,62,133,151,252,187,187,9,54,117,48,222,222,0,3,179,15,18,26,210,37,104, - 233,129,136,130,88,8,93,10,218,234,13,16,137,26,154,238,0,58,60,136,185,208,186,212,232,194,107,215,65,42,137,148, - 45,81,211,76,181,27,153,116,43,73,219,22,178,37,110,215,45,195,202,248,4,90,41,171,144,138,70,77,5,195,139,139, - 166,58,57,86,221,83,175,216,105,173,142,181,193,212,171,69,154,152,63,172,224,115,193,6,245,108,155,223,236,235,101,83, - 118,233,85,215,130,4,144,23,24,37,77,204,144,36,83,17,225,91,43,238,24,130,73,67,211,89,71,91,85,203,48,133, - 150,40,45,48,12,240,74,94,232,77,158,87,221,91,215,90,132,161,190,245,196,72,184,211,136,232,115,182,52,116,61,46, - 92,71,83,171,6,4,129,203,219,111,191,150,19,203,57,58,187,50,244,245,174,97,75,79,63,253,201,144,163,243,37,6, - 54,15,178,177,183,13,87,216,76,45,151,249,185,15,221,202,96,91,43,15,30,26,102,106,118,146,159,124,255,21,12,118, - 39,0,159,237,7,215,114,71,165,204,67,135,206,240,130,146,236,31,138,48,159,203,147,243,125,44,171,149,208,119,49,35, - 30,137,68,156,253,59,215,178,178,88,162,119,176,143,201,98,153,122,221,167,63,29,37,34,76,74,181,42,103,71,167,25, - 234,76,178,48,62,67,172,173,133,68,34,138,167,53,133,82,141,132,29,161,46,52,232,40,217,197,60,201,161,118,10,43, - 43,152,194,160,82,170,19,25,108,167,92,173,16,248,1,82,8,132,144,4,74,162,13,19,97,219,148,124,135,43,194,186, - 119,246,159,159,50,102,7,127,204,138,71,193,78,217,204,36,173,129,158,138,191,222,134,150,20,100,243,160,163,223,169,163, - 178,201,121,116,189,193,128,115,1,116,90,26,38,145,184,12,100,103,195,237,16,217,12,81,175,209,164,50,19,133,120,0, - 45,1,244,3,253,17,232,213,144,240,33,234,67,187,111,209,90,4,171,22,137,70,172,206,174,132,234,104,137,120,221,153, - 136,234,107,183,253,100,218,112,181,166,181,107,128,150,206,62,58,122,162,100,50,17,146,241,56,81,163,5,105,36,209,70, - 17,219,174,97,153,41,86,170,113,142,63,119,26,249,169,79,234,76,224,23,98,176,160,161,178,8,218,121,149,8,123,243, - 135,22,124,154,98,40,197,244,129,203,24,56,125,154,136,239,191,234,9,170,105,67,26,62,196,170,40,35,29,181,23,12, - 237,159,83,66,47,40,65,107,104,72,225,106,139,184,97,97,154,6,158,82,12,30,59,18,252,70,165,194,61,118,82,119, - 158,154,100,99,37,176,166,90,147,74,70,219,132,81,215,40,63,164,86,170,177,125,91,55,109,3,41,138,217,113,166,38, - 167,184,245,230,247,112,253,190,62,22,31,253,18,207,157,112,56,120,112,7,17,91,242,252,212,50,201,100,140,237,123,182, - 114,98,116,146,104,107,47,107,247,71,248,203,7,79,50,50,159,67,71,12,58,91,219,185,253,242,157,220,118,211,110,142, - 29,158,225,72,49,65,217,247,177,12,19,35,16,32,21,53,167,206,186,161,94,122,58,51,140,158,155,64,218,38,137,76, - 11,139,217,89,54,247,15,161,180,34,17,77,50,57,189,200,250,190,118,68,168,41,230,202,68,35,22,210,128,82,205,163, - 43,16,184,82,35,164,77,110,185,76,119,103,10,161,37,82,107,170,85,15,207,83,212,106,53,84,24,98,154,38,94,16, - 18,4,10,164,69,44,153,196,215,96,91,166,184,9,170,71,254,238,254,136,252,229,59,98,209,164,36,155,238,75,233,202, - 228,128,7,29,59,97,124,59,248,198,119,184,241,101,147,47,249,223,188,49,1,136,94,227,190,114,8,100,9,204,86,136, - 104,72,26,208,26,64,135,134,30,7,58,13,232,50,161,39,132,148,215,40,102,215,225,24,180,228,108,145,172,181,182,89, - 254,154,193,104,106,219,58,187,107,235,70,57,180,109,155,76,116,117,138,104,212,198,52,20,49,91,99,104,141,22,105,36, - 33,82,7,168,48,68,249,17,194,48,66,72,13,109,186,248,9,7,233,183,177,48,86,228,236,51,95,231,133,127,190,63, - 232,62,125,50,123,64,135,103,227,240,180,47,196,67,62,204,174,211,58,216,218,164,23,222,98,0,244,230,2,31,104,148, - 231,40,119,118,17,219,190,131,125,199,142,190,234,215,31,214,90,204,106,148,138,26,37,85,113,79,43,244,9,132,88,17, - 154,80,41,45,221,58,196,132,198,140,69,113,206,142,168,173,243,203,86,214,142,74,237,150,217,183,152,45,187,160,118,106, - 109,158,206,150,68,89,229,13,39,180,240,117,157,253,91,118,147,232,72,227,10,143,227,71,207,49,113,126,148,31,185,177, - 155,66,220,160,187,183,147,205,125,237,132,150,199,240,216,12,87,238,221,78,61,168,208,211,222,205,174,246,36,247,124,227, - 81,254,249,171,207,51,91,174,33,12,31,17,154,124,234,179,143,241,238,183,93,197,31,254,219,219,153,152,56,199,83,15, - 204,16,77,117,224,133,11,36,4,84,20,236,191,108,23,158,231,83,174,186,132,134,65,224,185,116,180,36,169,86,242,100, - 58,90,49,132,201,217,19,231,216,177,161,151,104,60,73,53,95,194,72,68,73,197,108,242,185,18,43,249,42,177,206,24, - 134,101,81,47,7,20,11,14,182,105,99,89,30,85,87,129,54,240,61,15,161,12,208,16,134,10,195,176,168,212,125,218, - 210,9,132,72,50,231,4,34,3,229,253,185,229,250,125,159,255,134,61,112,215,141,70,216,151,140,150,231,232,137,67,71, - 180,145,31,230,231,1,227,95,1,31,1,252,20,175,95,239,121,113,137,217,87,5,174,3,115,25,98,45,208,38,160,189, - 21,90,52,116,27,13,237,102,64,65,191,7,93,158,160,213,137,154,73,63,30,139,217,93,157,102,56,212,111,235,161,129, - 72,106,235,6,99,239,222,93,70,219,192,26,209,218,217,73,38,149,66,16,82,175,22,168,101,243,248,117,151,208,87,4, - 21,141,175,5,210,168,32,209,104,165,64,40,180,89,193,76,152,8,43,67,49,43,41,63,242,156,90,186,255,1,167,242, - 212,211,133,200,114,121,225,54,152,141,194,233,80,136,163,14,156,10,17,83,81,173,202,31,3,45,94,5,13,232,200,235, - 11,64,111,62,240,185,168,5,133,33,79,31,56,192,142,211,167,176,95,229,252,176,64,19,134,144,53,148,126,94,6,202, - 214,48,44,108,163,38,125,5,90,9,29,8,76,219,162,92,171,211,123,98,76,183,131,113,175,101,177,117,122,182,208,94, - 241,206,250,16,169,71,229,134,211,99,19,178,187,59,70,190,110,99,38,51,12,244,102,48,204,56,185,149,2,29,107,44, - 54,175,143,66,105,145,186,97,51,56,56,64,75,20,42,174,102,247,182,45,12,118,166,17,212,104,137,181,162,29,201,173, - 183,222,196,143,158,26,99,105,161,78,58,157,161,230,154,156,158,153,226,51,15,63,201,137,209,113,254,228,255,252,32,142, - 243,2,174,204,16,143,165,8,209,8,2,34,150,162,86,15,89,90,174,163,181,160,94,172,209,221,154,32,102,42,106,190, - 131,23,64,91,60,69,97,165,198,218,222,78,22,23,115,68,45,131,164,13,181,88,138,124,169,78,91,166,14,18,66,5, - 165,98,64,79,87,138,48,200,17,120,62,165,146,131,82,26,165,154,155,68,107,180,214,184,190,135,29,77,81,11,193,43, - 23,116,4,194,8,136,202,100,62,124,230,208,113,99,109,187,37,11,130,84,139,38,238,129,241,88,195,243,248,109,23,183, - 4,114,192,187,128,206,215,208,13,78,243,250,57,16,251,192,168,64,36,128,216,97,65,194,214,180,133,176,198,128,109,192, - 122,23,58,106,208,153,53,232,46,116,180,182,6,3,125,241,204,150,13,102,199,230,33,177,249,178,125,180,111,218,104,196, - 58,219,101,178,165,21,75,36,46,49,222,52,42,112,169,45,173,80,45,228,241,106,53,36,33,162,153,24,174,12,133,22, - 2,67,75,2,237,35,34,18,43,222,142,83,55,89,58,57,198,202,163,247,184,197,123,238,91,142,140,78,207,38,52,227, - 25,56,175,96,220,145,114,174,36,141,25,59,12,103,187,181,42,181,161,131,231,128,9,160,244,214,226,128,222,188,224,115, - 129,140,206,117,118,243,55,111,123,59,153,175,222,131,241,42,46,194,37,165,131,107,97,161,210,150,122,82,85,92,218,12, - 149,117,163,134,233,59,1,50,98,72,211,48,16,150,141,51,126,92,111,41,86,228,162,132,32,226,132,151,175,168,115,46, - 188,32,97,104,74,249,155,111,247,139,65,49,140,235,101,207,176,167,23,23,200,180,40,158,126,230,52,165,37,201,7,126, - 242,110,90,35,37,194,48,141,76,117,176,101,83,59,200,0,203,136,176,177,63,133,214,117,164,178,209,198,50,129,17,98, - 248,109,252,252,135,63,74,217,180,241,204,58,170,170,57,117,116,130,209,145,191,224,200,68,150,31,253,157,79,240,222,253, - 235,137,214,86,168,233,126,180,21,98,72,77,181,144,195,21,105,170,149,144,106,197,37,42,108,18,134,32,22,139,80,168, - 87,113,61,69,79,107,7,249,124,153,174,206,118,132,101,225,185,30,49,91,34,165,65,165,90,160,86,47,17,139,199,177, - 172,8,181,170,143,235,132,160,53,174,227,82,173,214,137,217,18,199,11,209,65,136,144,2,75,218,4,94,128,17,161,145, - 152,187,82,213,113,136,78,65,196,221,188,217,76,34,88,10,20,197,88,44,161,107,245,88,25,172,143,55,72,219,111,239, - 85,122,223,32,191,117,52,79,251,104,229,85,39,158,85,211,180,138,131,60,7,70,8,209,168,20,45,10,186,18,74,247, - 74,232,69,211,229,193,128,7,67,43,146,161,74,79,107,135,222,183,59,97,239,217,26,233,216,185,93,30,216,178,141,158, - 53,253,116,180,247,33,69,180,121,213,0,8,209,58,68,43,7,80,132,126,136,83,174,80,206,47,35,188,34,190,82,96, - 74,66,105,128,2,83,128,169,65,10,141,101,219,120,86,154,249,165,50,163,95,254,186,170,220,123,111,53,250,252,241,92, - 186,86,63,223,213,104,254,122,74,193,152,50,228,156,134,124,183,210,213,245,97,224,58,90,171,58,47,150,169,125,85,247, - 222,155,20,124,36,223,75,61,112,161,249,94,227,9,109,207,101,97,243,22,254,219,232,40,163,103,207,188,154,3,172,127, - 10,106,63,23,132,211,194,13,245,147,155,219,212,238,146,151,150,5,87,4,166,33,61,51,66,197,149,172,29,158,162,29, - 56,19,143,178,207,241,231,227,65,120,216,131,49,23,6,214,87,235,42,81,15,245,189,107,135,228,201,241,37,242,11,211, - 74,162,228,23,255,225,94,238,121,226,24,29,109,30,239,253,237,95,2,87,178,166,205,192,146,146,208,215,152,26,148,14, - 240,132,129,52,53,132,38,10,65,96,215,233,222,121,128,132,175,41,101,115,56,134,207,76,253,36,50,97,208,167,109,150, - 202,43,124,237,148,207,71,175,184,130,201,229,89,98,233,20,113,13,201,214,4,139,229,10,181,64,17,56,117,162,113,131, - 192,52,145,70,4,215,171,18,132,154,76,50,65,189,86,103,114,114,154,214,100,138,74,190,136,33,162,216,162,74,93,88, - 44,149,20,27,226,6,66,249,20,234,14,29,42,13,150,69,32,45,10,133,26,209,142,40,158,14,240,180,137,36,64,154, - 10,39,80,180,119,246,82,158,93,193,46,84,132,134,212,177,238,54,59,181,166,93,82,243,88,200,57,132,158,27,54,220, - 10,255,250,98,211,29,49,42,31,222,192,232,137,195,175,10,216,248,77,18,59,11,98,47,24,181,70,220,87,42,2,109, - 115,130,22,67,138,238,152,102,67,160,244,134,26,172,45,27,244,122,93,45,45,198,150,237,233,250,250,181,137,158,235,175, - 180,46,191,250,160,232,29,218,68,220,74,54,129,198,107,130,141,131,82,30,34,84,8,165,192,48,17,134,129,10,60,74, - 133,101,156,82,25,28,15,67,105,124,35,64,10,11,48,16,10,4,10,211,16,88,241,24,165,186,203,243,39,198,152,249, - 198,131,97,237,222,135,138,61,83,75,115,107,97,202,128,147,2,94,240,225,84,8,243,62,84,66,165,188,130,70,175,208, - 72,182,211,52,226,217,94,147,195,255,77,170,148,124,215,38,185,105,104,202,117,131,39,207,165,190,169,12,235,119,180,144, - 180,38,33,37,31,187,235,29,124,74,41,142,15,159,123,117,76,48,224,48,232,15,47,85,131,54,224,137,152,197,254,177, - 162,246,5,58,162,66,165,13,137,51,59,205,166,21,175,230,131,231,137,192,90,231,233,211,30,60,35,165,88,118,37,107, - 211,62,103,133,98,192,175,185,93,29,53,167,124,176,37,145,237,50,195,181,119,175,247,141,53,102,63,67,91,214,179,182, - 51,133,242,67,82,182,137,144,146,80,11,132,48,80,65,136,41,52,104,208,194,64,104,133,22,81,140,84,11,45,166,69, - 75,166,135,170,91,226,252,223,252,21,3,235,123,200,46,45,162,86,66,114,75,14,247,157,26,230,198,61,131,12,15,143, - 113,249,213,7,233,239,239,226,137,135,14,81,114,5,158,103,210,154,138,18,137,74,202,78,185,65,88,155,38,166,109,224, - 148,170,96,4,164,162,49,180,144,13,198,32,240,137,167,146,148,234,101,92,47,196,48,36,65,16,82,173,59,8,36,65, - 8,94,160,48,140,8,16,160,53,24,166,129,86,30,160,72,180,164,8,135,71,117,199,114,77,30,49,236,232,226,142,205, - 70,151,225,224,36,35,172,61,114,162,180,51,84,199,125,152,78,130,243,175,45,106,239,238,181,232,206,24,120,234,123,6, - 157,11,191,195,134,185,103,196,32,102,65,70,64,103,18,6,12,88,167,96,157,214,116,215,66,221,145,179,228,96,126,235, - 186,238,244,181,87,166,214,221,118,139,53,180,255,0,109,125,253,36,162,9,26,141,159,125,52,146,80,151,26,166,19,205, - 138,16,186,81,23,66,27,141,240,10,25,132,56,203,57,156,124,145,192,245,208,194,71,9,159,64,42,108,47,5,34,68, - 154,130,72,52,129,39,108,166,39,23,56,253,232,99,122,241,190,251,234,177,19,199,178,61,117,127,178,3,206,1,195,72, - 70,208,98,212,215,122,78,64,201,129,224,113,224,61,26,166,121,125,58,130,252,64,0,144,105,104,170,174,228,211,79,117, - 50,151,183,137,88,223,219,208,133,74,97,72,201,143,223,253,78,254,241,171,247,112,244,85,210,132,4,141,72,219,94,224, - 231,78,47,19,184,65,16,66,45,229,134,165,104,189,70,218,93,10,218,20,35,161,41,103,91,133,142,24,129,122,18,33, - 142,99,136,101,195,70,201,90,184,16,129,219,163,179,227,173,183,153,134,185,46,214,18,141,218,49,125,112,255,70,54,236, - 18,100,29,133,19,4,216,34,138,208,32,48,27,105,47,82,162,9,137,232,16,95,25,104,17,34,9,49,100,43,161,142, - 162,133,194,138,90,204,44,207,209,179,166,133,236,82,1,35,19,161,51,235,50,59,186,204,211,19,83,116,182,152,116,182, - 182,18,105,137,96,104,193,244,228,34,133,90,136,29,137,147,180,45,132,17,176,92,171,209,22,111,193,182,77,74,181,50, - 150,105,18,145,38,217,165,28,137,100,26,195,240,240,125,31,76,80,65,72,177,82,35,22,75,130,10,240,92,31,59,26, - 37,240,67,10,165,42,126,79,11,90,52,180,102,67,10,124,191,17,174,175,77,129,187,88,81,158,130,83,219,55,25,109, - 221,157,72,81,161,245,169,99,229,107,151,139,15,75,205,215,93,56,187,5,234,223,174,52,135,247,158,117,184,63,181,5, - 81,169,126,207,139,50,13,226,86,48,218,32,226,65,42,215,160,121,134,162,176,41,132,141,14,12,229,161,223,237,104,235, - 52,246,239,79,198,47,219,27,93,119,195,126,235,250,253,91,232,239,24,68,98,161,81,132,40,66,85,67,104,1,72,132, - 12,154,247,145,23,217,29,33,77,36,2,237,123,132,133,2,197,210,50,190,83,193,8,105,104,59,161,64,10,19,33,21, - 102,74,19,216,105,178,217,42,231,159,124,150,153,175,223,235,170,39,159,46,116,46,21,103,246,193,168,13,231,20,156,85, - 112,62,148,204,213,52,133,184,214,78,11,4,9,96,180,73,142,27,188,126,57,113,111,249,212,151,11,224,243,143,223,39, - 248,188,28,132,62,252,142,187,1,94,21,16,18,77,210,238,44,80,116,2,98,16,68,32,23,13,89,138,230,178,193,90, - 51,168,200,144,231,107,113,158,73,36,76,95,149,194,147,113,173,39,59,4,229,41,41,29,52,241,16,174,75,73,33,54, - 184,42,26,109,209,162,98,184,242,175,254,247,33,14,94,115,53,7,111,222,77,170,173,23,93,175,67,165,136,212,10,80, - 4,42,68,72,141,8,0,105,130,112,145,42,64,34,8,13,19,45,192,194,199,17,37,60,25,80,175,251,152,50,78,36, - 19,101,253,174,24,213,179,30,143,156,154,225,221,215,238,102,231,154,126,142,29,27,103,169,172,8,84,149,116,84,17,141, - 71,88,40,214,49,68,2,91,154,164,19,113,150,86,150,72,71,99,72,37,41,22,74,212,3,72,91,54,182,33,113,195, - 0,41,37,139,133,50,131,177,52,182,105,82,42,215,72,201,4,142,227,99,91,49,234,174,143,235,249,104,4,90,43,76, - 41,48,165,198,64,112,104,50,43,135,147,105,177,123,87,15,126,80,163,235,208,169,194,129,201,149,135,77,248,188,7,143, - 9,88,252,57,80,83,175,176,176,47,144,194,159,122,247,58,182,3,206,119,145,72,16,208,168,146,40,64,60,3,137,46, - 104,87,208,173,161,39,10,107,21,108,168,194,166,9,201,250,234,250,53,93,173,55,220,156,28,186,253,22,123,224,224,54, - 186,6,250,137,26,177,198,167,117,136,14,61,180,172,163,209,13,62,69,112,17,128,16,2,113,9,101,33,53,72,29,224, - 215,29,138,185,37,130,74,30,194,56,182,106,107,104,77,162,138,145,180,9,173,12,149,130,207,216,115,231,89,122,232,33, - 183,250,192,131,249,216,212,220,194,122,173,231,18,48,34,224,76,0,195,10,166,21,228,138,80,233,85,248,109,155,218,208, - 107,91,201,156,88,196,91,172,124,91,208,17,151,104,124,171,0,244,26,129,207,165,32,4,188,106,32,244,203,192,7,47, - 57,85,206,65,48,39,200,107,197,66,87,33,91,233,180,236,101,31,206,200,152,124,50,210,106,231,163,243,110,126,113,119, - 135,255,111,71,11,234,63,7,218,5,12,101,202,248,160,8,141,116,45,192,137,39,164,83,13,196,154,238,30,222,113,227, - 94,84,34,137,236,221,140,118,43,184,99,103,208,78,1,105,134,8,161,64,75,2,109,160,81,104,29,66,24,130,159,195, - 84,30,138,4,161,174,179,152,159,229,217,167,143,147,157,112,9,253,16,105,91,236,220,63,200,14,175,151,199,14,157,103, - 114,165,198,117,251,47,227,11,95,251,26,11,101,72,89,38,173,73,131,188,83,161,92,9,105,77,165,176,76,240,156,26, - 82,74,52,130,114,217,37,87,172,19,213,146,88,139,77,60,158,160,86,113,136,68,44,170,181,128,186,235,97,1,126,168, - 113,253,16,203,182,9,148,64,55,141,15,21,42,164,173,209,66,19,49,36,65,224,51,177,52,45,250,111,56,32,156,154, - 71,234,169,163,197,131,185,242,55,20,124,78,193,227,54,44,236,132,96,188,49,190,223,82,220,122,128,252,46,58,138,57, - 64,1,140,27,32,42,161,189,14,91,76,56,32,97,83,21,250,114,208,95,237,77,119,26,119,222,210,214,255,238,119,219, - 187,14,238,166,167,187,239,197,130,122,90,65,232,190,168,210,75,129,198,110,150,44,22,141,121,145,205,26,50,58,104,2, - 147,198,64,163,3,159,90,62,71,181,144,39,244,61,148,148,88,113,15,195,20,40,146,84,43,41,150,94,56,173,86,238, - 255,107,103,249,137,103,202,242,252,84,182,37,8,167,6,224,172,132,17,13,83,33,76,187,176,216,1,165,4,184,213,102, - 16,225,105,224,39,223,191,3,239,195,123,80,227,121,156,223,127,148,241,103,102,144,188,114,63,52,221,32,213,169,1,87, - 208,104,91,109,3,191,14,148,127,24,1,232,181,2,159,151,131,208,7,222,113,55,119,172,228,48,151,150,190,39,155,56, - 108,14,242,151,154,150,126,243,52,209,221,154,98,0,103,215,19,30,201,132,65,46,132,225,120,38,154,45,38,35,229,167, - 41,187,31,61,216,205,246,243,5,162,245,144,58,40,165,116,208,231,135,174,4,229,24,22,237,153,148,216,183,206,198,155, - 29,65,119,15,96,244,121,205,218,209,141,133,44,66,191,17,243,97,68,80,134,36,212,33,66,107,164,214,232,242,28,42, - 55,134,213,127,128,197,149,2,133,98,145,160,102,224,86,61,28,63,143,233,38,41,45,151,233,27,104,99,123,161,151,115, - 195,19,60,119,252,28,75,43,57,20,6,61,233,54,12,83,242,194,201,83,172,31,88,135,109,248,24,182,65,173,236,17, - 139,197,240,67,152,203,21,241,180,69,80,13,40,152,117,44,59,130,161,170,152,210,66,152,17,60,165,176,100,35,70,193, - 241,21,150,29,65,171,11,44,178,64,235,16,83,154,212,252,144,68,50,70,185,232,48,212,191,14,119,121,153,190,67,71, - 151,175,170,235,71,52,124,46,3,143,231,96,225,73,8,175,249,22,188,197,26,26,45,150,87,190,67,126,71,54,41,224, - 69,48,92,136,71,160,91,194,70,9,59,44,216,191,4,187,178,157,173,61,246,45,55,166,215,190,251,174,200,198,107,175, - 164,191,127,8,3,7,133,36,84,1,154,0,83,6,77,156,177,65,11,2,195,69,96,33,154,126,86,173,21,66,132,205, - 140,44,141,198,70,160,144,58,36,112,234,212,242,121,220,90,5,75,8,146,169,52,117,223,101,100,58,203,249,163,167,117, - 238,240,11,202,59,114,156,158,201,217,122,79,213,153,26,128,51,18,134,53,156,15,13,57,42,18,246,12,117,63,231,250, - 97,61,222,116,159,141,2,22,80,4,6,219,162,176,191,135,112,190,140,217,147,36,104,143,243,56,141,250,218,127,13,220, - 8,204,3,159,166,17,41,30,3,102,129,25,224,87,155,224,35,224,251,246,24,155,111,85,240,169,56,146,79,63,253,218, - 128,207,75,64,200,48,88,115,227,77,188,251,139,95,32,230,121,223,181,203,246,2,255,19,52,255,45,27,155,65,143,192, - 138,13,79,164,82,166,111,133,70,217,135,227,53,105,84,122,126,108,155,90,99,12,163,86,28,222,237,134,20,32,136,194, - 34,154,163,49,211,138,104,188,158,146,231,244,137,104,210,238,234,74,82,169,46,99,85,210,88,179,35,4,218,67,121,69, - 164,169,209,161,64,138,6,151,16,202,16,169,12,164,150,168,208,199,93,94,164,92,122,148,129,206,61,124,227,235,207,50, - 188,120,158,254,158,22,70,14,159,193,78,70,113,189,42,239,184,227,61,108,220,220,13,127,253,87,220,55,58,205,231,30, - 126,154,181,45,22,25,225,145,73,165,56,61,179,130,167,45,226,49,11,59,34,40,148,203,88,42,130,64,80,40,87,8, - 35,81,220,154,130,138,199,162,95,96,77,127,111,147,12,215,72,51,66,185,82,37,145,137,226,169,0,169,163,40,165,9, - 252,0,167,238,160,1,211,50,26,174,99,203,196,178,77,102,167,230,88,58,62,172,110,28,159,154,217,21,232,39,92,248, - 178,5,143,215,97,241,167,32,188,254,91,140,127,23,240,251,192,31,127,7,0,228,0,237,32,111,4,99,14,98,2,186, - 227,176,197,130,125,62,236,27,131,77,51,189,237,125,153,15,190,51,115,195,207,127,212,216,186,125,23,70,83,95,80,65, - 0,74,54,10,226,153,54,10,137,175,13,164,110,120,35,5,96,104,11,180,68,160,154,161,124,32,154,142,109,45,20,129, - 14,49,5,248,213,42,94,169,220,56,44,148,193,233,177,9,61,252,194,201,202,200,195,207,80,123,230,233,200,186,170,195, - 0,200,76,163,118,40,2,124,13,117,5,66,66,135,161,180,208,37,39,161,160,104,129,31,64,181,8,197,86,168,215,165, - 168,215,162,150,155,142,219,33,125,113,162,90,32,164,226,191,41,197,127,190,100,204,126,189,73,25,156,164,81,35,91,54, - 249,33,221,244,250,25,175,2,248,188,37,1,232,34,225,252,116,39,179,121,155,168,245,218,114,245,194,247,89,90,191,129, - 71,222,243,94,222,255,133,207,97,122,223,127,160,226,116,99,114,235,183,69,140,243,149,76,36,107,44,57,254,12,148,31, - 245,116,240,95,119,119,232,61,55,244,178,248,27,79,179,59,212,76,54,22,208,121,91,235,207,163,25,5,174,15,131,242, - 109,245,96,62,190,41,99,81,171,135,24,122,5,51,63,140,162,225,110,87,194,66,9,19,161,5,82,11,180,240,17,218, - 68,8,65,173,86,197,114,3,130,202,12,71,31,125,132,103,158,62,195,228,226,89,174,189,102,39,243,163,179,44,44,58, - 184,70,141,88,58,193,237,119,126,152,193,182,36,167,206,255,22,95,123,246,40,31,190,114,63,189,182,196,48,235,200,116, - 146,142,238,54,108,83,19,6,18,47,52,136,199,108,10,217,28,190,180,193,142,35,92,31,25,72,156,176,74,177,90,38, - 147,140,83,116,92,76,59,78,88,115,80,97,128,52,76,234,78,195,68,137,68,34,56,110,13,105,68,16,194,0,67,99, - 219,54,42,12,56,117,126,146,53,35,147,185,125,240,100,21,190,160,225,73,15,150,254,13,132,179,205,77,242,74,114,35, - 112,217,37,218,231,43,29,16,186,249,249,24,68,90,27,7,126,79,0,107,34,176,211,135,253,39,96,199,200,64,79,223, - 192,143,191,47,254,158,143,252,132,216,186,101,55,160,80,65,133,80,7,200,166,9,21,24,33,146,8,50,144,72,84,67, - 213,69,19,52,1,72,42,137,144,52,52,30,169,80,104,20,18,133,1,72,44,1,213,252,10,203,179,179,172,100,151,56, - 119,118,148,211,195,227,12,143,78,213,219,202,245,177,141,90,119,237,187,246,42,203,72,197,140,138,97,136,98,224,235,48, - 244,162,241,233,169,181,153,66,61,93,23,166,23,56,245,48,146,205,151,109,215,95,1,42,17,168,75,200,9,88,12,96, - 209,132,145,13,112,54,168,122,43,39,191,58,170,73,88,252,247,167,166,249,167,135,39,94,98,110,5,151,104,147,226,18, - 109,231,213,38,167,205,183,34,248,252,227,83,175,15,248,92,16,203,113,56,53,180,1,235,3,239,228,125,99,15,17,126, - 31,173,240,140,230,98,223,234,43,189,231,150,1,103,204,85,110,252,217,69,253,216,92,153,251,128,63,245,5,110,41,160, - 227,182,53,24,15,76,243,44,40,3,150,251,160,232,151,189,37,13,45,201,124,241,64,97,50,223,174,135,6,8,98,53, - 100,52,131,54,35,40,229,129,110,122,80,154,43,37,208,26,17,154,52,104,93,3,59,146,68,219,53,122,12,77,245,252, - 189,204,62,241,53,198,202,6,27,182,237,230,142,159,186,129,92,161,64,164,213,192,110,171,224,215,231,217,177,115,31,215, - 238,189,10,127,41,135,44,251,120,105,151,157,123,55,49,249,213,51,244,39,210,8,83,80,173,215,73,71,226,44,101,107, - 212,125,3,43,30,37,112,93,16,62,174,112,49,66,73,110,197,193,232,76,128,168,147,208,30,85,101,82,114,5,118,84, - 129,23,16,134,62,177,72,28,223,53,209,166,66,168,0,180,66,74,3,97,180,147,61,123,154,235,97,198,133,167,52,60, - 187,17,22,127,20,212,201,239,194,109,14,32,163,38,36,44,4,166,64,52,74,227,185,192,14,136,182,195,218,0,174,181, - 224,114,9,67,71,97,232,204,186,129,193,117,31,249,96,236,23,126,242,67,108,24,218,222,216,154,170,4,90,32,37,104, - 109,162,164,70,8,129,208,2,161,53,200,176,89,112,71,160,181,70,135,10,132,64,27,18,33,100,67,79,17,23,66,221, - 4,66,55,12,191,153,185,5,22,230,231,177,165,36,217,219,207,149,107,214,115,203,123,83,36,146,201,184,29,139,239,209, - 134,13,72,12,36,47,50,72,46,245,114,177,197,171,214,90,10,117,23,191,82,68,45,206,18,22,115,202,169,213,241,207, - 77,121,198,200,100,85,79,206,151,39,78,141,228,218,43,149,175,217,53,111,101,33,30,47,236,94,219,17,78,254,221,243, - 252,237,51,211,111,88,33,254,183,12,0,73,169,169,56,6,255,244,116,199,235,10,62,23,36,230,212,57,219,191,158,23, - 222,21,103,207,224,10,142,255,189,15,93,10,184,29,112,37,152,83,85,109,28,93,126,105,43,24,5,65,103,12,131,139, - 33,105,234,65,112,175,145,98,73,134,122,36,153,11,102,103,78,206,175,223,179,101,139,97,184,14,66,216,104,105,54,106, - 249,43,208,170,233,71,17,128,144,104,45,176,8,27,175,197,146,208,35,80,78,133,117,25,205,239,255,230,79,243,223,63, - 241,0,95,254,155,47,208,189,126,45,45,237,25,122,58,225,206,159,234,32,48,210,140,29,127,134,31,185,170,157,167,14, - 173,176,84,14,249,233,219,110,66,21,171,104,39,32,154,49,240,202,37,226,182,73,169,90,163,84,171,34,236,8,126,189, - 78,24,134,168,208,199,50,13,132,18,184,158,71,161,84,35,21,181,9,125,15,41,44,252,80,96,95,168,146,41,26,62, - 22,199,181,65,123,196,164,66,40,27,33,5,149,208,35,117,126,182,218,11,163,46,156,201,64,182,23,212,210,165,135,68, - 243,247,191,118,52,84,158,93,196,88,168,49,125,182,160,83,19,53,158,7,43,14,173,29,176,14,184,70,194,109,163,176, - 251,112,103,111,91,219,135,223,17,253,165,255,227,167,216,178,110,91,99,187,171,202,139,228,178,80,104,125,1,232,27,222, - 43,137,113,81,235,65,92,40,252,41,144,23,163,99,197,37,241,61,141,185,185,168,81,104,77,107,75,43,61,221,61,205, - 218,217,151,178,136,23,156,242,206,139,196,182,208,132,190,143,87,173,18,120,46,202,115,233,242,60,252,132,129,183,113,29, - 138,77,50,97,69,176,238,136,68,199,231,115,209,111,252,243,231,218,35,217,201,68,119,133,152,6,217,107,74,230,239,59, - 71,223,201,197,215,45,23,238,45,13,64,2,248,226,225,54,166,87,108,98,182,122,253,239,47,64,187,138,175,62,209,133, - 216,235,179,99,160,72,16,126,111,10,169,110,146,156,134,37,209,190,250,166,217,215,52,194,231,1,54,55,189,12,247,1, - 251,108,195,73,251,225,116,38,208,163,39,159,24,222,51,122,203,158,214,13,17,137,112,125,116,52,104,156,194,77,125,89, - 8,217,44,89,39,80,8,164,14,145,40,28,105,160,34,73,100,196,198,8,3,54,182,69,249,179,223,253,8,95,253,198, - 211,252,197,23,158,225,204,211,19,108,191,233,74,118,245,95,137,191,178,64,75,238,8,190,214,28,159,154,226,231,255,237, - 47,176,53,99,240,197,47,61,65,213,138,96,248,14,9,45,176,60,159,217,66,141,64,130,170,151,137,70,19,248,42,36, - 12,66,108,9,210,48,208,90,81,171,59,180,36,91,0,141,129,129,235,213,73,136,20,74,132,23,249,49,47,208,8,35, - 36,105,106,162,86,156,72,92,82,172,102,105,203,22,139,2,198,108,152,93,6,239,31,128,247,210,136,208,213,77,222,226, - 159,128,31,5,254,27,141,246,58,175,36,243,127,113,138,243,13,173,199,254,8,36,21,244,107,216,103,194,149,57,56,240, - 92,38,186,185,252,182,235,91,126,254,119,255,31,118,108,219,117,209,35,39,116,136,16,47,166,96,94,244,226,11,209,124, - 253,197,72,33,33,26,154,143,66,53,56,33,33,64,74,228,203,154,117,138,38,128,9,209,0,166,104,44,142,16,16,40, - 191,241,94,193,37,224,3,82,27,160,20,129,23,80,43,22,168,151,75,104,223,107,120,205,164,164,174,53,194,87,68,34, - 16,8,139,225,137,37,142,220,255,117,74,95,255,146,187,113,98,101,166,99,185,244,164,47,197,115,166,214,121,103,169,34, - 70,191,112,134,4,112,249,37,252,100,0,180,93,98,154,138,75,158,64,252,48,3,144,210,130,170,39,177,140,55,174,107, - 147,20,154,32,148,60,63,209,198,206,129,2,175,85,184,86,212,146,252,250,87,199,249,23,26,245,97,46,40,235,27,220, - 208,191,75,50,231,193,153,158,137,229,153,195,143,30,107,25,186,243,42,33,170,69,140,116,10,161,26,17,221,90,92,136, - 49,105,28,195,18,8,165,198,71,55,204,17,213,56,173,165,246,9,253,10,66,86,121,247,157,251,184,245,246,203,152,171, - 175,161,84,5,127,101,154,72,249,56,9,237,240,201,167,207,179,239,134,155,216,217,223,78,121,110,154,179,217,60,42,106, - 96,213,29,66,219,68,116,245,241,182,91,15,96,164,18,4,149,10,231,207,141,112,242,228,41,108,211,38,240,124,44,219, - 38,150,136,19,6,30,149,154,75,50,150,64,185,1,74,131,235,42,180,18,132,126,8,177,0,95,5,68,13,3,33,52, - 133,124,158,190,150,30,150,103,150,216,228,185,89,5,99,38,228,74,160,254,170,65,24,95,228,39,198,129,71,129,39,155, - 174,226,87,138,229,105,3,214,129,156,109,100,157,175,51,96,155,13,187,43,112,224,217,72,100,187,250,192,29,157,55,124, - 244,253,198,222,125,7,104,111,25,36,84,46,26,7,137,66,72,235,69,187,182,233,78,191,0,60,151,174,72,253,34,50, - 33,164,184,228,35,226,21,15,213,11,181,81,181,166,193,9,105,133,209,220,246,141,178,133,205,164,92,21,226,59,37,220, - 90,21,183,90,195,119,29,164,166,241,94,173,145,82,225,27,30,190,7,163,39,199,56,252,181,7,116,237,193,135,217,60, - 189,236,109,119,152,83,232,99,190,33,206,34,113,3,45,6,129,150,13,232,218,10,184,127,4,161,120,233,183,99,17,194, - 12,184,123,193,179,32,12,64,249,47,139,169,250,161,35,161,141,55,65,62,171,16,188,230,32,24,26,130,143,20,61,238, - 184,100,146,21,208,171,180,174,41,86,2,33,142,116,184,122,199,210,61,71,187,135,247,108,236,218,220,219,134,84,33,88, - 54,66,169,139,39,150,210,205,152,90,13,218,104,20,61,147,74,35,84,136,8,131,134,166,36,37,129,80,4,53,133,37, - 124,54,12,118,34,186,119,146,127,254,211,104,97,242,213,19,101,162,235,54,242,209,95,253,21,152,59,193,76,161,140,87, - 171,96,187,62,182,109,114,224,174,91,184,249,199,126,134,100,162,163,177,165,66,31,183,84,228,191,253,225,127,229,196,147, - 135,73,70,163,32,124,148,104,84,223,241,125,240,35,26,69,64,168,66,156,186,79,52,102,33,165,137,105,90,13,86,68, - 131,198,34,91,152,165,199,238,167,101,116,165,214,171,24,13,27,26,80,229,243,77,183,240,119,218,62,217,111,186,226,255, - 75,35,182,175,67,192,65,75,112,139,167,217,55,97,152,67,11,183,222,216,187,235,223,124,36,114,227,109,183,17,179,227, - 64,149,144,21,16,2,67,91,13,186,70,7,23,13,189,75,181,150,11,187,86,107,253,178,230,10,151,232,12,23,114,43, - 46,1,41,33,154,237,203,47,124,166,169,237,8,33,64,105,132,214,104,215,39,112,61,188,106,21,223,119,80,65,13,165, - 21,82,9,162,182,133,214,18,33,12,234,142,199,244,232,212,202,249,103,158,173,231,30,122,34,33,142,156,74,116,85,125, - 99,176,57,148,181,198,50,234,36,212,251,129,109,2,28,1,69,9,5,11,106,10,92,1,74,188,148,120,118,4,228,226, - 176,124,225,189,2,138,187,193,139,64,88,7,21,252,176,1,208,15,131,104,91,162,198,138,236,124,102,129,157,175,240,247, - 28,212,206,74,206,248,33,15,175,159,173,245,157,251,242,179,215,247,254,252,237,49,103,114,140,193,205,59,81,58,64,43, - 133,48,26,133,190,80,141,83,212,84,178,1,224,34,36,148,33,161,80,8,37,65,75,164,144,24,202,68,11,77,205,157, - 33,230,117,147,220,112,5,207,191,112,138,106,172,206,199,126,249,231,177,109,131,122,60,67,49,48,192,243,177,162,54,183, - 252,196,7,185,254,157,119,83,170,58,100,179,83,8,199,37,101,26,68,186,58,120,255,135,127,132,225,23,78,18,11,37, - 117,63,192,48,13,148,1,90,11,66,165,9,181,7,66,82,171,55,178,186,209,18,207,13,208,134,194,16,18,165,45,234, - 8,188,186,75,102,116,54,31,133,17,31,166,11,224,118,2,73,94,204,204,22,52,130,228,254,238,21,180,159,11,81,232, - 191,14,70,7,116,20,225,74,27,222,181,160,185,102,118,247,214,190,173,255,207,111,37,223,119,247,123,72,68,108,80,121, - 116,152,3,33,144,58,14,202,108,84,87,150,77,72,191,164,146,187,18,23,186,247,234,139,224,35,94,118,95,160,145,70, - 113,129,43,186,128,53,66,188,168,246,104,221,12,74,108,2,91,216,32,166,67,207,163,144,93,194,171,214,136,72,3,80, - 120,74,224,123,138,48,208,100,179,139,12,143,142,177,148,91,97,118,126,145,229,233,133,133,100,32,196,254,116,50,189,115, - 239,118,77,44,174,114,235,7,68,189,61,99,25,129,209,237,213,85,71,44,212,202,46,231,67,170,101,229,85,92,191,90, - 169,251,245,252,138,175,114,139,158,44,150,125,233,163,162,26,221,56,154,240,58,97,57,218,0,160,172,1,19,6,140,11, - 200,234,134,133,155,141,67,97,63,132,23,28,43,122,21,128,222,250,98,8,65,169,30,242,84,197,127,69,3,79,129,78, - 135,58,107,194,33,19,214,25,79,12,175,27,191,109,231,102,34,17,74,238,41,182,109,223,214,168,193,32,4,58,84,77, - 30,186,97,138,53,56,135,176,201,75,152,141,214,209,161,192,8,65,201,198,194,143,155,105,130,68,18,17,239,96,243,110, - 147,3,215,223,128,21,145,248,165,37,100,162,143,147,211,57,252,100,156,15,253,155,95,97,219,21,151,113,242,153,103,9, - 150,39,57,55,50,130,244,32,25,143,178,249,242,253,244,110,222,75,223,64,55,213,241,5,194,80,225,41,143,132,25,197, - 196,196,247,61,164,33,16,1,4,190,38,176,66,98,182,133,101,198,240,194,42,49,105,83,117,92,42,218,162,54,187,172, - 251,242,249,121,224,188,132,229,35,160,206,54,53,160,75,221,232,15,210,136,83,121,185,172,7,210,141,154,201,253,21,56, - 40,224,206,179,177,216,245,241,95,251,216,192,7,254,237,207,152,189,237,27,208,97,136,242,139,96,248,72,17,111,92,81, - 104,180,104,128,164,86,118,195,172,21,193,69,176,160,105,46,93,170,25,139,139,252,144,190,200,241,160,117,243,35,47,155, - 77,253,34,183,115,1,188,164,110,0,22,90,81,171,84,241,195,16,105,155,248,42,100,37,191,130,171,26,190,76,180,192, - 72,217,108,219,187,157,3,233,20,109,157,93,100,90,90,183,155,182,73,16,58,72,195,215,150,180,69,163,40,137,5,40, - 67,19,52,41,122,31,240,240,21,56,110,72,165,88,164,146,91,160,90,206,227,187,10,157,247,244,232,249,113,49,49,114, - 142,147,199,143,121,198,153,243,181,158,98,173,218,129,206,103,96,33,10,75,22,76,73,120,54,132,103,255,35,44,29,132, - 48,250,61,174,247,215,182,55,60,224,155,175,108,41,26,97,35,42,119,85,94,58,96,66,10,178,17,131,187,191,205,219, - 254,12,130,43,4,51,30,28,238,172,232,125,39,191,114,120,240,237,191,253,177,88,109,121,153,51,103,207,178,105,203,38, - 164,33,47,122,107,80,154,64,4,104,209,152,112,137,1,170,113,44,107,173,80,4,104,12,124,105,147,72,116,99,41,1, - 190,75,71,199,26,148,89,37,12,29,172,84,148,231,30,61,198,11,231,103,249,149,223,252,117,182,238,185,154,165,241,73, - 142,126,253,97,238,190,121,35,235,46,91,203,200,209,17,138,133,69,178,227,22,189,107,215,178,121,93,31,207,156,62,127, - 209,235,92,119,234,196,205,24,50,116,73,183,37,41,4,30,166,105,96,26,18,203,50,65,90,136,64,99,73,197,210,242, - 10,21,97,161,71,243,245,54,152,212,48,62,15,149,71,155,91,217,123,153,137,245,74,43,233,99,192,251,33,150,135,141, - 6,220,92,135,91,206,174,25,56,184,247,47,255,168,231,250,183,223,10,202,71,5,117,144,117,148,233,131,136,53,202,180, - 106,141,32,4,35,68,8,137,194,126,9,67,114,193,84,185,148,152,109,240,34,26,201,37,164,180,190,100,94,181,190,120, - 137,11,36,117,131,211,126,209,12,187,152,34,34,4,241,116,146,88,50,70,168,124,164,212,116,172,29,64,88,241,134,163, - 1,205,139,81,57,170,121,139,0,180,198,178,98,104,146,194,215,160,117,163,252,170,8,21,130,16,101,149,16,161,137,192, - 192,68,145,136,106,82,177,22,68,79,95,19,156,2,180,46,136,203,220,27,81,126,137,165,229,37,123,124,100,218,158,56, - 53,217,50,115,242,201,190,167,78,205,110,159,159,153,11,47,203,174,100,175,242,130,62,95,136,26,90,63,245,52,84,204, - 239,129,19,186,250,181,4,160,6,248,152,104,241,202,196,77,96,10,204,64,173,130,80,115,172,12,192,52,37,248,138,223, - 249,219,211,0,252,39,224,237,47,91,232,33,176,9,24,211,212,29,193,112,20,14,103,14,79,110,63,241,232,195,155,111, - 189,245,38,150,28,147,233,249,60,107,6,50,8,25,34,60,139,128,128,80,106,164,54,208,1,152,90,96,8,133,47,2, - 66,83,161,5,72,101,96,198,90,32,29,33,20,1,194,20,72,93,69,134,10,204,8,94,16,97,105,185,204,175,253,246, - 255,197,208,230,54,116,101,30,63,63,131,95,25,103,236,120,129,84,170,131,45,155,182,50,54,55,66,169,94,34,162,53, - 45,157,173,20,164,75,155,25,69,184,146,80,155,248,202,71,138,16,229,42,44,173,209,134,79,77,185,216,97,28,195,53, - 208,194,2,17,103,108,101,12,153,233,192,158,95,40,70,97,44,132,57,19,188,193,151,141,71,4,248,228,43,152,94,31, - 3,254,45,68,231,96,83,4,238,40,192,93,243,219,55,236,184,227,31,254,170,109,211,222,3,40,85,110,212,163,110,210, - 169,66,73,180,16,141,252,57,104,166,138,54,204,167,70,113,29,129,18,242,165,4,242,37,218,80,35,133,228,165,38,21, - 82,188,196,116,19,205,247,93,228,122,208,223,212,148,243,2,191,36,45,11,129,141,41,227,23,175,161,155,238,251,134,229, - 118,137,215,243,130,141,215,44,183,34,132,110,130,84,67,147,19,6,141,239,170,26,190,46,37,53,161,50,26,26,93,104, - 225,185,43,56,37,7,191,80,196,113,243,132,74,161,101,0,66,178,113,168,159,221,59,118,224,127,232,78,113,244,244,130, - 248,252,23,191,36,191,241,207,159,235,219,148,203,109,237,210,97,183,130,72,47,84,206,164,187,56,157,238,194,250,46,58, - 28,191,102,0,244,175,129,207,139,32,36,127,168,65,72,235,198,26,141,26,130,34,48,50,87,102,231,207,220,207,169,137, - 70,193,203,141,52,90,198,116,188,194,68,41,80,207,106,22,44,120,161,187,194,222,209,175,30,233,155,218,190,33,217,223, - 189,150,176,179,11,45,42,24,161,196,23,17,164,12,145,218,65,41,19,141,68,73,3,36,72,97,98,162,145,26,234,42, - 70,164,109,29,218,72,17,18,109,20,118,11,125,192,68,135,54,74,187,188,237,157,183,99,10,141,90,153,99,250,201,71, - 153,57,245,12,111,223,218,66,107,68,50,90,158,103,161,146,96,253,198,253,28,25,27,195,72,182,146,74,119,17,53,50, - 248,218,197,51,66,2,45,64,248,16,106,44,71,18,145,113,194,208,165,90,211,84,188,16,171,37,192,54,5,185,170,207, - 249,108,133,93,137,20,125,149,106,46,132,169,40,172,168,102,224,97,178,185,198,50,205,177,41,188,108,108,126,17,248,101, - 136,102,97,115,12,238,152,129,119,46,222,124,213,238,187,255,231,31,37,215,110,217,76,232,151,144,82,54,188,84,13,134, - 254,130,241,132,190,36,81,245,34,81,252,175,122,59,5,82,128,80,47,227,116,154,38,154,104,106,57,23,201,231,75,212, - 163,23,95,19,40,173,26,102,156,108,0,141,210,186,17,30,213,52,238,68,211,101,166,185,96,214,93,2,110,23,59,125, - 53,126,139,230,231,27,32,212,128,35,37,18,8,17,34,133,66,234,8,110,177,68,41,55,131,235,44,162,194,70,235,116, - 221,76,71,141,68,50,8,105,48,59,151,227,216,225,167,56,250,196,115,228,15,31,14,183,100,151,10,183,132,225,84,43, - 234,217,16,166,5,184,115,210,224,233,76,47,75,118,20,227,187,220,203,230,171,15,62,226,59,2,159,183,44,8,105,144, - 82,96,197,76,172,240,251,44,80,105,75,44,41,248,171,165,58,127,12,224,134,23,193,135,75,52,158,11,114,164,233,74, - 94,75,163,0,205,54,168,77,195,25,19,158,106,63,182,188,254,248,163,231,246,246,191,175,95,202,176,68,104,24,16,74, - 180,89,65,134,38,82,69,81,210,71,75,8,80,205,69,220,168,19,44,125,144,169,86,204,206,126,132,180,48,0,77,72, - 104,40,12,173,144,8,108,161,17,202,3,41,240,234,30,231,78,62,207,80,74,146,136,36,168,135,2,179,189,141,84,95, - 39,83,243,179,172,219,119,57,164,251,41,151,42,196,81,132,36,208,162,134,208,149,198,169,110,219,84,106,5,236,84,26, - 180,198,112,53,1,18,199,171,147,74,38,89,56,63,227,222,136,161,188,92,33,154,168,57,57,96,97,9,106,91,175,238, - 230,137,159,218,2,213,0,210,22,249,71,231,248,155,191,31,249,38,205,231,23,4,177,5,205,198,40,220,62,13,119,79, - 255,216,123,15,252,212,255,250,147,72,71,50,142,242,29,164,97,18,170,0,169,5,82,24,232,70,78,250,75,72,226,11, - 224,163,255,213,67,228,82,80,225,18,142,232,69,13,233,155,61,100,47,242,68,23,249,34,241,210,251,138,151,93,227,69, - 222,232,165,69,244,245,75,72,111,31,173,26,209,214,186,25,230,173,208,72,83,54,25,251,16,130,16,175,190,76,117,165, - 68,173,84,68,251,145,134,6,108,6,104,43,133,105,25,56,78,192,209,199,159,231,248,253,79,233,236,227,207,184,169,165, - 197,202,94,29,228,214,192,76,2,206,134,112,50,128,19,81,56,87,131,250,54,33,249,188,48,176,3,255,187,46,217,250, - 170,1,144,18,160,132,73,104,200,239,186,4,235,91,9,132,44,75,82,174,133,124,249,177,57,180,254,254,34,33,226,17, - 131,191,252,202,20,255,114,50,247,29,189,255,15,128,231,155,38,199,85,64,23,168,17,88,72,192,179,173,138,109,35,15, - 28,91,179,124,251,21,29,3,177,40,53,203,192,51,92,162,4,160,147,40,34,23,205,12,68,67,77,215,90,19,72,192, - 22,68,187,251,17,102,10,2,129,209,12,156,107,228,41,53,242,201,132,50,192,148,84,189,18,86,58,65,203,250,181,100, - 23,134,9,170,33,45,109,45,12,14,12,16,90,25,18,91,214,147,216,178,155,186,87,229,212,240,9,132,165,17,210,199, - 10,67,162,50,141,210,49,20,1,142,237,81,244,202,72,25,65,38,45,180,97,161,2,143,186,23,232,245,231,167,117,183, - 143,253,180,239,122,17,205,18,176,92,4,239,100,87,140,93,215,246,64,45,96,97,161,198,244,179,217,151,228,120,125,12, - 248,37,136,102,53,155,162,112,251,18,220,189,252,145,247,31,248,217,143,255,69,36,99,27,232,192,105,144,202,8,164,52, - 27,0,163,245,75,65,231,82,96,121,249,38,255,22,135,234,203,65,72,55,181,157,11,17,208,23,92,246,226,18,144,186, - 8,52,151,120,194,94,84,142,244,55,1,20,90,55,211,60,94,10,112,23,238,117,33,250,186,81,73,160,25,151,45,27, - 166,152,20,33,161,239,226,87,203,148,86,86,168,87,138,232,192,66,26,62,210,118,49,173,22,16,113,150,23,151,57,249, - 216,51,122,226,95,190,236,196,142,159,92,217,164,84,238,58,88,176,97,76,193,48,48,225,55,126,230,4,20,43,141,96, - 126,173,208,24,250,66,100,208,119,169,1,133,230,171,83,130,61,16,223,95,144,206,91,1,132,76,195,32,84,1,127,250, - 233,251,57,55,49,254,186,223,63,74,163,92,194,245,192,205,192,127,111,188,230,8,24,213,112,168,115,108,101,231,225,199, - 143,180,245,127,232,46,105,251,80,55,163,104,21,160,241,209,70,216,136,105,1,12,45,65,105,148,33,168,98,17,105,111, - 67,180,182,17,202,176,113,34,53,131,25,181,8,9,180,198,212,141,2,21,210,84,60,248,229,71,57,176,251,74,174,120, - 207,207,224,44,157,34,168,186,152,210,196,136,8,140,88,43,178,109,51,136,56,95,248,235,191,101,252,228,56,41,195,66, - 227,16,183,163,120,142,34,12,11,152,102,140,152,145,198,11,138,88,145,58,166,78,17,170,8,102,44,193,252,217,97,125, - 101,177,110,22,34,166,209,234,82,54,149,88,240,208,57,27,252,142,71,231,248,210,135,30,192,2,126,63,231,242,239,231, - 107,23,83,47,126,190,201,249,204,195,230,8,220,145,131,187,202,63,251,35,251,127,228,47,254,75,52,35,3,180,47,26, - 109,254,154,192,162,155,224,160,105,132,41,188,28,92,132,248,230,141,46,148,254,166,224,195,11,57,237,66,235,151,106,42, - 223,230,122,92,226,134,191,232,194,215,47,94,77,41,133,144,47,166,105,232,151,152,117,77,83,238,2,184,73,9,234,66, - 90,136,213,236,117,214,76,111,65,131,87,167,88,204,81,45,21,209,117,69,160,52,194,210,216,73,3,100,7,229,130,199, - 248,179,99,156,252,250,87,66,241,248,179,229,182,133,133,236,229,48,18,131,51,26,198,53,204,186,48,29,194,130,130,82, - 28,234,62,4,223,0,222,71,163,204,201,247,181,167,180,120,243,116,171,184,0,66,198,155,22,124,66,254,247,23,190,240, - 134,128,207,75,198,9,184,31,184,6,248,91,96,3,228,115,112,188,21,142,156,249,210,161,141,35,55,95,213,185,185,179, - 27,25,104,124,67,99,74,15,41,20,74,54,226,130,100,8,82,24,248,158,137,209,210,65,180,123,35,202,202,160,49,27, - 166,25,141,124,178,6,51,18,130,82,72,21,131,64,176,105,176,131,99,135,238,199,176,174,165,181,117,39,86,107,2,31, - 23,63,212,232,64,50,127,122,156,39,238,125,152,67,247,63,74,90,138,70,175,119,51,66,32,162,104,211,196,240,52,182, - 229,163,85,21,233,196,176,68,12,175,150,35,18,143,82,168,197,25,152,92,168,119,67,165,40,85,116,200,146,185,0,61, - 159,132,210,147,160,254,40,239,145,202,123,204,240,98,35,116,23,248,8,240,107,16,93,130,205,86,3,124,238,142,255,230, - 175,238,187,245,255,253,141,120,4,80,126,163,220,169,104,166,168,92,64,16,45,154,197,183,4,8,169,95,22,11,252,82, - 142,231,229,4,179,184,84,59,121,41,17,211,244,84,125,11,210,79,136,70,116,243,203,194,8,26,227,254,82,79,219,75, - 52,160,230,139,2,113,193,94,123,17,188,46,128,83,216,224,134,132,14,9,61,135,122,169,68,113,101,137,192,119,209,161, - 143,25,49,136,91,3,120,161,102,230,204,48,211,15,254,189,95,123,228,201,146,30,158,91,94,239,185,11,29,48,35,96, - 84,193,49,13,231,12,200,22,161,166,193,217,6,193,68,147,236,183,105,212,20,50,249,254,115,1,222,116,113,64,129,217, - 200,97,122,121,176,177,16,224,171,111,50,165,95,23,17,134,65,94,133,124,234,11,95,96,250,117,6,31,69,35,144,46, - 70,163,44,232,102,26,233,25,208,232,125,53,3,236,2,47,7,227,10,14,245,143,230,183,63,245,215,247,93,179,230,247, - 126,206,138,6,117,234,129,129,86,54,134,80,4,194,71,107,129,106,146,158,166,105,16,73,165,27,190,36,175,142,33,156, - 198,30,242,66,68,224,161,107,101,66,191,134,87,201,33,162,109,196,122,183,177,125,251,126,122,51,41,102,39,158,161,112, - 206,35,32,206,163,79,78,48,63,179,132,196,163,180,180,140,80,62,137,164,69,72,140,74,13,100,110,89,235,90,41,52, - 106,126,32,67,165,137,72,115,70,154,150,159,106,161,175,175,149,195,195,139,236,223,179,155,244,153,17,239,186,154,55,18, - 192,233,152,169,83,25,211,204,107,130,19,75,80,218,14,252,51,141,158,84,191,220,228,198,42,192,30,16,183,65,44,11, - 27,5,220,177,40,197,187,210,127,240,127,31,184,241,215,255,157,109,170,58,218,23,40,67,130,244,154,113,80,13,243,228, - 98,154,213,5,66,247,21,192,231,82,205,67,136,70,106,197,203,65,225,165,154,211,139,92,207,43,154,109,151,182,108,121, - 217,53,190,245,53,95,38,82,54,92,250,151,106,79,82,54,146,97,195,128,192,173,83,40,229,169,22,11,232,48,68,106, - 136,153,49,140,68,27,185,21,143,227,79,62,194,210,253,159,173,89,79,189,176,216,86,114,38,58,27,241,85,35,192,68, - 8,115,10,22,53,100,79,64,165,27,194,103,129,187,155,196,127,132,239,188,27,170,6,2,33,47,86,87,12,223,42,0, - 4,141,196,148,80,188,20,105,76,169,185,98,107,137,123,15,183,163,20,223,115,251,157,239,158,219,146,180,6,1,43,95, - 254,34,91,38,198,217,247,58,220,83,2,75,128,182,164,204,133,58,122,94,233,164,103,10,243,46,41,195,119,5,42,20, - 13,247,6,18,168,131,154,6,95,75,81,87,112,44,173,244,99,181,47,62,211,250,229,142,142,109,215,255,236,221,118,79, - 74,53,74,154,41,129,173,3,66,35,68,94,112,211,74,129,242,11,184,5,141,33,163,16,4,44,229,114,84,10,121,234, - 217,101,130,252,50,125,109,49,90,50,146,32,221,65,208,222,142,21,73,144,236,105,103,125,122,27,102,118,25,137,226,176, - 59,195,202,228,36,137,100,138,54,43,202,178,142,113,106,122,130,182,153,69,255,250,124,57,59,224,7,11,113,33,22,163, - 176,108,8,173,2,33,187,39,165,222,248,181,232,194,154,229,32,176,215,72,35,156,93,92,52,110,155,95,206,103,224,89, - 15,238,71,136,168,237,135,69,109,136,99,29,154,202,101,77,239,212,85,52,114,194,135,128,110,144,46,180,120,176,85,195, - 205,5,203,184,115,224,79,254,223,3,7,127,241,151,237,80,23,9,67,11,41,45,132,40,53,245,198,104,195,236,121,169, - 114,211,124,77,55,184,147,151,113,65,151,186,217,47,104,27,175,8,16,23,52,155,75,226,122,94,66,66,211,136,5,122, - 185,105,166,47,189,230,183,57,92,47,130,84,211,92,212,77,206,220,144,141,64,2,167,84,196,205,47,83,169,148,1,133, - 105,128,29,143,17,10,155,217,185,44,195,79,62,64,238,159,254,177,212,121,98,106,122,72,233,51,86,131,72,62,235,195, - 152,104,244,124,47,246,129,51,6,126,28,244,87,163,49,18,157,221,120,90,83,93,156,67,124,71,13,59,53,90,52,146, - 159,109,173,25,170,23,41,211,104,42,208,253,45,64,232,45,19,9,29,40,193,238,161,42,2,248,234,115,237,160,244,235, - 2,66,129,109,33,142,156,228,87,199,199,95,183,78,1,178,169,234,206,24,50,86,86,225,86,83,176,91,6,186,37,36, - 244,116,179,157,184,209,212,142,44,8,60,40,10,88,70,32,3,152,239,134,115,185,191,190,39,253,249,167,158,239,237,184, - 251,230,72,98,221,58,145,140,42,210,26,173,48,133,111,134,184,161,135,225,88,218,43,141,170,108,181,196,204,236,10,142, - 17,149,55,92,153,22,29,122,137,184,15,201,168,141,45,91,9,172,110,66,105,160,52,120,118,10,203,52,48,34,73,252, - 232,0,166,91,162,119,211,54,156,51,179,36,13,155,66,96,48,63,124,42,188,241,252,228,242,21,138,145,36,28,11,225, - 180,175,245,148,7,203,74,163,109,84,255,166,144,3,63,175,195,131,103,142,157,221,184,54,157,202,220,95,25,201,108,243, - 194,115,30,60,99,192,161,182,254,164,173,114,94,205,174,135,185,205,126,35,15,242,62,224,134,102,120,194,143,131,84,208, - 41,225,50,1,111,91,138,152,215,117,253,241,239,238,184,252,23,127,222,86,170,130,129,68,75,5,194,71,72,187,225,48, - 208,47,166,79,188,4,129,180,108,242,42,250,197,236,214,75,114,192,47,132,254,93,40,167,193,203,226,12,47,18,196,23, - 254,205,203,210,45,46,209,166,46,37,182,95,9,232,46,60,128,66,94,124,14,217,4,64,133,68,233,16,83,138,6,177, - 236,186,84,107,53,202,165,50,65,181,78,52,128,84,50,130,138,155,20,29,201,169,211,211,76,220,123,79,24,60,240,245, - 98,215,88,118,118,87,168,207,72,120,193,131,163,65,35,177,55,107,65,117,26,252,253,52,226,203,114,141,67,141,13,169, - 12,195,137,164,80,82,234,149,74,25,163,176,194,203,113,59,108,174,85,129,192,23,18,87,154,36,125,135,117,229,69,226, - 245,18,31,240,29,30,66,211,10,220,250,86,210,128,190,149,56,190,100,215,80,35,224,254,245,0,33,37,4,237,142,195, - 214,231,15,115,150,215,183,102,74,40,132,136,43,221,166,67,125,205,68,103,199,135,229,64,111,111,91,189,86,243,157,122, - 232,170,0,63,187,18,132,245,64,73,8,19,80,76,42,157,141,66,77,66,84,64,123,23,120,45,167,231,157,249,211,255, - 32,103,26,113,159,165,184,166,12,212,155,165,233,49,192,182,33,101,64,107,31,68,134,219,82,97,251,13,63,101,173,73, - 116,136,208,55,49,77,129,157,105,67,68,18,248,178,145,48,170,149,9,97,163,57,158,145,178,32,30,101,112,219,110,110, - 215,81,148,107,114,239,95,126,42,120,207,240,228,249,205,240,148,3,79,213,225,152,11,211,157,141,234,124,110,69,32,52, - 156,117,53,195,118,160,94,216,11,91,188,98,105,207,59,90,205,206,104,160,190,161,224,249,0,22,91,93,41,242,131,105, - 181,101,155,17,164,29,197,194,209,101,206,185,33,155,27,156,151,72,65,139,223,72,173,120,239,25,219,184,105,211,159,252, - 222,154,235,62,246,75,82,133,85,208,18,100,179,96,24,97,83,49,49,26,69,249,95,209,181,45,154,193,123,92,244,40, - 137,87,40,179,113,177,20,199,43,104,63,23,189,102,23,180,156,151,113,5,175,164,53,105,253,114,127,241,37,247,19,23, - 32,175,17,115,45,180,194,192,71,5,62,181,178,131,91,171,18,184,46,6,146,184,105,163,91,82,20,203,14,211,35,243, - 156,121,246,176,94,254,198,131,161,56,123,182,178,109,185,54,218,14,39,128,19,202,146,39,156,64,141,36,52,75,75,80, - 63,11,250,61,52,42,116,206,211,136,171,26,107,237,224,241,84,11,37,41,177,131,64,187,166,201,5,191,182,201,133,72, - 250,6,248,164,128,127,0,126,58,244,185,166,48,203,110,223,229,164,87,165,30,54,180,37,131,75,139,137,252,0,0,208, - 235,13,66,17,219,230,75,95,249,50,255,146,91,126,93,137,241,58,240,81,173,217,233,135,241,10,172,217,248,177,119,110, - 221,253,159,126,51,173,242,53,60,215,197,247,2,242,75,57,10,75,89,150,167,23,244,194,233,179,106,244,204,176,151,31, - 159,13,168,212,84,111,161,236,183,57,129,104,7,107,109,131,52,116,149,38,231,193,148,110,180,127,154,145,141,212,163,245, - 6,236,209,144,142,128,25,89,41,135,75,167,199,213,134,43,182,26,90,134,152,137,52,210,238,110,198,13,129,161,84,163, - 22,22,70,115,163,74,2,12,182,237,223,71,199,166,237,156,56,57,74,223,216,112,105,3,60,235,192,191,120,112,164,31, - 86,218,193,171,209,136,95,42,104,248,61,40,222,13,213,101,152,78,195,17,17,114,40,150,87,41,87,235,113,11,198,239, - 7,255,151,198,10,180,188,127,29,173,255,237,26,62,254,63,78,210,255,236,34,9,160,3,100,26,90,3,216,39,225,142, - 115,173,137,155,7,254,231,31,174,189,233,71,62,140,14,43,47,70,36,95,0,11,117,129,39,17,77,160,145,223,12,16, - 77,240,81,77,19,234,149,57,152,198,86,18,151,16,216,47,183,192,190,213,78,123,49,243,253,165,87,187,96,71,189,36, - 53,227,194,103,84,216,12,60,84,16,134,4,245,26,94,181,138,235,120,184,174,143,235,120,148,138,21,38,39,102,57,113, - 242,44,249,145,145,124,109,108,216,88,51,189,16,235,207,215,228,53,224,90,48,229,55,0,253,89,97,136,83,102,204,156, - 147,213,32,31,13,149,235,210,200,20,27,107,2,201,87,104,116,202,8,34,49,38,146,25,153,9,3,21,85,10,91,11, - 30,235,236,71,6,138,71,42,69,190,4,124,148,70,221,165,5,224,243,13,109,148,27,74,139,244,53,189,180,21,190,243, - 180,140,183,100,50,234,5,16,18,2,238,57,244,218,128,144,101,154,204,205,207,243,240,217,179,175,122,47,164,239,68,110, - 0,246,104,68,8,102,44,217,47,147,244,161,50,85,132,104,20,62,239,93,115,177,129,138,0,109,184,97,57,182,148,155, - 167,84,46,48,55,57,195,212,145,243,250,240,225,243,186,120,110,152,182,220,124,108,112,41,223,209,227,40,47,2,217,16, - 106,33,152,6,164,198,132,104,31,110,105,137,22,93,47,92,87,171,230,90,243,229,20,200,132,52,162,200,148,133,107,229, - 81,50,142,150,233,70,65,117,45,64,70,16,82,52,220,189,97,163,240,86,119,119,130,175,252,253,255,98,125,205,91,84, - 112,220,133,227,253,176,176,17,152,4,18,23,52,187,38,121,158,131,224,48,20,63,0,101,11,22,203,161,50,214,128,251, - 36,184,127,0,252,12,240,92,214,225,127,254,151,163,252,233,159,159,228,243,192,26,176,108,232,146,112,64,195,237,165,76, - 250,166,171,254,254,207,7,118,220,245,126,130,160,210,228,182,196,69,23,117,131,179,109,186,219,149,122,17,124,94,142,28, - 77,32,144,151,124,238,229,222,39,248,102,207,214,69,254,134,11,37,68,248,166,207,139,75,180,35,165,94,212,172,94,130, - 87,47,139,148,110,120,220,26,122,170,239,57,84,74,121,220,74,25,252,128,149,149,60,181,186,71,173,238,49,49,51,207, - 226,66,14,17,181,105,235,235,19,189,169,184,144,221,163,82,31,63,175,231,22,171,34,13,177,8,12,152,224,25,161,110, - 11,74,94,86,66,182,0,139,253,144,107,129,66,20,106,43,224,183,130,142,0,134,231,97,132,74,186,161,86,82,8,162, - 129,230,72,189,194,223,185,245,139,49,87,203,52,34,244,79,241,98,70,154,126,153,17,201,15,50,0,93,0,161,157,107, - 27,154,208,107,1,66,134,97,240,216,225,231,8,85,248,134,124,191,11,147,106,130,206,215,124,237,19,34,195,26,72,147, - 80,55,203,104,200,11,252,132,194,32,66,95,215,122,6,187,12,118,108,184,18,110,54,133,86,174,88,204,206,49,50,113, - 46,58,118,236,68,244,208,163,79,182,183,221,247,116,251,246,149,122,175,9,98,12,54,157,123,207,245,131,215,255,226,7, - 101,101,201,229,228,253,79,166,75,237,129,29,218,26,17,79,224,218,81,180,138,96,5,22,58,149,68,199,163,4,42,96, - 121,110,129,165,133,121,226,153,86,58,186,218,105,207,100,240,171,121,206,61,244,164,190,22,202,33,20,53,184,6,141,34, - 97,247,2,31,2,62,69,163,72,124,51,187,9,23,216,10,234,75,80,253,29,224,12,240,80,243,111,21,224,43,143,206, - 243,196,163,243,252,52,208,11,177,42,12,41,184,90,195,45,243,107,123,174,61,248,169,143,15,108,184,246,122,17,6,43, - 32,12,228,203,0,230,37,32,112,233,198,208,47,117,155,95,52,161,46,252,214,23,198,95,95,108,22,248,45,61,99,188, - 88,84,76,124,139,200,233,134,199,170,1,112,250,146,32,67,33,68,3,24,47,137,235,185,16,6,129,144,132,161,71,62, - 151,35,240,235,24,82,98,196,98,116,13,38,72,181,180,17,73,164,185,222,176,65,92,48,140,68,139,2,74,78,145,133, - 233,49,157,31,57,23,45,28,25,94,59,251,220,217,94,255,220,240,101,198,212,120,49,94,243,243,169,70,137,141,89,5, - 147,9,56,239,194,68,2,22,175,129,146,15,117,242,75,238,79,212,202,193,94,26,93,68,222,171,53,89,183,254,138,222, - 217,239,62,236,240,7,8,128,46,130,208,80,21,165,5,95,123,174,237,85,3,33,211,182,25,93,92,228,216,185,179,111, - 216,119,107,244,73,64,27,160,23,166,39,148,210,10,67,217,205,8,87,209,108,164,217,104,54,168,181,143,212,38,194,139, - 162,133,73,64,136,22,43,72,233,209,211,221,70,79,247,219,184,238,138,183,227,124,244,39,204,111,124,250,203,107,206,252, - 218,239,180,110,207,86,253,197,107,14,36,223,251,27,255,70,182,36,44,18,125,49,214,118,246,198,23,142,62,128,29,109, - 69,71,99,120,120,216,118,20,75,219,84,133,205,137,211,195,148,11,62,137,136,69,75,58,73,173,94,225,216,209,89,186, - 210,105,34,169,52,231,102,43,92,15,105,19,54,25,176,105,14,130,105,40,181,53,171,233,253,241,255,199,222,123,199,217, - 117,149,247,222,223,181,214,46,167,77,239,51,234,93,150,229,38,119,227,130,11,54,166,183,64,2,132,155,158,155,155,114, - 19,82,222,220,36,55,164,151,123,19,146,144,16,72,66,239,197,16,192,96,3,198,5,92,112,151,44,201,234,189,204,140, - 166,207,169,187,172,181,222,63,214,62,103,70,178,76,53,224,228,230,240,25,70,26,143,102,206,217,251,236,103,63,207,239, - 249,21,224,143,178,77,214,141,89,255,166,178,59,234,126,154,70,17,112,67,54,134,126,20,7,94,212,32,156,115,185,92, - 183,104,184,249,208,170,193,243,174,250,196,191,244,173,190,248,50,108,163,138,240,36,66,52,64,228,78,103,17,47,46,26, - 103,217,64,157,214,117,180,68,157,139,185,62,207,212,129,137,197,27,119,78,103,55,115,150,85,186,109,117,98,205,85,187, - 61,189,131,82,226,244,231,213,114,57,51,72,207,167,167,175,223,5,22,26,139,242,218,16,129,223,250,54,99,156,10,222, - 10,39,129,80,214,208,233,123,116,174,217,36,88,123,129,224,86,29,164,54,9,166,166,231,75,227,71,78,244,207,239,219, - 97,15,222,247,96,90,127,124,71,173,180,125,247,100,123,61,62,90,114,145,205,135,44,28,247,225,96,193,218,221,126,163, - 54,125,14,152,19,60,83,103,247,92,63,254,195,251,1,53,98,201,121,43,29,31,211,21,33,103,96,255,61,111,189,124, - 159,32,142,89,121,223,189,252,182,214,92,147,157,4,153,93,32,63,140,77,152,118,107,102,155,56,70,66,67,237,60,80, - 179,141,90,135,80,113,166,55,148,160,20,88,135,232,42,171,176,82,96,165,118,30,54,217,165,97,17,104,93,67,232,58, - 200,54,124,227,113,205,45,151,240,15,95,190,176,112,223,3,59,226,107,126,243,141,254,72,103,137,100,190,1,185,10,51, - 149,105,82,145,71,149,58,192,179,104,35,25,159,52,140,87,38,136,139,9,253,171,206,103,243,134,165,132,62,64,140,65, - 161,141,71,101,106,146,131,251,15,226,13,15,138,79,31,216,191,244,245,85,115,99,55,248,17,220,187,28,182,141,192,88, - 12,177,202,58,155,187,178,99,122,3,11,102,242,100,119,220,45,56,119,248,128,22,7,74,53,96,73,0,55,106,120,217, - 193,229,131,231,110,249,216,187,187,214,95,124,9,54,106,32,68,30,43,34,231,111,36,220,138,221,102,184,138,92,188,137, - 18,153,233,232,25,51,130,104,205,79,246,244,177,107,113,135,100,237,130,153,252,162,175,137,197,223,243,108,139,233,140,213, - 236,192,158,133,21,250,130,127,116,214,79,88,155,165,124,45,220,130,132,144,168,112,33,167,212,0,198,198,11,99,165,176, - 88,171,179,151,102,73,12,72,235,35,72,49,105,5,147,54,208,73,66,187,47,9,150,119,18,45,191,90,172,185,230,26, - 191,62,55,221,49,182,107,95,199,232,35,79,174,60,252,213,175,111,233,220,115,96,186,189,90,31,247,45,143,214,225,54, - 11,143,126,18,170,159,226,59,231,253,252,63,91,128,206,94,132,196,247,84,132,82,223,167,119,98,130,45,247,222,195,174, - 195,135,152,1,150,224,200,127,202,1,160,4,217,65,251,65,110,196,4,206,136,126,171,243,216,58,37,199,71,203,211,83, - 167,134,134,151,12,187,145,208,58,252,71,202,44,87,70,100,74,105,107,17,86,58,155,11,235,185,39,41,37,86,73,18, - 98,60,17,208,102,122,88,114,254,11,213,93,245,32,247,115,231,93,32,210,106,131,88,37,132,94,142,106,165,138,232,132, - 178,178,28,62,28,19,37,154,160,179,159,254,245,231,50,176,124,21,158,95,192,164,41,90,71,8,83,67,11,69,34,243, - 116,116,117,112,225,149,23,242,190,15,255,35,159,255,244,237,197,79,191,231,195,23,108,126,244,233,158,75,97,169,117,24, - 196,3,157,176,255,167,160,246,199,217,177,123,20,199,126,187,57,27,201,200,186,162,235,129,159,202,10,212,195,160,82,232, - 15,224,242,20,110,28,95,59,180,241,198,79,125,168,115,249,249,91,72,245,60,248,46,10,71,154,28,66,164,153,227,181, - 124,198,150,203,97,48,98,225,224,46,234,86,22,182,87,11,38,241,52,71,163,179,21,163,51,199,59,151,205,243,237,55, - 170,198,208,36,97,187,95,223,36,19,102,4,199,69,40,182,3,184,155,223,172,48,24,176,38,243,139,150,217,18,64,160, - 172,113,186,54,112,185,243,88,210,164,65,92,171,81,47,59,255,104,173,19,4,41,90,167,40,83,68,161,232,44,104,250, - 46,185,128,117,87,94,46,143,191,233,21,237,247,127,230,193,246,79,189,243,125,43,94,54,118,212,95,6,79,106,216,94, - 128,234,237,223,170,176,62,71,215,192,127,26,71,196,102,17,146,194,102,152,208,119,94,132,172,16,164,185,28,35,59,119, - 114,197,237,159,39,111,12,59,23,241,28,118,186,98,192,239,3,219,112,36,65,47,187,59,152,31,80,1,74,220,239,174, - 181,195,100,114,252,196,220,177,29,187,24,94,178,2,97,107,24,145,58,118,136,113,184,135,64,96,108,130,69,35,133,135, - 161,233,13,227,184,47,210,10,148,104,160,100,66,234,41,214,174,91,71,185,81,19,161,215,78,213,215,20,138,37,198,199, - 171,60,250,200,54,150,173,232,98,235,145,58,221,93,195,44,239,31,164,179,167,15,47,223,129,53,18,25,71,46,132,79, - 133,24,225,82,30,148,17,164,24,76,221,163,88,232,226,205,191,240,38,110,120,213,203,212,39,223,253,158,21,159,251,135, - 247,118,95,51,57,63,220,3,125,83,112,199,107,97,215,32,84,150,227,12,229,107,14,219,225,15,178,215,189,59,27,207, - 60,32,132,92,5,134,115,112,89,12,47,217,183,105,213,197,183,124,234,125,189,203,55,158,143,73,107,40,17,100,57,242, - 58,235,48,228,66,202,232,226,35,185,128,49,187,85,251,34,1,167,104,229,179,55,11,9,88,163,51,32,219,91,52,107, - 89,7,190,159,229,60,181,198,182,197,74,245,69,242,136,5,89,70,246,217,52,123,41,133,200,182,139,194,58,206,143,22, - 230,180,78,205,117,112,205,140,52,50,251,16,72,77,154,157,119,103,169,130,177,52,42,53,26,51,83,212,27,53,210,56, - 205,70,190,172,177,242,2,194,66,1,63,240,137,26,121,118,238,59,202,190,109,247,219,209,199,183,210,216,179,71,148,199, - 102,204,202,122,163,220,41,196,169,196,218,186,2,17,130,250,63,60,211,236,77,103,55,229,114,230,201,182,234,12,44,168, - 105,88,47,255,95,43,64,205,34,116,238,138,197,192,244,183,47,66,34,8,16,81,196,11,254,253,179,12,236,219,235,132, - 125,103,153,249,39,178,207,255,148,97,22,167,50,238,196,0,11,190,116,207,21,6,158,100,39,249,173,160,173,160,33,181, - 173,31,221,185,219,94,118,203,75,132,53,166,101,116,229,248,42,10,147,70,40,21,128,244,1,141,182,137,243,162,17,46, - 201,3,44,82,231,193,8,140,156,101,112,164,141,75,131,13,164,73,157,242,92,204,67,15,60,206,252,220,36,151,95,122, - 62,107,215,174,160,88,204,161,60,176,182,65,121,126,10,85,169,208,72,52,86,10,148,231,161,2,31,63,204,17,230,66, - 2,223,119,215,140,116,214,15,73,18,51,208,211,193,255,252,131,63,226,241,23,223,218,254,133,223,249,211,75,214,221,253, - 245,226,114,80,83,160,207,133,167,87,66,35,204,198,175,147,184,248,223,197,111,240,216,53,154,171,10,130,27,107,150,155, - 14,111,94,125,233,77,183,189,191,127,197,218,205,232,180,214,26,65,164,179,248,194,74,147,169,192,207,94,206,133,56,109, - 249,125,246,49,11,50,31,30,177,136,202,99,159,85,22,33,207,32,26,182,186,38,33,206,218,21,181,48,166,69,187,34, - 41,213,105,207,72,234,133,231,99,23,255,47,43,68,210,40,119,3,144,174,240,234,184,65,163,86,163,92,158,163,62,63, - 143,72,98,60,95,225,135,62,202,247,177,210,39,137,148,173,156,154,177,213,99,227,118,238,233,189,118,247,3,247,137,104, - 199,94,81,152,170,138,245,64,55,152,130,107,56,119,199,176,59,21,2,13,107,67,107,163,203,120,166,101,154,0,82,208, - 101,168,21,161,252,135,144,196,160,79,66,50,13,137,2,221,6,38,255,29,222,156,255,211,121,66,127,55,69,200,203,229, - 56,176,115,39,87,126,227,235,44,159,157,33,250,22,109,101,115,58,239,203,62,6,112,182,24,17,240,24,112,14,206,169, - 59,120,142,230,102,237,126,118,26,90,102,187,96,122,108,235,211,141,196,146,23,214,115,70,85,66,225,171,144,79,127,228, - 195,28,63,122,132,13,235,55,177,124,217,10,186,250,122,232,25,232,195,207,133,88,12,198,166,104,147,58,189,144,1,191, - 212,206,192,224,48,189,253,3,84,171,49,255,244,143,239,226,154,23,188,136,91,94,116,51,158,151,144,196,17,82,64,210, - 136,153,155,47,115,226,228,65,198,198,78,33,60,203,224,72,63,249,124,193,21,0,1,158,242,8,124,159,182,182,54,134, - 134,151,81,104,239,67,36,33,210,88,140,173,177,229,194,11,89,253,185,127,13,222,243,91,127,112,65,250,174,79,38,171, - 225,88,12,199,191,2,141,52,27,189,62,176,8,232,92,1,188,26,100,10,3,70,112,117,108,121,229,244,85,151,92,116, - 235,135,255,185,99,100,197,26,76,82,119,29,139,177,45,60,70,32,78,207,16,62,91,9,18,11,89,94,205,172,180,103, - 22,22,113,186,176,243,180,53,252,25,197,230,204,175,53,173,53,178,175,25,173,91,106,246,211,192,232,214,182,75,62,19, - 44,183,32,116,54,216,72,225,230,193,38,25,81,10,231,243,147,26,226,90,157,70,173,74,220,168,18,69,53,226,70,21, - 33,44,129,239,33,60,159,52,150,156,56,94,225,232,193,99,181,249,221,187,27,237,247,63,24,200,125,135,130,100,182,66, - 1,228,250,236,61,42,28,198,72,12,102,206,245,92,5,13,107,141,181,253,205,198,167,154,221,84,253,236,254,146,45,69, - 80,78,174,49,13,156,178,80,141,33,50,48,61,15,83,109,48,215,11,115,33,148,143,66,61,5,109,255,95,42,64,139, - 139,144,177,130,59,31,239,122,198,2,68,10,65,152,207,115,106,231,14,158,254,226,23,184,241,12,117,242,183,43,12,205, - 105,189,169,217,122,12,120,41,46,155,106,34,239,49,178,166,235,116,123,134,239,226,97,149,32,56,50,79,105,54,98,210, - 221,85,102,67,152,50,7,142,214,211,68,231,67,233,33,50,165,110,84,171,114,226,232,81,174,191,250,42,2,9,141,202, - 56,251,198,14,178,107,187,160,167,127,128,222,193,97,186,122,251,200,23,218,177,36,36,38,226,158,59,238,99,207,83,123, - 152,153,153,97,116,116,140,185,185,42,71,70,15,49,246,249,67,228,11,1,70,67,181,82,229,232,209,227,212,235,17,155, - 207,219,68,119,119,55,185,208,163,16,180,57,230,109,62,143,239,7,24,109,41,22,74,72,161,152,157,158,34,74,43,180, - 151,150,99,180,101,98,242,40,137,31,19,180,181,211,104,31,100,20,186,215,67,91,3,188,82,246,198,155,4,30,204,94, - 247,18,224,93,32,135,160,119,26,46,73,45,55,206,94,188,121,243,245,31,127,111,71,223,146,37,152,196,209,219,164,148, - 216,166,230,234,180,49,122,225,236,61,147,193,252,29,30,123,219,12,116,124,38,194,97,207,98,217,193,153,22,28,205,247, - 208,34,43,141,38,222,228,222,51,178,21,143,241,12,177,170,112,124,42,137,0,149,73,59,146,212,97,110,81,76,163,86, - 165,209,40,147,36,26,147,106,172,181,40,165,176,169,100,102,102,134,19,199,71,57,118,98,130,157,59,247,114,236,248,41, - 100,117,126,230,188,82,33,90,221,211,57,220,86,216,32,68,222,103,170,187,67,38,94,81,200,70,106,195,80,217,106,181, - 74,106,36,22,221,102,73,54,8,21,172,71,41,26,141,72,128,37,73,18,102,102,102,169,149,231,173,72,82,163,163,216, - 138,114,205,20,162,52,237,168,39,245,30,99,230,219,161,81,66,197,37,204,84,17,59,46,96,34,133,19,243,78,228,186, - 215,131,19,29,110,169,249,255,78,1,106,22,161,11,86,85,104,196,146,59,31,239,166,16,58,62,143,167,20,115,105,202, - 216,191,127,134,23,239,221,203,23,207,4,27,191,71,204,166,11,167,163,249,236,242,118,126,227,95,110,194,143,191,55,254, - 144,95,244,121,234,111,31,231,182,143,238,226,34,80,121,8,44,228,166,106,243,42,142,171,228,242,33,214,24,148,242,136, - 116,76,127,95,39,157,165,28,82,198,116,248,37,122,123,139,68,81,66,35,174,113,108,207,78,142,239,243,105,111,239,101, - 104,213,8,119,221,253,21,118,60,250,4,235,86,173,97,205,218,53,116,118,94,68,71,103,27,158,132,66,49,159,69,5, - 123,104,35,8,253,128,98,161,8,194,210,136,106,84,231,202,196,181,6,243,229,121,230,102,102,80,126,192,232,248,20,113, - 108,41,182,117,209,223,219,195,240,210,110,10,109,167,8,75,121,196,84,157,180,10,239,254,147,191,182,249,247,125,226,212, - 229,240,120,4,251,5,84,101,118,23,254,100,134,3,45,1,254,5,100,27,244,77,194,229,192,203,107,27,214,92,114,213, - 135,255,173,187,119,201,8,54,169,158,54,224,74,41,91,163,137,88,148,225,105,91,91,36,123,58,59,78,52,61,155,23, - 157,51,217,244,87,126,54,85,250,162,31,112,230,205,228,204,181,254,217,100,23,207,144,99,100,120,212,153,52,128,214,118, - 13,164,48,196,113,76,60,87,67,232,148,180,214,32,169,55,144,218,162,109,138,13,5,129,167,176,74,50,51,61,203,238, - 221,123,8,253,60,70,67,24,22,216,180,105,13,23,110,217,72,177,148,35,95,12,71,132,204,140,254,241,92,51,37,53, - 18,31,161,82,129,172,57,199,196,36,15,86,97,68,226,104,29,89,113,183,214,217,177,196,73,76,181,82,197,88,75,221, - 24,170,149,6,149,153,121,102,78,78,48,119,114,106,228,196,169,25,166,143,157,196,142,159,74,194,153,217,122,119,165,86, - 95,153,234,153,165,82,236,193,232,47,47,133,59,103,224,232,39,224,25,254,161,175,195,5,184,252,72,30,70,255,224,227, - 149,235,117,56,103,73,153,3,39,67,142,76,228,201,5,146,84,107,222,251,185,207,114,233,225,195,180,63,199,219,44,211, - 4,144,51,159,25,15,136,98,227,188,130,191,83,80,206,64,116,235,74,62,253,209,93,92,14,129,130,254,41,24,106,44, - 27,46,204,140,30,163,99,213,114,148,114,152,64,26,55,144,104,164,72,157,21,110,172,113,114,83,75,41,148,116,149,186, - 136,19,131,177,53,190,246,185,207,177,103,207,62,126,241,45,111,194,164,53,151,248,160,4,82,248,120,34,64,42,167,239, - 202,229,10,72,225,183,214,199,113,212,160,32,61,74,61,93,84,243,21,74,29,1,8,129,151,11,185,236,186,23,160,241, - 57,126,226,20,251,159,62,200,216,214,61,120,187,83,134,7,214,177,97,213,18,238,254,250,109,76,124,232,19,245,159,129, - 253,117,248,186,133,237,13,168,188,22,248,52,240,53,96,56,43,62,157,158,232,139,12,87,10,99,95,145,174,91,121,245, - 21,159,124,207,72,223,250,245,50,142,43,120,50,231,138,135,52,45,213,248,66,195,35,154,104,24,167,105,181,206,204,8, - 196,182,188,128,108,139,107,179,240,181,211,199,46,187,160,56,111,226,58,103,99,80,115,58,217,145,179,224,66,103,122,8, - 61,243,214,229,176,186,184,94,35,154,153,164,94,111,96,180,37,244,3,16,6,63,244,73,227,6,105,146,50,51,17,51, - 63,55,75,165,90,38,142,35,250,250,122,233,239,239,115,189,149,108,254,44,139,177,22,157,38,88,19,101,214,35,210,165, - 117,24,133,145,21,164,148,24,43,49,198,98,237,188,3,186,149,36,206,250,17,37,133,99,109,43,133,47,125,58,218,58, - 0,232,22,2,213,43,241,215,120,8,225,48,56,163,45,245,70,131,185,114,217,223,123,120,212,63,188,255,88,251,103,31, - 120,108,32,124,242,233,85,255,173,82,169,97,205,182,1,56,177,226,89,70,49,239,71,149,74,111,127,8,198,62,218,66, - 62,208,108,89,51,207,209,169,54,82,157,240,222,207,222,198,232,145,35,167,241,79,158,75,78,195,216,193,57,102,254,247, - 253,116,221,58,194,145,216,176,118,67,59,81,79,248,109,38,225,69,88,83,209,227,158,247,238,227,45,110,19,212,158,194, - 114,17,120,189,47,122,221,203,212,196,137,35,116,119,22,104,235,233,70,8,73,16,248,228,11,69,180,214,40,229,147,106, - 23,195,172,178,14,193,96,16,158,160,179,189,13,165,36,183,222,114,11,161,95,64,11,133,205,6,122,223,243,201,249,65, - 43,149,52,8,3,80,1,214,24,76,220,192,15,2,226,70,29,109,36,90,120,24,98,44,134,90,101,150,198,241,132,161, - 165,171,89,181,118,41,171,86,172,70,235,6,163,19,163,28,218,55,198,87,239,126,136,7,31,222,77,106,50,127,245,108, - 115,155,89,136,240,23,25,173,225,223,64,118,74,87,124,48,246,21,102,227,218,107,206,255,204,7,151,245,110,216,168,76, - 92,193,19,57,119,36,68,218,210,120,157,185,144,90,40,62,226,204,170,115,218,96,109,23,173,226,77,179,81,90,228,241, - 35,190,53,144,116,218,182,235,204,247,114,147,213,124,214,81,254,76,230,245,25,203,108,173,53,243,115,179,152,114,25,139, - 98,126,174,78,185,50,1,194,80,173,206,81,174,76,18,71,17,129,234,164,171,171,157,129,254,126,218,218,138,72,153,117, - 70,38,33,77,45,36,29,8,153,96,101,156,193,82,11,59,41,119,191,55,40,105,48,40,172,245,17,158,1,34,103,134, - 111,3,60,147,45,44,172,192,147,18,155,166,136,108,27,39,132,192,170,4,29,107,76,170,144,66,160,13,72,233,33,164, - 164,191,167,151,21,195,195,228,110,189,149,187,174,189,150,143,253,228,47,10,83,54,162,238,249,202,19,66,182,37,241,217, - 237,56,188,192,249,57,252,103,125,24,235,66,248,82,173,249,192,23,110,99,255,145,35,63,80,254,78,45,214,200,175,28, - 101,223,87,142,242,49,224,87,87,149,88,213,29,224,125,135,5,8,37,184,254,64,5,11,109,17,108,0,46,232,186,233, - 170,193,145,139,207,147,113,35,98,114,124,140,84,8,186,186,7,200,181,117,208,214,222,197,216,232,56,35,75,70,72,227, - 6,81,20,145,234,148,142,174,110,242,97,59,237,165,46,230,171,53,62,247,229,111,208,221,185,151,180,222,160,94,143,64, - 74,130,66,30,229,41,194,48,164,45,151,167,179,179,157,68,167,228,139,5,218,74,69,138,249,60,197,66,145,238,174,46, - 60,9,90,71,72,153,18,228,44,197,98,14,52,76,143,141,211,63,146,107,165,57,12,14,141,176,100,201,74,116,3,54, - 156,191,137,47,118,22,115,15,190,243,67,171,207,171,214,174,242,224,104,8,179,95,132,185,50,240,49,129,236,245,101,255, - 116,106,175,16,198,190,162,177,105,205,117,151,125,252,253,75,187,55,92,40,83,51,139,240,3,164,86,32,26,88,97,90, - 68,189,103,52,55,77,173,150,149,173,228,136,133,235,126,209,72,181,88,166,145,117,54,38,43,26,226,140,17,204,158,225, - 233,179,184,8,157,205,60,236,89,73,140,103,233,150,78,251,183,214,221,48,186,251,250,72,219,114,164,137,100,223,177,157, - 124,226,195,159,68,199,13,222,252,230,215,177,106,233,74,2,31,60,63,135,16,160,83,141,78,235,88,233,54,124,86,11, - 39,94,85,83,46,128,205,10,44,10,139,2,180,43,58,210,2,1,22,15,99,99,132,108,128,245,17,228,240,164,205,190, - 22,46,104,213,178,96,75,99,12,82,72,180,53,72,17,34,164,235,55,53,218,33,211,153,191,184,240,45,211,26,190,242, - 129,79,113,232,95,62,208,120,203,169,169,173,5,120,172,34,228,169,113,163,245,209,179,148,246,245,128,55,113,4,122,151, - 130,209,63,26,183,193,31,104,151,5,4,158,59,9,239,255,236,103,56,114,226,200,15,252,119,202,69,7,58,0,142,29, - 172,112,240,96,139,215,243,29,109,191,2,240,115,176,92,193,181,243,249,240,226,117,63,251,230,110,161,192,39,193,183,30, - 181,83,167,40,4,57,114,237,29,108,222,178,133,251,238,189,135,250,241,83,248,74,224,133,62,29,221,61,116,13,47,161, - 212,214,131,151,239,225,227,255,248,143,124,241,142,123,92,23,147,36,8,33,9,115,1,133,66,1,129,32,159,203,19,248, - 10,172,161,82,174,210,213,221,73,62,95,160,171,171,135,174,174,46,70,70,70,104,47,21,9,67,143,36,137,72,211,136, - 92,33,199,208,224,32,29,157,93,172,169,230,88,190,102,53,42,231,131,174,97,162,8,43,37,235,54,46,97,253,95,255, - 145,188,239,134,235,134,143,252,247,223,186,98,213,161,227,187,18,216,185,18,230,254,28,100,81,138,254,138,229,10,105,236, - 203,103,214,175,188,238,202,207,125,100,121,247,234,117,152,120,14,165,50,110,143,48,217,152,37,159,209,172,159,222,9,101, - 209,128,173,137,71,156,177,164,18,103,124,77,46,98,173,216,22,31,200,46,96,194,173,49,236,76,133,215,217,138,82,211, - 235,199,88,123,58,23,168,201,206,166,153,122,154,21,176,22,43,209,25,138,161,36,126,177,11,207,192,11,110,186,150,203, - 175,125,1,79,111,219,202,201,163,71,153,173,86,88,190,116,8,33,12,70,155,140,116,154,249,159,73,137,149,25,243,219, - 164,46,138,71,8,82,157,96,173,197,243,36,58,115,4,240,60,39,136,85,66,161,173,197,26,131,20,22,41,36,18,31, - 35,220,88,230,150,112,205,110,83,162,17,88,233,82,86,180,141,64,198,40,233,226,180,149,108,35,159,239,230,169,253,199, - 248,216,187,255,129,238,47,126,117,242,102,109,158,204,195,93,26,238,233,78,162,99,69,72,54,61,219,212,240,197,127,50, - 108,185,85,112,254,13,130,164,241,159,167,8,89,32,231,43,106,145,225,215,254,246,171,28,57,49,246,67,127,14,205,4, - 207,37,192,123,61,201,197,61,57,60,251,173,187,181,82,78,209,85,142,131,198,108,180,188,2,91,218,126,230,245,171,122, - 47,63,223,75,102,38,65,130,18,18,171,83,230,167,38,9,11,5,122,6,7,121,205,143,191,17,226,136,204,113,222,141, - 24,70,32,85,129,147,71,143,241,158,127,125,31,249,92,1,109,44,54,116,54,238,97,24,80,200,135,180,149,74,228,195, - 28,190,239,49,95,158,99,249,242,141,116,119,119,211,104,68,88,11,245,122,141,253,251,247,209,211,211,203,208,208,32,109, - 109,109,116,116,245,99,45,76,76,213,153,156,170,113,240,192,9,252,251,190,201,170,117,43,216,180,105,21,253,131,195,96, - 12,169,174,33,76,204,181,55,191,146,167,254,199,193,254,147,191,249,123,75,3,232,172,64,110,8,122,99,195,21,70,155, - 151,77,175,92,118,205,165,183,125,100,217,192,234,13,232,164,150,225,25,11,70,239,54,51,18,179,226,153,91,46,123,26, - 5,206,62,203,46,115,113,78,215,194,184,214,210,128,101,69,200,62,99,228,90,92,184,236,194,38,236,89,116,95,205,63, - 159,46,209,176,103,248,155,137,69,100,200,38,118,212,44,122,210,209,38,210,24,233,9,206,187,228,82,54,108,58,135,71, - 30,124,136,173,59,246,48,52,208,198,178,101,75,65,27,140,78,81,153,190,204,100,111,30,65,224,2,8,108,83,162,225, - 88,214,70,91,135,235,89,147,21,70,137,18,62,40,87,40,181,209,174,32,10,139,20,214,141,240,38,205,206,65,22,92, - 153,141,245,158,113,131,180,47,115,228,138,93,236,59,122,138,79,125,226,227,76,124,246,206,198,117,19,83,135,54,195,55, - 35,196,189,6,30,182,216,99,159,132,250,215,112,132,211,51,81,223,59,1,207,11,225,241,47,89,172,129,11,110,250,207, - 81,132,154,197,39,74,52,175,253,253,251,185,235,209,177,31,217,115,17,56,191,149,39,82,195,223,157,170,125,219,39,190, - 186,232,241,33,95,73,1,5,81,104,235,92,245,154,151,21,66,155,160,149,79,67,164,88,235,238,70,42,244,93,116,142, - 54,8,153,137,112,173,6,227,236,163,132,244,104,212,26,252,217,31,255,9,211,83,243,25,224,232,86,183,74,42,10,197, - 2,237,165,18,197,66,129,48,8,176,6,242,185,18,82,122,36,137,97,217,178,229,244,244,244,162,148,34,77,19,164,10, - 8,130,144,66,62,143,151,145,15,131,48,68,74,137,167,20,137,182,236,223,115,152,93,79,109,103,205,154,117,92,117,237, - 53,20,59,219,73,227,42,96,56,122,236,168,144,224,75,40,25,88,171,225,82,99,237,205,135,206,93,125,237,77,183,125, - 164,127,233,186,115,176,105,109,209,78,235,116,132,199,32,90,23,108,243,179,64,60,163,112,60,91,186,197,89,87,235,54, - 235,128,132,57,115,239,213,234,100,68,115,164,177,218,145,15,197,162,228,138,179,128,211,207,64,144,172,104,241,121,206,70, - 108,180,103,254,173,89,192,44,152,180,129,31,6,188,224,198,27,168,204,76,179,111,223,14,14,31,31,37,80,138,37,67, - 131,46,5,181,105,105,111,116,134,217,184,191,43,33,49,194,18,71,177,11,160,12,36,198,24,148,82,173,231,178,160,204, - 23,72,97,220,22,12,135,43,45,144,61,101,11,196,51,50,165,224,231,105,203,117,113,104,106,142,79,127,232,147,236,252, - 228,109,233,198,99,167,38,95,1,219,242,240,64,3,30,76,176,59,45,76,142,65,250,55,217,43,219,250,108,29,144,16, - 224,133,240,196,157,238,80,252,71,47,66,139,139,207,171,255,215,55,184,251,241,241,231,197,115,138,128,53,22,46,195,185, - 200,61,235,8,86,77,169,147,226,131,208,190,146,182,171,72,152,43,161,181,34,17,18,41,36,133,82,27,197,174,46,12, - 2,161,156,233,150,149,2,76,118,113,74,15,33,139,252,223,191,250,99,190,246,213,123,41,22,219,169,79,79,35,84,118, - 199,204,238,132,82,74,10,133,2,82,72,76,106,89,187,102,57,3,3,3,228,11,121,164,20,164,105,74,20,53,0,40, - 22,115,88,43,72,82,237,18,208,133,179,44,73,18,67,181,218,32,200,21,40,22,187,8,59,187,56,114,248,4,135,143, - 126,140,235,111,186,142,53,27,86,115,228,232,97,182,125,233,75,141,107,161,145,192,144,148,226,74,140,189,113,199,138,161, - 11,174,251,224,59,123,151,174,91,139,73,235,136,51,182,86,139,35,142,229,194,226,170,213,251,156,214,113,156,134,241,156, - 93,169,116,186,233,87,51,53,116,17,6,100,79,239,169,16,34,43,68,153,145,153,213,167,249,61,139,51,87,237,167,133, - 197,219,103,84,25,113,166,6,77,136,211,10,174,177,22,217,180,4,201,248,78,214,106,48,150,82,103,59,23,94,122,21, - 229,185,89,158,124,236,17,158,124,106,39,171,151,47,167,187,179,205,69,47,25,247,111,77,86,52,173,176,167,61,133,36, - 77,241,148,122,70,113,182,214,180,70,86,105,2,172,0,109,53,40,137,49,41,82,8,164,20,228,253,128,92,208,203,225, - 137,25,62,246,217,207,240,244,71,63,155,172,218,119,96,236,23,96,127,39,60,213,128,135,53,60,81,128,19,171,161,250, - 105,119,180,190,163,197,13,255,89,138,208,243,177,248,156,129,237,240,30,224,167,127,250,28,254,249,68,133,79,127,249,232, - 179,118,77,18,40,207,207,113,108,114,138,145,13,27,8,81,228,186,186,240,61,31,161,20,86,184,145,196,98,91,156,22, - 132,194,104,139,231,151,184,255,158,123,249,220,103,110,167,175,119,144,169,233,153,86,212,142,177,6,41,37,249,124,158,70, - 212,160,92,46,211,213,217,201,242,85,43,25,26,30,65,41,133,214,6,79,73,180,214,88,4,129,31,16,167,41,129,167, - 72,180,211,34,133,65,224,198,34,9,243,149,57,162,169,41,124,21,16,4,138,193,193,62,180,213,124,254,115,183,115,197, - 216,69,28,63,126,136,244,224,177,134,15,121,3,91,164,177,151,110,239,41,157,123,225,251,254,161,103,243,133,87,97,226, - 8,35,125,20,49,173,128,10,177,136,216,144,137,106,91,113,196,44,26,139,22,37,139,158,141,168,124,118,236,198,44,152, - 248,44,170,23,130,166,188,99,49,190,100,91,106,249,211,126,214,179,36,92,156,253,132,202,236,215,125,235,228,139,211,210, - 80,155,5,106,145,135,144,177,150,182,246,78,174,185,225,197,156,56,124,128,29,79,62,70,173,86,101,96,176,15,169,124, - 172,78,156,187,163,116,157,139,196,137,117,141,160,101,51,219,244,36,58,19,104,151,82,160,132,201,18,83,156,216,213,243, - 218,200,231,138,196,218,112,224,224,17,30,189,253,54,115,244,246,59,162,129,227,99,227,111,128,61,109,240,84,140,216,170, - 177,187,12,28,59,9,51,47,1,93,248,46,232,45,222,226,19,246,31,185,8,89,32,23,40,162,248,249,87,124,22,23, - 161,16,184,126,77,7,87,252,220,70,110,89,219,193,7,255,113,123,139,85,157,224,108,75,11,2,147,130,198,218,116,207, - 99,123,184,234,134,155,17,74,33,132,114,162,200,236,205,216,244,45,151,44,164,58,120,97,59,123,119,238,224,207,255,244, - 47,73,34,77,20,149,169,71,141,76,81,237,70,135,56,142,137,26,17,197,66,158,217,217,89,134,6,7,89,189,122,53, - 141,200,225,7,82,9,132,114,129,119,66,42,16,130,124,24,56,193,100,26,187,205,145,213,132,228,240,60,143,158,238,110, - 166,166,103,104,52,34,246,238,61,200,206,157,154,205,231,111,102,233,210,21,60,245,212,46,190,126,199,109,220,34,17,90, - 179,66,193,154,93,133,112,237,198,127,249,63,93,47,184,238,70,97,235,17,66,129,146,198,189,182,197,235,110,177,144,154, - 213,74,156,104,74,48,90,235,47,113,70,247,97,22,9,65,57,109,252,18,139,198,161,179,93,33,11,0,180,131,36,68, - 51,135,203,90,215,41,44,170,116,14,12,62,163,152,136,51,54,110,167,81,240,237,183,125,255,58,185,140,125,134,98,191, - 181,224,104,254,44,157,50,178,98,53,3,67,67,236,222,241,20,7,143,29,99,184,127,128,66,224,101,231,72,103,218,56, - 155,253,59,183,26,73,146,52,27,197,221,77,168,249,209,122,89,158,70,201,128,92,88,66,19,80,158,139,120,242,129,135, - 217,245,239,95,76,204,35,143,151,71,102,231,38,46,132,189,121,216,26,193,182,58,98,143,192,158,28,133,242,11,32,249, - 213,246,46,78,116,13,210,35,37,187,231,103,88,89,153,65,68,141,51,209,181,179,23,160,211,138,208,151,93,21,61,255, - 122,65,18,61,255,139,80,171,243,137,29,230,243,124,44,62,139,31,73,61,197,11,37,111,186,164,159,6,112,17,206,119, - 163,153,52,80,21,66,251,82,76,247,167,230,216,206,219,190,56,63,251,203,63,219,222,81,116,209,58,153,41,51,11,216, - 165,27,208,173,1,233,121,76,141,141,242,119,255,247,239,153,24,159,33,151,203,51,53,51,77,106,82,87,160,76,243,46, - 168,80,158,66,42,247,230,27,24,24,68,41,73,16,40,146,36,117,108,0,169,8,139,33,90,55,215,213,58,99,201,186, - 255,102,141,197,106,139,198,141,114,189,61,221,204,206,206,49,56,56,192,142,157,219,184,247,190,123,88,182,108,13,155,206, - 217,64,190,161,77,91,66,65,194,186,157,146,96,201,219,255,184,235,186,87,191,65,17,213,48,126,8,178,140,178,153,6, - 158,179,103,168,59,178,176,205,152,68,89,1,70,184,162,156,145,17,207,228,215,44,12,84,153,207,134,205,112,35,97,207, - 88,179,139,69,225,128,205,95,103,22,105,195,154,155,173,133,84,141,69,102,138,11,237,203,25,124,159,211,177,44,193,89, - 85,206,139,190,195,216,102,176,32,173,32,196,133,232,101,50,239,203,108,28,212,110,175,122,238,150,203,232,29,26,100,235, - 163,143,210,219,86,160,187,187,27,116,236,54,174,210,224,206,16,45,240,185,169,133,107,210,15,22,176,49,197,252,124,72, - 181,86,101,108,239,54,83,126,106,135,174,60,242,68,213,223,181,127,236,2,99,143,117,192,9,224,64,2,59,234,206,184, - 96,172,13,91,126,0,244,23,195,2,83,195,107,197,230,193,1,117,56,78,210,131,198,144,235,236,229,64,154,176,244,200, - 211,36,90,63,171,168,215,59,27,223,202,11,224,241,59,50,96,250,198,231,119,17,122,62,143,93,223,242,121,27,203,124, - 93,179,29,24,233,207,51,244,91,231,19,76,69,148,254,113,7,179,149,36,78,60,113,40,128,71,151,60,250,228,250,237, - 159,252,218,5,87,255,212,155,149,17,211,8,225,2,121,164,112,111,71,163,53,202,186,214,186,50,59,207,7,223,251,126, - 118,237,216,69,28,69,8,145,32,36,36,105,236,52,142,40,60,207,157,242,40,138,16,88,186,187,58,25,25,25,161,17, - 213,17,66,226,251,30,105,170,73,146,132,102,250,152,203,145,119,22,31,82,186,11,192,24,67,163,17,83,44,134,24,13, - 82,105,122,186,187,9,131,60,66,88,246,31,218,203,232,201,113,102,166,102,233,152,153,211,61,16,110,131,92,254,207,126, - 39,184,229,231,127,73,88,61,143,246,173,179,165,208,165,140,163,96,22,21,133,179,24,132,53,49,27,187,80,114,172,93, - 232,140,22,219,170,158,54,102,137,38,85,81,180,144,102,113,154,48,93,156,54,146,185,159,233,10,123,26,55,176,70,163, - 60,31,225,133,153,98,158,211,114,220,23,35,207,86,44,162,1,180,86,238,238,247,138,111,119,13,157,153,174,209,98,124, - 187,215,43,132,187,38,13,22,132,143,240,21,198,90,6,135,151,115,221,139,122,120,236,129,251,56,120,232,48,43,150,47, - 67,90,131,78,154,192,57,24,235,50,227,23,119,108,98,17,160,142,128,219,190,248,37,238,255,200,199,245,155,70,103,234, - 75,97,34,132,109,30,60,154,192,46,13,39,4,76,24,152,150,80,233,117,170,119,198,128,13,61,35,28,237,25,22,210, - 198,166,45,204,228,170,64,136,207,79,159,119,233,183,165,173,240,108,69,232,137,47,91,182,222,101,241,195,111,107,252,246, - 95,197,231,251,120,148,218,124,46,188,117,41,23,254,252,6,30,186,114,128,183,129,169,106,59,38,148,120,172,31,182,237, - 254,195,63,153,62,180,103,39,82,228,49,153,49,149,37,197,24,231,88,100,165,162,49,55,199,71,223,243,30,226,90,68, - 169,212,65,165,214,32,54,134,84,27,124,207,71,41,15,164,32,213,174,147,73,163,132,98,190,68,79,103,47,7,247,31, - 68,9,69,224,5,8,43,240,164,162,144,203,103,120,129,115,220,83,158,36,181,9,81,26,97,208,104,171,209,104,82,82, - 240,140,243,32,178,146,92,46,164,191,127,128,165,35,203,81,184,0,196,113,66,241,69,48,252,194,235,188,55,252,206,111, - 8,146,170,243,50,178,30,210,26,164,204,66,126,229,226,150,66,186,213,176,84,8,225,33,240,129,16,107,189,150,105,152, - 108,117,42,58,139,220,177,153,69,109,19,59,106,154,218,122,24,60,180,144,24,164,91,231,11,201,233,213,40,179,226,192, - 229,198,91,33,17,82,144,70,117,202,19,167,152,31,27,165,50,126,146,104,242,20,233,236,12,186,86,197,54,195,250,172, - 205,46,186,208,197,22,101,161,197,86,200,5,172,78,200,236,87,44,40,231,91,133,192,178,224,55,36,178,96,78,43,90, - 126,207,2,167,231,50,210,71,120,190,27,155,76,132,213,117,210,198,28,141,218,4,158,109,112,197,37,151,81,204,151,120, - 252,209,173,212,27,41,126,88,112,63,35,43,232,74,137,236,6,34,90,36,204,230,50,194,26,205,155,127,242,21,252,194, - 255,252,25,188,82,206,134,16,9,24,77,224,113,3,247,43,120,226,48,28,30,132,185,17,208,62,139,12,233,173,37,112, - 218,170,103,232,171,82,99,158,245,227,172,29,208,217,138,16,60,255,58,161,255,44,197,71,2,149,147,85,118,254,212,189, - 116,92,220,199,69,219,166,248,6,144,51,214,8,37,231,45,118,98,201,177,195,51,31,253,173,183,182,255,247,15,189,55, - 236,110,47,98,90,35,8,40,1,149,249,89,190,248,233,219,104,43,150,8,194,144,125,251,15,80,40,148,90,249,214,190, - 23,16,37,49,82,10,124,207,167,45,95,96,227,134,141,220,244,162,155,40,21,139,28,58,112,144,167,119,238,98,104,104, - 152,222,222,94,226,36,65,74,141,82,210,249,14,103,23,180,84,206,129,49,73,157,57,173,82,30,86,24,18,163,9,189, - 0,99,52,74,41,58,58,58,73,211,148,106,165,202,204,244,36,199,144,94,233,77,175,84,191,247,215,127,156,217,136,153, - 204,144,75,101,0,111,102,237,102,4,167,231,172,187,24,229,197,227,202,226,116,27,219,180,171,48,77,252,102,241,154,91, - 60,99,196,113,205,136,229,76,97,168,205,112,35,97,89,180,165,202,222,99,133,54,124,47,164,49,63,79,189,58,75,195, - 90,60,207,119,5,48,12,145,126,128,244,60,60,47,64,249,185,204,175,91,101,171,109,88,112,247,182,78,203,150,61,167, - 166,62,94,176,32,1,81,205,239,21,22,132,6,145,96,77,226,182,97,90,211,168,167,36,141,8,157,38,160,83,116,154, - 160,20,40,225,196,201,198,8,206,219,188,153,142,82,59,15,62,248,16,23,92,176,153,174,238,78,82,157,58,75,143,172, - 35,115,55,22,78,103,61,91,139,77,234,92,243,202,91,213,238,37,75,75,91,255,226,29,35,107,118,236,223,220,1,7, - 19,56,30,194,252,17,72,255,12,231,16,250,19,56,83,57,128,224,251,232,78,188,111,211,17,62,47,139,208,127,4,192, - 249,91,22,157,156,135,40,249,168,188,231,200,138,117,205,204,35,19,236,124,100,66,108,132,224,103,160,24,91,150,234,212, - 92,154,131,181,39,160,120,255,254,125,234,186,167,119,112,213,21,87,161,117,234,140,57,37,212,231,102,121,232,222,123,200, - 133,1,231,157,119,9,191,244,171,191,157,141,88,13,18,157,32,4,164,169,118,126,49,64,71,169,141,43,175,188,138,203, - 47,191,12,33,36,213,106,157,161,145,37,244,246,246,243,212,182,167,16,66,48,60,50,66,154,166,232,38,111,196,146,233, - 205,92,247,97,140,193,247,125,247,166,213,6,229,123,153,133,105,198,164,149,130,92,46,207,192,96,63,213,234,44,155,54, - 175,229,111,222,241,215,162,173,61,143,77,51,210,27,11,192,110,19,225,104,25,58,103,238,132,153,68,124,209,90,62,89, - 4,183,152,86,113,49,42,115,17,68,182,210,39,220,159,23,214,241,130,133,173,90,211,155,199,102,27,42,87,188,52,146, - 5,162,162,200,254,134,12,80,133,28,197,48,135,95,244,153,154,156,194,88,67,33,204,19,71,17,38,106,184,130,128,2, - 2,60,79,162,60,137,242,37,158,167,50,16,223,98,140,64,72,31,229,185,104,63,33,165,219,236,53,253,160,141,37,19, - 108,145,38,17,113,28,147,164,13,162,168,130,213,105,182,197,116,60,48,79,228,8,252,2,161,151,35,110,104,166,166,102, - 152,157,155,102,174,54,65,84,143,178,85,190,102,199,142,237,92,121,213,21,173,232,105,41,188,214,117,189,32,204,93,136, - 10,50,22,26,213,26,231,92,124,161,232,123,207,219,219,238,251,179,183,95,60,242,249,187,109,31,80,131,59,95,10,251, - 246,67,244,1,92,142,88,9,231,2,177,49,137,184,81,72,106,194,146,96,159,219,88,158,197,69,200,26,184,240,69,63, - 218,34,212,44,62,245,72,243,218,223,123,254,23,159,179,105,254,199,222,191,139,173,119,28,166,109,46,230,10,231,129,227, - 165,144,31,128,238,105,24,206,195,106,15,206,155,131,139,239,246,212,57,201,27,95,218,253,143,127,244,251,106,245,178,149, - 24,147,56,113,32,150,168,90,225,169,199,30,69,38,49,47,184,230,26,62,245,233,59,56,114,228,56,202,47,160,211,20, - 165,36,105,154,98,173,37,77,52,109,197,60,151,92,114,49,87,94,121,5,214,66,154,26,108,38,84,244,130,128,11,183, - 92,196,222,189,123,57,124,248,48,43,86,174,196,36,177,3,174,165,192,195,203,88,183,238,46,154,166,105,182,69,81,206, - 151,90,138,140,105,11,105,10,81,20,227,123,138,246,206,18,191,246,214,95,163,163,179,3,155,214,79,67,102,69,203,112, - 43,251,63,35,51,112,52,91,23,55,85,18,139,41,130,217,158,222,54,67,129,155,104,188,144,8,171,78,147,97,156,222, - 1,217,204,59,121,193,176,127,161,11,50,89,244,241,98,31,48,231,182,108,179,11,19,25,16,148,250,233,180,121,30,248, - 198,215,137,170,53,206,219,120,14,165,66,158,188,23,146,154,132,88,87,73,106,154,200,90,132,84,153,255,15,72,169,48, - 169,118,91,69,213,202,115,59,29,196,182,26,157,197,30,88,107,49,198,253,59,87,44,148,243,254,17,1,141,40,98,174, - 58,195,244,244,33,198,70,79,186,227,236,251,116,119,119,209,213,217,73,208,231,152,238,107,215,175,33,77,83,234,245,26, - 129,159,253,62,165,178,209,107,1,220,151,82,34,68,182,17,203,10,118,163,94,161,191,163,141,151,255,213,219,114,183,231, - 131,75,249,196,157,178,31,152,150,66,189,205,216,189,1,212,255,21,23,48,80,1,142,77,28,197,122,62,151,44,93,70, - 49,151,107,117,231,205,71,156,234,239,189,0,45,46,66,79,126,197,109,199,126,84,43,122,55,118,73,162,72,243,154,255, - 245,13,238,121,226,249,91,124,154,50,12,223,157,36,241,83,174,169,102,7,200,198,190,89,191,109,223,172,15,228,87,65, - 167,134,190,192,37,63,172,50,176,110,10,86,31,47,230,151,151,175,187,112,96,203,127,251,153,224,69,47,127,25,97,32, - 51,191,98,139,20,6,29,215,217,189,253,41,26,213,42,231,158,179,129,201,137,105,62,251,185,59,220,77,52,78,29,153, - 76,90,180,78,17,66,225,41,197,198,13,27,185,225,134,27,72,146,20,157,9,13,201,124,117,76,166,13,218,176,97,3, - 39,78,156,96,122,122,138,246,142,14,146,36,193,243,188,86,209,81,74,225,123,62,22,75,24,230,78,187,147,42,41,73, - 83,157,17,24,107,76,207,76,240,147,111,121,35,107,214,175,194,196,53,7,160,47,6,123,79,91,90,57,194,159,148,106, - 1,111,22,103,168,220,173,92,100,163,145,97,44,52,173,80,23,143,89,139,137,118,180,182,88,66,184,49,47,91,136,45, - 116,69,214,100,79,193,169,188,155,58,168,38,171,24,229,64,92,99,60,194,98,39,87,95,247,34,62,127,219,109,188,227, - 159,222,197,213,87,92,134,77,18,74,109,5,186,251,122,233,236,234,34,151,207,101,5,195,98,181,198,88,75,16,8,68, - 170,177,54,117,4,71,99,92,184,99,166,162,183,139,214,248,70,184,174,211,104,65,212,72,152,153,157,97,98,124,130,180, - 150,16,199,117,188,64,82,106,47,177,116,168,159,174,238,118,194,156,27,249,82,29,56,177,170,214,164,105,140,64,100,57, - 242,142,211,149,218,20,223,247,179,162,227,116,97,14,71,116,12,121,79,10,82,99,80,158,79,172,99,66,47,228,250,223, - 249,149,240,35,19,99,151,108,185,123,43,61,198,114,80,96,126,205,178,175,2,141,71,112,38,124,6,248,234,232,1,182, - 206,141,211,155,47,160,179,194,96,172,37,244,20,47,60,127,133,99,219,159,165,96,124,199,134,100,63,106,158,80,171,248, - 196,134,87,61,143,139,143,205,10,207,16,112,37,120,69,232,152,128,174,45,16,10,144,167,32,167,160,87,66,183,20,244, - 24,203,176,133,37,51,176,108,174,32,135,14,175,236,239,111,187,225,230,210,85,175,127,179,220,124,233,133,4,94,1,155, - 156,194,164,22,43,2,84,230,5,124,96,247,110,162,74,153,101,75,151,225,249,57,30,120,232,235,28,63,57,138,31,230, - 136,35,131,49,154,36,137,81,217,93,111,201,146,165,188,228,37,47,67,8,137,214,6,41,21,82,42,226,56,113,155,21, - 107,144,74,18,197,17,253,3,253,76,76,78,50,57,57,73,119,119,55,58,91,163,54,127,22,214,226,7,65,246,51,220, - 155,27,4,105,170,1,131,54,49,213,250,60,55,220,124,61,151,92,117,25,38,174,184,81,71,102,106,245,236,130,63,29, - 58,56,195,102,35,179,134,16,173,113,141,108,3,40,22,81,110,154,32,242,217,155,254,211,229,23,217,103,105,155,200,146, - 163,52,160,145,210,100,18,23,223,121,130,139,69,72,141,176,173,142,200,8,141,176,150,32,231,243,186,183,188,145,77,155, - 214,50,126,242,56,133,192,99,226,212,56,99,123,198,17,66,146,207,23,80,50,160,84,106,163,171,187,7,41,37,81,84, - 35,12,36,133,98,17,233,41,167,50,207,70,48,79,9,7,196,167,138,153,185,89,198,199,199,49,22,38,38,198,25,27, - 27,5,97,89,58,50,204,234,21,195,20,139,75,16,170,9,44,187,206,197,24,137,181,6,99,146,214,177,116,161,149,174, - 139,107,18,16,83,215,250,180,58,85,215,1,137,204,192,222,44,12,79,214,245,237,81,220,160,51,95,224,53,127,250,7, - 193,39,254,215,219,46,185,252,222,237,116,91,24,21,232,255,105,217,63,0,241,57,110,60,3,96,162,86,97,162,86,57, - 237,28,228,124,197,21,254,48,42,239,60,134,190,231,2,244,163,44,66,22,200,7,146,70,244,252,46,62,38,43,60,123, - 64,14,66,113,37,44,77,224,252,60,108,106,64,151,113,240,100,62,133,190,26,116,54,160,189,177,172,191,39,89,190,188, - 45,190,96,93,225,220,87,190,70,94,125,238,58,70,250,7,92,102,130,174,145,234,4,41,2,16,26,33,52,73,189,194, - 145,189,187,153,61,53,78,127,223,0,105,106,40,215,98,238,252,202,61,68,137,110,145,118,149,244,48,104,164,112,42,242, - 107,174,185,150,158,238,62,170,213,42,74,121,45,224,209,243,92,17,106,94,228,72,137,54,134,158,158,30,198,198,198,208, - 90,227,251,62,113,28,103,186,176,212,141,6,8,148,148,142,187,34,5,214,100,133,201,151,204,204,205,115,209,197,231,113, - 243,173,55,162,147,154,219,250,100,119,221,103,51,142,63,19,57,88,144,88,44,30,85,78,231,250,180,92,126,196,194,144, - 181,96,193,209,140,10,48,173,177,102,1,164,182,8,227,10,101,101,118,154,156,47,241,252,16,25,128,80,138,211,242,115, - 178,223,34,113,199,95,120,25,39,74,39,156,179,229,2,84,8,147,227,99,108,188,96,51,36,142,115,19,71,41,213,106, - 149,249,249,10,251,247,63,77,181,86,165,86,109,96,109,64,106,52,65,62,231,214,212,97,64,62,23,162,68,70,50,52, - 144,36,17,66,64,177,173,64,161,144,99,227,57,107,232,235,235,166,88,204,163,141,161,158,38,78,63,5,72,233,35,164, - 69,72,183,217,84,173,132,215,172,208,24,155,141,113,162,213,145,25,52,86,187,142,71,74,153,121,253,100,99,104,182,62, - 151,6,12,26,172,32,214,13,250,187,186,120,205,159,254,126,112,199,111,191,109,203,197,15,238,138,11,150,114,44,168,236, - 183,28,95,147,221,42,158,205,95,171,22,120,217,120,44,206,74,67,248,174,45,89,127,216,69,168,89,124,106,13,205,107, - 126,239,254,231,101,241,105,190,244,113,16,47,133,48,129,193,58,156,155,131,203,27,112,201,231,61,54,219,13,203,58,54, - 109,88,139,10,115,178,109,176,223,43,14,244,169,225,213,43,68,247,134,245,44,93,185,134,82,190,23,80,36,204,128,174, - 96,117,136,81,138,84,54,240,76,17,37,60,180,46,51,57,54,74,84,157,163,167,173,136,137,99,194,98,23,59,118,238, - 99,215,222,131,72,233,99,18,231,100,40,148,69,38,144,232,148,11,46,184,136,145,165,203,152,171,84,156,130,218,44,208, - 242,141,113,178,11,132,112,64,179,204,86,199,214,50,56,56,232,248,66,66,180,64,103,165,36,113,156,16,248,97,166,145, - 106,70,12,91,2,63,68,155,26,221,189,93,188,248,101,183,32,133,37,205,182,46,205,78,166,181,133,130,69,110,132,11, - 43,240,197,199,244,116,165,148,93,64,212,178,191,54,234,13,140,73,241,2,133,239,231,51,69,183,201,138,141,62,61,4, - 80,184,146,37,22,17,21,149,144,8,147,80,158,42,35,165,68,169,60,97,91,9,145,203,163,194,124,11,204,118,227,161, - 68,216,180,213,137,89,107,209,169,97,253,230,75,240,194,93,140,31,59,196,146,158,54,71,233,203,41,242,249,78,250,250, - 186,193,46,37,77,99,210,52,65,199,16,197,17,73,154,146,36,49,198,106,226,56,194,87,110,52,245,51,87,130,32,116, - 254,74,190,231,57,145,177,49,164,73,138,167,4,158,231,103,128,52,40,105,157,32,213,64,170,117,70,207,200,172,52,76, - 179,112,103,93,163,176,142,74,145,166,89,23,156,58,199,4,41,51,247,129,12,7,202,60,177,155,61,160,198,16,39,49, - 3,125,3,220,248,231,127,152,123,248,87,254,191,139,46,216,126,120,202,90,38,58,160,254,183,48,121,5,216,194,179,92, - 27,255,62,210,205,231,66,159,103,51,5,253,158,60,161,23,23,33,107,224,194,155,127,48,69,104,113,241,121,229,239,126, - 131,175,111,61,245,188,235,120,74,56,141,215,227,16,52,160,91,194,234,28,92,106,224,170,195,176,121,199,133,231,46,217, - 244,171,63,81,120,217,173,47,99,160,103,192,129,182,162,105,146,41,1,141,38,198,152,121,140,54,72,5,82,134,46,251, - 93,128,103,4,216,8,140,97,110,252,56,181,242,20,109,197,54,172,129,212,104,144,130,47,221,249,32,243,243,49,97,62, - 135,240,193,232,4,147,26,148,231,81,44,229,185,224,188,243,169,55,234,20,138,153,37,71,118,199,109,105,159,132,116,171, - 253,51,174,119,41,37,97,16,158,230,141,99,12,4,65,136,177,169,75,35,213,22,79,42,180,244,48,66,18,155,136,87, - 191,246,37,132,161,64,235,4,37,189,76,104,9,70,8,148,16,11,155,31,107,29,231,166,85,22,100,6,248,106,36,41, - 88,207,221,91,69,132,65,96,200,35,172,65,89,3,196,68,213,41,170,115,83,180,229,115,232,32,68,230,219,80,65,9, - 229,23,90,64,175,21,26,105,23,118,97,182,137,237,88,199,142,46,22,59,137,171,13,60,37,49,58,166,58,125,202,17, - 23,189,128,32,215,70,144,43,160,2,31,25,184,115,34,132,116,204,243,102,183,104,45,171,214,109,34,138,99,78,156,58, - 202,96,95,31,113,220,192,87,162,101,221,33,149,64,90,137,10,45,126,46,0,2,132,40,44,216,189,102,224,126,146,141, - 178,198,58,207,30,112,96,180,209,238,247,89,109,80,74,162,164,66,42,55,198,217,236,123,108,230,138,208,202,32,147,14, - 103,210,58,93,24,149,141,205,70,63,145,173,227,197,34,19,126,131,176,25,193,85,100,185,101,86,58,59,14,43,208,81, - 194,210,229,67,164,127,246,191,58,182,254,244,111,93,113,254,228,220,108,21,230,45,60,60,47,68,185,240,44,23,255,233, - 29,233,115,84,128,22,23,161,31,20,48,221,196,124,234,177,225,53,191,119,255,243,174,248,88,96,30,104,3,245,50,104, - 159,129,85,121,184,72,192,165,71,225,162,3,195,35,171,54,254,218,207,181,253,198,207,191,89,245,118,14,0,25,167,195, - 58,203,4,157,1,192,50,107,79,221,159,5,18,149,113,80,82,48,6,105,5,66,106,102,39,198,168,204,76,161,178,107, - 39,49,134,48,95,224,233,93,251,120,224,193,71,200,229,242,88,44,73,154,96,113,188,144,56,142,185,250,234,107,241,125, - 143,70,189,142,167,20,86,186,213,185,53,6,43,37,202,115,227,88,148,38,40,207,195,164,89,14,185,82,173,55,107,189, - 94,207,214,199,153,12,32,3,173,211,36,109,201,50,130,192,99,124,106,156,235,111,186,156,190,254,126,146,184,134,151,141, - 122,205,206,71,102,12,240,150,162,92,186,55,190,182,180,156,139,17,6,105,125,192,50,63,55,138,141,35,2,191,157,160, - 208,129,10,18,231,101,44,36,214,8,138,109,29,232,218,60,42,53,216,184,70,101,118,30,153,243,9,219,58,200,21,123, - 16,94,9,33,60,76,22,33,217,12,2,180,100,90,55,173,81,133,18,181,40,225,11,183,223,197,45,55,191,136,182,66, - 142,52,170,161,107,117,170,229,6,101,41,240,194,0,21,4,120,190,115,144,244,131,0,233,41,132,82,110,181,109,13,27, - 54,110,100,91,181,204,212,116,153,238,142,34,164,177,99,107,219,5,203,179,56,141,241,60,229,36,31,89,81,55,214,102, - 76,118,213,234,38,69,86,224,148,146,11,86,105,86,32,133,211,229,185,163,230,176,42,87,180,28,165,192,99,193,122,196, - 66,75,231,101,140,235,142,132,114,91,75,99,22,114,140,28,30,232,192,112,163,227,172,19,202,18,102,149,200,126,183,163, - 78,164,115,49,235,55,108,98,230,143,127,123,100,255,255,252,131,235,214,197,102,84,195,216,209,192,219,51,16,167,137,176, - 150,249,124,192,124,16,32,173,37,159,106,202,129,231,98,204,4,207,109,1,250,65,142,99,205,226,211,72,12,175,254,221, - 231,23,230,211,180,214,120,41,136,9,40,120,48,226,193,230,18,92,53,1,151,62,220,217,190,33,247,250,91,187,223,240, - 255,253,154,88,179,226,28,208,13,108,60,237,66,3,133,204,138,131,68,102,109,252,2,101,159,214,197,189,248,0,74,9, - 213,185,57,42,51,83,232,196,96,53,248,94,182,209,193,227,158,123,31,100,106,118,146,124,169,3,107,154,124,29,73,18, - 199,44,95,177,156,222,222,30,26,141,6,237,165,118,124,169,136,162,24,47,155,255,91,9,161,82,18,134,33,66,72,82, - 145,144,36,77,162,161,211,139,197,218,16,71,13,167,128,111,42,240,133,68,102,172,92,97,161,92,153,165,171,43,207,5, - 231,159,139,77,19,60,233,157,238,134,218,234,58,50,37,185,200,36,180,214,145,41,143,31,62,142,50,150,145,165,125,104, - 13,74,5,120,70,83,173,205,145,154,6,186,86,165,216,149,71,133,237,164,4,24,169,240,130,54,74,93,35,124,234,67, - 31,228,130,13,231,176,97,205,106,106,233,12,245,233,57,226,234,28,42,232,33,87,234,70,5,42,187,168,220,69,107,16, - 104,44,66,73,148,181,116,13,143,48,93,174,240,206,119,253,43,151,95,186,133,75,46,56,159,48,40,96,51,191,101,157, - 52,72,226,42,66,204,99,90,84,33,129,31,230,200,23,10,228,11,69,84,24,112,222,69,91,216,250,205,7,169,213,26, - 116,20,242,206,61,50,203,100,107,130,189,89,127,114,122,240,97,38,18,150,25,174,70,147,40,152,241,157,68,43,46,58, - 219,46,105,183,73,211,214,249,73,35,101,86,220,105,173,192,23,19,12,23,127,246,60,119,99,106,110,24,157,175,145,114, - 231,196,72,76,10,73,146,18,132,57,114,249,60,190,239,147,234,20,164,64,153,2,74,5,92,255,250,215,243,213,195,71, - 87,86,254,250,221,87,23,96,255,140,16,147,123,124,239,212,80,156,152,59,215,47,231,238,117,75,200,197,9,22,75,212, - 168,146,79,52,4,242,185,47,64,63,168,34,20,20,125,230,107,9,111,120,30,21,159,230,203,57,23,72,193,239,131,158, - 58,108,204,193,149,21,184,242,126,212,102,251,202,155,6,95,243,135,111,245,207,187,224,82,55,92,153,26,146,4,45,93, - 210,128,27,50,196,34,81,35,139,20,214,42,187,91,101,122,40,233,220,232,116,163,78,101,106,18,27,215,51,149,182,227, - 199,4,97,64,173,150,240,248,227,187,16,82,16,69,13,103,189,137,91,151,231,243,121,150,142,44,101,118,102,22,63,8, - 24,236,31,68,167,14,227,105,110,179,172,181,153,118,201,117,94,105,156,128,117,56,131,49,6,99,45,137,54,148,218,219, - 153,58,213,112,220,34,207,207,108,64,4,198,186,87,161,4,204,205,159,226,101,215,223,154,113,12,229,66,113,21,153,118, - 201,90,164,205,46,46,148,147,38,52,191,142,199,212,196,36,127,253,39,127,206,235,127,236,101,220,250,146,27,48,8,114, - 126,129,163,99,71,232,234,76,41,132,41,181,169,57,188,182,24,194,118,68,152,39,5,130,246,94,242,157,3,252,201,95, - 189,157,151,191,244,22,174,190,246,114,122,250,186,104,68,85,210,250,113,210,234,4,190,151,35,95,106,71,22,243,8,207, - 203,52,87,142,123,172,177,228,10,69,174,190,230,106,226,242,44,91,183,110,101,223,211,59,89,187,118,29,171,87,174,166, - 189,171,45,243,172,209,200,236,60,10,161,48,198,146,212,42,36,181,26,85,53,67,174,80,32,44,182,177,97,253,6,118, - 110,125,146,80,121,174,131,177,110,205,110,108,243,220,36,173,237,94,83,24,108,22,5,38,234,212,180,228,18,45,81,109, - 230,223,212,204,184,215,153,38,183,169,225,18,194,97,84,74,41,7,174,167,174,232,45,246,187,118,92,48,147,177,225,131, - 214,249,215,70,131,117,227,153,39,20,82,250,156,56,118,146,71,30,125,146,217,217,10,197,82,7,113,234,92,17,139,82, - 153,216,243,101,174,163,157,74,190,83,153,82,238,220,155,42,141,11,114,198,110,219,106,236,212,61,74,154,163,3,221,20, - 147,52,27,83,93,167,103,197,247,65,68,252,110,139,144,49,112,209,247,138,9,41,1,165,0,121,231,33,222,254,190,29, - 220,115,100,254,121,131,243,120,192,86,8,87,65,135,129,145,8,46,12,224,5,79,192,101,135,46,58,103,213,213,111,251, - 205,220,77,183,190,132,130,10,177,73,12,194,67,202,16,43,3,55,70,145,102,155,6,90,2,70,219,132,69,133,61,205, - 200,202,98,192,164,96,83,230,167,166,209,81,132,176,6,147,106,164,200,129,48,4,65,158,199,30,223,197,209,99,163,89, - 158,151,165,16,134,164,58,37,142,35,86,173,88,65,224,5,196,141,4,129,108,17,7,155,250,159,230,22,68,91,227,120, - 27,25,15,136,76,221,78,147,109,108,28,95,168,84,44,146,38,49,158,39,50,31,99,31,163,13,185,32,96,98,242,36, - 55,223,122,61,155,206,63,7,19,71,144,173,248,23,2,134,229,34,43,13,15,211,50,252,113,24,152,37,101,195,166,245, - 188,229,167,222,204,206,173,59,248,192,191,126,136,55,188,233,21,148,43,227,124,237,158,187,217,180,97,21,43,87,44,161, - 183,111,144,242,244,12,86,149,233,232,233,197,43,228,177,218,240,226,87,190,10,21,132,116,182,133,220,113,215,55,24,30, - 232,101,203,69,231,208,81,10,49,105,132,174,55,168,68,117,100,181,64,190,173,132,44,228,241,51,233,8,128,82,30,58, - 142,232,40,42,94,250,226,23,50,55,51,207,209,35,199,217,190,107,27,198,26,114,69,159,66,49,79,160,60,172,5,223, - 15,41,149,218,41,22,10,228,194,34,86,8,226,122,131,36,113,30,203,75,70,150,114,96,255,62,150,44,29,65,74,157, - 101,185,11,172,116,36,64,99,178,77,85,54,146,138,150,232,55,163,14,88,209,74,181,16,66,100,227,58,45,110,77,166, - 241,200,192,125,215,197,164,38,201,156,10,36,210,247,22,156,32,141,113,124,41,211,84,214,139,133,200,33,75,107,75,38, - 1,99,171,88,227,179,100,89,63,93,189,215,179,103,247,33,238,190,231,126,238,184,235,94,150,159,154,173,188,30,100,5, - 194,57,72,61,33,170,195,74,140,165,16,201,56,49,43,192,218,165,253,28,236,235,66,87,170,174,248,26,251,109,141,129, - 212,203,87,108,226,185,42,66,82,193,137,189,238,239,3,155,3,103,215,9,103,221,255,63,131,148,228,75,84,106,137,62, - 127,128,169,191,122,132,187,102,35,30,255,1,22,150,115,28,79,135,47,0,215,1,131,208,138,13,241,128,163,184,236,247, - 141,64,63,168,97,232,172,194,6,9,215,9,184,101,14,110,250,90,33,127,149,255,214,95,89,241,75,255,242,14,111,203, - 249,151,184,187,154,6,33,83,172,172,162,69,138,176,2,165,113,130,165,22,249,77,52,47,203,150,36,193,178,192,203,16, - 214,32,173,161,60,53,73,101,118,26,29,71,88,171,29,160,168,20,169,177,120,65,145,143,124,228,223,217,181,239,32,66, - 185,55,162,146,146,70,163,193,242,101,203,24,26,26,162,81,143,72,226,24,223,243,25,25,30,161,163,163,163,181,209,106, - 90,115,10,225,124,166,155,212,27,99,109,230,247,99,81,205,55,167,148,8,4,73,28,81,40,228,220,29,93,187,72,159, - 74,121,150,21,43,135,185,238,69,87,67,90,205,236,49,112,41,7,210,100,177,55,205,77,140,187,176,164,16,206,12,29, - 119,193,10,64,73,159,153,201,41,94,112,229,69,212,171,101,142,30,59,65,169,163,141,70,82,101,205,138,213,236,221,123, - 132,147,227,19,44,93,178,20,133,161,94,153,67,160,221,230,40,215,70,163,81,65,165,13,174,190,250,18,166,167,78,241, - 228,227,219,104,52,160,189,171,159,160,24,184,245,115,98,168,215,42,164,141,134,203,140,80,14,232,23,82,49,123,106,20, - 91,155,65,40,139,239,91,6,135,135,24,26,30,166,212,222,70,88,200,17,132,1,18,231,201,164,181,102,126,126,158,217, - 217,121,198,199,79,49,57,57,73,189,94,35,142,234,40,41,41,22,157,217,255,216,216,40,93,93,93,24,92,87,226,232, - 0,166,101,231,138,16,142,46,161,53,82,73,247,125,198,32,61,183,20,176,89,247,104,23,235,227,50,230,183,109,158,39, - 200,86,236,11,139,3,22,165,125,216,211,178,202,68,171,104,181,206,107,147,243,36,5,210,115,14,11,82,66,152,83,44, - 95,57,204,13,55,92,201,245,55,94,137,215,91,244,106,115,243,114,249,212,60,23,91,42,235,96,95,175,177,15,105,120, - 200,8,246,140,64,121,87,185,202,147,161,207,234,66,64,109,182,66,96,53,117,105,241,148,68,158,225,198,8,240,226,55, - 252,236,115,87,128,90,69,200,19,156,218,111,216,244,181,71,73,139,48,94,8,232,233,201,35,197,233,133,200,97,15,224, - 121,64,168,136,235,154,131,255,223,55,136,63,187,143,156,117,145,189,143,253,8,10,80,115,217,171,128,30,240,11,78,30, - 177,202,131,75,5,188,164,10,183,30,201,5,87,140,190,244,166,245,55,252,243,223,119,188,254,167,222,76,33,144,152,36, - 1,27,33,189,196,109,147,132,231,114,233,49,8,210,86,139,221,60,80,34,147,83,52,137,59,198,106,87,72,140,70,232, - 148,70,121,142,249,217,105,116,26,97,172,70,91,199,225,72,77,138,16,1,115,229,132,127,123,223,71,168,214,27,24,43, - 104,107,111,7,99,220,232,181,108,153,3,142,149,135,239,135,128,96,96,104,136,190,254,62,7,122,74,143,32,112,1,131, - 152,172,0,9,209,42,100,162,73,39,206,86,232,82,56,223,231,35,71,14,35,149,32,137,99,138,133,18,38,49,204,205, - 157,226,197,47,190,14,105,106,84,102,167,168,205,206,81,47,207,81,153,159,162,94,157,195,152,212,109,210,50,81,169,176, - 26,27,87,136,203,179,196,181,121,132,73,128,20,233,183,51,63,51,71,18,31,103,213,138,33,226,196,99,247,222,131,116, - 118,118,210,217,81,164,127,160,135,83,167,198,121,240,129,135,24,30,90,66,87,103,23,229,242,60,198,166,40,31,6,6, - 6,216,187,243,105,186,58,66,134,6,186,233,235,237,101,108,108,150,221,251,14,82,141,27,228,242,57,242,94,232,88,193, - 113,76,163,82,6,163,81,158,68,6,62,243,83,147,212,231,103,200,229,115,8,105,209,58,198,104,75,144,11,201,5,1, - 133,92,142,66,230,137,93,42,21,233,104,111,163,152,47,208,214,94,194,243,157,128,180,86,175,49,61,53,205,228,169,9, - 124,223,167,82,169,80,107,212,41,149,10,24,173,23,121,240,100,55,58,165,88,236,53,100,164,235,58,117,147,37,173,84, - 171,224,104,171,91,27,43,247,217,197,229,144,69,243,8,68,102,60,118,250,67,46,26,197,154,221,206,153,141,192,2,77, - 34,4,235,186,87,173,13,105,26,145,36,13,58,219,10,92,124,249,37,98,228,165,47,149,135,86,13,201,3,135,14,89, - 127,186,220,200,195,148,128,83,169,16,83,5,168,30,135,180,227,212,12,175,59,118,138,251,246,159,224,156,64,114,168,191, - 131,208,242,172,5,232,185,143,102,22,160,60,75,254,155,39,217,122,223,1,62,210,87,224,231,94,187,158,210,149,195,12, - 175,232,32,150,2,153,24,172,208,164,13,152,154,134,162,136,40,253,221,67,76,111,61,197,200,143,24,231,105,184,15,5, - 20,151,195,146,8,46,16,112,241,60,156,51,26,248,107,219,111,189,161,239,210,183,254,98,113,253,149,87,73,95,42,116, - 50,143,80,2,37,52,86,65,34,20,2,137,167,21,34,177,88,37,137,125,80,26,148,21,167,3,74,66,96,141,118,46, - 131,25,200,40,17,36,245,58,243,83,51,217,70,202,160,141,118,88,2,96,137,41,20,123,121,228,177,237,76,78,78,227, - 135,62,104,133,231,249,164,113,196,234,213,171,29,142,22,248,20,10,5,199,245,16,34,219,130,168,12,60,150,72,37,145, - 218,44,128,224,144,37,97,58,44,161,121,193,232,196,141,15,66,74,230,231,231,105,107,203,83,106,43,33,165,228,228,169, - 19,68,141,121,172,142,168,204,78,162,27,13,140,105,218,196,106,188,208,163,26,85,9,148,71,80,232,68,8,69,125,110, - 154,250,236,56,202,104,12,150,56,200,97,165,194,47,212,8,114,134,250,20,68,94,68,255,96,129,199,182,143,17,230,125, - 36,18,29,87,56,119,211,42,60,47,228,67,31,191,141,203,46,187,140,203,175,188,136,180,94,167,82,63,76,231,224,74, - 150,175,63,159,253,71,118,178,102,249,32,158,74,57,111,211,48,147,83,115,28,62,60,198,212,232,36,3,3,61,244,247, - 116,211,221,213,78,206,247,169,207,205,209,72,26,116,122,18,235,73,234,177,162,77,248,142,252,137,113,196,195,84,18,40, - 15,79,41,180,72,29,142,150,73,83,124,169,72,109,138,231,229,51,128,55,68,73,143,52,49,204,205,205,83,175,71,204, - 150,231,24,24,236,115,199,189,25,211,179,136,155,36,90,148,240,108,21,46,29,46,36,69,115,92,166,101,38,223,148,84, - 156,206,161,114,93,171,181,214,1,255,176,40,117,195,182,64,108,33,84,166,219,91,48,34,91,176,4,177,153,7,146,251, - 253,22,227,10,28,18,171,33,78,12,105,84,163,83,5,188,236,149,183,50,122,197,150,194,214,79,126,97,237,161,15,255, - 123,199,154,153,202,64,151,181,253,99,240,192,74,216,117,94,170,167,147,84,39,41,208,54,58,67,223,138,126,234,249,80, - 72,125,118,38,208,115,218,1,53,47,42,105,45,231,31,223,199,184,78,121,186,150,80,121,108,140,187,62,187,143,158,221, - 211,4,93,33,141,130,79,41,12,184,243,253,17,223,252,178,34,248,210,33,214,238,220,207,97,183,214,38,0,238,255,33, - 117,64,159,7,174,117,99,22,243,160,166,161,93,194,50,31,46,77,224,230,10,188,100,2,174,180,47,185,97,253,133,239, - 254,219,254,23,252,214,175,230,6,151,175,20,202,196,96,211,214,93,199,10,133,144,62,194,42,164,49,72,147,186,187,91, - 203,250,32,91,129,90,155,201,1,12,214,68,164,81,13,145,52,16,94,136,231,121,152,70,141,217,137,113,210,168,6,164, - 104,147,130,132,52,50,40,44,97,33,135,80,37,62,240,193,127,103,223,129,195,248,97,128,49,78,159,21,4,30,203,150, - 45,167,90,169,129,21,52,26,17,181,90,13,63,240,233,233,235,101,96,112,8,132,179,147,80,202,61,23,231,51,166,50, - 8,78,46,152,97,129,19,152,10,65,144,11,73,117,194,216,232,40,131,195,67,248,126,224,240,159,48,196,90,216,191,255, - 8,86,75,134,135,187,48,196,120,120,40,27,184,215,232,105,194,246,62,60,47,71,90,47,51,59,121,138,70,45,97,199, - 246,221,28,63,54,202,190,61,71,169,206,59,182,116,154,166,212,203,243,148,242,10,27,25,6,122,122,40,21,139,200,64, - 129,74,209,113,66,79,95,39,171,86,175,224,115,159,189,131,123,239,254,38,231,172,63,151,174,174,18,213,202,44,131,67, - 75,216,187,247,0,158,167,241,130,132,52,54,20,115,221,244,247,119,225,231,19,198,167,78,113,228,240,40,163,99,115,212, - 106,154,82,123,39,57,63,196,214,34,230,39,103,152,175,84,233,236,40,33,209,120,153,191,182,219,248,25,60,101,240,173, - 1,5,49,17,49,113,43,93,85,10,141,18,174,75,77,211,24,41,161,173,84,164,183,183,155,174,206,118,210,36,201,116, - 95,114,193,161,17,50,108,48,91,193,227,54,163,10,133,146,178,21,61,237,198,68,167,217,50,34,3,168,165,200,70,173, - 108,89,209,106,172,79,143,153,118,133,200,129,230,82,40,100,214,237,168,236,239,74,122,40,169,50,204,73,128,72,51,135, - 2,145,25,215,137,22,93,66,102,22,33,113,163,74,177,144,99,221,11,46,147,225,181,151,183,237,139,107,75,226,61,135, - 134,59,45,189,30,132,17,164,101,79,69,126,46,72,87,87,26,102,122,178,204,236,112,15,86,10,34,99,8,172,165,106, - 29,65,245,229,63,241,243,63,216,2,52,166,83,118,102,23,247,36,208,126,188,76,238,206,67,188,225,222,195,236,220,41, - 40,141,119,65,94,49,88,158,102,197,244,24,135,126,136,5,104,67,86,120,78,2,151,128,151,64,123,2,43,115,112,137, - 132,155,107,112,235,168,20,215,153,27,174,89,119,193,223,253,69,207,101,191,251,214,252,208,234,213,194,166,113,203,50,162, - 57,199,187,109,146,104,193,170,34,235,40,76,198,217,240,154,35,142,196,89,74,152,6,113,163,76,220,168,33,133,192,15, - 243,72,229,99,146,152,185,233,9,162,90,5,97,82,140,118,65,115,113,154,34,45,46,19,94,73,70,199,230,249,208,71, - 254,157,36,117,93,68,154,26,210,56,102,227,198,13,36,73,194,220,220,92,166,160,150,45,196,105,96,104,136,225,37,195, - 173,77,138,88,36,136,212,214,224,121,30,94,118,135,116,44,95,71,114,84,153,131,98,189,81,103,122,106,138,129,129,193, - 108,125,235,188,127,218,218,59,177,214,227,240,161,19,84,171,101,86,172,90,138,78,12,74,248,72,101,192,131,124,251,48, - 158,42,18,85,167,137,27,117,254,230,255,188,147,201,169,83,12,14,247,80,43,215,153,155,158,228,196,241,221,236,218,177, - 139,137,137,73,150,45,31,33,213,41,97,40,8,60,223,17,0,173,67,231,140,142,200,229,60,182,92,180,133,35,135,143, - 240,165,47,222,65,190,208,198,224,96,15,194,54,200,229,122,216,182,237,73,86,172,26,68,39,9,214,72,18,211,160,88, - 240,24,234,233,163,187,179,11,107,53,71,78,28,100,239,129,157,104,19,145,247,3,146,56,101,122,126,150,206,142,130,27, - 19,173,117,219,46,43,16,190,202,64,122,72,172,192,88,31,172,135,20,22,107,98,140,9,176,54,196,52,77,245,173,117, - 198,111,153,20,36,73,19,140,209,100,203,242,86,209,144,139,198,34,145,37,158,52,61,168,149,116,93,167,20,77,157,150, - 69,121,94,203,199,89,8,199,106,106,222,48,220,8,230,131,53,25,21,99,209,184,101,221,54,78,54,59,46,139,35,58, - 54,237,177,141,197,247,252,12,163,84,25,83,218,117,106,142,24,155,153,193,42,247,164,141,53,164,141,152,161,129,62,214, - 222,112,173,55,187,102,121,223,190,125,251,151,250,211,229,145,18,116,91,99,101,155,239,55,172,49,245,168,30,235,246,241, - 89,202,147,243,92,121,98,154,59,78,206,240,115,39,103,88,118,114,134,77,191,249,59,63,128,17,236,91,60,252,172,184, - 236,29,173,131,158,228,226,245,43,137,236,217,55,79,5,96,89,86,144,158,227,9,145,41,160,221,253,124,239,167,160,211, - 194,18,13,235,125,56,127,10,46,60,226,123,235,195,235,175,237,191,240,87,126,62,127,238,141,215,202,48,12,177,105,140, - 142,235,25,203,212,158,150,180,41,165,2,19,103,231,218,57,20,54,205,38,69,179,213,198,96,211,24,147,212,72,163,138, - 107,171,189,16,47,95,34,149,57,60,19,83,157,155,165,58,95,70,24,157,141,102,218,109,169,210,166,5,171,32,244,11, - 60,245,212,195,76,77,207,160,188,144,212,52,28,5,223,88,114,185,28,214,66,169,216,70,24,134,173,118,61,8,67,226, - 40,33,110,36,142,222,47,100,118,103,204,146,47,140,88,72,121,200,116,67,198,51,196,73,130,242,90,217,20,244,246,244, - 44,240,75,178,21,176,214,41,74,9,122,123,135,120,234,169,253,168,32,224,133,87,93,76,117,126,194,129,233,132,120,66, - 96,26,53,66,36,183,221,241,21,250,123,114,188,254,199,94,73,154,70,136,53,110,75,103,116,157,19,199,39,57,116,236, - 20,245,40,69,121,30,154,58,164,26,79,231,28,48,171,4,136,0,173,45,82,214,120,227,155,95,194,19,79,236,228,206, - 47,221,201,241,99,199,120,193,213,151,177,254,220,45,60,112,191,230,248,145,41,134,6,122,137,117,140,23,186,142,207,75, - 99,58,218,36,29,237,221,12,175,232,160,161,83,230,230,170,108,219,181,155,217,233,121,82,93,103,229,202,129,204,195,56, - 243,104,150,62,130,16,85,112,145,53,182,150,162,210,4,207,52,0,67,148,122,238,70,35,82,20,34,19,238,186,68,82, - 99,156,83,163,144,153,53,171,36,27,129,132,235,60,180,3,124,129,214,185,114,203,129,102,188,82,214,233,224,196,170,22, - 78,147,74,180,70,173,166,45,73,22,163,172,252,108,3,37,23,162,119,50,115,163,172,163,163,21,71,100,172,93,228,104, - 32,90,9,25,206,184,126,65,38,35,51,246,126,115,175,105,5,212,107,117,132,240,184,244,214,23,137,213,87,94,214,247, - 240,251,62,118,229,248,251,63,189,124,117,181,177,170,163,214,184,39,129,251,47,132,3,59,231,107,181,234,124,205,46,113, - 114,37,214,3,179,207,229,26,254,185,126,212,129,45,192,255,206,10,197,115,253,56,4,28,6,127,47,140,0,151,249,112, - 249,20,156,183,211,87,107,210,27,175,27,188,234,127,252,66,112,249,139,110,32,231,123,24,93,67,235,90,70,18,92,164, - 79,60,51,241,160,229,18,191,144,224,233,128,66,199,227,48,81,133,56,170,101,197,37,193,15,11,168,176,128,80,62,218, - 122,212,202,83,212,102,167,145,214,162,211,20,147,17,204,146,40,118,73,150,190,203,137,210,90,241,232,227,219,72,98,77, - 16,122,104,60,164,108,160,132,79,28,167,132,97,136,181,150,40,138,92,8,97,38,32,77,146,36,139,219,1,109,221,22, - 38,77,93,145,243,148,202,182,52,11,236,89,4,156,56,126,2,207,247,233,31,26,0,11,61,189,189,45,127,161,133,196, - 5,129,84,146,36,53,12,141,172,225,209,71,118,179,100,112,136,53,171,123,73,162,42,194,72,68,90,3,155,176,111,247, - 110,234,243,243,188,225,13,47,162,94,157,65,144,67,83,201,216,185,57,134,87,140,48,180,124,136,36,169,64,154,3,36, - 158,116,121,33,90,104,231,25,40,66,23,29,100,83,26,81,149,139,46,218,196,154,213,171,184,227,75,95,229,95,255,245, - 189,92,180,101,23,107,86,159,203,158,29,219,25,236,27,6,17,115,226,228,60,163,51,101,218,58,67,218,243,237,116,149, - 138,180,151,138,4,34,33,239,215,25,238,210,76,79,205,80,141,34,210,52,6,225,186,8,41,221,152,114,114,116,156,79, - 127,230,118,110,121,237,107,57,127,195,16,186,92,37,170,186,124,52,165,12,130,26,70,72,132,8,50,198,53,248,74,144, - 26,237,28,2,172,113,221,135,176,173,209,215,100,95,211,90,59,135,69,156,48,24,32,77,12,94,224,57,6,181,21,40, - 229,116,120,58,43,140,142,62,101,23,34,118,140,105,221,240,36,194,17,21,155,140,104,235,70,54,151,31,183,128,31,25, - 187,40,245,3,131,54,73,214,253,56,125,153,151,101,192,11,156,31,146,64,57,83,53,33,50,61,95,147,34,144,82,155, - 159,165,61,23,240,162,223,249,101,127,255,77,55,173,120,234,79,255,166,123,217,99,79,13,116,67,127,29,238,91,3,79, - 143,192,84,29,210,31,8,15,232,7,241,240,128,227,192,19,56,215,181,231,74,102,150,41,119,69,8,221,22,174,138,225, - 199,238,246,197,101,83,87,93,212,251,226,223,248,53,117,253,139,111,33,244,60,76,218,192,234,104,65,108,105,113,41,18, - 139,131,229,22,100,218,88,161,178,194,211,76,182,52,78,65,173,35,162,242,28,166,81,113,216,143,159,71,228,219,32,44, - 97,132,135,50,160,27,101,202,83,167,28,215,71,39,217,29,70,56,47,31,41,145,194,195,24,167,171,154,158,169,179,227, - 233,189,248,185,208,17,5,147,20,129,197,247,20,133,124,17,173,83,188,76,94,209,244,239,177,205,162,150,69,242,72,41, - 241,60,143,70,189,209,98,222,106,227,86,193,173,13,77,150,47,222,136,234,244,233,94,4,206,200,94,107,221,42,64,158, - 231,161,124,223,69,189,56,110,49,131,35,203,185,253,43,95,231,205,111,120,9,61,29,69,44,9,73,109,26,99,12,79, - 62,177,141,205,155,55,146,36,77,95,194,8,95,228,92,241,147,130,122,162,241,101,72,177,80,36,170,215,81,162,136,69, - 160,213,52,158,103,65,75,140,141,81,184,149,184,53,146,168,214,160,152,151,188,238,199,110,229,208,161,81,190,252,149,175, - 115,247,93,15,18,122,138,11,183,172,162,171,167,200,71,63,248,97,187,245,51,95,73,214,244,150,76,111,88,50,229,190, - 222,176,184,126,141,58,247,210,243,185,240,130,117,12,245,20,24,26,30,160,222,112,91,31,33,36,202,83,153,154,220,210, - 222,86,98,207,206,221,236,255,242,111,38,151,222,112,149,186,241,77,175,147,203,70,122,168,85,230,193,72,148,113,26,183, - 200,102,242,153,76,49,239,216,201,105,54,138,201,214,104,212,196,120,76,162,209,166,105,117,226,198,42,173,93,103,105,180, - 113,239,169,44,245,212,117,56,246,180,104,103,215,58,45,176,233,155,93,145,75,69,37,115,175,116,203,4,169,156,59,163, - 181,26,147,69,48,139,204,123,201,104,235,54,182,210,69,55,233,108,116,84,202,91,40,106,198,56,220,72,169,140,63,229, - 192,109,149,17,34,211,52,193,206,204,112,206,133,107,89,254,137,119,182,63,242,79,31,184,236,224,59,63,208,179,162,17, - 47,1,238,11,225,225,126,56,122,171,11,167,108,93,207,63,20,12,168,55,27,123,150,3,221,192,191,2,61,197,14,46, - 237,29,33,18,226,25,24,16,192,41,160,19,23,228,183,18,231,177,211,200,100,16,223,207,71,195,49,153,101,27,44,53, - 112,235,126,120,113,254,247,126,123,240,173,239,123,167,60,103,195,58,72,106,24,19,211,116,201,19,50,19,141,46,10,150, - 91,28,24,215,76,62,48,25,2,36,5,72,171,177,105,132,169,149,137,42,179,68,213,50,146,132,32,8,81,249,118,200, - 119,160,113,6,240,202,104,170,83,99,36,213,10,214,56,51,47,164,92,224,142,180,230,118,67,24,150,216,246,212,65,62, - 119,251,151,209,8,226,212,117,50,82,24,148,244,24,28,28,162,90,173,146,36,73,166,94,135,52,141,105,111,47,81,106, - 239,96,112,112,8,47,195,17,140,214,204,77,207,16,6,65,203,106,85,52,59,59,107,241,149,211,143,149,43,101,186,187, - 187,168,84,202,140,143,143,83,42,149,220,27,46,73,48,64,172,83,154,214,23,82,57,142,75,163,30,115,96,223,97,46, - 187,228,18,226,164,138,16,154,3,123,199,248,240,135,190,192,181,215,189,16,223,115,223,175,132,139,148,110,254,222,32,200, - 243,192,3,223,228,228,196,52,203,55,174,198,16,97,76,13,79,88,20,37,192,199,11,156,53,171,181,26,37,125,172,17, - 238,98,53,150,246,206,18,151,92,118,46,43,87,13,211,168,205,179,122,213,114,188,98,158,169,39,118,233,155,31,223,62, - 126,109,165,177,115,253,220,252,211,203,79,142,77,136,237,79,199,251,238,190,87,124,253,129,111,122,135,15,159,82,34,223, - 70,190,187,141,192,47,96,82,71,53,182,56,147,181,158,222,62,214,12,173,48,171,62,250,133,164,99,219,46,238,186,239, - 126,83,238,108,147,203,54,110,20,18,141,212,25,195,93,57,156,78,96,178,205,149,204,54,84,11,162,204,214,184,147,145, - 244,154,197,164,89,128,90,235,115,165,144,202,59,205,92,77,74,47,219,106,57,224,218,102,226,81,129,43,46,82,218,108, - 11,237,181,164,46,94,107,228,118,62,220,82,101,110,147,25,77,180,233,229,228,249,62,65,224,103,108,124,215,121,57,44, - 203,100,210,25,215,77,53,77,236,90,64,186,84,25,171,27,164,53,52,226,10,202,19,172,186,241,133,42,58,127,67,223, - 222,71,30,29,41,205,213,122,67,80,101,152,223,12,101,1,73,4,44,125,219,219,158,191,5,104,60,251,119,219,128,23, - 3,251,129,92,86,68,244,247,241,145,56,182,131,232,114,78,132,235,36,172,46,231,219,59,123,175,186,74,245,118,117,183, - 14,238,66,116,174,204,76,157,108,139,7,198,162,216,149,197,198,222,2,11,38,193,52,230,73,107,243,196,245,42,58,137, - 241,124,69,144,43,161,114,29,200,92,59,86,6,174,179,209,154,168,60,77,52,63,135,53,41,137,78,91,119,134,36,137, - 51,31,95,137,18,78,45,237,7,37,62,253,153,47,179,99,247,94,132,39,73,83,227,46,62,157,98,181,165,183,183,159, - 32,240,93,17,3,226,36,194,247,61,148,39,201,23,139,12,12,12,18,134,1,74,10,226,70,131,153,217,25,74,109,165, - 204,145,207,1,210,2,119,65,75,41,169,215,234,76,79,79,211,209,222,65,20,69,84,170,21,242,249,60,73,146,32,148, - 114,14,50,217,103,173,181,83,170,251,146,131,7,142,114,244,240,9,70,134,251,24,25,233,167,222,136,249,236,109,247,242, - 133,219,239,181,227,147,147,246,170,107,46,22,70,39,89,132,112,132,16,62,18,69,41,95,96,106,42,226,111,255,224,239, - 141,61,62,97,251,87,111,20,29,221,157,40,13,54,13,156,207,178,202,116,75,77,2,103,6,176,198,113,138,242,5,73, - 18,209,222,86,224,188,205,235,81,50,65,134,30,39,31,221,101,58,30,223,177,43,116,180,175,47,21,224,169,101,112,112, - 147,182,199,214,77,206,141,182,109,219,53,123,242,142,187,204,211,79,110,15,170,94,222,107,95,177,78,180,183,119,96,83, - 221,186,80,251,134,134,197,209,71,182,177,98,116,44,218,56,95,157,62,118,239,55,27,219,43,149,220,240,69,151,200,246, - 146,71,156,206,131,240,90,248,152,204,58,3,107,51,183,1,227,120,60,77,140,167,233,119,36,165,204,162,178,29,251,76, - 41,185,16,13,155,45,10,164,204,198,160,236,66,111,74,6,29,107,221,165,152,98,44,86,184,116,18,229,57,221,97,115, - 141,191,248,103,54,109,81,140,209,25,55,75,162,148,199,212,212,12,199,142,31,39,73,52,93,93,189,20,10,237,88,235, - 225,41,191,165,49,107,254,91,23,86,96,22,109,218,50,66,43,26,169,242,206,21,179,49,199,242,13,171,233,186,233,166, - 210,131,79,63,61,28,30,31,239,233,0,149,56,190,208,124,47,196,67,111,123,219,243,119,4,107,221,9,50,240,250,1, - 96,45,240,170,53,43,145,97,232,248,41,223,75,125,148,146,122,185,98,211,19,39,79,73,184,175,23,66,190,124,199,245, - 255,120,205,182,115,47,253,139,63,41,189,241,205,63,142,34,70,39,213,150,8,112,97,173,105,221,217,207,236,11,108,54, - 79,59,115,246,24,29,85,208,245,26,186,81,93,24,159,188,128,48,95,64,132,29,224,231,29,144,104,65,144,146,68,21, - 170,243,115,45,221,148,144,2,171,29,17,77,103,134,237,205,45,135,20,130,70,148,178,119,239,33,151,78,33,83,144,10, - 147,56,64,51,142,99,170,149,50,29,157,157,24,107,168,204,149,209,58,37,232,238,106,49,97,141,209,132,97,128,213,134, - 122,189,230,180,77,74,182,212,211,58,251,221,178,201,164,21,144,36,9,149,74,133,122,189,78,177,88,92,192,30,22,105, - 102,141,78,177,169,135,111,37,229,104,134,35,39,142,114,238,218,77,220,123,223,253,172,95,183,132,253,123,70,57,116,100, - 154,141,107,86,26,241,137,207,148,111,31,110,235,120,249,79,189,74,216,250,52,146,46,172,6,45,171,36,54,101,100,100, - 41,175,8,84,188,241,35,95,168,238,253,242,131,118,246,103,222,216,177,226,199,110,240,11,237,17,34,138,177,186,13,76, - 1,107,99,16,117,132,72,200,231,139,236,217,125,152,157,187,246,242,19,111,122,5,181,250,28,113,84,7,163,240,108,129, - 40,74,45,48,7,236,177,240,144,15,186,14,29,30,116,23,160,167,4,35,75,27,233,186,232,225,167,55,158,124,108,247, - 198,219,207,253,226,138,252,141,47,40,92,116,227,229,172,94,210,139,213,41,65,201,67,191,248,74,255,240,227,91,103,214, - 192,225,203,82,91,63,252,193,207,45,253,244,99,59,151,109,250,213,159,204,95,126,213,5,248,141,50,73,156,100,9,166, - 54,99,60,123,25,197,126,193,186,214,247,61,148,148,36,81,228,248,62,86,144,232,20,79,153,150,32,217,225,52,167,167, - 184,182,44,245,237,98,91,219,76,47,47,133,147,50,89,73,20,167,25,111,200,203,206,143,110,42,104,157,5,136,92,196, - 1,178,78,30,210,209,217,133,69,242,205,111,62,198,39,15,221,206,154,213,235,184,224,130,243,105,235,110,39,95,244,40, - 20,10,248,210,221,112,146,216,121,133,59,174,216,130,127,139,38,64,89,75,206,226,88,231,147,83,12,15,247,240,186,143, - 189,179,248,201,63,252,203,203,226,15,124,161,125,9,20,186,193,36,176,29,168,63,247,5,200,146,9,13,5,207,85,148, - 152,201,112,160,49,224,43,253,125,204,108,62,151,174,158,30,12,180,192,211,239,92,233,26,144,236,217,107,87,125,234,179, - 243,231,192,19,85,152,235,133,137,87,157,56,57,245,165,159,253,239,151,60,246,181,123,251,127,230,183,127,157,243,206,57, - 7,72,177,182,138,209,73,214,146,11,240,146,108,26,203,185,243,29,213,137,230,231,169,215,103,93,38,148,21,110,87,32, - 12,129,231,225,23,125,100,62,135,48,29,238,46,164,18,231,110,152,132,232,234,44,38,213,104,75,118,23,116,109,182,214, - 137,203,231,82,77,63,22,141,31,230,217,179,239,48,7,15,31,192,147,57,103,195,160,117,6,110,250,104,171,105,36,41, - 189,65,72,17,231,37,236,251,33,190,23,18,4,5,164,80,212,171,53,68,175,3,64,157,209,216,194,69,161,117,38,139, - 200,18,19,92,70,188,3,45,171,149,10,213,122,149,238,30,103,47,234,186,51,55,22,26,1,158,239,17,39,154,36,181, - 28,63,58,74,95,119,23,202,179,76,207,215,185,239,193,157,204,205,84,233,94,210,77,116,106,55,47,129,220,248,59,62, - 24,223,221,217,21,220,242,186,91,69,50,119,10,148,135,79,9,105,37,29,29,17,43,194,180,214,3,79,119,79,78,29, - 159,249,171,127,24,217,122,207,215,206,89,250,43,111,236,93,118,233,133,120,34,135,174,213,92,232,30,10,67,74,148,148, - 89,189,98,132,191,248,155,247,50,173,125,126,230,45,47,67,86,29,238,148,164,30,179,115,53,177,44,75,203,243,33,250, - 123,168,253,24,204,215,225,100,59,120,62,20,2,231,203,189,114,185,54,23,13,111,219,121,201,161,109,59,55,125,249,179, - 159,95,90,184,229,134,252,245,175,125,57,27,58,218,88,127,227,53,60,254,206,15,229,245,116,57,74,225,209,165,240,68, - 207,211,251,207,219,241,43,127,188,233,99,111,120,197,240,205,191,240,122,213,91,8,73,234,21,148,13,157,75,161,15,202, - 198,32,36,146,16,223,151,236,216,190,23,223,111,99,243,133,231,17,37,51,152,40,65,105,133,39,116,230,9,21,128,20, - 232,36,109,185,73,186,162,147,96,154,182,45,74,181,240,31,33,157,231,135,77,45,86,57,5,190,78,242,116,246,14,80, - 77,43,40,147,34,18,75,98,157,24,217,36,206,176,77,91,183,1,13,124,144,194,167,191,119,128,87,189,252,165,236,220, - 181,155,183,191,227,159,249,219,183,255,189,61,167,123,64,247,118,180,201,225,85,171,200,47,25,22,157,157,29,98,253,198, - 245,116,46,233,161,20,122,4,197,144,124,144,119,72,145,1,235,187,27,87,65,135,40,235,209,16,208,217,83,228,13,239, - 248,43,245,129,246,190,115,27,239,254,104,178,58,110,28,10,225,72,179,0,137,231,16,227,117,107,232,36,114,219,158,231, - 120,125,46,129,39,30,124,132,244,193,71,184,165,179,147,183,175,90,197,202,222,94,82,192,51,250,59,250,57,218,83,20, - 199,79,177,6,236,131,80,94,15,187,125,40,123,48,254,234,56,62,245,228,7,62,116,229,223,125,249,171,203,250,94,245, - 178,252,117,175,125,37,215,93,117,57,249,176,132,181,115,78,179,147,6,88,34,226,122,149,202,220,20,245,202,73,108,195, - 93,176,94,16,226,169,28,72,139,23,128,231,229,240,189,65,87,144,189,6,72,141,16,121,182,62,190,27,79,39,172,94, - 94,114,153,88,102,33,165,50,77,210,204,103,199,3,163,157,225,148,181,72,229,243,212,246,167,169,215,27,72,175,13,171, - 117,102,239,96,49,110,209,66,189,81,71,72,153,97,64,30,185,92,142,32,8,73,226,196,197,23,27,67,26,39,196,73, - 66,20,69,132,97,216,178,90,245,148,215,242,126,110,102,72,181,214,237,88,226,56,162,80,200,19,199,206,211,198,233,151, - 60,71,48,139,99,132,176,196,137,165,90,174,51,50,52,76,20,53,40,181,117,113,223,55,30,165,222,104,112,222,249,231, - 50,174,149,72,160,182,57,181,243,143,253,245,187,218,30,235,42,117,95,114,203,229,34,173,52,32,81,24,25,227,21,75, - 200,124,71,156,50,179,195,74,238,106,183,116,151,30,217,121,249,232,127,251,189,45,135,174,190,116,101,215,155,94,221,177, - 250,178,245,180,11,73,28,91,82,91,192,143,35,6,7,218,184,238,234,139,237,29,127,255,47,186,61,158,151,175,253,201, - 215,72,223,143,105,152,148,106,181,134,128,192,56,83,8,249,112,198,1,219,3,122,35,232,21,16,245,194,220,78,56,209, - 7,251,125,216,190,14,182,172,62,56,122,209,158,119,126,120,237,55,110,255,218,240,137,87,190,164,125,203,207,254,184,232, - 127,221,43,75,179,239,254,80,169,13,142,196,240,100,14,30,187,34,73,175,222,247,161,219,94,240,222,39,182,158,115,245, - 111,252,82,120,229,69,235,208,209,156,179,242,208,30,66,120,248,138,140,119,229,156,12,254,252,143,255,214,252,196,229,87, - 214,174,121,229,11,67,127,197,144,111,83,13,73,197,157,79,98,132,245,91,145,211,218,58,111,33,79,132,46,11,77,8, - 140,145,11,221,144,112,238,142,214,6,36,86,211,222,222,197,195,95,127,154,233,250,94,70,54,44,165,171,179,68,87,80, - 164,80,242,240,177,232,68,99,116,66,170,147,44,214,59,193,10,227,168,4,82,113,225,249,235,249,231,119,253,61,31,248, - 192,199,236,204,59,62,208,120,113,66,88,127,124,167,152,130,186,133,153,3,158,31,197,189,237,121,57,212,87,202,15,244, - 250,221,93,189,150,124,65,106,15,225,231,124,26,113,34,210,68,136,40,182,162,166,181,80,57,161,148,178,178,160,125,142, - 118,150,250,151,159,106,116,10,199,200,193,211,139,52,42,223,119,167,34,21,65,146,176,121,231,3,168,36,250,129,140,100, - 194,97,56,44,153,157,101,199,19,79,224,175,92,201,165,235,215,49,154,47,226,39,201,183,237,186,140,231,225,123,62,5, - 224,239,129,235,161,241,135,112,100,43,84,27,48,113,17,28,222,52,54,118,241,142,127,254,215,141,31,253,200,39,134,63, - 245,194,23,22,110,250,137,31,231,250,155,46,101,160,171,155,164,82,229,212,177,253,68,245,58,58,173,97,68,10,66,226, - 217,60,8,65,24,8,148,50,120,42,36,8,123,17,170,4,54,198,120,21,148,232,228,201,39,182,242,207,127,247,65,254, - 247,31,253,12,86,85,80,34,135,162,66,108,155,137,74,11,138,116,99,28,111,68,10,73,146,194,182,167,158,206,146,33, - 88,72,86,0,140,73,65,26,146,164,129,53,9,81,92,199,247,21,160,49,54,205,70,170,148,122,189,158,229,77,185,181, - 124,144,249,251,52,199,5,167,144,23,45,207,104,128,192,119,49,47,190,231,103,29,83,102,33,225,172,11,221,198,204,243, - 65,107,142,30,58,72,169,173,216,2,84,133,16,116,116,180,211,209,217,65,26,43,84,216,41,82,24,53,240,196,249,213, - 70,238,208,31,252,237,69,79,21,255,96,213,249,215,93,33,146,169,57,18,157,71,22,3,212,208,128,210,219,15,207,43, - 196,30,35,152,53,214,238,29,210,118,71,116,239,195,23,159,120,232,209,243,199,206,95,183,180,235,229,47,111,95,253,162, - 43,68,79,41,79,82,241,41,91,201,171,111,125,161,221,248,190,79,234,218,63,124,216,124,106,223,17,239,210,95,253,111, - 114,229,186,62,130,66,160,44,120,10,100,10,66,122,138,255,91,12,185,38,78,145,245,152,62,87,140,204,19,80,253,125, - 56,180,31,78,85,97,175,128,39,206,133,245,201,209,209,115,103,254,225,223,206,125,236,190,251,87,207,14,247,23,151,64, - 93,193,116,10,251,82,56,96,224,248,42,24,239,222,121,160,250,185,95,255,223,23,236,251,169,215,151,222,240,166,91,241, - 61,75,28,37,120,228,144,120,136,32,161,30,85,217,176,121,35,231,93,112,142,173,124,240,227,250,196,231,190,24,249,55, - 191,48,237,252,137,87,230,58,214,12,8,17,105,116,212,128,36,1,153,102,17,105,46,225,213,26,144,66,97,132,108,197, - 221,139,204,122,54,53,26,105,37,82,248,8,242,12,140,172,225,61,63,253,139,201,13,105,61,153,238,235,150,141,174,110, - 149,95,187,214,27,220,184,94,244,175,24,97,201,146,126,58,219,114,132,129,165,16,148,48,217,150,20,43,136,26,41,190, - 87,224,23,126,225,151,229,189,203,55,22,239,251,179,191,49,151,159,154,176,23,65,57,130,167,72,147,29,140,77,233,116, - 108,170,207,64,91,234,80,133,86,146,116,152,33,88,6,2,235,188,208,187,50,71,160,74,30,182,106,41,247,42,225,188, - 236,213,139,151,174,19,205,20,200,239,235,67,41,66,157,226,237,124,128,115,230,38,233,200,212,228,223,207,22,172,23,120, - 20,184,52,91,199,55,181,90,2,56,31,248,48,176,105,118,150,63,59,118,156,253,198,80,238,237,117,140,228,111,225,3, - 98,165,196,171,84,216,116,242,36,95,7,206,3,86,128,249,18,212,150,194,120,10,71,20,28,29,129,83,23,71,81,165, - 125,207,30,253,224,231,110,247,63,249,149,123,195,121,191,32,214,174,94,74,163,122,16,17,73,156,223,118,128,17,78,135, - 19,248,142,206,46,101,72,174,212,133,42,118,160,101,10,94,29,37,251,184,247,158,199,245,47,191,241,231,163,11,182,108, - 244,94,250,170,43,132,49,57,68,90,192,36,51,36,38,33,73,13,198,56,98,159,109,234,115,16,72,79,50,51,23,241, - 177,143,127,142,249,114,29,169,194,150,126,168,169,138,22,210,97,11,195,35,195,84,202,101,146,36,33,78,92,183,146,203, - 231,40,20,74,228,139,37,250,250,250,91,152,78,46,151,35,151,203,157,230,78,208,36,162,57,16,186,70,163,222,192,90, - 71,74,108,235,232,68,8,209,50,44,203,96,119,60,47,192,232,148,167,182,61,201,146,165,75,90,155,65,169,20,129,23, - 226,41,143,48,204,49,55,53,46,250,247,238,58,220,109,184,67,195,99,157,81,194,145,7,30,239,143,54,109,236,24,94, - 61,76,18,205,33,61,143,234,227,59,35,182,239,123,82,89,30,46,88,142,90,24,175,101,231,165,215,216,147,157,39,38, - 231,167,238,126,64,60,177,125,87,219,76,247,176,223,183,118,25,129,151,208,222,214,43,78,126,253,97,214,142,77,84,139, - 251,143,206,222,245,245,251,189,249,225,165,126,189,28,137,182,199,183,141,118,194,55,107,176,111,255,210,222,248,134,151,92, - 140,89,210,203,138,147,211,244,68,9,51,64,21,208,171,151,216,125,133,48,233,105,196,179,210,152,227,53,56,32,224,64, - 9,78,20,199,39,199,242,251,143,28,42,193,99,10,30,213,112,34,7,101,13,211,26,38,11,80,63,55,74,228,177,71, - 159,108,187,251,192,201,226,208,5,231,139,190,238,18,58,78,193,170,44,119,76,18,248,121,180,240,101,253,174,251,88,87, - 139,166,234,59,247,28,63,126,215,125,241,201,169,185,92,95,111,191,144,253,93,210,10,139,48,54,211,214,57,50,163,208, - 110,60,246,164,135,20,94,198,168,118,157,144,242,220,6,214,74,103,96,56,48,178,18,253,196,86,125,209,238,253,51,107, - 103,202,187,87,158,60,245,116,251,142,93,19,115,247,220,95,59,246,149,187,211,167,190,118,31,15,60,252,184,183,239,216, - 184,56,49,17,83,77,61,252,124,158,66,123,59,126,222,177,216,173,110,176,225,220,13,162,235,186,203,229,103,246,238,146, - 246,196,68,60,12,71,19,120,60,133,135,44,60,98,224,9,31,30,43,192,163,1,60,18,102,31,121,120,196,135,199,61, - 216,25,194,174,188,235,22,191,33,224,94,223,218,237,135,172,157,217,244,182,183,25,245,146,21,231,56,127,145,239,241,67, - 72,1,65,192,188,73,97,251,253,12,206,79,209,151,97,54,63,140,2,180,18,120,181,214,148,38,39,41,38,9,7,187, - 58,91,6,234,223,174,0,125,3,216,12,228,129,29,96,127,22,226,131,48,171,225,164,128,131,22,14,247,192,177,243,77, - 58,179,124,116,212,124,253,11,119,228,239,124,234,80,126,217,69,235,24,236,107,39,137,28,211,85,18,226,7,41,82,20, - 193,20,201,183,43,194,206,14,180,42,146,98,240,85,192,189,119,61,200,87,222,244,179,213,181,227,39,167,110,253,223,191, - 218,182,124,245,106,169,100,55,245,250,52,81,189,74,28,107,180,112,185,230,82,169,69,32,166,196,247,124,246,29,28,227, - 246,59,238,67,27,151,81,165,141,201,120,59,182,101,222,174,60,197,64,127,63,73,146,16,134,97,139,88,88,200,231,105, - 107,239,192,243,3,6,7,7,169,84,42,204,205,205,209,222,222,222,250,190,166,61,135,148,110,11,150,38,9,245,122,157, - 90,173,70,28,199,88,225,128,74,99,140,219,130,9,129,54,218,89,148,134,1,7,15,236,227,228,137,227,12,15,15,83, - 40,20,1,137,209,6,147,26,124,207,35,159,11,153,26,61,70,207,238,221,227,253,134,251,45,60,2,204,245,214,27,109, - 187,190,241,80,95,99,243,154,210,200,234,97,172,81,212,183,29,142,147,199,182,61,225,195,19,59,96,186,0,105,23,148, - 171,48,30,9,14,43,193,145,94,152,30,56,62,158,238,190,243,238,226,131,251,15,149,114,131,35,98,120,195,57,76,157, - 154,162,246,224,35,199,122,96,219,218,249,250,232,182,187,31,236,248,242,216,104,225,220,70,116,178,95,235,7,124,216,183, - 175,171,20,7,107,6,201,21,67,70,67,159,205,135,79,49,3,204,0,135,54,44,231,67,29,121,57,210,209,97,143,143, - 79,197,1,148,115,112,202,194,97,96,79,0,79,120,240,100,93,136,163,58,80,245,131,66,216,47,26,155,92,15,179,21, - 24,19,48,177,222,82,111,63,116,212,191,247,193,199,59,146,145,149,254,202,117,43,193,68,24,237,52,88,88,75,123,87, - 7,163,247,127,179,209,55,53,191,61,128,123,219,106,141,253,114,235,174,74,245,174,175,219,164,26,133,114,100,73,40,59, - 219,178,248,69,7,40,123,74,183,54,175,205,121,64,168,166,215,143,51,169,55,194,45,37,242,249,2,39,103,102,100,124, - 223,67,39,74,136,175,74,248,98,9,158,88,1,79,175,77,210,189,235,102,203,199,87,30,25,157,146,143,110,175,142,223, - 253,141,248,208,61,247,153,167,190,122,143,61,240,228,14,230,199,103,68,106,60,225,229,138,104,1,75,150,143,112,201,43, - 95,204,214,208,43,28,222,177,163,115,56,210,70,194,9,3,79,3,251,103,225,216,1,56,49,14,39,230,225,196,180,251, - 56,94,132,99,2,14,249,176,199,135,157,13,120,58,129,35,67,48,247,215,160,223,248,182,183,225,9,249,125,64,197,82, - 210,240,2,134,70,15,145,28,218,201,88,117,158,149,63,34,211,176,26,112,245,161,67,220,118,242,36,226,242,203,88,210, - 209,65,242,221,2,212,192,0,104,237,214,132,149,125,48,154,194,118,3,143,117,193,133,111,49,233,165,7,238,252,220,249, - 31,219,241,224,234,235,255,248,55,11,215,94,117,1,113,89,59,169,187,9,176,214,195,47,6,228,218,219,209,170,13,132, - 36,39,75,124,225,75,119,114,255,79,255,82,114,235,248,132,255,200,138,165,253,43,55,111,86,66,150,72,210,136,90,99, - 14,99,5,214,74,200,172,54,155,160,176,187,187,73,60,21,114,114,116,130,212,56,150,181,209,169,115,198,75,77,166,60, - 119,164,182,52,77,169,214,106,52,50,15,231,92,46,68,8,168,55,26,89,102,151,243,140,158,154,158,98,110,110,142,129, - 129,129,5,155,212,108,164,211,70,163,50,207,155,52,117,164,198,106,181,130,231,251,36,113,130,206,120,63,90,107,242,249, - 60,169,209,68,81,196,83,219,183,227,73,65,165,90,161,84,106,39,8,66,26,245,26,105,154,96,140,231,112,138,92,136, - 17,228,51,130,123,213,131,71,19,40,108,158,156,11,182,255,250,159,95,227,255,253,255,238,63,247,134,23,210,144,70,130, - 75,201,121,8,196,91,193,222,13,118,9,212,102,45,117,96,178,33,196,49,15,14,92,147,166,7,199,239,184,247,138,39, - 239,121,96,237,209,87,221,218,21,172,88,45,165,146,149,78,109,190,14,204,223,92,111,28,89,115,108,236,188,46,216,149, - 194,148,5,253,226,137,57,246,221,189,29,5,36,229,6,201,162,243,159,79,13,129,48,70,9,56,1,244,129,93,14,141, - 163,48,30,193,196,90,144,135,193,204,251,210,188,125,197,32,7,106,49,155,142,79,48,15,209,52,28,233,132,57,5,199, - 151,193,161,225,67,199,175,121,236,55,254,232,162,175,253,226,79,12,190,224,167,94,169,2,79,19,55,98,132,214,116,117, - 21,232,190,228,60,191,190,247,120,84,128,29,177,146,7,75,218,12,218,153,249,205,245,127,251,216,150,185,207,127,229,156, - 220,143,191,108,73,223,107,94,150,207,181,21,33,174,97,50,224,88,217,108,3,108,29,7,72,169,192,57,88,26,231,221, - 108,132,32,169,85,24,222,114,190,216,147,15,252,161,70,50,223,64,108,75,5,147,214,216,64,64,187,133,158,60,12,110, - 132,193,77,38,237,53,19,211,131,241,196,116,87,125,247,225,82,237,243,95,27,56,224,121,67,71,6,7,11,233,178,193, - 112,186,183,35,23,172,90,233,47,61,247,60,30,127,237,107,6,30,250,208,39,94,116,101,172,27,10,198,139,48,243,105, - 136,62,212,215,205,96,123,27,7,14,30,109,221,252,127,215,65,28,81,46,107,36,174,200,232,53,197,214,240,254,253,48, - 161,133,36,108,212,8,14,63,206,227,227,71,88,251,28,225,72,223,239,163,22,69,60,241,205,135,185,229,242,203,232,250, - 30,139,144,7,12,131,57,8,213,21,80,59,8,147,9,28,154,23,114,247,10,107,47,93,118,124,226,202,135,126,227,109, - 91,202,191,242,203,3,183,254,216,11,105,164,117,148,113,166,233,165,206,78,164,215,71,66,153,128,28,159,249,216,167,120, - 232,215,126,179,114,203,196,116,53,133,98,254,130,11,242,189,67,75,49,186,76,101,126,28,27,57,5,181,54,41,70,91, - 252,64,185,13,136,118,43,82,109,44,105,170,217,127,240,176,75,193,96,193,71,88,32,72,181,65,41,71,92,75,226,20, - 107,156,245,66,18,167,248,126,64,177,88,36,31,58,249,130,231,121,142,207,83,169,180,186,35,173,77,198,204,21,89,2, - 170,201,220,236,154,210,15,141,214,154,98,91,137,40,170,103,250,38,183,190,215,58,37,151,207,241,248,147,79,114,248,208, - 97,150,45,91,74,165,82,71,14,73,192,9,92,141,78,73,211,8,131,34,150,109,52,82,81,144,216,206,216,193,242,39, - 21,124,221,3,177,121,114,142,253,191,246,167,215,242,119,165,190,153,184,33,187,93,60,149,120,11,240,242,204,175,169,238, - 220,41,237,16,212,235,214,30,30,133,153,72,136,163,157,214,238,185,161,145,108,153,253,216,231,54,77,75,217,222,5,219, - 53,108,87,176,47,129,61,171,140,89,38,92,103,187,207,135,248,162,106,196,37,7,198,91,55,175,33,224,224,34,166,188, - 56,203,242,35,155,108,116,7,232,70,246,30,241,172,68,90,129,201,58,247,127,129,244,245,48,85,133,39,187,221,181,118, - 228,170,36,57,122,236,29,31,184,242,246,3,251,55,92,249,91,191,144,31,233,233,163,81,157,69,10,205,210,27,94,16, - 158,250,212,87,250,243,113,154,151,150,195,8,177,211,90,187,35,132,39,194,83,83,23,215,254,254,253,151,237,251,210,125, - 155,251,222,242,250,129,190,235,174,240,115,93,3,136,70,13,97,83,36,22,147,166,238,153,25,157,73,187,36,224,12,225, - 172,110,48,178,106,5,187,54,172,239,74,158,220,62,4,20,123,44,7,31,2,221,11,19,75,224,112,23,132,51,144,143, - 17,5,129,237,244,160,216,14,133,18,44,85,105,122,142,62,126,124,40,61,126,220,31,0,111,30,218,27,208,115,89,46, - 223,145,211,4,13,33,86,230,172,93,86,129,29,63,37,68,237,215,63,245,46,214,94,123,13,47,125,201,143,243,197,47, - 221,115,26,141,166,150,25,252,93,189,232,152,126,207,82,140,102,247,55,170,35,186,142,236,100,213,232,17,118,192,115,182, - 114,127,46,120,67,68,17,247,126,243,97,174,187,252,50,58,59,58,90,196,188,239,5,240,14,192,182,67,180,27,78,46, - 179,102,182,140,56,26,192,209,107,103,235,149,187,255,234,237,47,188,179,144,239,187,233,213,215,17,71,51,20,114,125,248, - 133,54,12,49,129,24,224,99,239,127,55,123,126,229,183,199,95,90,105,60,29,184,147,176,118,217,11,175,42,42,124,234, - 177,38,169,205,227,153,186,179,68,85,202,217,36,32,72,18,237,232,241,64,16,228,72,146,148,39,183,62,69,35,74,240, - 61,129,177,41,24,213,98,164,57,129,161,19,192,234,212,129,195,133,66,129,48,8,72,19,195,124,92,163,119,64,58,14, - 84,163,65,173,90,35,23,132,217,136,119,198,5,39,197,105,120,16,64,18,199,36,73,12,130,76,107,102,90,65,127,179, - 179,179,220,127,255,55,72,210,148,249,185,121,226,40,198,247,67,146,36,38,142,99,226,36,194,226,145,198,101,148,138,137, - 124,169,68,172,125,235,8,9,169,239,64,233,123,37,232,181,147,51,122,247,175,252,246,213,39,7,10,225,53,80,21,160, - 119,0,247,1,31,3,126,43,3,56,243,110,148,215,255,2,211,55,88,91,85,112,60,22,98,91,27,118,77,187,49,69, - 11,199,37,236,170,194,120,23,140,213,97,123,10,166,46,101,237,27,195,189,122,133,239,157,150,95,158,19,130,227,99,83, - 20,234,17,241,183,120,47,136,51,254,44,206,120,223,231,28,152,109,39,160,254,98,56,44,97,38,129,227,35,48,154,255, - 210,3,47,186,227,196,196,69,235,127,253,87,74,87,93,184,14,157,206,227,15,245,49,223,221,217,63,56,54,57,130,49, - 185,57,24,87,80,109,131,113,33,196,254,146,181,187,114,251,14,93,89,253,253,191,188,120,124,211,186,181,226,101,47,238, - 94,243,226,27,188,222,193,110,68,92,65,103,90,178,38,107,217,136,24,35,20,34,219,156,182,21,187,105,223,114,65,169, - 241,228,246,21,121,88,90,135,253,151,64,101,22,204,16,152,149,144,252,37,84,126,222,90,49,5,199,43,32,102,92,154, - 111,41,129,135,45,116,20,192,203,131,44,66,73,66,31,141,122,95,10,131,218,109,196,70,243,136,184,108,45,203,239,126, - 16,174,125,5,27,54,110,56,173,0,125,39,55,251,239,234,130,180,22,166,106,85,198,100,76,199,98,178,220,243,236,209, - 136,34,190,254,205,135,121,225,229,151,225,117,118,226,125,7,27,178,179,233,198,196,130,67,162,189,20,170,59,176,251,231, - 161,170,133,240,175,141,211,206,47,252,237,187,175,28,216,60,84,218,114,241,58,114,94,63,34,168,33,100,59,31,124,199, - 59,25,251,173,223,61,126,83,212,248,134,134,29,22,86,207,230,139,107,87,95,122,190,80,212,209,181,50,164,150,84,7, - 88,45,209,52,220,109,86,40,84,38,85,208,169,65,169,54,118,239,61,194,201,147,167,92,168,96,22,146,103,50,55,69, - 175,233,189,108,93,56,93,189,94,199,247,61,230,203,179,228,146,156,219,194,120,30,214,172,68,24,67,212,168,97,172,118, - 235,220,38,246,211,202,102,207,248,24,89,122,130,1,231,49,29,69,206,134,213,104,116,154,102,221,86,66,24,6,60,249, - 196,99,148,231,102,41,21,243,36,105,76,35,106,100,99,90,246,243,165,159,177,101,53,185,80,226,11,105,45,90,148,64, - 252,155,235,28,244,159,194,216,46,248,134,133,198,218,153,185,67,29,149,249,110,43,217,17,26,202,87,184,84,52,74,25, - 126,88,207,126,178,6,118,3,111,133,72,193,216,46,107,167,27,176,39,20,194,171,75,17,89,109,170,239,242,189,244,173, - 198,38,161,214,141,195,64,163,187,131,111,44,25,224,65,125,58,101,67,41,201,73,33,248,229,131,39,158,181,0,125,55, - 239,153,28,240,9,208,183,194,76,55,108,77,161,218,13,241,181,219,246,218,79,253,202,111,111,25,253,221,95,45,189,230, - 213,55,83,236,21,212,134,58,58,205,216,228,50,31,250,234,112,98,24,146,97,40,111,149,226,64,155,182,147,33,28,44, - 193,246,252,206,189,151,204,236,220,123,254,163,159,248,236,170,244,69,215,247,174,127,205,139,228,218,149,61,4,113,13,83, - 49,52,82,1,94,128,210,9,74,164,104,37,17,166,74,215,85,23,4,99,239,249,208,170,53,150,115,12,60,5,84,125, - 176,126,118,179,62,226,206,129,109,128,126,218,9,181,211,155,161,113,24,102,134,64,238,2,209,6,98,0,60,1,97,234, - 146,96,58,178,17,234,212,56,182,118,29,80,124,247,135,225,143,222,10,66,127,247,13,195,119,116,96,133,196,0,115,149, - 154,243,167,201,188,75,44,207,223,71,45,138,56,255,155,15,115,217,196,4,137,82,24,241,253,149,74,15,184,0,116,55, - 140,167,214,62,0,124,249,134,137,241,39,119,254,233,59,235,185,96,53,109,61,189,88,217,205,71,255,242,159,152,252,141, - 223,60,246,130,168,113,183,134,219,45,236,139,161,48,191,102,99,199,138,181,27,193,84,80,113,29,163,45,41,22,45,42, - 24,17,103,33,115,26,99,82,164,213,40,233,168,246,123,246,29,165,92,174,226,43,233,66,246,204,226,188,115,219,18,204, - 98,33,77,83,2,223,35,151,11,240,125,137,177,41,65,224,19,6,62,2,75,163,94,39,201,212,210,14,247,113,96,119, - 83,41,45,113,98,198,32,8,9,124,31,107,13,141,70,131,184,17,145,100,192,116,212,104,224,7,62,211,211,211,60,245, - 212,54,2,223,233,146,242,249,128,56,142,136,227,40,187,176,61,60,149,209,249,133,64,6,62,210,247,91,117,206,7,113, - 151,235,50,181,128,49,11,95,71,240,193,37,154,119,74,195,253,101,152,237,7,126,26,120,109,214,253,248,139,72,107,217, - 104,68,135,139,48,140,34,152,94,109,237,169,138,54,115,13,41,210,137,149,35,252,159,229,67,220,213,81,34,1,62,219, - 221,142,106,196,200,40,125,198,71,162,159,219,119,114,0,236,3,251,110,168,247,193,222,58,220,81,144,226,246,31,47,215, - 31,158,250,139,127,152,189,235,182,187,40,118,15,209,253,194,171,75,115,176,82,192,112,55,132,99,192,161,165,195,220,38, - 68,218,6,211,35,240,84,10,183,11,120,111,63,188,103,195,161,163,159,233,123,247,251,31,249,230,27,127,105,226,115,255, - 252,49,115,232,100,3,89,232,193,107,11,65,214,145,194,195,218,34,58,205,147,214,35,86,92,184,145,227,171,151,142,36, - 112,142,129,37,101,8,206,119,16,3,53,22,34,149,197,233,98,109,0,29,67,242,147,16,255,6,68,18,170,19,48,189, - 27,78,204,57,238,220,110,11,147,135,65,231,0,101,191,143,137,229,219,147,11,21,158,209,84,230,43,46,127,92,8,254, - 163,60,186,162,136,223,125,240,33,126,126,199,14,26,158,71,34,229,247,84,54,69,182,153,59,8,108,133,164,29,142,104, - 248,106,27,124,101,237,55,183,239,251,210,255,125,39,141,134,229,206,95,255,221,200,254,238,31,61,125,121,170,191,20,195, - 103,44,60,233,9,81,152,130,165,237,55,95,87,234,236,25,164,17,107,146,52,197,88,13,162,225,140,226,61,7,24,75, - 233,10,137,182,77,27,77,143,67,135,142,208,204,55,183,100,248,79,214,13,37,73,66,146,164,45,169,72,163,81,207,100, - 68,34,35,34,6,180,181,181,99,45,52,26,13,106,149,106,150,7,238,182,93,77,75,6,33,197,130,129,89,22,84,87, - 44,21,169,215,235,206,80,107,33,34,47,243,149,150,60,244,208,131,212,170,85,4,130,192,15,72,181,161,209,168,19,69, - 81,246,124,220,129,51,198,32,172,34,159,47,34,60,217,58,250,33,112,0,248,128,251,179,46,193,244,180,101,207,148,177, - 59,13,140,190,11,226,165,89,231,211,147,73,113,78,102,255,238,91,61,20,48,213,222,70,90,40,112,220,83,226,51,253, - 221,76,251,222,247,124,145,124,175,227,123,30,120,63,240,215,208,232,130,253,210,218,47,74,33,62,241,242,114,253,75,242, - 247,255,252,208,151,254,244,29,182,227,156,243,68,226,201,162,128,124,0,42,41,20,184,125,203,38,246,158,187,156,82,33, - 180,195,16,23,224,148,132,173,53,248,130,17,226,125,67,240,111,215,78,204,222,214,255,183,239,127,228,209,31,255,31,227, - 95,123,251,187,147,137,163,167,80,165,30,76,24,144,40,67,138,65,164,138,174,66,55,118,195,186,194,60,172,148,176,172, - 13,242,191,8,172,206,54,201,143,103,29,219,183,42,12,205,73,96,30,56,1,118,214,221,48,180,1,27,60,7,174,23, - 223,242,225,123,1,113,220,224,166,237,15,242,249,193,181,212,242,37,22,242,35,254,227,60,94,114,232,48,162,82,225,223, - 55,111,102,214,247,191,43,29,153,205,222,76,63,9,124,57,251,218,79,64,227,23,225,64,10,247,244,65,223,145,119,254, - 115,225,75,95,249,106,91,241,177,39,183,173,132,111,212,225,126,31,118,10,65,155,176,118,233,177,32,24,217,252,162,23, - 10,73,149,212,206,97,109,140,180,206,30,65,10,133,209,100,118,12,174,250,184,20,76,69,20,165,28,61,54,234,128,229, - 36,93,176,118,205,56,64,77,187,141,166,104,49,73,19,210,196,145,202,42,213,170,91,183,183,181,163,148,200,54,37,134, - 66,46,143,144,146,56,137,1,129,31,248,24,227,152,177,2,233,214,238,153,71,241,244,244,36,113,220,64,27,77,163,209, - 192,247,125,60,223,103,247,238,61,236,221,179,151,92,232,236,52,172,181,78,31,100,52,229,242,28,185,92,216,26,197,154, - 26,51,63,231,163,23,4,222,173,187,238,59,112,38,85,43,129,74,22,206,209,140,188,94,36,133,250,158,186,109,63,155, - 79,127,20,157,122,243,245,189,23,184,1,26,67,150,253,158,176,243,137,224,248,185,150,35,39,223,247,241,43,230,191,122, - 95,223,160,231,111,51,105,116,18,72,162,98,158,40,244,68,161,183,221,70,199,39,17,181,136,28,216,54,136,231,96,188, - 108,237,108,4,71,66,33,182,143,88,54,143,76,78,159,55,255,222,143,174,63,249,233,47,172,60,122,243,245,35,93,175, - 127,121,113,233,166,85,120,73,21,146,136,156,77,233,187,226,82,111,223,237,95,27,190,18,150,166,80,186,9,102,207,201, - 158,91,31,80,254,46,143,173,92,4,206,243,131,44,64,57,47,96,235,216,17,46,57,180,131,142,90,5,59,178,241,91, - 197,60,63,175,31,22,88,61,49,201,173,15,63,204,23,151,46,37,254,14,95,134,5,84,232,81,236,43,210,103,45,61, - 217,129,175,10,193,234,40,173,111,159,168,238,202,195,23,150,206,150,39,244,99,79,134,30,236,52,176,53,132,99,57,104, - 84,45,189,18,122,231,151,246,119,174,88,51,140,52,9,126,45,160,62,171,72,26,9,90,217,204,46,193,137,65,37,158, - 243,151,22,128,244,40,87,235,204,204,149,93,146,106,83,95,151,233,181,50,143,52,164,116,185,95,22,50,37,123,22,131, - 99,45,149,114,153,84,59,100,67,107,87,68,38,167,166,24,28,26,66,27,227,236,53,117,150,25,134,6,147,105,172,180, - 38,78,98,166,166,167,41,228,29,97,177,214,136,90,69,236,145,71,31,161,88,44,58,83,45,207,195,88,67,181,90,165, - 167,187,135,70,189,65,146,56,47,37,151,129,5,58,241,72,101,129,138,81,207,32,126,236,3,30,2,54,101,221,139,121, - 142,222,220,103,43,6,63,170,71,4,204,66,114,200,114,242,133,80,158,23,156,28,18,98,155,57,62,90,170,11,113,164, - 164,228,158,57,109,26,43,227,152,251,26,117,139,49,46,162,121,209,207,104,119,31,81,25,198,231,173,157,17,66,28,70, - 200,199,74,66,172,108,159,47,159,87,253,212,231,46,57,244,229,187,207,219,127,203,13,131,171,95,249,226,96,205,121,107, - 177,74,177,246,178,45,124,165,191,171,199,156,154,89,146,66,231,18,24,237,118,93,12,41,240,89,92,224,230,143,66,153, - 254,172,191,179,232,7,220,115,226,32,159,223,245,8,55,103,99,216,127,228,135,197,121,10,13,87,107,60,182,123,15,243, - 89,31,247,237,94,149,1,122,54,13,176,230,61,175,227,252,70,210,122,67,4,161,199,145,253,19,54,120,203,39,103,195, - 122,250,88,13,14,27,183,217,153,42,192,108,9,210,237,32,87,128,104,128,39,134,151,132,125,67,75,64,38,164,182,76, - 156,206,145,16,147,106,237,178,211,180,51,244,210,194,173,197,141,209,4,126,200,190,253,123,153,154,158,35,8,115,89,170, - 230,162,43,202,100,209,127,214,233,194,76,150,233,222,244,152,9,130,160,149,243,21,199,49,24,75,173,90,229,216,209,163, - 244,245,15,144,102,244,123,41,165,43,70,153,69,131,84,46,158,55,141,83,78,157,154,96,233,210,17,170,181,90,203,14, - 116,219,142,29,140,79,76,48,60,56,224,114,231,27,53,230,230,202,88,107,153,157,157,161,90,173,96,76,63,158,231,161, - 73,51,103,65,73,42,13,54,244,229,217,238,182,31,199,197,35,249,217,197,250,159,237,225,3,211,238,195,62,12,243,203, - 44,187,114,214,30,77,65,21,125,191,241,84,28,215,255,16,204,137,185,50,183,140,79,225,183,121,207,90,68,219,220,71, - 60,111,237,68,206,218,233,26,28,138,29,227,120,247,134,249,242,11,231,63,249,239,91,14,124,241,43,75,182,95,123,69, - 207,218,55,252,88,176,246,242,43,232,219,120,78,208,56,245,64,78,65,104,23,185,202,248,217,53,48,138,243,109,87,207, - 135,2,84,244,3,238,61,126,128,247,239,126,148,206,31,192,221,232,71,253,40,0,159,92,24,165,190,109,225,66,128,240, - 37,42,149,173,55,129,39,5,81,123,142,193,246,208,60,89,79,103,111,128,249,0,120,59,216,139,221,156,204,52,216,21, - 78,241,59,90,124,122,207,169,143,188,237,15,150,47,191,98,11,253,131,253,12,181,15,225,217,105,114,170,141,184,58,141, - 64,99,108,232,50,161,132,15,66,16,4,121,142,30,61,73,28,155,86,212,110,147,249,108,157,149,139,43,26,210,81,252, - 109,43,194,215,109,183,234,181,58,245,122,157,48,12,241,148,34,214,9,167,38,38,168,84,42,207,72,220,212,38,235,156, - 204,194,10,190,94,143,40,151,43,204,205,151,201,231,10,132,97,200,212,204,12,199,30,127,188,209,38,165,138,226,216,239, - 234,233,116,73,17,137,38,137,28,151,105,102,118,150,254,106,149,66,62,159,153,162,25,148,210,120,42,38,202,73,121,182, - 134,100,183,227,209,240,42,254,115,63,60,96,7,176,20,226,99,16,231,129,210,77,87,146,91,49,200,137,127,250,184,123, - 207,125,155,72,225,69,155,103,91,130,180,8,243,7,160,218,14,51,41,140,182,193,246,77,213,218,218,202,151,190,182,246, - 216,157,247,174,20,155,206,41,92,52,57,121,12,216,173,96,38,6,83,57,227,186,142,29,190,195,16,252,80,199,85,239, - 217,138,207,251,118,63,250,221,173,201,254,131,62,222,149,97,59,133,111,83,133,172,113,24,71,11,143,48,22,180,107,147, - 143,2,189,142,153,195,49,224,66,224,114,96,5,216,105,167,66,121,248,146,169,153,158,177,191,122,215,229,251,61,57,242, - 228,210,161,206,210,133,23,22,251,183,44,83,165,117,151,176,118,237,106,74,254,12,245,90,68,16,228,29,94,163,53,66, - 10,142,30,61,74,162,173,75,218,104,122,49,11,167,126,55,194,100,91,48,183,138,39,179,224,108,90,105,68,113,140,78, - 83,252,192,39,8,3,202,243,21,102,166,167,221,184,102,108,43,230,87,9,73,98,210,140,5,237,108,65,165,116,88,144, - 167,60,242,249,2,113,148,224,43,159,189,251,246,243,170,169,169,169,109,61,221,249,131,97,208,45,148,114,91,81,79,97, - 234,49,198,58,32,60,142,35,114,97,136,20,206,49,47,77,53,167,166,230,145,58,80,153,171,18,157,96,123,178,21,187, - 197,241,125,150,0,23,253,144,47,130,31,5,54,180,248,186,210,75,6,24,122,221,141,144,21,160,239,118,172,44,0,79, - 128,190,2,166,82,167,191,218,39,161,175,0,203,55,26,189,212,108,223,30,26,152,180,82,238,212,198,140,111,2,179,129, - 103,26,52,75,135,193,177,251,71,85,128,206,44,62,207,199,49,202,126,171,78,229,123,120,236,199,153,223,255,222,115,244, - 28,115,192,71,129,123,178,150,251,106,168,156,11,79,104,152,29,134,39,71,82,179,70,31,58,177,180,118,232,68,127,249, - 51,12,29,232,40,141,60,116,238,218,174,53,175,185,53,184,238,166,11,32,73,49,54,64,72,69,189,150,242,244,206,253, - 68,105,130,239,41,23,5,148,113,126,180,113,186,32,165,188,214,129,145,66,97,172,35,11,166,105,74,20,69,72,169,240, - 85,72,146,164,212,234,53,202,213,50,169,78,152,153,157,164,189,171,141,36,73,145,210,169,223,61,33,208,169,198,42,231, - 114,23,248,30,74,73,106,229,50,126,143,199,241,153,9,186,79,30,169,94,232,137,233,199,69,184,52,78,34,82,29,19, - 120,121,106,166,1,194,144,36,49,141,70,204,220,220,60,133,124,17,37,4,66,26,142,29,29,101,223,137,99,108,136,202, - 210,66,177,12,185,95,3,249,151,89,94,195,226,115,248,24,206,61,204,240,255,200,35,77,73,171,245,239,235,71,152,108, - 34,159,131,218,90,168,165,48,49,9,135,114,144,87,66,72,35,101,162,181,174,134,16,165,223,98,252,249,97,99,101,222, - 243,181,248,216,179,108,63,100,118,119,236,18,66,230,133,224,45,198,216,243,129,186,227,129,144,126,31,7,240,95,221,29, - 153,151,63,7,179,254,195,89,39,4,112,23,152,79,193,140,15,79,213,224,160,231,172,96,123,124,232,25,128,21,75,231, - 42,91,230,31,120,242,226,175,76,79,175,191,232,218,75,242,29,57,139,173,67,222,11,24,155,172,48,54,117,18,223,115, - 62,65,206,22,214,37,17,52,237,51,28,33,217,189,106,99,156,249,124,24,6,132,97,64,20,53,16,66,81,42,181,161, - 148,199,204,236,44,81,163,129,84,146,233,233,41,150,44,91,146,117,47,26,161,157,19,162,148,210,129,210,198,1,219,243, - 115,51,4,74,146,6,146,147,199,14,218,159,47,151,119,14,167,246,120,151,79,71,156,212,58,203,179,51,148,74,61,228, - 194,128,164,94,195,90,147,217,126,164,40,207,167,90,174,112,252,248,113,70,79,142,146,120,130,137,134,9,82,23,21,215, - 61,233,204,192,158,193,253,91,130,147,94,180,159,229,61,225,101,56,133,230,191,30,103,219,78,153,236,184,41,208,71,161, - 50,0,21,191,144,231,112,103,59,246,196,216,183,223,60,253,40,10,80,201,15,184,231,135,92,124,100,230,222,159,1,14, - 167,223,16,178,55,153,196,41,225,113,40,189,88,46,68,174,96,109,151,18,162,77,11,33,127,25,140,6,61,6,113,27, - 204,231,96,190,243,123,188,113,158,194,81,253,159,2,126,253,57,124,157,198,117,69,86,64,60,235,136,101,51,195,112,244, - 8,248,41,108,5,118,151,96,118,243,190,35,165,135,62,243,232,154,87,252,220,139,136,235,179,228,148,199,145,147,135,152, - 169,214,9,50,202,157,102,33,218,89,156,102,21,75,43,194,215,121,240,116,48,54,54,70,181,90,109,121,243,52,85,237, - 113,146,64,98,153,158,158,166,86,173,17,71,17,190,239,172,52,13,206,228,160,201,51,82,74,209,219,211,231,120,64,149, - 10,29,149,114,125,189,101,42,134,184,88,176,169,177,41,81,37,38,31,54,144,38,193,24,75,45,170,227,123,1,149,74, - 5,157,166,204,204,204,112,252,248,9,82,29,225,135,57,142,7,65,190,2,61,237,208,86,1,249,123,110,59,116,26,248, - 41,178,177,108,219,25,199,50,1,254,12,120,159,27,121,255,235,241,109,138,145,93,116,60,237,162,209,239,249,52,222,122, - 29,65,142,175,30,219,199,251,127,136,197,71,0,181,52,161,166,19,33,114,69,100,154,218,102,225,153,119,237,119,216,13, - 109,83,80,58,7,228,28,36,155,17,73,44,212,176,181,233,197,21,99,214,104,240,27,144,134,142,137,57,147,192,142,10, - 60,249,155,48,62,233,138,18,179,223,67,27,255,33,215,181,112,103,118,17,60,87,175,183,201,48,77,192,46,117,192,97, - 122,24,234,26,234,17,20,86,165,44,253,234,63,189,179,247,241,115,251,58,95,112,233,38,76,108,216,189,247,8,105,234, - 17,72,141,16,6,107,85,43,21,193,117,60,38,51,46,115,0,178,51,47,183,248,190,79,189,94,119,172,232,32,32,159, - 119,78,134,113,28,19,71,49,22,195,252,220,28,113,20,97,180,195,125,48,6,154,60,164,204,116,44,8,67,250,251,7, - 24,30,25,228,224,241,147,204,167,135,180,208,182,77,66,187,110,196,62,97,145,52,85,232,84,210,214,214,78,146,66,165, - 92,161,90,173,50,49,49,65,28,39,116,117,117,209,221,221,197,201,209,19,144,164,32,172,48,66,120,202,90,85,5,241, - 101,156,213,174,127,150,110,39,231,192,218,211,58,225,175,3,247,2,111,248,175,26,243,159,3,148,255,231,29,15,242,240, - 248,177,31,218,88,5,153,255,206,212,73,222,246,228,221,246,47,58,251,81,167,142,52,145,120,175,12,61,33,172,246,96, - 163,116,221,120,232,65,69,99,103,165,213,195,147,112,237,216,11,175,61,239,188,23,92,42,102,39,39,244,215,239,123,208, - 118,60,189,119,242,74,120,56,114,222,190,247,127,22,198,151,131,249,48,176,231,123,120,158,163,192,205,25,56,253,214,231, - 104,46,22,103,220,153,194,236,2,27,135,121,207,25,116,223,127,237,236,204,242,175,188,245,207,207,143,254,244,119,243,183, - 190,248,6,14,29,61,134,109,8,116,62,71,98,26,88,76,11,136,110,146,16,91,157,86,182,189,114,49,44,130,70,163, - 225,142,117,62,79,24,134,204,206,206,82,46,87,156,197,134,175,72,146,132,90,181,138,213,198,113,90,105,70,234,209,202, - 187,87,202,3,41,41,150,74,188,232,133,55,178,173,187,163,248,205,219,62,222,251,210,24,211,83,179,70,229,114,4,185, - 60,169,182,120,40,124,223,39,159,207,145,38,186,37,219,104,111,107,99,249,178,229,204,151,231,169,233,24,109,61,18,161, - 66,109,211,188,15,222,83,124,119,225,147,54,187,81,213,255,235,218,253,207,81,128,238,31,61,252,67,41,60,249,69,179, - 251,91,64,204,3,249,218,60,203,106,243,210,130,122,28,194,14,24,66,136,203,140,181,87,31,18,226,130,253,109,249,145, - 178,231,7,75,202,149,202,154,68,79,117,89,27,142,14,14,44,187,244,207,254,160,125,96,73,55,131,186,206,242,95,253, - 73,238,248,200,167,186,238,251,235,127,41,93,19,107,171,161,190,23,238,15,97,214,251,62,218,205,49,224,175,113,174,89, - 127,225,73,46,15,60,102,107,9,223,143,10,165,153,240,33,113,196,187,221,174,48,217,115,96,70,193,145,18,76,174,28, - 157,136,126,251,247,254,62,191,231,104,196,145,99,147,248,158,33,53,202,229,145,147,182,58,158,230,248,181,240,57,91,163, - 91,75,28,199,148,203,142,151,211,214,214,70,163,209,200,64,233,6,82,58,161,105,28,199,212,106,245,108,156,115,193,132, - 126,150,57,238,140,254,21,65,16,16,197,17,59,158,126,26,99,44,231,93,118,177,124,104,244,196,242,13,247,126,99,180, - 61,49,137,78,35,27,9,45,146,58,200,176,68,154,56,158,82,169,88,68,72,183,137,51,198,80,106,43,177,102,205,90, - 158,220,177,29,163,13,13,107,187,36,44,139,160,227,56,84,58,157,24,242,59,46,244,2,199,222,205,204,40,254,235,241, - 31,185,0,61,151,128,113,83,165,108,179,121,61,7,108,2,177,20,188,13,142,89,95,24,135,194,171,193,111,146,160,170, - 80,208,208,51,15,189,1,172,173,90,123,213,232,186,85,151,180,255,204,27,251,46,95,191,138,64,133,236,123,236,137,222, - 59,191,124,207,210,104,215,238,116,175,151,250,235,38,142,146,51,147,40,105,200,123,138,159,124,243,171,248,55,196,208,67, - 127,250,206,23,92,13,83,198,137,230,182,11,168,174,201,166,176,239,181,110,220,11,188,124,207,4,159,127,242,4,151,159, - 55,196,108,57,250,174,139,80,179,8,158,4,190,8,252,21,142,108,55,147,225,77,109,144,171,67,239,140,16,61,95,90, - 186,169,237,156,45,215,51,58,238,115,228,248,52,50,144,36,137,70,170,44,86,165,25,137,44,23,46,189,166,129,188,51, - 17,211,84,170,85,26,141,70,22,1,227,183,204,198,92,18,134,32,8,2,146,56,166,50,63,15,38,75,212,108,30,33, - 65,43,39,94,74,69,177,80,32,73,19,142,28,57,194,255,207,222,123,135,89,118,149,87,222,191,189,247,57,231,158,155, - 43,231,234,234,156,179,164,86,4,101,129,4,152,12,6,27,99,123,28,39,224,48,51,30,143,103,252,217,51,223,140,199, - 51,159,51,99,112,24,27,27,147,49,89,36,33,161,156,67,119,171,115,206,149,211,205,39,237,189,191,63,206,173,150,192, - 2,36,1,99,140,123,63,79,61,221,93,93,85,125,251,222,123,214,121,223,245,174,119,173,92,87,137,242,186,205,217,227, - 247,63,86,144,214,46,34,173,49,132,202,104,75,28,57,248,217,44,149,197,69,234,141,6,158,151,161,217,108,210,221,213, - 69,24,134,148,203,101,214,172,88,193,179,179,115,76,98,187,87,192,166,12,140,30,131,233,127,15,145,126,137,96,146,144, - 50,217,241,165,107,248,159,33,0,9,65,44,101,123,177,51,253,33,101,96,29,136,60,56,11,224,204,129,19,67,126,53, - 20,5,116,91,232,7,134,60,232,79,192,79,131,121,83,190,81,66,191,130,238,105,232,173,92,187,107,100,231,127,255,181, - 114,247,64,39,34,104,130,54,108,126,211,141,220,116,251,13,234,196,185,115,234,200,193,189,228,85,128,20,14,73,98,112, - 157,2,245,133,38,175,121,253,107,249,235,135,158,90,118,252,190,39,110,90,13,81,11,58,250,224,184,7,51,7,161,54, - 10,201,203,29,235,206,84,2,94,243,11,159,230,139,127,246,166,139,32,244,82,72,104,128,101,109,0,218,0,44,127,222, - 196,194,1,21,66,191,7,27,191,226,23,87,230,111,255,247,106,108,104,45,141,153,67,84,195,6,70,105,156,184,157,217, - 69,202,249,44,129,207,82,37,180,196,9,201,118,96,95,179,209,32,12,67,114,217,108,170,70,214,154,102,179,73,171,213, - 66,42,117,209,86,181,213,10,8,162,224,185,239,109,47,168,218,118,210,156,239,251,228,242,121,42,149,69,130,8,206,158, - 159,167,114,104,143,185,206,198,250,110,225,150,26,137,80,69,55,139,17,128,150,72,55,213,251,88,99,218,85,86,10,214, - 75,153,230,35,3,3,84,54,175,227,161,39,22,203,151,53,163,181,192,198,60,156,252,63,48,189,30,108,242,50,110,124, - 230,210,53,252,207,3,128,44,16,73,7,227,120,104,27,176,97,102,130,53,243,51,116,130,188,17,252,50,228,37,116,132, - 208,211,132,78,153,182,246,125,10,6,99,24,170,194,80,5,122,106,80,182,2,133,227,96,188,140,66,73,101,141,206,156, - 23,248,135,6,250,51,183,189,241,181,114,239,209,147,100,78,9,58,203,37,138,133,28,88,75,214,81,172,28,234,99,253, - 138,59,72,116,148,142,138,157,212,3,39,209,134,188,178,188,253,63,190,71,125,248,220,111,174,115,79,156,114,135,211,229, - 233,131,26,246,77,193,161,41,184,224,164,147,178,248,229,84,67,243,149,128,87,255,226,167,249,244,255,126,3,215,108,30, - 120,158,37,198,55,30,221,110,55,151,196,117,189,164,226,174,9,96,61,233,206,205,210,81,192,60,120,53,24,108,193,234, - 249,141,151,117,6,54,161,85,15,9,235,53,226,200,160,156,28,56,96,147,22,178,221,34,89,1,86,183,163,163,121,46, - 129,2,1,81,146,80,111,181,240,252,44,70,107,114,185,60,214,10,170,213,26,113,162,201,250,25,172,77,201,230,74,165, - 70,171,217,34,49,49,74,40,208,34,13,202,75,119,60,48,218,162,163,4,29,197,100,253,12,243,19,83,120,135,142,55, - 71,33,156,87,73,167,107,98,154,129,69,43,131,175,138,40,55,3,38,117,89,108,182,34,206,157,187,64,177,80,166,187, - 171,139,32,9,81,142,195,134,21,107,216,31,132,254,215,159,222,187,250,85,113,184,83,192,222,22,44,220,7,209,203,105, - 167,18,224,230,239,182,148,183,160,228,243,242,183,196,37,96,248,129,2,32,11,120,214,112,213,133,195,220,239,120,220,214, - 90,20,73,109,65,90,40,36,48,80,134,49,9,43,37,140,58,48,92,135,190,42,20,103,161,107,54,235,117,68,35,195, - 133,100,100,89,174,184,98,76,245,173,24,19,163,171,150,211,209,211,73,177,163,156,110,118,43,69,44,211,55,127,80,171, - 80,175,213,240,179,89,28,165,40,148,10,196,81,8,113,72,61,142,9,230,170,104,29,35,73,205,206,93,79,146,245,179, - 40,2,86,12,117,241,150,255,249,91,153,191,253,221,63,94,151,28,56,56,182,51,8,119,108,183,28,205,167,142,120,187, - 45,236,86,82,158,190,222,218,230,110,107,41,191,68,18,121,113,49,224,15,126,247,62,94,241,177,119,18,235,23,190,247, - 246,1,159,108,19,171,246,121,109,133,126,129,159,23,164,0,228,100,160,179,9,93,131,151,191,194,25,218,182,138,147,143, - 29,34,168,158,163,101,23,241,113,113,18,137,176,41,73,108,141,109,175,107,136,212,74,213,202,52,5,68,164,235,20,73, - 162,169,213,27,216,118,75,230,186,94,234,19,100,210,118,76,107,147,110,180,43,39,213,22,181,35,132,93,215,35,245,210, - 75,227,168,181,182,88,163,201,250,89,226,176,133,178,10,226,128,150,76,172,128,74,54,54,121,153,56,196,194,224,185,14, - 65,16,210,108,77,161,209,41,178,10,67,179,213,96,247,238,221,172,92,177,130,209,177,101,88,107,112,81,108,216,118,25, - 7,102,23,123,174,57,126,116,121,6,122,59,64,173,120,153,213,140,37,157,156,46,126,19,217,255,82,142,54,154,225,142, - 110,166,87,172,164,162,155,200,122,149,75,40,244,3,6,64,202,90,118,206,95,96,38,181,103,204,207,195,72,6,54,40, - 216,94,133,45,23,96,197,184,82,189,141,145,193,162,90,191,42,59,118,197,78,53,184,102,149,216,177,106,37,203,87,173, - 160,220,217,133,239,101,83,155,137,139,44,81,59,18,24,131,115,113,15,250,249,102,151,75,69,118,59,128,205,88,116,28, - 161,117,66,216,74,91,138,11,231,207,113,106,124,130,78,87,210,211,231,179,126,243,10,126,249,189,255,69,158,56,125,54, - 119,244,177,167,151,127,233,222,71,7,157,131,199,183,94,153,36,59,6,225,158,121,99,191,250,6,56,124,3,52,110,125, - 57,207,216,254,73,248,127,239,193,253,47,183,242,66,100,208,111,189,132,31,213,72,43,35,87,164,22,152,57,153,93,38, - 122,251,55,99,215,133,124,241,83,159,194,209,22,87,5,88,225,160,141,66,182,125,127,165,109,87,60,8,172,208,88,76, - 154,220,106,185,216,110,93,140,207,53,134,40,142,72,146,24,33,5,197,124,30,37,37,58,73,40,149,74,72,36,58,49, - 224,166,62,63,214,154,139,217,235,162,45,76,76,55,229,45,157,61,157,136,87,222,80,248,203,187,238,46,28,17,210,179, - 73,154,202,42,132,161,165,107,132,24,60,199,75,109,67,144,88,145,134,234,157,60,125,28,99,34,86,44,91,145,166,104, - 184,14,174,163,158,167,106,74,95,237,151,187,8,41,72,69,164,241,203,2,49,139,35,125,20,14,227,157,101,60,213,65, - 62,10,33,142,46,161,195,15,10,0,233,118,27,49,3,110,63,244,87,97,179,15,87,87,96,215,177,172,191,97,230,242, - 237,131,125,215,93,235,93,253,202,235,88,179,125,19,165,222,18,121,229,165,218,14,27,164,235,5,82,131,105,160,69,234, - 25,147,218,73,60,103,7,170,137,46,10,234,150,198,192,105,252,111,123,103,201,182,121,138,182,185,186,231,103,41,118,66, - 223,208,8,213,90,149,35,135,14,179,231,248,41,134,122,106,140,246,117,50,188,105,140,91,119,109,161,246,75,191,152,121, - 246,196,185,129,3,127,254,119,221,225,223,127,182,60,134,21,85,8,71,225,200,239,66,252,44,223,217,224,234,155,193,56, - 248,248,94,54,150,125,222,252,238,157,200,246,243,243,219,164,102,101,153,23,57,121,11,128,159,3,114,105,21,217,63,239, - 137,78,205,180,208,45,67,247,186,173,92,119,227,235,169,125,240,12,149,112,150,192,81,184,194,34,76,106,84,33,105,71, - 177,96,211,88,222,246,126,185,92,210,9,33,176,58,173,94,178,217,44,66,8,162,40,192,152,152,108,214,79,213,208,82, - 48,60,60,140,239,103,73,146,246,247,88,211,190,37,200,118,224,161,105,71,28,65,43,174,99,61,75,95,247,144,152,188, - 234,186,85,231,158,120,128,188,83,67,40,7,99,4,113,4,202,203,33,133,139,53,1,88,75,179,25,144,241,28,60,207, - 97,106,106,18,41,29,150,141,44,163,49,62,201,166,179,231,230,242,112,38,129,217,41,72,142,72,69,67,170,151,93,119, - 44,73,27,50,128,76,162,23,105,58,103,113,165,143,148,169,243,163,74,82,7,130,53,203,86,177,80,173,50,117,242,2, - 59,234,141,75,40,241,143,9,64,121,160,7,196,30,200,59,66,172,114,225,106,107,237,43,15,185,206,229,181,31,185,125, - 108,215,123,126,193,219,186,107,7,5,191,128,192,96,147,8,155,36,216,168,73,34,65,40,16,142,66,90,209,78,249,20, - 40,218,126,53,230,121,250,76,153,82,182,22,241,92,27,110,211,59,190,18,2,164,109,103,102,181,69,120,23,91,32,65, - 169,84,230,138,171,175,98,205,154,21,60,249,232,67,156,58,91,101,168,167,27,217,10,105,105,135,141,203,70,184,233,35, - 31,112,255,71,125,126,107,246,43,15,84,122,225,228,28,92,16,176,176,234,101,220,121,35,96,213,103,246,19,172,237,166, - 33,37,203,129,199,218,119,225,23,123,1,185,41,160,203,101,208,33,96,232,116,71,87,231,53,87,46,48,53,115,23,83, - 93,87,176,241,21,111,166,59,83,230,207,63,240,159,136,131,121,144,18,35,44,74,184,23,239,250,75,155,239,75,207,162, - 227,40,116,98,46,198,246,64,170,11,106,54,91,212,42,21,178,126,6,199,145,200,172,79,146,36,244,245,245,165,213,81, - 28,167,49,64,24,172,144,88,253,156,235,165,235,58,105,61,106,28,148,113,168,53,102,216,177,109,61,6,205,179,135,246, - 34,164,33,137,13,198,10,84,152,96,12,56,34,133,101,171,53,137,134,90,35,198,74,69,237,236,41,180,84,12,156,31, - 215,87,52,235,39,13,236,137,224,194,70,72,30,24,93,205,254,114,23,222,119,145,174,98,73,165,13,253,115,51,116,36, - 213,54,24,127,103,240,249,134,91,134,181,184,214,50,222,217,73,112,227,181,76,30,60,130,57,113,230,82,67,246,253,2, - 160,63,250,54,101,109,51,189,67,11,23,58,178,176,85,89,123,243,20,220,120,124,211,218,45,215,253,222,255,40,239,188, - 245,6,124,105,208,113,128,14,43,41,123,96,69,138,37,66,98,101,59,66,214,166,246,17,72,137,177,23,67,61,219,9, - 195,233,189,74,182,163,126,133,32,229,52,172,120,222,202,65,59,232,181,237,153,188,68,188,166,111,24,147,2,89,28,209, - 81,46,243,202,91,110,227,240,190,189,84,90,13,114,210,165,228,251,140,31,59,66,169,220,201,141,255,254,87,220,103,238, - 126,112,77,127,98,183,52,97,207,29,80,217,242,50,7,41,122,166,193,51,255,225,43,84,141,97,61,105,192,225,75,109, - 27,22,193,13,211,232,218,254,227,221,203,243,242,217,73,222,117,29,60,112,230,28,11,250,77,12,94,254,42,222,229,6, - 252,221,95,252,54,173,160,138,235,186,36,137,198,145,41,249,156,130,143,196,74,133,213,105,76,139,213,150,48,8,113,93, - 23,207,243,176,214,82,171,86,218,57,94,57,28,199,161,218,168,224,185,46,25,207,107,155,216,123,116,150,59,218,160,37, - 16,74,181,127,103,211,169,24,128,208,68,205,6,25,167,196,236,220,60,55,221,112,3,29,221,163,196,145,226,216,241,227, - 204,205,156,64,234,10,88,7,209,158,214,117,117,119,131,116,168,44,214,169,53,3,2,3,207,30,216,207,234,74,189,89, - 134,227,45,56,148,129,133,86,177,195,30,236,234,19,57,99,172,80,223,157,178,199,2,83,3,35,156,211,33,5,179,72, - 189,29,120,253,162,192,231,121,63,67,36,9,189,133,28,135,175,186,12,175,191,151,209,125,135,113,106,245,75,64,244,189, - 6,160,95,250,54,127,89,1,246,65,190,2,91,115,240,198,211,112,243,145,219,111,89,247,142,63,255,3,119,221,232,114, - 108,179,130,177,22,225,8,148,77,121,3,35,5,70,202,246,82,81,42,241,183,198,192,146,110,101,201,64,253,249,4,0, - 96,133,69,44,177,1,82,128,89,186,203,155,246,59,34,229,36,210,175,177,207,17,7,109,13,140,149,233,198,85,198,245, - 89,189,122,19,179,227,103,56,119,250,4,103,107,167,88,187,118,45,147,227,211,92,117,195,205,60,118,245,174,158,214,131, - 143,111,20,66,172,18,214,158,107,119,151,47,249,124,1,56,163,13,111,79,43,153,139,250,167,151,2,64,46,136,24,84, - 11,156,161,145,117,170,115,205,47,242,208,177,143,114,251,214,25,30,57,244,121,206,235,55,177,122,215,143,242,46,41,249, - 196,223,254,1,243,115,51,120,174,135,54,17,74,164,201,168,8,137,182,18,108,130,104,123,53,47,217,180,46,69,47,87, - 43,85,146,68,35,16,23,199,239,67,3,67,164,118,169,9,181,90,21,221,219,151,6,13,168,231,216,55,108,74,108,59, - 74,165,9,28,78,234,237,99,90,130,133,201,5,118,237,220,198,19,79,28,228,250,107,223,194,248,244,9,14,60,251,21, - 38,39,199,201,100,4,165,130,123,113,234,134,6,71,56,184,174,67,84,111,209,105,76,64,26,199,51,61,12,225,233,124, - 153,80,185,228,237,247,136,119,177,134,172,202,144,213,14,53,251,124,255,156,244,125,243,237,192,231,249,199,104,131,210,134, - 103,86,45,103,95,87,39,87,29,56,74,120,246,60,74,107,226,54,117,112,233,124,31,91,176,67,169,195,223,144,15,175, - 220,15,175,58,245,186,215,174,251,213,191,121,159,232,233,42,162,163,10,66,88,144,10,109,21,70,180,147,60,165,32,165, - 118,108,187,164,79,53,32,75,117,134,64,164,241,51,237,23,223,216,165,132,13,217,230,122,82,228,145,242,27,151,45,49, - 75,127,175,210,76,236,165,22,36,245,46,37,17,26,43,45,210,66,190,144,197,118,117,35,19,203,93,119,223,207,211,207, - 222,197,149,215,94,203,198,29,87,208,243,250,59,178,71,30,124,124,237,86,107,215,71,130,61,79,88,234,127,202,115,254, - 195,47,134,187,185,146,212,198,242,245,164,177,38,19,164,158,198,75,174,139,47,22,128,18,72,52,204,150,224,216,192,189, - 159,155,152,188,252,142,209,210,213,239,225,209,83,159,226,154,141,115,60,113,230,243,156,27,191,150,177,157,63,194,47,13, - 12,242,249,143,252,37,123,246,62,141,20,22,75,26,51,100,219,185,244,32,48,38,193,90,8,163,8,41,4,158,151,193, - 207,248,56,82,165,211,179,196,16,6,17,58,209,20,11,121,180,78,173,56,150,252,160,51,110,6,107,45,137,214,237,205, - 248,212,156,94,41,133,116,124,34,109,209,113,136,43,18,106,243,9,165,206,44,215,94,181,149,135,31,57,206,216,234,43, - 25,25,219,197,225,67,15,115,248,192,3,212,234,227,72,17,162,128,140,155,198,205,234,86,132,159,203,209,104,70,194,166, - 11,196,241,95,10,73,179,107,152,46,109,172,254,30,250,241,41,43,24,16,121,38,169,34,173,37,80,105,142,154,43,51, - 72,94,154,70,62,19,70,152,98,158,71,174,189,156,179,27,86,211,113,232,56,131,211,83,232,182,141,238,165,243,93,0, - 208,35,223,226,226,136,83,102,198,247,96,109,3,118,29,223,117,217,138,159,252,195,223,17,61,93,101,140,105,130,171,210, - 182,202,74,84,27,8,46,142,157,77,123,74,99,211,88,153,148,93,110,79,184,172,109,195,144,2,43,144,164,230,235,90, - 132,169,203,95,123,26,102,144,72,68,202,175,90,211,30,99,139,246,224,169,189,81,213,206,155,50,194,32,210,102,36,205, - 170,151,146,66,111,15,65,164,185,253,142,219,249,195,223,251,35,238,249,210,221,220,252,218,87,177,237,182,155,249,108,199, - 31,246,111,91,92,92,81,177,162,119,28,59,225,130,254,78,133,255,210,50,105,54,229,196,46,122,74,91,82,129,225,67, - 192,239,242,210,244,40,115,144,236,133,115,49,60,120,93,210,24,249,226,123,255,237,171,78,118,255,81,207,198,109,239,228, - 174,147,159,225,138,145,179,140,85,239,229,153,201,141,120,189,87,243,174,95,93,199,138,187,254,134,175,126,234,111,105,180, - 2,132,148,56,9,196,42,193,8,75,70,120,72,3,58,140,145,89,73,198,177,132,141,58,65,210,66,40,65,198,207,128, - 53,40,71,209,217,213,141,177,150,36,14,201,122,57,180,73,176,50,211,30,4,216,244,102,34,210,40,232,40,73,109,85, - 131,32,192,69,129,136,105,73,203,212,228,52,229,142,65,110,188,97,29,247,62,178,155,254,161,27,217,124,249,205,44,223, - 176,133,67,251,30,231,236,241,251,16,97,72,33,91,64,121,150,196,26,140,114,105,136,212,144,204,2,21,107,56,219,168, - 176,58,55,74,168,147,239,225,157,85,82,23,169,78,90,58,46,15,175,95,143,149,18,247,185,250,238,37,29,169,13,82, - 27,206,151,75,156,191,122,39,199,163,152,177,74,133,76,43,160,171,25,162,171,181,75,104,242,114,94,167,109,223,130,32, - 61,12,76,67,41,7,171,38,4,171,58,111,184,38,179,97,213,10,48,205,20,80,218,166,232,152,212,10,73,146,182,93, - 98,169,52,21,150,56,14,9,91,13,130,160,133,20,2,141,197,241,92,116,98,81,72,208,130,68,107,162,88,227,58,30, - 82,72,180,17,120,249,84,60,39,17,8,37,41,20,10,40,183,61,186,183,96,147,118,176,158,72,91,51,99,45,210,202, - 182,103,177,73,135,249,74,82,232,233,160,50,49,193,47,252,236,59,120,255,251,63,205,196,228,56,155,55,111,224,254,171, - 174,206,215,191,242,229,101,74,138,161,78,99,15,255,123,104,13,240,237,61,102,50,164,155,216,51,164,155,216,75,220,153, - 36,93,57,249,125,224,115,192,79,1,231,95,68,69,37,73,87,49,118,66,101,23,236,14,97,232,142,250,212,216,95,253, - 254,111,92,206,47,255,169,191,105,251,79,115,207,225,15,177,189,251,36,55,47,123,146,7,46,92,160,150,187,158,87,220, - 241,111,89,177,250,50,62,251,177,223,227,248,161,221,100,29,7,37,178,41,99,227,8,140,4,65,76,54,83,38,91,44, - 34,125,65,206,115,200,56,170,205,163,9,242,249,34,202,245,104,5,1,190,239,163,148,67,98,82,32,87,74,33,244,146, - 252,65,145,201,248,152,212,166,158,140,167,144,74,225,185,89,154,145,69,182,34,102,231,38,24,27,27,229,134,107,87,241, - 204,254,61,148,114,59,65,141,176,121,251,32,99,195,27,56,114,240,75,204,77,95,192,247,32,239,187,52,98,80,237,16, - 178,165,214,232,193,233,51,52,130,26,201,247,48,222,91,34,168,217,8,81,116,232,238,234,72,23,109,173,229,187,53,163, - 112,218,161,134,177,82,244,118,119,211,227,56,228,187,58,185,112,239,35,168,90,253,18,162,188,212,231,211,125,161,242,21, - 40,130,156,135,14,11,203,38,10,217,238,93,183,220,146,150,249,246,185,221,33,33,192,10,145,190,184,34,45,215,177,154, - 168,213,96,126,118,146,70,179,70,28,181,104,5,13,116,3,226,88,179,88,173,208,106,182,208,218,48,51,53,211,246,37, - 22,136,88,210,213,213,197,220,194,2,70,74,138,165,14,234,173,58,177,78,245,42,43,87,143,210,223,223,71,169,80,162, - 183,183,143,108,169,4,82,161,218,83,155,165,164,80,129,104,175,40,216,180,220,247,50,116,118,247,112,235,171,174,101,122, - 98,138,193,129,53,172,127,253,237,153,217,175,124,121,100,153,49,163,46,20,159,133,214,239,125,135,234,37,3,172,252,14, - 32,37,218,237,217,223,167,220,25,47,230,126,126,57,152,24,22,12,226,172,143,157,219,185,48,31,253,207,63,248,13,255, - 199,223,243,159,217,113,245,59,121,236,208,215,152,169,60,197,173,91,15,113,120,98,146,131,19,55,144,95,249,42,254,197, - 191,219,206,51,247,125,132,7,238,251,4,179,231,79,145,83,2,235,103,168,89,77,214,201,128,86,72,235,16,197,150,86, - 37,38,151,41,224,186,46,205,122,147,222,222,62,242,249,220,197,22,55,73,98,130,32,32,159,47,96,180,126,78,6,97, - 12,142,163,200,102,253,148,196,206,229,48,198,144,36,9,174,43,137,163,144,106,181,198,252,124,149,129,161,94,214,173,201, - 112,234,196,5,58,75,155,152,171,79,147,47,174,231,138,171,7,57,121,226,49,142,236,189,27,130,38,42,159,67,40,41, - 45,8,167,253,156,53,90,117,30,108,125,127,46,222,45,133,49,148,84,36,250,123,107,97,38,172,69,91,139,136,34,230, - 10,5,158,184,241,26,42,247,63,134,170,84,47,161,202,75,1,160,167,190,197,221,217,3,37,160,171,5,67,206,182,157, - 133,13,91,54,129,14,46,146,194,66,166,160,35,68,58,38,215,180,35,94,130,128,51,71,78,18,183,90,156,60,123,138, - 133,197,5,130,32,68,89,133,53,6,63,147,105,231,139,91,134,7,135,211,133,73,199,161,163,51,79,28,133,12,143,118, - 164,137,161,113,68,198,43,210,217,81,38,137,99,22,91,117,22,39,35,38,130,128,3,218,82,238,232,164,171,167,143,190, - 129,65,186,122,123,17,106,41,35,93,94,220,137,2,75,161,92,162,114,161,198,202,85,3,212,226,212,200,97,211,77,215, - 240,245,193,254,126,59,49,181,78,8,49,16,88,59,223,13,137,255,45,238,143,75,169,1,115,164,33,121,223,174,170,89, - 11,252,87,224,20,112,125,58,69,252,182,99,54,63,173,52,169,97,29,11,190,144,137,76,146,9,62,246,222,255,132,174, - 84,217,126,199,91,25,191,48,198,223,223,251,113,110,222,58,75,199,232,151,120,236,236,49,90,185,155,185,234,246,247,176, - 249,218,215,242,204,131,159,102,247,61,95,100,122,230,48,142,178,8,153,39,50,9,36,1,50,48,68,6,130,36,70,38, - 10,165,28,6,7,7,47,26,142,165,94,215,105,162,234,18,32,165,55,25,139,227,166,162,66,221,30,203,63,55,154,119, - 145,82,18,199,49,11,243,243,20,242,121,124,63,203,200,64,63,213,217,211,212,235,46,165,66,39,243,205,10,34,238,100, - 213,170,219,232,239,26,228,192,179,119,179,24,206,209,240,60,215,166,97,154,50,223,150,122,124,47,189,151,104,131,127,0, - 148,11,133,111,200,129,255,94,31,11,120,73,194,92,46,71,207,29,55,113,100,255,17,70,246,29,226,18,61,253,34,1, - 232,53,223,60,94,78,171,31,254,2,100,25,178,13,200,55,202,157,94,185,88,120,238,242,124,190,27,95,59,31,70,27, - 141,43,4,11,211,179,92,56,115,158,7,191,126,31,197,114,39,195,163,203,72,104,209,55,214,137,142,90,116,119,116,81, - 89,92,36,54,17,142,43,40,230,75,36,113,76,152,196,20,75,229,52,143,42,138,40,148,10,228,11,57,16,22,87,102, - 41,116,20,210,246,75,150,49,214,210,108,133,204,207,92,96,118,234,2,67,195,35,44,223,184,1,148,215,78,134,16,44, - 169,26,189,76,6,43,37,86,196,44,46,84,33,137,25,91,53,74,112,221,174,238,250,39,191,176,62,3,107,198,224,204, - 155,160,146,255,54,79,212,19,164,86,171,223,137,100,94,178,136,248,98,187,10,250,207,124,251,152,153,32,125,206,133,0, - 37,16,242,140,180,42,145,33,182,85,229,99,127,241,223,57,55,127,154,31,121,235,47,16,103,255,35,159,223,255,247,108, - 236,219,205,109,203,14,112,114,102,154,51,19,219,241,58,47,231,234,215,255,18,219,175,123,3,207,62,248,9,30,255,234, - 199,169,213,171,180,156,136,134,209,120,65,11,191,208,194,46,54,81,178,128,155,117,241,51,62,158,227,34,132,162,209,106, - 162,164,75,24,68,196,113,140,231,101,80,109,65,160,235,58,237,73,153,38,155,205,34,5,248,190,79,24,134,105,204,15, - 16,199,17,173,102,147,74,173,2,18,54,111,238,99,239,254,35,52,163,245,248,110,158,102,18,208,170,75,74,29,107,217, - 113,117,7,15,62,249,89,106,179,23,164,133,108,29,188,127,3,226,119,193,126,183,245,201,146,37,111,196,115,137,171,159, - 4,62,109,204,247,12,220,190,45,233,221,54,116,107,109,219,72,183,181,92,216,127,248,18,186,188,152,215,109,241,5,62, - 169,83,182,69,168,52,106,94,230,11,37,225,56,18,99,211,81,174,160,173,223,177,96,49,24,171,81,82,208,170,55,88, - 152,159,97,239,222,39,201,21,92,54,110,94,77,179,213,162,148,201,224,23,50,72,147,33,142,34,202,229,18,133,114,137, - 68,39,68,65,64,33,155,37,155,203,167,252,141,209,228,140,143,114,36,137,73,72,76,130,18,138,140,78,91,2,233,164, - 161,125,133,130,79,169,109,200,30,55,42,204,140,95,160,111,120,20,107,4,86,56,136,139,194,69,7,199,247,113,154,25, - 38,46,156,33,142,12,110,206,101,228,77,175,247,206,127,242,11,171,54,88,187,206,192,83,143,65,229,67,192,193,111,226, - 111,2,224,215,72,179,180,95,236,69,178,68,115,126,1,184,163,253,125,47,52,244,93,34,251,115,105,5,160,141,148,122, - 10,165,164,73,136,51,18,220,22,247,125,238,125,212,79,158,227,245,239,254,77,70,175,255,89,78,158,126,128,227,143,127, - 134,203,86,76,112,229,80,200,145,241,195,204,85,174,194,27,216,192,43,223,248,107,92,126,205,235,248,244,223,253,79,78, - 28,60,128,54,14,213,100,150,48,108,161,100,6,33,4,189,189,189,228,115,89,194,32,196,216,212,27,104,41,1,99,201, - 196,222,201,56,23,125,130,148,227,160,148,66,57,10,207,115,46,102,143,45,249,18,197,113,68,181,182,136,227,123,40,199, - 5,19,177,110,93,31,143,63,117,150,56,92,75,206,87,72,63,33,137,93,92,217,143,162,72,35,140,29,4,93,198,210, - 177,8,78,25,162,151,91,49,136,54,232,76,146,186,215,205,145,186,40,22,121,241,170,244,239,89,53,100,45,197,56,230, - 224,214,13,212,138,5,244,254,195,112,137,23,122,249,99,248,54,24,137,66,62,143,116,36,214,36,41,255,44,100,26,73, - 35,20,182,173,235,17,198,18,54,27,180,90,117,250,6,123,232,40,21,105,197,85,188,188,79,169,179,139,170,205,49,61, - 49,137,104,70,148,10,69,206,94,152,160,214,104,176,56,51,67,78,185,244,12,150,24,24,30,192,43,228,241,51,62,120, - 30,158,35,113,76,130,176,6,169,45,113,24,166,21,142,209,72,145,198,254,10,99,81,2,206,158,62,73,161,212,65,190, - 208,209,142,45,94,26,249,75,220,140,79,33,219,73,88,63,68,179,17,82,206,185,172,223,181,139,61,163,195,189,27,207, - 93,88,174,161,191,23,198,143,67,252,4,223,24,209,211,108,223,89,95,234,182,181,109,183,110,187,72,247,195,14,240,15, - 87,62,18,82,143,146,159,77,43,160,76,40,101,102,210,203,40,199,177,88,147,42,140,115,46,236,221,243,5,78,76,236, - 225,214,183,252,75,174,190,225,237,68,3,235,121,224,200,215,233,170,62,195,43,86,213,136,230,191,204,179,103,158,161,82, - 190,153,222,225,43,233,91,185,139,243,71,143,80,82,62,137,81,44,198,18,43,211,74,181,163,163,3,173,45,173,86,72, - 62,159,199,109,139,21,151,44,91,93,215,35,81,26,167,13,50,182,237,23,148,198,252,152,246,126,24,228,218,124,80,163, - 209,32,10,35,146,208,208,106,132,184,82,162,154,130,245,235,11,60,253,196,17,124,103,53,184,10,229,184,84,171,115,220, - 126,199,107,56,59,189,215,137,235,139,93,2,74,205,182,47,244,2,47,111,23,76,3,171,219,207,239,111,241,141,246,173, - 255,40,109,144,5,147,104,122,87,47,103,119,111,55,157,247,62,204,194,37,16,122,249,0,100,128,169,70,5,109,52,158, - 16,8,41,150,214,183,144,207,11,249,22,54,193,36,33,97,28,18,26,136,172,67,182,208,65,172,5,159,253,224,231,147, - 252,145,51,81,249,194,68,131,102,43,156,179,194,132,81,8,88,65,162,77,67,39,40,87,234,70,214,167,81,40,120,153, - 238,110,183,212,215,231,169,254,190,172,237,239,247,220,145,97,89,88,214,75,71,111,7,165,124,14,207,53,160,35,146,176, - 133,176,144,81,10,27,133,156,57,126,130,141,219,46,79,31,156,18,24,155,234,31,51,121,31,213,82,216,216,112,104,239, - 1,54,94,185,133,209,177,85,176,126,99,62,60,119,97,181,130,205,85,184,240,255,192,228,8,232,85,237,202,36,79,170, - 247,153,253,46,248,129,165,29,165,107,218,96,246,205,23,79,79,90,113,185,2,10,129,177,185,89,37,164,193,161,16,180, - 208,174,36,214,14,89,215,82,153,57,206,199,255,228,215,56,254,208,125,220,244,182,159,101,195,214,215,177,184,112,45,247, - 159,122,136,13,229,211,108,31,29,103,166,254,73,162,243,67,228,106,147,88,199,208,148,139,120,162,128,105,37,120,74,210, - 217,217,73,198,203,224,56,46,133,66,234,19,20,133,81,202,233,56,146,32,104,145,205,230,47,102,205,107,157,242,63,218, - 24,146,86,3,109,76,234,17,148,205,166,70,102,237,141,251,88,74,106,139,115,120,202,210,242,44,218,10,178,89,201,101, - 59,243,60,189,247,16,61,93,215,80,79,90,116,44,203,112,249,117,155,25,191,115,64,6,231,143,229,114,80,168,131,219, - 1,65,129,151,182,127,190,180,186,28,144,250,119,247,112,209,115,251,31,253,8,32,14,35,114,133,60,111,186,241,90,62, - 122,239,195,232,75,32,244,242,0,40,11,198,206,204,196,81,148,168,76,214,77,53,55,214,182,137,222,182,74,217,10,48, - 49,113,171,133,175,92,58,253,60,25,229,227,10,159,7,247,61,203,194,71,63,95,191,221,154,195,89,216,35,211,106,249, - 31,12,136,108,172,177,113,3,170,13,244,248,148,171,57,216,21,195,64,4,61,11,66,246,93,200,251,69,53,220,159,111, - 140,141,22,114,107,87,120,107,118,108,21,195,171,150,211,219,85,34,136,91,116,151,60,166,43,11,84,234,243,148,139,93, - 232,68,163,149,64,197,22,33,92,158,125,234,9,146,19,231,216,125,224,36,251,190,248,69,198,182,111,167,153,207,58,79, - 192,218,87,10,110,139,45,139,30,220,223,7,115,222,243,218,176,230,119,121,39,13,129,219,72,45,68,119,242,141,230,235, - 30,105,124,143,134,188,128,129,5,207,235,108,42,71,120,90,32,149,34,81,2,97,5,73,96,112,85,1,215,141,217,247, - 244,231,57,120,224,49,118,94,117,19,55,191,254,103,24,89,255,54,206,206,157,224,220,133,167,232,244,142,210,223,125,138, - 145,174,57,114,202,39,104,25,172,87,33,10,22,200,229,11,100,243,57,130,176,133,163,36,158,151,65,8,73,156,196,56, - 110,6,99,37,141,70,64,177,20,130,205,33,109,26,241,19,39,1,137,78,240,253,18,54,106,96,13,132,97,152,106,130, - 28,143,140,231,17,4,33,100,28,162,160,6,139,22,175,100,104,36,62,197,142,60,163,67,49,227,51,135,160,80,96,197, - 134,213,204,84,3,236,64,159,154,131,222,2,140,72,40,253,66,106,24,247,146,193,125,201,210,228,205,252,96,198,244,232, - 36,161,92,200,243,230,27,175,37,119,223,195,44,84,47,129,208,63,0,160,225,111,65,66,251,41,49,104,179,96,250,143, - 159,106,86,166,23,51,197,229,253,34,229,129,12,234,226,186,68,58,148,55,70,147,232,4,37,5,133,124,142,64,39,8, - 44,173,243,231,185,202,154,233,28,220,19,192,23,61,24,247,47,6,0,191,240,157,77,131,106,64,209,131,46,15,122,58, - 172,233,95,85,111,246,36,71,78,245,53,142,156,26,108,222,245,64,255,184,159,29,126,106,221,218,1,239,53,183,248,59, - 111,184,154,213,195,221,148,18,216,247,204,30,174,187,249,150,116,132,172,193,120,30,135,190,254,40,147,79,62,203,168,117, - 136,109,76,56,95,227,236,221,247,49,236,23,196,99,219,119,12,179,111,223,43,110,208,201,100,3,78,159,132,106,247,243, - 110,164,115,237,73,213,119,115,98,210,77,249,183,124,83,27,118,30,232,6,53,9,61,2,70,79,249,217,174,138,78,112, - 19,75,36,93,26,58,65,201,4,132,197,146,128,149,56,190,143,164,202,67,247,126,138,221,123,30,231,234,27,223,200,43, - 110,125,11,254,208,143,48,94,27,231,236,133,103,248,250,222,251,241,243,46,30,5,116,24,145,152,0,215,47,2,6,161, - 68,187,186,209,237,236,120,77,162,227,116,162,169,53,73,152,16,169,22,202,247,144,210,193,90,73,28,181,200,203,12,126, - 156,2,163,177,10,84,134,70,28,227,88,40,228,114,32,114,44,52,4,93,210,210,172,47,162,242,69,106,21,65,71,38, - 203,193,201,167,25,222,122,13,221,197,65,230,206,61,66,105,216,99,143,155,25,92,21,135,235,68,106,198,54,245,157,84, - 11,182,13,54,89,82,239,159,191,36,141,81,250,65,63,113,146,208,93,200,179,251,198,235,232,190,247,33,184,4,66,223, - 8,64,31,248,22,37,164,74,51,183,26,2,170,250,194,249,248,212,83,187,245,200,138,55,56,152,56,229,128,158,95,48, - 11,129,17,130,216,26,60,47,131,206,103,72,26,49,213,48,34,123,252,92,50,10,167,99,120,170,12,251,143,64,237,99, - 60,103,216,245,66,21,195,43,65,172,5,57,148,218,187,122,58,245,141,206,73,33,202,69,107,187,243,48,212,31,180,54, - 13,237,221,123,217,227,135,14,109,121,255,167,191,216,187,235,221,111,146,239,124,237,143,112,126,226,32,179,179,85,122,74, - 101,172,178,60,113,207,3,204,60,248,12,189,137,203,162,14,72,124,23,139,164,208,140,233,118,51,116,92,117,19,95,157, - 154,237,223,49,113,110,99,14,150,73,56,114,20,226,28,255,48,66,247,187,45,203,91,164,30,64,180,43,161,227,41,247, - 211,45,96,163,145,106,237,25,100,222,152,180,183,21,130,52,173,194,74,164,18,196,38,85,121,199,38,65,90,75,62,231, - 19,53,230,248,218,231,254,150,189,143,125,157,181,87,95,207,214,203,110,98,164,176,145,185,74,158,124,182,129,113,154,232, - 208,65,24,151,222,174,62,60,55,131,209,22,235,62,71,154,10,169,48,86,224,42,139,2,148,240,49,38,70,27,23,43, - 20,249,194,16,35,99,221,212,227,41,26,141,42,74,7,100,140,164,228,122,52,99,152,175,213,241,114,57,98,109,137,162, - 38,217,2,56,56,100,45,8,109,153,156,156,166,111,104,25,107,174,184,153,153,185,113,156,224,8,59,95,113,35,95,191, - 255,80,169,126,124,207,72,6,186,207,130,243,63,32,105,188,192,243,109,218,36,115,12,252,27,224,198,246,215,252,83,242, - 130,214,73,66,35,159,227,236,13,215,176,101,223,97,226,83,103,47,45,181,46,1,144,255,173,91,7,13,76,41,56,210, - 169,147,43,206,61,252,104,39,111,125,61,98,105,157,93,152,180,245,18,233,116,74,27,155,218,48,196,26,27,197,248,174, - 143,240,74,20,206,94,168,23,82,223,151,115,171,160,245,44,240,249,239,240,160,124,176,99,160,71,65,111,134,240,46,168, - 29,2,177,222,90,153,128,147,133,156,65,236,206,97,247,223,26,69,215,109,59,124,120,215,23,255,243,255,90,243,191,142, - 158,45,188,225,221,63,198,153,163,103,233,185,246,74,238,253,244,167,169,60,180,155,46,55,71,147,16,47,159,101,106,106, - 156,201,133,89,150,245,13,144,201,56,12,58,25,250,55,110,80,227,19,231,122,214,65,103,5,188,46,104,244,145,106,127, - 158,127,7,254,174,198,180,164,41,132,197,118,235,85,77,63,50,157,176,198,194,245,161,114,214,158,21,194,83,82,32,77, - 106,76,2,169,162,215,216,37,11,1,129,209,237,142,55,106,33,133,164,232,100,104,206,30,229,145,79,61,203,222,47,127, - 148,101,3,43,112,154,51,8,25,99,28,7,43,12,153,124,7,224,209,106,134,228,114,170,29,1,38,241,60,31,19,4, - 109,11,15,133,112,125,66,4,58,49,100,173,139,137,67,74,189,131,172,94,117,3,129,219,160,90,25,167,114,254,12,141, - 241,83,152,218,60,133,172,194,218,132,230,194,28,126,206,197,68,9,113,224,35,203,30,177,142,152,159,169,51,189,80,97, - 227,13,175,39,50,157,248,225,35,244,173,88,77,82,188,6,151,191,17,9,168,12,168,4,196,23,218,213,230,11,157,1, - 224,39,219,191,38,255,68,47,52,155,36,116,231,114,76,189,98,23,149,66,30,111,223,161,75,32,4,56,175,248,22,127, - 81,1,115,4,102,90,112,160,27,206,78,236,217,55,92,175,7,94,54,171,48,70,183,149,207,207,191,83,165,147,176,44, - 138,140,149,148,186,122,120,252,169,103,233,156,156,152,151,112,214,194,236,57,208,111,0,254,11,112,250,59,60,176,165,26, - 107,105,204,58,1,182,3,244,97,208,191,13,225,126,108,173,46,228,116,36,196,153,110,163,79,188,91,39,175,248,218,7, - 62,116,197,99,103,207,117,154,205,91,188,147,251,15,138,234,19,251,88,153,47,19,232,128,40,171,104,85,107,184,40,114, - 217,28,243,205,6,211,181,58,203,178,9,3,67,131,84,148,83,210,58,233,117,33,191,31,22,178,237,187,239,104,187,90, - 89,154,132,137,23,104,13,94,10,225,246,252,11,168,0,69,3,27,4,98,71,75,80,170,72,97,173,54,36,198,166,123, - 113,109,107,18,251,60,204,23,168,212,39,210,154,182,108,161,133,194,82,118,75,216,56,224,216,137,71,232,236,232,99,96, - 96,3,70,70,132,166,198,192,80,47,74,57,24,29,227,58,94,106,28,143,192,104,157,146,200,113,140,149,14,210,86,72, - 140,143,16,121,226,56,34,227,123,24,221,162,94,159,33,215,177,154,129,238,229,244,119,93,65,188,174,194,252,212,41,42, - 211,39,80,139,231,112,231,199,105,53,102,201,72,151,164,161,193,248,160,20,245,230,44,214,19,248,189,35,196,149,3,140, - 22,230,161,112,25,39,78,156,134,179,135,227,66,26,85,168,151,146,80,95,8,128,254,93,58,37,164,183,205,163,253,83, - 142,100,182,198,16,7,17,3,91,54,176,63,159,195,63,116,148,124,165,246,207,58,90,200,121,226,219,0,128,77,187,134, - 51,57,56,161,247,29,216,122,238,240,177,194,134,203,55,162,105,181,151,77,219,190,199,82,34,218,134,89,38,163,136,48, - 36,174,67,50,49,75,95,20,77,27,56,231,67,245,44,216,113,210,176,191,255,240,2,83,161,239,212,194,40,158,139,251, - 217,2,201,39,173,153,217,134,172,205,41,103,194,96,39,110,215,58,56,118,207,253,215,254,233,179,7,6,244,53,55,136, - 45,195,163,84,234,53,50,217,12,213,133,58,253,221,61,248,29,61,244,234,144,90,189,70,208,10,113,98,139,109,181,104, - 10,81,86,176,49,20,98,75,217,90,115,12,90,18,188,30,200,180,65,48,216,14,205,24,162,10,36,175,2,51,198,115, - 49,210,170,61,53,179,223,226,34,81,109,238,98,22,56,75,26,53,61,4,185,0,6,21,182,107,193,245,212,28,86,40, - 209,246,225,65,182,141,226,45,218,166,254,58,142,148,104,169,72,172,193,74,75,98,12,194,26,12,6,35,19,172,107,8, - 165,32,223,223,67,215,96,63,245,202,28,174,3,25,233,18,71,33,174,163,136,194,144,140,159,26,146,213,226,56,117,20, - 48,22,35,211,113,187,140,12,210,19,132,162,69,70,120,120,246,44,3,250,20,241,252,8,85,49,66,226,244,163,253,101, - 184,67,187,24,28,189,28,25,207,19,213,207,241,232,221,159,39,172,30,167,25,79,192,180,71,103,103,9,108,72,84,247, - 200,196,45,138,242,12,34,51,64,192,48,167,15,252,111,26,166,34,4,162,96,176,221,125,224,191,29,90,255,235,155,158, - 179,159,110,243,60,147,252,240,100,193,139,118,75,118,104,213,24,238,216,8,93,135,142,81,46,22,200,122,223,56,15,210, - 198,180,29,37,126,200,1,168,247,219,220,173,207,64,18,195,84,6,142,118,206,207,205,28,190,231,190,222,181,151,111,148, - 26,131,176,18,99,44,82,138,246,226,168,196,85,14,145,23,161,28,69,53,137,48,71,143,7,101,152,146,48,81,131,214, - 191,39,93,59,200,127,15,30,120,210,174,138,214,89,211,186,160,205,169,33,169,108,2,203,234,136,29,215,108,189,92,174, - 29,26,33,10,154,36,36,204,78,204,179,122,221,90,138,217,60,213,122,149,176,217,66,70,134,178,85,224,88,198,122,250, - 216,219,219,159,143,38,206,95,230,166,180,250,122,139,93,48,136,18,216,142,246,150,255,188,129,113,9,51,207,192,220,143, - 64,179,149,238,113,133,203,161,121,103,26,251,99,103,193,22,33,185,21,204,70,176,109,87,1,100,27,132,154,237,22,204, - 73,253,1,18,43,68,224,88,27,238,21,34,179,104,141,202,180,13,121,76,123,186,40,108,90,13,25,44,113,18,131,146, - 23,183,213,109,123,41,216,160,144,196,72,45,17,81,150,206,82,23,157,69,143,218,92,72,62,91,66,99,112,165,67,33, - 151,197,113,93,220,140,135,148,18,173,19,60,215,193,106,75,66,136,84,46,54,17,224,36,68,73,66,98,19,108,220,162, - 39,43,88,53,50,78,61,58,205,212,130,195,228,162,207,108,216,71,160,198,176,249,101,228,186,183,113,213,237,195,60,240, - 241,223,68,196,51,76,78,78,18,199,13,146,160,202,217,83,139,76,29,254,26,195,253,62,13,255,90,166,39,231,184,98, - 213,58,30,184,230,21,153,167,31,184,111,249,21,176,173,14,7,222,10,117,7,226,223,121,222,107,124,45,124,15,13,58, - 126,176,142,27,39,88,4,147,27,215,242,112,108,233,126,228,32,151,111,88,131,20,130,158,142,46,98,223,225,212,112,192, - 234,249,35,63,212,32,228,204,124,7,222,194,135,69,11,135,58,224,232,153,47,126,105,108,226,39,223,92,28,232,43,163, - 19,221,118,62,20,24,99,17,6,114,194,197,58,14,67,165,46,142,213,90,168,233,153,192,75,141,167,102,124,136,127,227, - 121,63,59,7,252,53,112,231,119,113,39,17,192,161,116,34,162,255,212,232,133,6,204,42,41,131,174,108,14,207,90,180, - 209,92,152,155,98,205,242,149,4,58,161,53,59,75,173,81,163,209,168,147,203,231,201,10,197,162,74,200,27,67,180,110, - 149,247,224,236,196,104,167,160,39,31,155,43,124,75,3,172,159,3,207,73,219,176,166,130,57,7,166,61,152,12,82,35, - 179,200,73,53,116,83,37,104,154,212,43,32,114,97,254,38,168,89,72,198,65,151,161,181,3,90,25,72,202,160,175,4, - 179,10,120,28,90,89,107,231,91,82,182,158,208,137,103,164,159,238,102,37,150,68,164,249,92,210,128,86,233,230,191,35, - 36,198,104,210,42,41,5,39,129,76,197,78,137,64,138,182,119,180,142,241,4,20,179,69,60,223,167,22,215,136,147,144, - 56,118,208,198,224,122,30,25,63,131,49,138,36,136,136,194,16,75,130,144,14,117,147,80,84,26,47,80,216,102,72,100, - 251,121,252,252,50,78,214,106,140,20,38,25,235,213,108,236,155,195,154,113,206,205,238,231,196,124,15,83,199,135,201,116, - 108,102,211,150,171,56,183,239,126,84,62,67,103,79,23,171,151,239,224,150,215,102,153,159,158,103,114,188,14,225,97,154, - 11,243,140,150,11,220,246,186,183,115,239,153,211,35,171,206,156,190,170,8,199,5,204,172,129,137,78,176,141,118,165,171, - 190,7,220,91,234,109,109,47,70,87,127,203,246,200,90,164,146,66,57,202,10,243,127,79,194,232,0,115,51,21,166,39, - 22,184,229,202,157,88,11,113,162,193,194,189,59,251,104,57,30,187,118,239,35,225,135,51,167,195,217,245,29,190,224,49, - 104,85,225,120,14,246,116,60,245,244,166,211,247,63,189,110,224,45,183,99,68,170,17,86,58,139,164,133,69,145,144,32, - 133,193,149,30,78,208,192,204,205,68,18,170,57,104,124,1,204,31,180,73,216,165,22,175,249,93,60,240,12,112,21,169, - 10,246,6,96,30,226,24,230,134,140,158,58,120,116,223,134,96,120,84,29,189,48,73,103,95,47,245,86,64,92,173,147, - 247,179,20,10,57,18,155,208,208,33,129,182,104,161,72,170,13,122,123,202,202,125,235,155,74,214,186,229,217,106,125,32, - 142,66,194,74,213,122,81,152,196,54,164,30,104,225,90,73,41,137,66,181,184,216,234,136,194,86,103,28,71,202,232,166, - 50,118,209,215,186,233,98,181,132,64,195,84,11,230,69,10,70,129,133,105,9,51,2,230,151,193,76,4,243,71,161,238, - 131,235,66,102,194,24,47,191,118,141,44,47,44,18,214,235,72,87,33,141,193,152,212,168,40,117,55,209,32,76,123,83, - 61,141,82,150,8,16,169,58,221,74,151,68,26,172,136,17,194,16,39,233,96,160,209,104,97,149,68,138,84,152,105,219, - 62,220,73,18,227,72,213,22,150,90,180,246,208,45,133,173,215,241,125,23,137,33,50,33,94,71,15,197,254,107,145,249, - 14,78,212,207,115,118,122,150,130,188,64,89,158,98,176,212,228,21,131,14,54,57,203,68,235,28,135,91,57,206,61,61, - 207,79,255,244,187,24,29,217,198,211,251,31,97,106,246,12,202,184,108,94,191,138,254,101,99,220,249,217,221,204,197,69, - 70,135,70,217,250,227,255,218,123,248,189,191,179,233,117,213,249,27,170,48,177,6,30,126,4,22,159,1,251,197,231,77, - 12,95,238,49,192,244,194,12,29,29,57,162,56,249,14,0,132,152,24,215,120,158,123,49,125,246,255,246,153,254,166,106, - 192,72,201,167,124,88,238,72,250,18,243,67,211,134,126,51,0,127,219,179,46,37,163,167,66,216,223,209,106,157,62,254, - 55,31,28,91,127,253,43,253,114,159,151,78,188,108,2,2,148,204,160,114,25,162,106,19,167,88,162,88,109,208,129,142, - 73,199,249,118,241,185,201,207,119,38,235,218,15,76,61,239,207,75,21,207,211,192,47,183,63,159,125,30,169,123,11,4, - 121,56,219,1,199,87,46,204,108,123,242,196,190,158,140,246,40,248,89,202,142,34,235,251,104,87,80,181,17,249,21,3, - 12,244,118,210,104,53,177,113,194,220,212,52,51,187,199,185,108,213,70,209,33,60,146,82,55,90,88,132,53,34,177,198, - 109,186,16,4,1,42,189,248,157,32,12,243,73,98,168,36,26,27,37,152,32,180,45,221,50,68,129,201,86,234,177,91, - 173,5,162,82,105,9,173,181,103,146,200,105,52,22,125,99,230,114,48,147,129,211,26,142,135,112,18,33,93,97,205,170, - 9,199,235,222,118,245,53,156,250,210,157,132,214,96,100,90,221,72,1,86,166,147,48,97,212,146,137,118,26,84,36,68, - 154,72,138,76,189,149,72,117,89,54,129,66,182,132,182,130,88,235,116,130,102,64,40,65,156,36,237,148,12,80,66,97, - 116,186,43,39,29,151,196,24,164,8,145,97,140,13,242,180,132,64,197,30,243,139,211,60,244,192,123,217,114,217,13,116, - 140,141,162,115,131,196,238,8,13,189,129,11,211,103,136,142,29,166,171,40,24,27,113,48,245,115,252,220,187,175,103,93, - 95,157,39,30,254,51,194,240,24,219,7,71,169,212,138,28,222,115,132,83,135,87,242,166,31,123,7,95,254,200,71,72, - 14,31,100,96,229,70,46,220,254,134,238,71,63,254,215,87,95,13,115,13,88,240,97,119,3,154,57,190,55,171,20,19, - 139,21,94,123,197,90,74,133,252,119,4,33,99,140,181,63,96,54,171,145,235,112,202,110,162,247,177,125,63,156,45,216, - 99,47,98,124,12,180,20,156,148,112,40,127,255,189,27,14,127,253,254,209,235,222,113,135,208,214,96,149,65,227,165,102, - 244,74,33,132,32,227,123,72,215,33,178,246,37,197,168,23,219,147,142,114,202,63,177,145,84,41,188,240,60,78,224,120, - 155,200,245,248,198,45,243,126,72,234,112,65,195,190,85,179,139,151,77,214,102,186,54,93,245,10,89,12,67,50,170,192, - 140,12,81,197,28,43,55,109,100,104,205,10,156,98,150,32,9,137,130,16,105,45,217,66,47,245,147,19,248,89,72,116, - 11,141,70,234,20,61,77,75,80,148,2,161,99,172,16,20,164,2,207,65,102,221,37,79,52,81,149,90,25,101,149,103, - 133,155,196,113,46,49,150,80,107,148,1,211,10,160,214,52,157,211,211,13,255,236,177,185,176,82,155,30,17,226,168,197, - 84,34,216,220,88,191,161,99,217,134,245,84,63,246,145,84,151,211,54,230,90,138,72,22,214,98,132,2,37,73,255,233, - 212,9,50,137,13,70,75,144,62,74,106,76,18,98,146,152,108,54,67,24,54,137,147,0,65,202,33,105,13,185,108,39, - 90,39,169,17,125,123,9,53,181,47,81,88,19,145,36,9,17,14,81,208,174,146,154,9,73,125,150,82,118,142,112,230, - 62,138,93,43,144,129,68,235,136,196,106,178,217,18,178,184,134,11,245,44,181,51,17,181,70,133,91,54,94,205,35,247, - 222,201,198,177,38,221,197,49,162,102,158,137,164,130,191,90,48,25,87,201,184,176,101,203,229,60,248,137,207,18,52,37, - 35,171,54,240,208,246,237,203,123,247,236,185,126,21,76,159,133,218,74,56,42,32,204,182,227,154,95,46,36,40,128,86, - 204,93,79,29,231,95,253,232,237,20,115,89,162,56,254,118,247,189,31,188,201,153,235,48,151,47,147,60,182,239,135,114, - 90,230,108,126,17,61,116,8,201,65,184,96,16,79,246,52,195,13,39,255,224,247,203,43,175,92,95,30,90,54,132,49, - 25,140,10,145,194,162,28,23,161,28,28,199,165,148,117,201,27,243,146,28,115,239,109,143,98,111,32,221,193,122,8,120, - 42,173,194,184,21,24,35,221,249,249,237,209,110,26,175,216,136,8,82,75,8,41,5,225,125,7,236,225,217,218,124,3, - 246,116,88,246,244,30,62,190,108,124,221,198,190,53,157,157,92,168,205,211,179,125,61,87,223,124,61,110,46,131,113,4, - 185,98,30,71,41,38,206,158,37,14,90,108,186,122,39,31,63,240,33,234,170,68,62,91,0,107,240,4,100,61,135,188, - 54,132,128,201,180,109,72,196,115,153,101,75,30,57,153,216,193,70,6,100,130,239,40,148,77,16,82,146,104,144,221,5, - 220,222,188,76,214,174,47,26,179,181,248,165,135,246,44,47,31,56,180,238,199,9,23,38,161,152,189,102,123,214,201,8, - 194,48,198,207,58,109,240,73,35,101,172,105,71,239,200,4,35,20,82,120,88,171,48,177,192,234,152,56,106,18,199,117, - 50,74,144,207,101,233,44,118,160,148,64,8,155,154,134,197,17,174,114,136,181,161,21,182,200,229,178,40,165,136,162,40, - 181,93,69,16,39,26,147,24,116,18,35,176,233,186,134,147,163,190,88,167,195,87,188,229,103,95,203,192,96,23,113,28, - 34,76,130,52,169,105,153,227,148,153,152,147,124,238,171,123,25,159,126,156,43,182,230,56,118,110,145,226,250,87,17,200, - 83,28,57,118,138,153,133,73,74,125,17,214,134,228,76,68,227,224,103,89,59,186,130,135,74,46,141,184,138,51,221,98, - 195,117,183,136,207,157,155,88,251,115,115,83,183,102,211,61,252,135,214,97,79,91,152,95,132,166,110,143,234,159,95,13, - 191,148,115,102,124,154,63,254,240,157,252,226,91,95,69,169,144,251,118,32,244,131,7,64,34,37,172,127,104,73,232,23, - 3,251,58,29,133,46,14,10,158,54,150,21,157,79,61,51,240,212,95,254,237,198,219,126,227,151,92,55,163,211,241,173, - 112,144,210,65,58,10,157,196,116,117,22,201,186,110,219,98,254,219,191,105,124,82,187,139,92,251,223,242,218,119,175,32, - 29,127,47,145,225,23,99,120,107,195,221,236,126,219,213,100,60,7,225,58,24,207,97,112,172,143,161,223,255,124,184,23, - 142,187,240,240,198,74,107,205,125,7,14,118,30,187,252,106,119,231,245,87,112,245,107,95,133,151,205,165,62,214,66,32, - 76,140,176,130,254,129,33,166,207,157,167,111,69,63,21,23,62,253,241,79,4,87,117,14,76,140,40,213,202,11,37,202, - 25,95,120,70,91,143,36,84,74,218,80,91,217,178,86,33,5,197,40,168,106,173,109,36,85,102,198,58,217,166,116,164, - 201,122,194,31,232,43,228,123,123,138,185,82,103,169,156,119,133,34,65,52,234,216,48,192,201,186,236,220,190,131,207,52, - 131,242,157,23,78,101,87,68,161,94,117,229,14,113,122,110,254,226,126,138,16,92,180,187,16,237,63,91,97,145,210,66, - 146,144,104,77,28,6,228,178,138,109,219,215,176,115,231,6,6,7,250,89,190,124,53,205,38,60,240,192,19,68,113,66, - 20,69,88,107,209,73,154,15,102,109,66,146,164,6,244,105,56,161,67,46,155,199,81,46,129,14,169,213,2,114,37,15, - 43,99,172,208,104,13,141,106,147,122,117,134,164,187,132,49,25,164,128,216,90,4,25,180,245,249,223,239,251,3,62,251, - 165,123,121,219,107,199,24,240,135,137,206,62,192,200,174,215,80,11,86,80,218,182,140,214,228,126,142,31,219,199,80,209, - 208,229,58,76,28,121,152,142,242,28,17,167,56,51,211,203,224,192,24,121,109,96,235,86,255,35,247,126,109,219,59,160, - 80,196,174,183,112,48,134,67,83,105,209,59,57,13,181,24,194,206,151,89,170,92,152,154,227,125,159,248,10,255,242,109, - 175,254,39,7,66,63,212,99,248,229,47,226,139,22,83,222,37,249,5,107,207,157,135,7,59,96,244,204,135,63,222,115, - 244,214,107,135,151,111,94,78,38,223,131,240,28,60,215,195,145,30,49,134,216,106,98,215,83,34,245,20,194,182,57,155, - 111,30,193,215,72,125,148,243,109,82,90,191,192,164,107,137,80,92,250,92,235,169,19,108,253,177,63,97,247,117,235,185, - 80,240,177,203,122,25,60,62,193,44,216,5,88,40,73,113,176,104,236,225,222,61,251,214,53,174,189,105,224,198,31,123, - 39,137,14,48,109,163,117,4,104,41,17,214,160,74,29,248,3,9,65,163,202,174,155,47,35,249,244,167,247,190,101,252, - 100,3,40,170,116,75,221,145,96,36,68,6,90,54,157,110,77,89,88,84,208,20,233,194,68,70,67,46,134,76,12,158, - 62,66,182,226,120,229,179,29,221,195,251,7,7,135,157,161,193,242,178,190,65,183,47,223,75,172,96,172,91,240,234,157, - 235,57,209,95,114,31,218,119,76,252,233,246,157,226,209,15,126,100,137,12,189,152,151,150,122,46,153,52,5,68,184,72, - 35,48,73,72,49,235,242,138,155,174,225,182,219,94,201,166,77,107,40,20,178,104,29,226,120,89,246,236,57,77,24,5, - 68,113,154,59,18,197,26,41,51,8,35,48,164,153,97,126,166,221,138,216,152,40,12,41,20,242,212,91,13,130,88,147, - 49,160,109,4,186,65,172,21,81,51,166,213,146,248,8,116,220,66,40,69,44,92,156,156,207,211,207,62,195,125,15,222, - 69,94,249,100,84,39,121,191,128,27,79,83,158,184,11,71,75,142,78,187,148,70,54,51,58,230,33,22,158,37,8,103, - 48,174,230,208,161,51,172,217,212,65,159,189,158,82,239,54,130,112,158,203,86,95,205,201,181,55,149,255,122,247,23,182, - 118,28,220,189,106,103,189,181,107,53,28,207,194,129,24,14,78,193,97,5,167,47,164,34,209,208,121,25,111,246,241,233, - 121,254,236,19,95,229,23,223,254,42,138,249,236,119,228,132,46,157,255,11,0,52,255,34,191,240,33,160,15,90,87,194, - 65,3,247,14,158,155,26,222,243,71,239,237,44,253,206,111,229,50,190,38,155,45,80,46,101,80,66,18,217,24,183,152, - 71,45,27,245,245,225,227,217,16,252,155,64,190,234,121,165,244,18,152,212,73,85,176,159,123,9,99,85,155,104,114,137, - 102,242,171,123,56,6,76,57,138,13,214,162,64,14,9,242,218,82,114,32,211,165,49,61,235,151,131,202,226,196,97,10, - 131,82,96,219,53,153,149,14,177,213,20,122,122,177,81,196,230,109,91,184,48,50,224,150,78,76,22,45,20,3,48,115, - 105,118,151,246,192,22,192,203,66,38,129,121,224,209,4,206,56,16,9,200,56,80,80,144,247,133,40,88,232,238,76,162, - 193,177,217,137,179,149,217,137,206,211,251,232,61,151,43,244,62,211,213,215,39,58,186,243,163,235,199,252,98,206,119,94, - 185,113,187,200,116,244,184,217,98,153,201,233,185,148,116,54,105,194,136,84,41,63,99,76,140,181,6,87,248,68,97,204, - 202,229,67,252,198,175,255,75,182,108,92,1,54,33,138,18,162,86,12,196,40,233,50,59,51,135,239,231,9,163,6,202, - 241,240,132,106,251,100,91,176,54,245,90,106,171,160,43,149,10,165,82,137,122,195,16,39,1,82,1,184,8,225,96,73, - 147,48,144,138,133,74,19,163,178,104,33,17,38,196,8,129,181,25,190,240,169,123,136,155,10,95,41,102,79,44,128,238, - 161,123,32,198,149,103,136,231,224,194,211,179,68,227,231,89,185,186,159,242,138,141,116,13,140,112,254,244,9,78,79,45, - 32,131,26,29,180,144,241,33,186,202,89,84,255,50,70,54,111,96,230,71,222,236,76,158,61,85,126,232,209,251,202,143, - 60,122,215,242,213,39,246,110,223,105,146,211,157,112,32,129,103,38,96,183,129,83,59,97,177,6,177,247,18,11,162,243, - 211,115,188,255,227,151,64,232,159,204,20,108,233,60,145,146,192,118,21,44,28,21,226,41,215,218,209,206,47,62,52,248, - 212,234,79,109,187,230,23,127,222,169,45,44,96,35,7,71,129,16,22,47,227,209,185,105,75,46,184,235,222,225,2,12, - 20,225,248,40,180,158,239,187,236,1,79,146,202,173,95,108,95,255,66,239,182,237,137,22,245,52,126,106,192,71,108,149, - 214,222,120,24,113,249,131,163,3,93,255,250,218,45,128,64,75,137,37,73,53,52,86,32,177,160,5,170,157,79,223,85, - 238,66,74,151,248,242,29,195,247,156,248,242,254,72,8,119,118,217,80,39,91,55,149,71,134,150,201,206,76,54,62,188, - 119,95,179,116,255,253,23,182,65,103,132,141,52,156,146,80,237,2,49,14,202,3,71,88,155,113,32,167,5,29,210,210, - 215,1,195,87,192,232,21,205,122,223,98,179,222,213,56,127,178,120,240,192,147,189,143,143,173,222,184,113,219,206,206,219, - 55,174,227,238,191,249,36,103,206,78,226,100,50,237,69,223,246,30,152,76,147,79,165,6,75,68,54,47,120,219,219,223, - 72,189,94,101,102,102,134,254,190,94,132,208,224,136,52,58,25,143,241,241,25,164,244,145,78,140,21,85,140,141,144,210, - 18,69,26,99,12,82,42,98,157,16,5,33,66,8,226,56,68,74,129,54,45,170,213,6,249,108,9,95,229,9,194,42, - 74,65,146,68,84,26,139,212,77,3,43,19,124,1,190,155,101,247,238,125,124,245,174,123,208,72,106,113,131,103,15,159, - 226,252,226,38,186,199,58,81,73,196,196,220,34,187,118,173,101,245,152,33,227,183,72,58,60,76,118,136,51,213,5,182, - 223,242,106,238,251,227,15,179,102,125,63,214,137,105,212,22,41,134,103,144,11,130,78,127,3,185,194,50,198,222,244,11, - 52,238,248,113,239,252,222,199,134,62,243,192,157,125,35,123,239,91,179,179,190,176,173,11,182,37,240,164,134,253,187,225, - 108,17,230,55,65,180,159,23,31,113,187,4,66,191,240,182,87,81,42,92,2,161,127,84,0,250,173,23,249,133,173,116, - 212,205,40,232,9,107,199,107,130,7,187,12,253,231,223,251,151,217,71,58,10,235,95,249,83,111,144,141,197,102,26,27, - 44,5,50,134,193,45,235,220,211,66,140,89,107,215,122,176,111,1,90,30,207,173,44,36,237,10,40,251,18,30,240,18, - 80,133,164,41,21,243,160,174,130,114,21,214,10,184,38,177,246,154,61,142,186,108,207,170,141,203,6,174,190,76,14,246, - 244,3,150,216,73,144,218,32,100,6,131,64,137,246,35,176,26,161,65,228,178,20,125,151,107,127,250,39,250,159,90,179, - 166,227,242,237,59,221,205,87,94,33,7,6,250,241,148,2,145,97,174,81,235,254,47,111,253,137,98,249,203,95,93,92, - 14,235,76,90,13,86,130,174,156,126,56,159,73,134,39,170,97,54,209,205,94,168,248,150,201,4,142,251,144,55,208,165, - 5,253,121,33,6,242,198,142,45,179,108,89,125,230,76,240,145,102,115,235,202,222,219,123,243,139,117,250,154,77,78,233, - 136,166,35,145,56,68,113,219,78,22,137,84,6,99,45,90,27,86,173,92,201,232,112,7,199,142,31,96,177,209,162,191, - 103,144,114,49,135,213,17,137,129,153,233,89,194,216,67,71,154,160,25,163,117,76,34,99,4,14,142,82,132,65,11,107, - 92,28,71,96,180,69,107,75,146,88,28,233,225,170,136,66,206,39,104,52,83,123,85,44,73,28,179,48,211,64,73,69, - 147,26,245,106,130,176,17,7,142,28,229,45,239,124,35,171,214,174,38,95,40,208,221,81,102,213,202,110,30,127,226,107, - 116,84,78,179,110,101,142,19,167,78,81,77,178,116,14,150,168,31,127,132,19,39,190,192,230,155,111,227,177,199,31,230, - 83,159,123,128,119,47,191,149,238,145,45,212,235,17,65,116,146,188,62,75,71,253,36,121,14,80,173,116,18,184,27,88, - 189,227,54,130,237,183,58,11,103,158,233,125,234,177,207,117,116,223,251,197,209,229,11,211,91,123,96,127,2,79,207,195, - 211,111,134,83,175,72,205,79,227,23,107,195,122,126,122,142,247,125,252,43,252,203,183,191,250,18,8,253,99,2,208,111, - 191,20,77,66,27,136,28,104,97,57,28,193,151,70,19,237,156,248,159,127,168,30,42,103,215,94,251,250,183,136,168,122, - 6,27,43,84,162,232,218,190,220,185,176,105,213,160,222,127,124,125,219,246,116,166,10,250,239,218,213,79,22,216,192,119, - 182,86,48,237,15,153,2,160,152,6,25,167,252,76,126,27,244,44,194,38,7,174,31,151,188,242,220,192,200,202,198,142, - 173,165,155,70,134,193,8,62,255,39,31,226,186,55,188,154,245,87,109,66,219,24,107,52,162,157,154,97,37,88,43,81, - 70,98,173,68,72,197,77,183,190,138,155,110,123,109,38,93,116,139,176,198,164,22,22,38,160,59,239,243,250,255,248,43, - 29,119,223,119,223,192,170,86,184,50,132,21,37,152,94,86,240,26,215,254,206,91,57,114,190,198,226,175,127,212,58,25, - 87,111,74,52,43,180,73,230,33,248,40,44,92,111,57,171,172,205,70,136,161,38,200,85,54,46,141,9,102,14,206,84, - 122,175,236,233,228,45,219,119,176,122,120,144,175,29,220,195,133,153,69,140,147,5,41,177,73,76,36,99,148,200,98,2, - 203,201,99,167,184,238,154,215,176,108,85,63,205,0,142,31,62,199,252,220,34,35,195,125,4,65,68,101,113,30,215,45, - 179,56,191,136,159,201,17,71,146,70,163,74,198,151,248,25,159,68,71,88,155,32,132,135,231,101,136,99,112,28,31,97, - 20,229,130,139,235,89,164,155,38,126,26,12,94,198,101,97,174,202,212,133,26,142,239,208,217,53,72,177,84,226,95,239, - 188,140,92,71,169,189,165,223,78,26,181,146,7,190,250,36,193,66,200,232,96,204,230,245,203,153,89,116,104,212,170,68, - 97,139,93,215,92,201,195,15,31,226,191,253,225,167,89,140,28,238,255,242,39,120,203,143,175,162,232,119,81,149,155,168, - 216,117,212,90,169,101,71,201,158,98,212,59,77,101,106,15,161,222,66,121,232,42,226,119,110,119,155,55,189,97,240,209, - 251,239,238,203,220,243,169,53,151,205,143,111,238,130,13,9,60,213,5,71,3,56,223,130,249,22,132,241,139,0,162,241, - 153,121,222,251,137,175,240,115,111,185,149,174,66,238,82,202,233,63,6,0,245,190,140,111,10,129,255,15,170,151,195,238, - 10,176,170,169,197,233,255,244,135,60,214,146,107,118,188,253,102,105,91,85,130,160,2,133,50,133,55,189,161,103,126,255, - 239,109,40,192,218,105,56,243,21,88,252,111,237,159,147,5,254,15,208,249,45,52,28,73,123,244,222,9,162,9,238,83, - 224,143,65,105,10,186,61,232,3,134,93,88,101,96,203,161,156,191,109,239,154,13,99,219,215,95,38,70,50,9,173,184, - 142,107,50,20,206,204,241,224,255,249,48,65,229,141,108,191,237,26,52,139,168,56,1,229,161,201,34,173,196,72,137,176, - 81,106,178,166,117,59,58,90,96,81,72,233,32,150,242,233,117,194,117,87,95,197,3,183,221,56,52,243,185,175,12,118, - 10,54,212,45,199,15,159,93,12,30,251,47,159,215,255,106,253,16,191,1,140,253,250,79,51,246,181,199,40,61,178,151, - 66,250,248,205,221,16,174,135,112,25,214,137,97,110,26,244,181,63,254,182,242,132,163,168,157,153,32,235,101,217,62,180, - 140,85,195,203,248,155,175,125,153,163,11,149,180,66,145,16,11,137,65,35,177,92,56,63,142,137,13,97,208,164,92,234, - 229,198,155,174,103,252,252,105,46,156,63,207,137,35,231,168,53,91,148,74,5,114,121,143,86,171,73,18,71,120,202,69, - 181,165,157,158,155,199,203,164,177,58,73,172,145,42,38,8,234,100,28,15,199,247,136,146,16,17,164,137,24,253,189,125, - 108,218,124,5,235,214,173,160,111,176,135,98,169,132,114,220,52,230,89,199,36,173,58,66,73,140,86,168,140,225,228,193, - 11,220,249,247,15,115,235,149,189,140,207,88,38,38,103,240,179,89,100,70,160,114,61,124,242,238,125,124,232,131,79,17, - 219,60,142,155,240,212,83,95,100,126,113,130,155,110,254,49,150,173,186,145,200,207,18,20,251,72,138,61,232,214,10,26, - 245,167,41,101,46,48,160,38,89,152,57,78,203,221,72,166,107,35,234,45,219,85,237,230,55,247,62,250,192,103,58,7, - 191,242,209,209,85,243,211,59,58,224,176,128,61,6,246,238,131,147,62,204,119,180,239,109,223,110,247,112,106,122,158,123, - 190,254,36,111,127,235,109,196,65,240,131,55,134,151,75,130,211,31,82,0,122,185,126,199,191,10,246,189,80,217,6,207, - 84,128,229,141,186,158,252,205,255,126,243,151,159,217,179,110,251,123,126,202,31,30,44,18,53,91,148,111,186,193,187,240, - 55,31,93,95,56,123,97,151,134,99,151,195,193,253,16,149,219,163,245,163,164,118,120,226,121,31,103,64,172,2,121,1, - 252,13,144,143,82,109,98,95,19,134,29,88,230,195,88,13,70,23,97,240,28,12,76,45,27,232,17,107,175,204,245,101, - 186,168,207,46,226,118,65,156,5,145,40,10,194,195,209,154,167,62,254,85,148,231,177,229,198,109,152,164,133,21,46,137, - 214,120,74,99,117,64,101,126,30,41,92,202,93,253,128,131,69,182,251,61,139,21,150,176,85,33,137,19,10,221,195,236, - 250,137,31,237,57,240,185,175,12,189,2,177,198,40,177,34,214,102,241,213,199,38,235,61,199,38,77,2,12,61,190,15, - 198,103,196,49,144,66,8,222,97,173,249,20,216,38,72,3,29,64,127,0,114,213,101,59,212,198,177,17,190,246,251,127, - 198,154,142,110,116,28,208,159,205,241,234,203,118,113,246,174,47,147,56,30,194,58,56,66,18,91,131,116,4,71,143,29, - 199,154,52,251,188,85,171,34,112,25,89,53,198,208,178,101,140,173,88,164,220,55,200,163,143,62,205,161,67,7,169,54, - 230,112,132,67,198,201,18,39,49,186,73,154,124,42,36,142,43,144,74,160,140,193,10,77,98,18,58,187,58,89,179,110, - 5,155,54,111,100,205,186,181,12,13,15,145,205,57,24,27,166,22,32,6,76,146,164,105,35,78,123,173,195,182,141,234, - 85,7,239,253,203,223,224,169,19,71,40,117,110,228,240,196,113,150,173,42,49,49,222,224,236,217,179,52,131,152,179,147, - 139,44,38,77,148,235,33,181,79,87,214,99,252,228,147,124,224,240,1,54,111,121,45,175,188,253,205,116,47,91,142,113, - 61,34,53,74,152,93,206,108,120,6,79,239,102,48,123,148,188,152,226,216,228,50,146,194,46,74,29,235,176,111,251,101, - 167,250,138,59,70,239,187,251,115,195,197,175,126,120,227,206,122,101,103,55,236,9,225,225,8,30,219,2,167,239,132,240, - 150,111,83,101,91,32,115,248,36,79,62,186,151,61,219,214,254,192,105,110,172,182,120,113,130,211,158,16,255,176,97,145, - 243,114,191,177,9,252,28,216,223,129,234,245,240,76,12,97,95,146,204,21,62,249,185,27,158,120,122,239,142,158,159,121, - 91,207,21,119,220,72,255,166,85,28,124,215,219,6,103,255,251,31,94,221,13,251,59,224,194,126,152,105,144,138,11,51, - 41,143,195,29,224,132,224,27,200,157,132,156,16,162,179,0,35,218,218,81,23,70,66,24,173,193,232,108,70,13,85,151, - 143,118,71,27,54,20,135,175,186,194,221,184,124,132,43,202,30,95,255,139,123,161,101,209,229,60,117,211,164,172,125,92, - 153,37,16,146,216,9,232,52,134,7,63,242,25,138,3,93,44,91,191,10,27,7,184,142,38,104,85,169,77,77,18,6, - 45,84,38,71,161,88,66,122,105,59,102,1,132,33,104,86,153,60,119,18,147,64,20,132,92,121,237,101,242,145,203,86, - 13,5,79,159,24,113,16,87,186,66,196,85,107,199,31,135,202,27,160,89,252,202,35,145,0,91,149,82,72,229,48,26, - 71,252,120,74,184,103,67,88,225,192,242,102,111,79,103,207,142,77,157,29,253,253,68,158,143,49,150,68,1,73,200,246, - 101,99,108,26,26,100,247,248,56,158,244,17,86,146,88,141,116,28,206,157,31,103,97,190,194,208,96,153,90,163,73,117, - 113,14,227,196,116,116,245,48,48,54,200,107,86,142,113,203,107,111,229,217,189,123,121,240,222,251,121,248,193,71,153,56, - 63,133,148,30,57,183,128,227,42,194,168,65,173,17,226,251,14,125,125,93,172,90,179,156,173,91,183,177,117,219,22,134, - 151,13,166,182,171,198,16,235,132,80,71,169,37,172,77,121,162,116,12,105,177,54,245,132,178,6,92,47,195,158,199,143, - 241,249,79,61,194,181,175,249,121,250,10,27,89,49,154,165,48,178,154,199,38,79,240,245,103,31,192,77,36,82,101,80, - 94,54,141,36,180,13,50,142,207,112,255,86,140,8,153,158,188,155,143,188,255,62,198,86,92,201,229,55,188,145,225,245, - 151,33,61,151,68,46,71,139,229,28,174,236,161,211,28,98,77,247,121,102,91,179,204,206,174,193,45,109,39,91,90,71, - 231,143,254,170,92,188,229,142,222,175,124,254,131,221,93,119,127,113,213,85,113,99,101,1,74,49,124,169,4,167,247,131, - 254,78,237,152,186,247,9,214,61,178,7,97,127,0,5,209,75,202,248,31,70,0,250,249,31,187,227,101,127,115,40,4, - 227,90,219,229,159,189,183,50,219,10,247,84,97,222,135,115,219,79,158,62,53,254,159,254,215,229,15,127,242,139,171,86, - 190,243,71,75,249,85,171,229,190,130,191,188,175,30,12,7,144,149,164,194,195,129,182,14,104,64,144,47,35,70,98,107, - 215,74,88,150,129,158,196,218,254,58,140,205,73,70,167,187,75,189,254,214,141,197,190,107,175,202,110,189,254,58,57,184, - 97,61,157,93,93,228,60,15,18,77,117,110,150,51,219,78,179,247,177,253,100,108,142,156,91,38,12,99,84,70,226,34, - 8,181,65,139,58,185,88,242,200,231,191,194,200,202,159,69,217,144,96,161,202,92,181,78,88,115,112,165,196,198,81,218, - 178,184,217,54,87,4,104,77,88,91,64,154,4,172,96,126,250,2,163,203,71,89,249,230,215,246,237,121,250,143,187,175, - 210,102,27,208,237,192,116,11,38,59,225,212,28,156,171,192,124,193,152,16,27,155,12,216,115,32,26,208,225,195,234,16, - 58,162,203,118,12,12,44,31,201,0,204,218,132,185,249,10,29,253,69,140,78,200,36,17,55,239,184,156,221,231,63,77, - 228,104,18,43,48,214,128,181,44,86,235,156,60,115,129,161,129,14,226,32,2,5,149,185,84,76,209,217,219,143,142,35, - 28,79,114,249,149,219,185,226,202,29,252,196,79,253,24,251,246,28,224,137,199,158,230,240,225,163,8,145,142,224,215,174, - 219,201,43,175,191,150,117,27,214,208,211,221,129,200,120,96,53,38,14,208,137,69,27,1,66,33,80,32,36,66,164,27, - 249,105,46,156,68,155,36,213,39,161,48,49,188,247,15,255,128,53,27,174,99,243,85,111,34,23,204,176,125,85,7,103, - 90,189,108,191,106,43,123,239,251,56,81,165,65,44,45,218,196,16,249,184,210,16,198,85,170,181,2,93,221,157,108,223, - 178,21,76,194,249,201,3,220,245,201,67,44,95,249,74,118,92,119,7,157,99,43,9,173,193,235,221,202,124,180,146,218, - 236,110,86,230,206,177,206,123,154,201,197,25,234,254,86,156,100,140,114,223,213,116,253,202,118,121,250,85,111,239,250,240, - 159,254,215,87,190,227,216,222,74,25,14,206,193,248,209,212,219,233,219,15,55,180,70,54,91,63,144,23,169,37,221,16, - 216,244,188,63,255,176,0,145,243,59,191,246,238,151,255,221,74,98,90,17,61,119,63,206,211,173,176,57,11,39,214,193, - 124,0,39,70,44,123,226,221,7,118,46,238,254,205,205,161,159,233,93,158,36,167,53,92,80,16,68,164,251,92,127,159, - 246,231,170,19,49,96,148,122,85,148,232,91,166,50,238,234,70,95,87,201,27,91,150,203,237,220,84,232,189,242,106,247, - 170,237,155,233,31,91,70,33,95,64,160,177,38,65,199,49,81,171,133,43,28,10,249,78,174,184,126,23,123,158,217,71, - 216,140,73,132,139,41,42,78,76,143,179,170,220,75,81,56,52,109,64,62,91,96,238,228,9,230,206,156,162,80,204,80, - 169,212,121,252,201,61,124,240,125,127,205,205,175,190,142,119,253,228,59,8,91,33,174,159,180,125,28,52,205,197,69,90, - 243,139,88,29,162,227,244,197,159,157,156,224,182,55,189,195,255,223,79,28,219,250,245,3,7,123,152,158,93,219,91,173, - 47,174,176,204,101,96,82,192,73,13,135,106,112,2,107,103,14,64,115,17,148,11,125,2,198,166,17,197,145,87,189,106, - 48,167,28,180,209,204,218,128,189,19,11,220,177,236,10,154,245,5,194,176,197,182,21,43,184,122,205,58,30,56,121,140, - 68,185,169,233,153,84,4,81,200,161,163,39,184,250,170,205,184,78,10,14,214,66,101,118,22,79,42,114,165,46,180,128, - 132,4,97,45,221,125,93,220,248,170,91,185,254,230,155,105,181,26,24,157,0,134,92,161,128,114,50,64,132,77,52,38, - 137,48,86,35,5,40,71,130,78,9,122,179,148,45,212,78,154,21,50,181,106,148,86,97,181,197,205,149,249,226,167,238, - 228,171,247,220,207,143,189,231,15,241,187,122,112,170,83,152,150,192,196,9,157,221,253,244,116,140,50,62,127,20,199,1, - 45,35,146,88,224,186,89,92,229,210,106,213,152,153,75,144,86,179,124,120,140,203,119,172,38,138,66,90,213,89,206,237, - 254,40,97,243,42,220,225,109,248,189,61,72,153,195,25,188,141,115,141,115,148,155,79,49,82,154,160,170,90,76,235,38, - 51,147,5,230,239,188,11,142,236,182,203,42,139,13,9,201,210,82,243,146,31,211,203,145,120,188,148,243,188,148,170,212, - 120,236,123,120,161,54,72,227,190,151,28,58,127,104,42,160,197,234,119,97,122,32,37,34,140,232,49,150,67,41,113,28, - 119,192,244,2,84,90,112,202,194,238,14,88,39,130,176,23,152,116,225,169,24,42,187,218,252,79,51,125,98,101,221,218, - 222,86,146,92,190,251,230,235,111,189,252,103,127,212,95,121,229,101,116,118,15,80,46,22,17,184,24,83,131,216,98,194, - 6,70,91,148,148,72,161,144,210,96,116,140,112,44,107,215,175,99,120,120,132,202,153,89,180,74,149,136,98,237,0,182, - 179,135,218,145,11,20,157,28,74,11,178,70,179,255,177,61,100,55,174,226,11,239,255,115,90,159,248,66,243,109,245,32, - 56,60,61,145,63,123,219,171,51,43,150,151,83,235,83,37,105,213,106,212,230,22,176,173,16,107,12,2,7,169,52,97, - 88,161,103,112,132,255,250,145,191,235,90,172,78,117,77,78,76,177,239,254,251,147,175,126,226,51,11,165,221,7,207,111, - 105,197,43,251,97,163,129,19,9,28,158,128,83,82,136,166,180,118,5,208,51,49,48,210,189,245,149,215,148,209,49,74, - 41,138,197,28,143,157,121,140,27,47,187,140,92,38,75,37,105,209,211,108,242,214,43,94,193,222,11,231,168,4,17,24, - 139,81,2,141,228,196,153,51,233,84,80,72,28,41,72,140,1,163,89,24,159,34,9,5,229,254,126,140,6,173,99,140, - 8,81,34,53,148,205,102,51,72,229,97,173,198,152,8,171,147,182,177,25,96,28,4,10,33,52,90,167,213,158,20,96, - 218,161,201,194,62,39,180,177,88,148,80,8,165,8,170,1,127,249,23,31,76,35,169,29,135,140,205,97,18,7,215,19, - 184,40,92,153,165,123,104,152,83,103,159,197,87,5,164,236,68,136,0,76,66,18,122,40,207,18,199,77,90,58,199,248, - 220,4,129,182,148,187,202,20,250,124,60,71,160,226,99,36,103,26,52,167,71,233,27,217,4,57,65,208,53,68,93,189, - 158,227,115,251,25,245,206,112,244,145,255,195,153,15,223,213,124,91,99,97,124,8,78,231,225,104,4,79,184,112,170,148, - 210,129,47,171,98,88,2,18,251,188,95,29,210,165,105,219,150,144,44,217,201,214,158,167,103,211,237,143,239,213,70,255, - 210,73,248,70,7,136,127,214,28,208,11,189,88,178,141,206,165,116,80,54,25,192,124,8,199,28,200,218,244,115,149,63, - 133,232,227,41,127,196,111,183,65,8,33,68,108,173,51,186,125,179,115,213,107,95,77,78,129,112,92,146,184,137,49,18, - 169,34,148,178,88,157,65,57,233,2,37,218,193,160,17,78,130,49,6,183,203,163,88,234,164,170,23,201,40,135,34,1, - 117,163,25,216,186,134,163,231,39,232,52,30,74,122,148,242,125,124,237,107,15,17,253,201,159,52,55,62,125,224,244,6, - 56,225,128,245,79,78,108,56,116,247,189,171,150,253,226,207,72,176,152,48,160,58,63,67,43,104,34,19,129,81,14,70, - 217,246,210,173,67,125,113,138,98,169,72,127,95,137,254,254,78,182,109,223,225,220,246,227,111,239,125,228,254,71,122,159, - 253,212,157,43,159,249,234,189,23,54,207,45,142,142,192,186,12,92,136,173,157,5,70,34,40,231,118,236,40,143,109,89, - 35,34,211,196,35,139,239,120,156,91,152,227,240,228,4,87,141,142,225,196,17,213,102,157,145,114,47,55,172,219,204,157, - 187,159,190,184,21,47,5,28,60,116,156,133,169,10,185,140,160,110,67,132,54,233,135,99,89,152,157,34,182,49,221,3, - 253,8,52,173,122,19,37,21,158,239,35,165,194,232,180,181,82,202,37,165,59,20,194,166,246,159,82,24,76,210,74,237, - 91,93,63,37,151,133,76,173,65,5,36,54,193,36,9,74,42,172,80,72,191,192,61,95,254,18,207,236,222,67,222,207, - 227,187,14,82,104,10,94,157,130,235,96,19,23,233,186,116,116,14,225,56,30,142,167,176,198,65,138,12,218,36,88,101, - 16,142,192,34,152,157,95,192,40,15,47,170,147,143,93,172,22,24,207,67,10,69,193,153,71,133,211,156,157,216,143,59, - 186,158,190,213,155,241,115,93,36,93,59,152,138,214,51,123,236,110,251,182,198,194,248,6,184,43,128,251,66,56,161,96, - 162,158,190,255,146,59,190,139,247,181,253,38,16,58,3,124,186,125,225,188,166,77,110,223,73,234,91,253,76,27,116,30, - 2,238,227,59,135,47,188,220,51,7,140,243,226,133,151,255,44,0,232,155,79,41,181,38,13,247,66,232,183,53,68,69, - 224,179,237,23,115,24,120,36,5,44,83,178,118,174,12,7,131,63,122,255,225,207,52,170,27,95,249,175,126,70,118,142, - 173,32,235,58,184,145,70,203,24,227,104,192,199,42,131,197,32,172,147,218,149,138,4,240,208,54,193,70,17,69,199,197, - 203,88,20,2,89,151,228,189,94,26,165,18,83,173,152,250,226,52,227,251,247,210,119,112,207,244,174,106,229,41,15,30, - 138,5,207,198,144,235,181,188,250,244,103,191,208,177,248,99,111,237,45,120,14,213,233,243,52,26,243,196,26,92,225,161, - 188,12,210,245,168,86,99,76,61,166,191,71,81,89,152,160,220,55,64,98,21,150,26,189,93,157,188,225,77,111,225,142, - 55,190,174,124,232,208,193,242,189,31,248,208,216,222,79,126,121,124,228,236,248,248,58,107,23,59,64,237,67,248,157,175, - 188,118,56,239,186,196,129,1,109,176,137,197,10,151,251,14,29,96,219,200,74,50,218,33,116,35,22,27,243,220,180,97, - 51,15,31,57,200,124,162,209,113,140,231,42,46,156,155,228,194,133,25,214,172,30,36,177,49,174,21,40,229,146,96,16, - 34,161,190,56,131,181,33,221,125,253,228,114,89,234,245,26,65,101,145,92,62,139,235,151,16,202,193,46,205,118,69,234, - 21,36,226,144,168,89,37,136,106,56,158,2,161,176,184,32,228,115,222,223,74,34,176,200,118,66,71,210,108,242,129,15, - 252,13,6,131,192,69,57,89,116,70,227,183,170,248,202,96,148,139,245,36,57,183,128,175,114,228,242,89,146,40,33,8, - 44,202,85,196,196,248,94,9,37,37,36,134,176,90,37,204,250,84,106,46,197,66,9,98,8,26,53,180,235,145,205,100, - 240,11,45,42,23,30,101,234,248,179,228,122,70,217,120,229,245,20,186,6,88,179,122,7,254,189,127,63,23,193,83,45, - 184,127,57,204,45,19,66,127,170,220,203,121,225,80,196,126,203,41,152,32,245,87,202,72,73,40,21,179,97,131,147,213, - 89,222,3,124,0,184,11,248,125,210,72,160,159,109,87,58,191,218,254,222,190,118,107,244,239,128,155,219,85,79,208,6, - 136,137,239,227,69,219,221,6,186,195,237,235,42,119,9,128,190,69,135,246,60,17,225,82,170,68,0,188,11,248,205,246, - 215,156,1,115,6,38,98,184,175,79,27,191,242,103,127,55,243,208,157,95,91,165,110,191,165,47,127,245,102,127,100,245, - 58,58,70,87,146,207,57,148,221,58,94,94,98,93,23,171,12,18,9,70,128,91,96,113,186,78,208,168,50,176,58,79, - 44,66,166,106,57,166,171,13,62,252,135,127,106,221,163,251,155,43,26,141,122,179,177,104,182,199,102,122,165,225,233,8, - 190,14,60,222,99,153,88,128,162,6,213,247,204,225,222,163,255,237,79,110,244,254,159,127,87,8,91,53,112,50,248,126, - 129,102,173,202,196,161,99,236,254,234,67,230,192,35,123,76,77,9,249,147,191,253,107,114,231,101,27,113,43,53,242,229, - 158,84,200,168,53,134,58,174,48,108,219,184,142,173,255,223,255,155,63,255,171,239,89,243,213,143,125,110,249,103,62,244, - 145,41,177,239,208,244,179,153,226,240,239,95,127,117,65,64,234,241,99,36,65,173,137,167,60,158,61,127,138,199,78,29, - 225,218,21,43,73,154,243,52,77,72,87,161,155,235,86,175,229,179,207,238,70,41,31,7,65,16,180,56,53,51,193,198, - 205,99,228,27,49,218,21,88,145,178,30,70,91,48,134,218,252,34,58,140,233,27,25,166,80,42,209,168,24,154,139,45, - 16,33,126,54,79,198,207,130,84,104,44,113,28,17,53,234,36,65,19,235,8,156,76,14,161,60,140,21,237,8,238,118, - 44,135,84,8,44,24,139,116,61,238,185,251,30,158,120,236,9,164,204,32,165,32,155,207,32,20,41,32,73,11,86,227, - 56,2,63,171,200,100,28,162,40,198,36,186,189,100,107,137,163,152,197,133,5,114,126,22,207,245,48,81,196,252,252,2, - 185,124,158,90,189,138,239,250,56,174,131,18,1,45,233,226,185,46,130,132,110,223,229,193,187,63,196,23,62,255,127,184, - 229,77,239,166,35,174,165,51,17,168,10,168,127,26,244,96,255,24,79,245,175,16,70,27,123,252,133,232,75,33,136,132, - 130,36,194,181,150,3,213,89,94,101,18,46,36,14,127,14,188,17,56,72,234,69,21,183,39,181,223,188,44,189,20,70, - 240,173,184,160,239,231,201,2,203,219,143,173,126,9,128,94,26,65,119,152,52,217,50,76,117,64,118,11,212,119,192,179, - 139,80,45,195,254,142,243,147,155,26,127,249,161,13,115,127,197,202,135,123,75,253,193,198,45,101,59,208,159,17,29,174, - 83,30,232,35,55,188,140,114,247,32,94,28,81,244,5,34,59,192,193,67,167,56,126,244,0,141,146,203,236,252,130,205, - 29,57,95,95,57,63,55,181,78,71,147,131,105,16,197,148,132,170,77,237,82,15,145,146,196,179,247,130,190,28,130,34, - 60,174,160,167,250,55,31,41,63,45,212,21,93,111,185,53,27,5,33,167,31,123,218,94,248,250,61,65,241,240,201,249, - 177,122,60,190,25,154,53,232,120,242,151,127,125,153,255,191,254,123,199,166,87,94,43,164,93,32,147,247,16,202,69,10, - 23,99,85,59,23,62,97,120,176,151,127,241,43,191,232,206,252,204,59,71,190,242,229,123,71,234,95,249,58,179,211,19, - 212,23,150,81,236,44,145,4,9,245,70,3,148,131,80,138,47,237,126,130,109,163,99,100,29,159,36,105,161,116,204,173, - 219,118,240,236,133,115,140,87,234,40,41,8,195,144,233,249,25,172,35,200,40,73,160,4,137,146,88,29,227,41,7,172, - 192,2,173,90,157,233,11,227,244,13,15,81,236,236,38,172,212,168,86,22,152,175,84,210,197,87,44,137,209,32,5,210, - 88,60,199,161,88,236,38,155,43,160,73,3,28,219,126,176,96,117,250,103,210,120,25,41,21,79,60,254,20,81,148,224, - 184,25,132,84,72,7,144,22,215,19,64,130,78,82,71,183,32,108,17,197,17,142,147,73,237,65,180,190,104,186,6,16, - 132,1,58,73,200,21,10,212,27,117,102,103,102,25,28,24,68,72,65,38,147,65,74,73,20,4,216,36,0,82,23,131, - 171,175,216,204,71,62,243,73,123,240,247,126,253,194,45,94,166,208,137,136,19,172,206,183,51,198,102,162,144,215,75,41, - 173,49,198,55,198,10,251,141,224,51,23,54,217,216,92,224,125,115,147,252,86,28,114,167,73,216,108,45,3,207,123,159, - 186,207,187,145,62,159,19,250,65,57,75,2,94,143,139,41,54,151,0,232,197,32,247,147,237,143,165,243,46,176,59,161, - 218,7,135,154,112,182,9,207,248,176,108,196,176,98,217,84,117,5,83,15,143,54,160,187,9,158,150,66,170,82,209,9, - 189,140,87,211,113,113,206,147,185,8,71,121,113,28,220,22,132,11,34,136,26,142,53,81,65,155,105,7,14,39,112,50, - 134,243,110,90,25,55,27,208,234,128,186,128,214,211,96,63,6,60,0,250,55,97,60,17,226,254,162,181,170,241,215,127, - 59,113,242,99,31,31,115,132,16,157,141,86,109,5,204,122,112,74,167,9,203,181,28,140,244,93,152,190,242,200,207,191, - 231,242,125,111,123,195,178,235,126,226,93,106,205,154,49,92,39,64,100,36,42,159,65,74,175,221,96,42,172,209,244,229, - 242,252,196,219,222,193,59,223,240,22,158,121,244,81,190,252,185,59,89,190,97,37,171,214,108,32,182,233,174,87,94,249, - 140,207,47,178,255,220,5,174,26,25,193,177,9,149,70,147,114,161,196,91,174,185,129,191,248,234,151,48,194,144,203,120, - 140,12,244,19,155,4,199,145,100,28,149,242,52,142,147,2,134,49,36,73,130,227,186,52,235,117,198,207,158,161,119,112, - 132,76,103,39,29,74,48,55,53,65,18,181,82,133,183,214,88,11,137,177,168,92,14,199,203,130,112,48,86,98,72,23, - 139,133,181,169,159,52,169,1,155,148,233,37,153,36,73,10,8,72,252,76,150,66,190,72,83,202,118,76,147,32,142,45, - 81,108,72,76,186,221,239,186,46,73,148,18,239,82,74,146,36,193,247,125,76,146,198,122,87,106,21,138,249,34,139,11, - 139,20,139,69,242,185,2,90,27,28,199,197,201,8,130,184,129,235,150,105,180,52,190,245,184,124,199,21,162,246,232,3, - 185,245,173,74,171,19,188,6,244,199,208,251,223,32,122,255,252,68,156,205,20,116,165,123,72,202,48,178,66,63,55,188, - 86,82,49,93,91,224,134,233,227,68,223,52,85,250,167,120,17,119,0,215,180,129,200,254,19,251,63,56,63,8,15,66, - 183,251,218,61,16,91,88,92,9,213,6,156,179,176,55,130,14,13,189,121,40,21,193,193,88,97,23,171,66,67,78,66, - 183,133,46,1,142,72,189,202,38,85,106,92,21,3,139,81,58,18,159,143,160,53,15,73,23,152,22,169,195,98,134,116, - 195,127,233,109,57,11,81,100,237,241,30,168,249,176,119,172,25,244,164,77,7,45,155,38,131,76,59,48,23,65,104,161, - 75,194,241,13,245,214,153,217,191,254,232,149,15,126,229,222,245,15,223,126,71,247,142,183,222,33,215,109,26,65,84,18, - 28,39,75,54,87,38,147,205,164,182,111,66,160,77,21,28,151,93,215,95,199,182,203,183,112,230,252,25,246,29,220,71, - 161,51,143,209,17,113,93,35,4,60,116,228,0,155,187,251,192,64,236,74,162,86,139,109,67,163,236,88,177,146,39,78, - 30,98,229,216,8,91,214,175,79,39,227,158,32,231,102,144,198,208,50,26,29,155,116,148,174,210,216,29,132,32,168,55, - 24,191,112,158,254,225,81,114,165,18,157,194,80,153,153,78,101,12,142,3,198,16,145,128,235,226,120,89,180,85,169,143, - 180,48,169,254,199,74,108,234,68,157,166,112,96,0,69,127,255,0,74,165,127,151,36,22,99,12,142,114,240,51,30,142, - 82,40,149,69,57,62,249,66,23,202,113,241,51,25,146,40,38,12,195,52,231,204,113,112,92,23,225,56,132,129,197,74, - 73,179,213,36,155,201,50,63,63,79,33,95,164,179,195,35,73,18,188,140,143,227,103,8,2,131,163,4,73,43,98,197, - 224,50,38,95,125,91,215,251,238,127,40,249,209,249,133,100,23,220,146,128,73,224,193,159,131,211,155,38,79,4,159,136, - 154,230,129,242,16,195,78,6,169,35,148,77,249,65,7,251,79,18,108,190,213,185,177,253,235,103,191,203,106,104,105,216, - 249,66,64,102,127,88,1,104,105,130,22,181,127,63,0,230,35,208,250,21,104,77,164,137,170,103,22,83,253,172,176,109, - 240,112,193,77,192,183,144,117,64,68,16,89,104,212,32,30,2,83,77,61,124,226,205,96,159,4,142,181,53,20,29,47, - 80,70,183,109,103,109,111,90,29,157,109,193,164,3,174,74,57,0,109,32,9,32,89,3,166,15,56,11,141,22,84,18, - 56,219,3,7,123,199,39,47,155,248,171,191,222,246,196,103,63,181,102,239,107,95,213,179,253,45,175,87,171,55,172,32, - 9,38,168,26,131,159,41,146,237,200,33,10,185,118,230,87,140,231,43,214,174,91,199,202,213,154,237,235,54,242,166,55, - 190,158,143,124,232,99,60,249,212,51,236,62,190,159,67,43,86,177,105,108,25,113,220,34,1,188,48,224,214,157,59,57, - 120,234,16,171,215,172,96,160,167,11,97,3,80,18,225,56,120,198,160,181,67,100,108,58,209,146,138,36,138,145,164,173, - 85,24,71,204,205,78,147,205,46,35,83,44,211,227,231,169,204,205,210,172,86,17,90,227,229,114,148,251,250,17,78,134, - 37,27,75,113,241,109,151,86,57,75,138,104,107,210,102,172,88,204,97,109,130,209,18,207,243,200,102,51,52,37,40,9, - 81,20,34,133,139,69,80,234,236,70,58,138,56,138,200,102,179,196,113,140,214,26,165,84,90,169,73,121,145,23,66,164, - 45,89,28,197,76,76,142,35,133,160,84,42,209,106,74,6,6,71,72,10,1,34,8,136,234,17,141,36,98,120,120,136, - 210,27,223,236,220,249,236,177,209,35,7,158,44,190,182,217,236,44,65,201,194,125,231,172,57,54,54,119,161,22,55,107, - 118,117,190,155,185,234,36,65,18,179,81,8,250,237,15,103,202,196,171,219,215,199,233,151,43,237,187,245,38,138,115,243, - 204,61,179,7,233,121,208,174,16,83,45,149,133,40,38,250,30,78,224,156,31,196,39,209,182,201,106,128,65,176,14,68, - 127,0,252,113,187,133,115,129,63,7,70,160,50,3,236,39,141,232,185,162,253,241,31,219,147,1,159,139,33,128,223,192, - 65,125,43,194,220,1,150,129,249,91,8,126,25,2,213,254,89,91,128,25,210,165,198,101,109,128,44,195,226,126,216,31, - 195,249,24,158,29,130,77,195,115,149,157,83,127,251,137,29,207,124,254,171,107,142,190,225,182,158,245,111,125,181,187,114, - 205,90,146,102,196,66,117,1,145,115,201,117,116,145,45,150,144,202,193,152,8,33,160,163,167,200,237,111,126,45,55,189, - 238,102,14,238,63,194,103,62,246,247,156,219,189,159,245,118,8,33,12,137,128,40,106,177,186,187,135,203,86,172,98,221, - 230,245,120,133,44,178,25,33,148,2,165,80,66,224,42,23,235,88,172,11,113,172,193,145,8,157,102,139,121,74,224,9, - 145,146,192,158,143,113,93,202,67,163,100,59,155,136,56,193,201,122,8,199,35,209,2,229,40,140,142,145,194,166,244,15, - 50,245,38,146,22,97,204,197,59,97,162,99,44,38,181,246,48,49,25,79,160,51,18,209,212,40,149,250,25,107,12,185, - 114,9,39,227,161,16,184,174,139,159,205,18,180,90,237,133,216,24,199,203,224,56,110,186,110,34,36,81,16,81,169,86, - 208,70,51,206,56,153,140,143,239,101,9,234,77,108,62,38,215,161,40,117,15,147,13,13,141,100,134,142,216,208,187,235, - 26,198,215,45,239,248,204,163,143,94,251,234,19,71,11,253,208,23,192,215,250,97,207,191,105,85,231,163,86,213,24,224, - 66,251,117,206,192,15,85,5,180,116,252,246,175,43,218,215,5,75,96,241,29,226,33,230,129,207,190,230,86,110,253,139, - 247,49,98,52,221,83,147,56,174,228,136,84,56,24,6,50,62,61,129,166,231,175,62,72,183,16,20,30,120,152,137,103, - 246,124,67,48,196,203,105,0,157,127,10,79,234,82,117,212,106,127,44,69,52,47,137,190,158,4,150,50,238,159,31,106, - 247,114,9,195,214,243,166,27,75,158,212,223,172,164,205,167,178,130,56,134,153,69,88,172,192,25,23,246,245,192,83,125, - 11,149,203,170,31,248,228,246,103,63,245,149,181,123,126,228,166,190,45,239,120,131,179,105,229,106,104,105,42,141,73,234, - 153,25,242,133,34,133,114,23,210,247,1,131,214,45,148,35,216,190,125,19,59,118,94,193,189,95,254,60,207,254,221,157, - 44,235,236,69,39,9,6,77,220,108,240,218,107,175,167,123,243,102,18,29,227,96,113,164,72,163,119,132,197,113,21,82, - 186,237,40,30,131,20,14,38,1,109,45,153,124,129,82,87,55,202,203,96,68,59,198,71,72,220,108,17,149,181,152,196, - 64,34,80,210,1,13,66,56,128,193,202,84,246,96,76,123,13,67,210,142,39,2,180,69,161,210,93,181,56,162,90,173, - 224,245,141,162,45,8,71,161,172,73,205,253,51,89,92,225,145,241,4,198,164,36,112,54,227,35,164,160,22,133,88,171, - 83,0,138,116,218,24,73,136,147,152,102,171,73,146,36,184,174,199,208,192,32,218,196,100,101,142,108,174,68,100,13,89, - 223,163,51,59,12,197,132,70,165,197,138,158,126,146,183,190,205,127,108,207,158,203,183,220,125,87,231,170,36,234,76,160, - 83,194,83,29,48,62,10,225,89,248,161,143,59,94,58,183,181,193,231,2,16,89,251,130,23,251,125,82,242,176,82,124, - 162,148,101,199,96,31,119,36,9,228,124,252,229,203,16,210,50,166,20,214,106,132,227,177,44,219,193,178,63,122,47,18, - 139,174,207,209,251,145,143,193,227,79,131,235,96,58,74,72,235,178,99,235,14,68,154,197,242,195,3,64,223,170,109,19, - 63,0,143,193,73,249,171,216,135,217,10,84,26,112,46,3,251,243,240,244,182,106,237,138,234,135,62,119,213,163,247,62, - 177,254,203,183,221,80,188,254,213,55,137,213,43,135,41,169,12,141,185,57,26,243,21,178,29,93,100,59,75,72,191,136, - 72,210,84,83,237,86,185,252,134,87,240,236,87,31,198,54,83,99,144,136,4,17,135,20,115,5,162,201,121,154,11,117, - 148,167,41,229,178,184,74,97,132,64,184,18,29,130,39,37,74,164,36,178,245,124,188,108,150,76,190,3,161,92,172,0, - 217,22,52,98,116,170,243,65,180,45,72,12,2,157,42,193,5,88,155,90,146,24,97,48,50,13,128,182,109,112,19,104, - 50,25,15,129,197,65,129,181,212,155,17,101,45,209,56,88,233,226,181,127,180,151,201,82,200,228,136,117,3,207,241,176, - 94,134,168,221,134,229,50,62,137,142,241,114,57,18,99,8,195,16,107,45,9,9,142,118,112,179,46,51,115,211,56,174, - 162,175,175,15,89,149,68,42,71,190,3,176,17,210,228,32,235,210,211,81,38,104,54,169,87,155,100,174,187,81,29,237, - 237,91,179,248,249,191,207,111,173,84,251,124,24,136,224,129,81,56,57,2,141,14,48,179,255,12,128,40,211,254,117,117, - 179,69,156,36,212,129,74,251,243,79,9,201,111,43,197,61,158,67,36,21,125,82,226,39,58,29,98,104,131,49,49,82, - 66,164,12,214,106,60,35,48,42,4,66,116,146,96,149,160,244,51,255,130,235,127,238,23,136,177,36,214,66,163,194,143, - 190,253,29,92,121,197,46,126,235,143,222,135,251,183,31,33,8,130,111,107,56,232,112,233,124,79,42,180,98,90,21,197, - 13,152,173,67,197,131,115,49,28,47,66,227,138,241,137,210,39,246,61,187,218,121,251,155,157,125,199,78,225,74,24,234, - 235,101,100,104,144,122,101,145,74,109,145,66,161,76,161,80,70,102,60,84,226,82,204,22,216,120,227,149,156,251,194,61, - 116,228,92,76,168,49,86,18,88,141,188,48,203,252,133,41,250,215,14,97,17,184,25,15,35,210,85,136,200,137,16,82, - 224,23,20,210,113,17,174,151,110,246,91,121,209,58,35,69,151,54,202,144,122,69,199,34,37,129,211,225,187,70,152,246, - 215,90,213,94,64,77,37,123,50,141,64,73,199,191,89,47,101,229,148,33,140,99,180,38,21,132,90,157,2,149,149,96, - 28,130,40,68,155,164,29,145,108,200,23,10,56,97,72,181,90,197,245,50,72,157,78,200,60,99,169,215,235,88,107,113, - 93,151,32,10,48,85,131,159,241,89,88,88,160,84,42,145,113,61,230,231,231,112,28,69,169,92,38,136,67,92,225,18, - 134,17,126,33,79,38,87,32,12,66,202,155,54,139,153,129,158,225,123,62,253,247,165,93,39,78,246,116,194,64,19,30, - 184,10,246,1,51,42,29,120,252,80,182,97,255,144,211,176,108,8,163,116,170,9,156,22,146,91,51,62,139,58,161,0, - 20,172,109,79,2,237,139,191,243,106,131,105,214,254,1,23,100,162,128,213,171,86,242,193,247,255,41,51,191,244,139,204, - 252,241,251,89,248,224,71,49,173,214,11,254,116,121,9,62,190,55,156,149,38,85,10,23,149,100,205,166,149,113,73,136, - 57,13,39,45,156,93,180,4,87,190,242,122,110,121,213,237,220,241,250,55,179,126,199,229,156,188,48,197,157,95,185,155, - 19,39,207,32,173,67,115,113,158,11,103,142,48,57,113,154,160,50,139,9,106,92,126,227,117,168,190,46,90,145,193,117, - 50,104,12,218,104,220,70,200,153,61,7,73,34,77,173,25,208,10,99,164,116,177,66,225,248,57,220,124,17,167,88,66, - 100,243,224,100,48,109,127,35,33,213,18,149,136,21,162,93,253,144,122,69,27,129,163,21,50,17,105,116,128,85,96,28, - 172,149,169,49,91,170,45,111,127,127,250,125,133,114,39,94,214,71,170,52,220,208,117,60,16,26,217,38,128,116,148,160, - 112,81,174,194,113,20,74,41,92,215,37,12,3,132,16,248,190,79,171,149,110,80,105,109,240,50,25,124,223,191,248,152, - 16,208,10,90,196,73,76,162,19,78,159,60,197,252,252,60,97,24,50,55,55,71,189,94,187,168,101,74,172,166,21,70, - 169,239,134,114,80,40,58,186,250,112,223,245,19,197,7,111,190,113,215,241,76,230,45,46,252,152,129,87,39,176,106,13, - 100,71,254,9,143,222,95,238,141,114,137,182,72,218,124,145,252,62,92,11,81,24,98,26,139,244,174,89,197,150,247,255, - 111,86,61,121,63,215,255,236,187,209,126,134,228,155,8,236,75,0,244,61,122,97,11,215,110,165,244,23,191,65,199,215, - 223,199,201,95,251,9,62,150,246,220,158,128,210,98,185,84,216,250,186,219,157,184,85,35,142,99,70,71,151,243,198,183, - 189,157,91,94,243,90,38,166,23,248,179,63,255,32,71,14,159,38,235,23,48,113,200,212,212,89,230,166,206,209,89,42, - 50,118,249,118,154,77,141,171,124,12,224,68,26,7,48,243,77,206,236,63,65,189,209,98,110,122,134,185,137,105,130,70, - 11,199,91,90,56,109,3,133,77,39,88,130,52,27,222,144,242,48,73,219,15,218,146,170,168,149,213,56,58,74,53,63, - 8,18,36,186,237,196,8,233,254,151,112,74,224,116,32,156,34,80,64,73,31,109,210,189,48,99,192,26,141,181,6,163, - 65,73,23,136,48,218,146,201,102,113,92,15,209,254,58,99,82,49,98,46,151,67,169,148,173,75,18,141,53,134,142,142, - 14,178,217,180,104,183,198,162,28,69,43,108,17,4,45,140,78,56,119,246,44,73,146,10,25,167,166,166,9,131,16,129, - 68,73,7,137,32,10,67,28,169,80,66,225,58,25,58,243,157,12,189,246,77,238,161,159,250,233,181,247,12,15,189,166, - 9,239,116,224,13,30,108,207,64,231,111,129,204,241,195,181,224,249,98,222,175,223,111,225,162,5,116,16,18,53,42,244, - 175,91,205,235,254,252,253,44,127,226,126,214,252,234,191,161,176,115,219,69,224,185,212,130,125,23,199,180,73,234,210,255, - 243,47,136,223,118,43,145,54,184,74,17,158,28,103,52,213,16,117,88,24,74,6,122,74,67,107,87,96,226,38,160,136, - 162,22,17,134,193,193,1,182,110,187,156,255,241,187,239,229,243,159,189,155,155,110,122,5,175,187,227,70,214,108,94,65, - 216,106,82,57,119,150,45,187,182,49,241,240,51,152,200,226,40,133,147,24,34,215,144,23,25,78,61,117,16,191,183,3, - 183,84,32,50,1,97,16,208,170,53,200,117,116,224,186,30,202,115,145,34,165,211,141,16,8,156,116,149,130,148,7,18, - 194,164,122,31,218,58,37,82,165,143,112,188,20,112,144,128,70,7,13,230,102,43,60,187,247,49,142,28,57,194,209,19, - 199,169,84,106,28,61,122,146,102,43,193,207,56,56,42,105,147,214,138,32,0,147,104,92,39,65,8,75,161,80,166,88, - 238,32,8,26,120,153,12,82,73,226,40,194,113,20,229,114,153,106,181,138,209,134,140,239,224,121,30,97,54,36,73,146, - 139,130,71,173,53,213,106,21,155,203,33,149,195,233,51,167,88,189,106,53,126,214,103,97,110,17,37,93,84,94,161,28, - 7,19,39,32,13,158,227,166,109,32,22,153,24,134,215,110,161,241,158,213,93,247,126,225,179,215,238,120,248,161,238,101, - 214,14,68,112,207,182,212,76,111,250,42,184,100,75,255,253,186,78,130,144,136,144,242,250,53,116,254,254,239,99,103,39, - 248,179,233,169,75,0,244,114,80,253,249,228,119,63,233,86,242,248,31,124,20,241,135,31,7,173,113,114,25,114,198,178, - 28,60,3,253,17,12,251,91,54,229,187,123,186,48,205,22,105,60,160,193,145,134,218,194,34,73,28,80,44,148,56,120, - 232,60,31,254,232,151,248,252,231,190,196,101,215,109,227,71,223,248,35,92,181,115,39,133,129,46,198,46,95,207,249,199, - 14,162,146,20,40,194,56,198,119,125,50,145,160,118,118,150,161,237,61,196,113,11,172,165,58,59,75,109,126,17,229,58, - 160,210,145,186,163,36,142,151,69,121,62,158,231,225,185,46,74,201,148,10,34,181,221,176,34,109,205,194,102,131,218,204, - 2,23,206,79,50,49,62,207,131,143,238,225,200,177,115,140,79,157,231,212,233,99,52,90,1,202,73,223,54,89,63,79, - 46,87,194,81,146,40,10,8,227,38,89,225,130,200,131,53,56,78,68,146,52,241,157,44,158,235,163,164,68,88,112,149, - 11,14,184,142,139,231,198,116,118,116,210,106,181,112,164,67,208,12,40,20,10,180,90,45,146,36,65,41,133,227,56,68, - 97,72,144,196,20,50,30,245,122,141,169,169,41,186,186,123,8,90,49,70,27,250,7,7,241,179,89,50,94,134,56,12, - 193,88,50,153,12,74,57,36,38,70,9,129,151,47,211,241,174,127,225,31,94,187,97,235,236,39,63,214,185,165,86,237, - 143,161,95,192,67,255,17,206,84,161,53,115,233,109,254,253,3,162,48,194,132,115,80,200,210,95,94,117,9,128,94,44, - 223,182,84,170,6,221,69,196,181,27,80,218,48,215,126,242,150,3,178,61,61,144,142,195,212,147,199,152,157,175,16,64, - 193,194,138,166,80,203,54,189,243,237,57,229,56,36,66,97,173,69,160,81,54,66,135,117,226,86,29,19,69,224,68,72, - 33,169,198,134,175,220,245,8,143,221,187,155,107,175,187,154,55,191,237,181,108,217,188,138,153,195,231,17,115,53,66,98, - 76,148,208,116,35,138,110,142,233,125,39,176,89,65,71,119,145,156,155,33,227,103,81,66,96,226,136,56,136,16,114,73, - 152,232,34,165,139,227,56,184,109,0,114,92,23,99,12,65,24,50,55,49,201,204,169,227,212,166,78,227,235,136,142,174, - 46,170,147,1,31,252,139,191,162,34,11,72,71,225,59,138,124,161,204,115,121,209,32,132,38,142,66,130,32,100,97,113, - 154,14,20,88,31,33,13,158,151,106,132,48,144,201,228,176,218,16,133,17,174,235,144,245,211,132,184,180,210,18,248,126, - 22,185,180,162,17,37,20,75,69,106,213,218,197,10,72,72,73,20,199,52,91,45,178,94,150,233,233,105,124,207,167,80, - 44,209,108,212,153,153,158,97,96,100,20,33,52,94,198,67,34,72,116,132,148,160,156,20,132,132,176,136,80,179,252,154, - 235,229,252,216,138,177,199,255,238,3,165,45,199,143,246,20,161,59,134,251,11,112,120,13,84,138,96,47,5,55,127,31, - 79,162,73,18,141,231,94,2,160,23,77,48,119,237,92,5,63,125,11,167,119,172,34,142,147,23,236,159,109,62,71,249, - 61,127,65,117,166,34,61,232,49,176,198,172,95,55,180,252,218,43,68,208,172,3,42,157,120,91,129,213,22,97,4,7, - 14,28,228,252,249,115,56,174,0,155,96,145,248,210,39,136,52,95,186,231,94,238,185,255,126,110,186,237,149,12,121,89, - 174,232,30,196,183,224,8,65,172,35,60,153,26,238,139,4,142,61,245,8,61,158,143,182,2,63,159,167,216,221,135,223, - 145,238,118,57,202,65,154,42,96,48,66,210,136,19,90,173,58,173,234,34,73,216,162,90,93,32,151,132,12,122,134,53, - 195,14,121,175,139,76,161,72,166,152,167,171,203,39,138,29,132,80,8,173,211,165,84,155,198,246,8,33,104,181,90,100, - 188,12,66,89,154,149,25,60,4,161,1,33,124,242,66,96,100,3,39,155,101,100,120,37,231,78,61,75,43,104,144,203, - 117,147,196,26,207,115,201,248,89,130,86,61,53,63,75,12,89,223,167,218,38,151,93,215,33,142,19,176,233,106,137,144, - 146,48,12,241,253,44,26,195,249,137,243,140,58,203,144,74,176,88,153,71,184,146,238,238,30,100,46,135,146,50,173,180, - 68,186,80,155,113,61,12,26,35,32,105,54,233,30,24,70,255,187,95,239,220,247,137,15,95,179,242,235,247,116,13,192, - 64,12,95,237,135,167,223,7,115,185,84,164,112,233,124,159,207,37,0,250,78,0,84,206,177,242,55,223,78,97,199,42, - 28,11,241,124,125,105,10,253,15,201,61,33,57,143,37,1,47,3,195,13,88,237,92,113,69,103,174,171,19,130,26,200, - 182,157,131,117,8,91,134,56,178,8,225,18,90,139,176,94,234,179,108,19,12,49,214,1,215,129,88,107,190,252,149,251, - 209,38,130,155,111,229,142,181,27,104,132,53,116,20,17,37,13,172,7,11,103,166,216,212,157,165,91,47,18,197,134,160, - 57,195,98,237,60,21,105,137,98,1,26,242,158,70,235,24,132,196,24,131,82,208,145,243,232,202,185,100,59,193,179,46, - 33,9,129,114,208,78,30,145,43,19,213,27,36,42,139,138,45,74,90,180,1,99,82,0,18,237,134,84,107,67,172,45, - 174,155,65,68,33,34,73,136,84,145,122,224,80,84,6,109,2,2,58,200,229,251,200,250,62,142,227,226,58,146,172,159, - 67,39,233,184,189,213,170,147,203,103,169,87,91,180,146,136,124,190,192,212,204,20,65,216,74,205,207,172,33,227,186,196, - 90,163,141,165,25,180,200,250,62,137,73,24,31,63,207,200,208,8,249,98,129,218,226,44,185,172,143,82,233,22,189,178, - 110,10,100,66,181,157,52,221,116,191,77,9,162,48,0,41,232,121,231,187,114,199,135,134,183,206,125,226,227,229,245,81, - 152,159,7,103,5,60,81,134,185,16,180,250,103,52,37,187,4,64,63,128,199,91,49,64,199,174,245,80,105,164,201,16, - 124,139,119,164,35,241,166,23,217,120,126,134,253,144,179,48,90,135,145,149,175,185,53,231,180,219,47,41,82,247,63,105, - 53,166,109,73,225,251,62,153,76,134,40,1,41,69,106,229,209,206,113,183,128,163,20,56,18,18,143,71,158,221,203,174, - 177,21,120,128,107,72,205,200,200,112,238,248,105,114,45,232,89,110,41,120,154,66,162,233,83,146,4,151,216,180,72,226, - 4,69,38,37,161,29,133,227,121,233,191,101,12,88,13,137,37,116,125,76,174,3,223,203,144,241,114,248,249,2,181,230, - 34,97,164,177,194,71,155,182,72,13,153,122,253,8,145,114,58,194,162,117,128,235,100,105,181,2,162,56,192,136,50,21, - 221,192,247,52,106,209,18,75,129,240,179,32,60,194,168,65,54,107,113,148,68,39,169,124,192,81,30,113,148,144,205,101, - 169,84,43,184,142,147,90,223,11,73,28,199,72,41,105,180,90,169,37,145,76,249,32,107,12,25,207,35,20,33,179,243, - 179,105,101,41,139,84,22,22,112,29,7,87,185,36,50,78,167,45,142,69,74,217,110,69,83,98,91,202,116,89,55,170, - 69,244,188,226,6,103,118,112,112,213,254,15,126,192,221,50,53,237,89,40,238,134,39,94,7,231,207,64,216,184,116,25, - 92,2,160,127,12,242,199,2,255,225,240,57,242,111,255,159,237,139,239,219,16,108,2,8,18,78,44,212,132,73,55,244, - 87,200,177,177,190,161,93,59,132,14,67,116,98,176,194,34,164,66,0,113,156,198,221,44,44,204,147,196,26,219,94,198, - 20,136,180,221,17,6,172,192,24,11,66,227,8,135,179,115,21,158,188,112,134,155,150,175,34,14,170,24,9,42,148,12, - 100,75,28,57,126,150,229,43,150,83,246,154,248,82,35,66,11,73,130,114,219,91,238,90,161,68,146,122,60,199,33,56, - 14,82,57,168,92,1,215,203,64,182,76,156,205,164,73,176,6,66,147,86,79,218,90,148,112,144,82,161,173,69,24,157, - 174,122,0,190,239,183,219,81,75,172,35,170,139,85,220,36,194,201,100,72,156,14,90,97,3,234,211,148,186,7,137,202, - 125,8,225,97,76,189,29,131,220,194,115,51,24,99,145,56,180,90,1,253,3,93,56,142,75,165,86,193,115,93,162,56, - 68,170,244,249,114,93,151,36,73,136,227,228,226,90,147,163,20,158,239,81,169,84,112,84,202,109,37,218,32,133,32,231, - 231,8,140,65,250,105,84,184,54,26,199,49,40,153,142,253,149,82,24,107,80,66,160,91,1,229,101,43,136,126,254,95, - 143,238,251,240,7,95,189,230,196,241,238,28,244,41,184,127,59,156,116,160,230,94,42,132,46,1,208,247,227,44,245,249, - 9,233,242,36,22,116,71,158,241,31,185,138,133,235,55,227,198,9,147,201,119,96,3,60,23,142,156,103,230,247,63,67, - 0,153,44,140,6,176,62,185,106,87,111,247,72,31,81,216,192,81,109,245,133,0,163,53,73,28,33,133,192,243,188,246, - 184,184,13,64,162,173,57,54,242,121,44,84,170,157,49,74,114,215,222,103,184,106,120,57,217,172,143,209,9,194,104,178, - 34,131,34,203,185,169,144,174,117,62,166,217,66,198,2,233,132,184,133,44,20,58,49,38,3,218,34,173,70,74,129,227, - 185,72,223,71,171,12,137,148,36,194,1,225,96,69,130,32,6,41,169,214,154,52,234,77,92,223,193,42,7,129,76,221, - 17,17,8,37,72,18,147,106,114,172,70,11,77,117,161,134,215,168,113,228,232,126,190,254,236,125,76,157,59,77,148,127, - 146,155,239,248,89,250,139,5,138,197,50,177,142,136,162,0,172,37,151,203,131,149,228,243,121,130,32,32,10,67,186,58, - 59,152,157,157,65,199,49,38,142,113,189,12,113,18,183,129,39,125,129,172,16,88,1,65,20,81,173,215,112,149,199,204, - 236,44,66,64,185,212,193,92,98,112,28,143,193,193,65,162,56,253,191,248,89,15,129,65,72,69,18,235,139,45,115,90, - 57,41,140,209,200,254,97,17,254,155,95,233,127,236,99,31,190,113,211,99,143,116,15,64,95,8,247,70,176,231,231,97, - 190,4,102,242,18,102,92,2,160,239,25,25,15,108,219,181,142,205,221,69,186,194,152,226,80,23,211,55,108,225,102,207, - 101,98,160,19,25,166,214,3,223,241,248,30,162,210,196,79,127,102,65,192,170,10,172,236,186,225,218,172,227,8,116,144, - 182,46,44,45,142,26,67,18,133,56,40,58,203,29,233,218,65,156,70,1,89,107,177,86,60,103,79,1,233,132,77,10, - 140,167,56,51,53,205,67,135,14,242,234,203,47,35,172,46,160,140,129,48,98,89,103,63,11,103,23,176,43,251,16,109, - 19,121,169,66,12,46,153,108,23,38,155,71,27,131,176,26,129,193,96,137,218,160,107,149,192,90,147,250,157,144,238,132, - 105,35,105,133,49,219,119,172,231,192,193,99,180,106,6,63,151,79,125,161,69,42,102,140,163,4,221,230,86,98,27,179, - 103,239,93,76,157,58,196,98,165,130,146,154,108,214,165,57,255,56,159,252,192,89,150,13,172,38,138,82,71,71,219,222, - 130,15,154,1,126,54,143,16,130,124,46,155,146,197,94,134,124,46,143,49,154,140,231,81,15,154,44,9,31,4,224,184, - 46,218,104,162,56,198,247,50,52,27,77,188,76,170,251,153,155,155,195,113,92,148,227,50,55,59,75,119,119,55,89,149, - 218,128,184,142,76,247,221,108,2,66,166,147,53,241,60,208,23,2,27,71,184,142,67,199,187,127,42,255,100,111,239,229, - 43,239,252,92,215,6,75,111,29,242,235,224,201,16,102,22,190,117,200,234,165,115,9,128,94,26,248,12,116,21,248,87, - 255,225,141,172,29,234,166,22,167,187,74,54,78,24,176,22,147,68,47,108,248,251,2,39,171,44,247,43,203,33,16,111, - 132,206,22,172,136,203,229,222,101,87,110,151,54,142,192,36,8,153,102,179,99,83,151,108,107,12,70,8,252,76,106,69, - 33,180,65,182,243,183,82,140,50,207,245,130,128,181,26,109,64,185,89,30,56,122,152,171,182,110,199,117,92,116,28,99, - 147,24,215,117,209,161,195,190,3,211,236,220,186,130,36,94,76,147,37,52,196,205,4,229,45,201,12,219,252,146,53,41, - 207,34,117,234,120,212,254,207,10,36,72,197,108,181,198,186,45,59,248,236,47,254,42,15,125,253,1,62,243,233,47,240, - 200,227,79,48,61,61,155,174,116,136,244,255,35,69,186,160,42,5,196,225,44,211,179,139,248,170,140,159,45,147,201,58, - 100,85,1,226,26,141,234,73,10,165,30,226,8,48,26,107,192,38,134,70,189,134,21,6,173,99,114,126,17,41,4,171, - 86,172,224,232,177,163,132,73,8,22,60,207,5,225,98,77,250,28,104,163,145,66,16,132,1,25,207,35,142,99,178,126, - 26,63,61,61,61,157,182,139,90,115,226,216,49,70,199,198,200,102,179,40,41,200,249,153,246,243,107,47,62,183,66,164, - 196,186,84,2,48,8,99,241,129,177,215,254,136,123,168,92,88,155,124,226,19,222,246,40,206,135,105,248,228,195,155,224, - 204,187,33,248,219,75,216,113,9,128,190,11,122,135,0,216,91,206,241,200,131,251,137,155,209,119,178,75,249,246,252,143, - 171,40,158,159,227,149,224,52,83,151,198,97,239,138,171,59,70,214,175,33,138,67,162,168,69,198,207,97,172,139,144,2, - 99,211,181,3,229,58,184,174,131,148,18,41,68,106,99,33,190,177,245,122,110,196,102,112,141,69,187,25,206,87,170,60, - 121,248,48,183,108,221,66,171,85,1,13,73,20,147,203,229,56,121,230,12,189,3,29,12,150,2,164,78,64,91,76,80, - 195,77,124,28,79,97,52,88,218,91,241,8,208,54,213,199,72,129,65,128,112,81,46,44,212,22,232,90,182,21,63,231, - 115,251,235,110,231,213,175,186,133,147,103,79,243,133,59,191,194,103,63,115,39,199,143,159,161,217,76,87,63,148,235,34, - 99,133,75,142,76,33,143,167,92,60,199,193,87,25,28,89,194,45,130,227,8,114,25,129,117,115,52,72,39,128,74,57, - 100,125,15,35,98,36,26,109,210,231,37,155,203,210,221,213,197,133,201,113,148,146,132,73,76,20,133,40,169,144,202,185, - 8,32,66,136,180,146,65,18,4,1,74,130,14,2,38,38,38,88,54,186,140,36,78,24,191,112,129,174,238,238,148,195, - 91,106,251,218,207,174,49,9,82,181,95,15,13,74,9,176,2,97,65,132,17,91,110,184,77,44,244,12,44,123,252,175, - 254,50,187,177,86,237,85,80,94,132,175,254,71,56,161,33,108,94,154,144,93,2,160,151,123,44,176,239,212,52,242,143, - 238,252,174,109,25,52,80,78,171,170,172,132,145,89,88,230,222,112,77,33,155,245,9,170,77,116,16,33,179,37,44,2, - 71,74,130,56,73,167,96,206,243,114,167,236,18,215,163,17,66,126,67,11,38,132,196,8,77,198,74,180,21,68,158,195, - 151,119,63,197,229,171,86,83,114,50,52,117,147,172,85,96,4,29,165,97,246,236,57,67,247,53,35,228,141,64,146,16, - 55,154,104,55,192,233,44,145,40,23,35,36,82,39,8,97,144,10,72,156,212,149,82,25,12,160,173,75,66,134,124,169, - 64,28,199,24,18,164,53,172,94,179,138,95,249,15,255,150,119,255,228,187,120,248,225,71,249,216,71,63,197,3,247,63, - 68,171,213,32,227,122,196,65,72,98,193,235,44,180,195,84,61,148,35,200,248,46,249,98,145,140,159,37,12,2,124,64, - 219,0,233,74,164,74,53,62,249,206,78,226,150,65,152,84,39,53,56,52,196,236,252,28,205,48,160,157,74,125,177,130, - 115,29,7,173,77,10,28,214,98,140,166,86,171,226,103,92,242,249,18,205,48,96,110,97,30,41,211,240,196,106,165,130, - 171,20,214,164,156,85,169,92,198,242,60,159,35,33,218,228,123,186,123,102,173,193,90,8,171,117,122,183,236,80,103,255, - 237,175,15,220,245,161,191,45,222,112,252,136,219,1,98,6,238,250,87,112,34,130,214,225,75,24,114,9,128,94,42,240, - 44,192,255,207,222,123,199,89,118,223,245,221,239,95,57,229,246,185,211,103,103,123,209,54,173,122,177,154,37,119,185,202, - 13,8,37,33,129,0,126,72,131,39,161,132,36,15,36,36,144,74,66,66,28,74,32,4,176,41,46,184,55,92,100,201, - 234,171,174,149,86,219,251,238,236,244,91,79,249,149,231,143,115,103,180,54,205,96,9,21,239,239,245,154,151,118,71,187, - 51,103,239,156,243,185,223,242,41,156,2,126,128,111,186,203,250,75,143,4,42,80,23,176,105,57,174,76,95,246,186,107, - 20,244,33,183,72,235,113,69,201,129,116,30,151,231,136,193,59,50,8,132,20,197,140,199,14,222,149,165,196,15,38,226, - 43,96,4,133,113,188,207,13,62,84,156,238,119,249,232,93,119,243,247,223,248,38,66,151,98,113,96,37,97,20,211,239, - 84,121,250,217,62,235,215,150,169,55,60,42,239,35,58,179,184,216,67,185,4,57,216,94,31,35,83,84,37,38,144,67, - 24,47,176,54,3,21,146,187,18,41,154,80,123,180,47,200,139,86,40,50,3,222,180,169,15,149,120,251,123,110,231,205, - 111,125,3,15,222,247,8,31,252,221,63,228,161,7,31,37,138,67,74,81,137,32,136,72,211,28,143,32,42,5,24,231, - 17,40,36,18,147,91,242,204,162,148,64,105,89,16,6,131,128,74,84,193,135,130,220,230,56,60,81,28,177,121,203,86, - 30,127,226,113,20,25,90,234,162,85,146,174,208,153,5,33,198,20,192,157,166,41,129,214,24,227,72,243,20,132,164,159, - 37,164,54,167,159,244,9,195,128,86,171,77,225,40,154,227,128,90,163,134,84,18,55,88,48,40,169,17,82,23,44,174, - 11,218,178,94,123,153,117,211,107,104,254,248,63,173,60,252,209,143,94,127,197,151,63,175,134,189,143,13,124,165,4,251, - 183,192,82,5,252,69,29,217,69,0,250,166,42,149,73,10,13,215,142,231,177,124,86,192,19,32,231,138,66,104,58,219, - 185,99,100,227,206,93,216,212,146,244,59,8,233,138,42,198,23,27,163,94,175,11,222,161,68,145,12,97,141,89,157,251, - 60,199,50,94,49,79,24,84,65,120,140,42,102,53,101,35,80,42,230,107,7,158,100,219,206,77,188,97,199,165,244,150, - 90,8,227,176,57,172,25,154,224,228,241,51,124,224,171,79,112,235,171,119,113,199,117,83,216,164,199,252,236,25,98,29, - 81,206,45,54,201,88,204,12,102,104,136,145,53,101,130,64,35,188,4,165,153,157,159,71,72,69,183,211,197,171,25,234, - 141,26,82,87,112,94,33,149,194,225,73,147,28,137,224,198,91,111,230,85,55,221,196,129,125,251,249,202,151,190,202,51, - 207,60,195,220,220,18,74,4,100,169,37,233,91,42,165,50,161,87,68,198,147,24,143,49,142,60,205,80,113,9,107,29, - 100,142,37,215,37,40,85,208,81,8,162,152,243,76,76,140,50,58,210,228,212,233,110,81,149,12,44,69,140,205,65,20, - 91,49,47,32,140,35,140,49,56,147,99,58,150,48,138,152,95,92,160,223,79,152,28,155,196,26,67,179,217,196,123,79, - 169,92,66,105,69,16,40,226,114,92,172,227,157,35,203,51,132,176,3,198,53,104,173,7,111,4,158,60,203,168,40,73, - 237,111,127,79,233,228,244,248,117,230,247,63,80,155,204,237,68,79,138,207,143,35,30,250,53,231,230,43,224,22,120,101, - 229,182,95,4,160,231,241,40,10,95,103,65,17,18,118,252,121,158,41,165,160,34,168,183,96,172,113,211,117,213,122,163, - 129,107,183,240,214,160,66,129,84,2,225,5,46,203,200,211,180,136,151,246,126,96,71,81,188,227,66,65,144,91,25,64, - 23,174,132,172,154,181,163,36,18,65,104,138,90,174,87,141,249,208,253,95,99,247,186,45,108,40,197,44,119,91,104,23, - 146,229,142,169,181,27,105,239,123,154,95,248,149,79,32,126,244,157,212,134,234,220,125,239,62,226,44,229,71,190,235,38, - 134,71,3,226,126,196,51,71,231,105,68,109,42,227,13,50,93,66,232,136,131,7,159,162,185,118,43,222,11,22,102,206, - 211,91,156,163,212,104,82,105,142,82,173,84,10,95,34,95,120,10,101,105,23,240,236,216,179,149,75,118,108,227,220,153, - 179,60,244,208,163,124,229,139,119,113,238,244,108,17,76,24,4,148,42,37,172,205,8,203,37,114,60,229,64,23,179,111, - 40,230,58,78,128,41,82,53,34,165,137,163,136,32,214,92,126,249,30,218,189,22,110,169,69,154,24,210,36,91,229,4, - 33,4,65,84,48,116,196,32,230,71,56,143,233,247,9,131,16,37,36,75,75,11,56,107,145,82,210,239,247,168,155,58, - 81,20,130,244,88,107,168,86,171,72,41,144,97,136,179,30,231,138,24,162,149,159,197,10,113,209,123,240,221,140,145,215, - 191,49,58,63,57,124,89,247,215,254,111,125,211,242,98,121,9,175,55,194,67,85,152,237,129,41,93,196,148,87,30,0, - 125,171,206,117,9,133,153,188,164,176,164,204,95,128,235,139,139,55,191,81,7,35,91,46,223,173,36,96,50,131,183,25, - 74,23,43,102,37,21,153,45,230,22,82,73,156,119,232,32,24,168,203,47,92,189,251,63,245,13,60,126,16,56,232,49, - 20,179,26,25,132,204,183,219,124,224,11,159,231,159,221,241,86,156,42,24,214,74,20,38,242,223,247,198,55,241,95,126, - 111,150,159,254,165,207,33,34,232,38,57,161,81,28,88,106,177,123,199,4,71,143,44,115,234,200,44,127,247,221,55,242, - 222,219,47,195,36,243,232,234,40,235,199,199,120,228,153,253,116,83,197,182,29,59,49,198,50,127,110,134,246,210,34,181, - 122,131,218,80,131,168,92,69,6,33,86,120,172,119,164,38,69,34,153,88,59,206,29,27,238,224,181,175,123,45,143,63, - 246,36,95,250,226,157,28,63,114,140,36,55,84,170,117,84,168,177,222,147,103,6,99,220,96,123,101,168,196,101,164,119, - 144,59,172,51,232,82,5,41,2,166,214,172,99,235,37,219,185,251,174,175,17,170,128,36,179,160,6,100,1,231,49,185, - 41,12,213,100,97,65,43,133,24,48,206,29,89,158,211,106,183,240,206,17,134,154,90,173,86,204,216,36,76,6,147,184, - 208,208,235,118,169,213,235,133,188,68,20,145,67,193,96,213,239,157,199,13,126,47,165,198,25,73,214,74,41,95,114,185, - 92,248,7,63,182,57,251,205,255,169,183,207,156,143,60,52,143,193,253,13,56,190,5,146,228,34,174,188,178,0,40,191, - 106,43,187,119,175,35,252,163,175,145,165,127,53,248,176,20,9,25,215,3,163,47,212,245,1,79,8,17,119,188,31,213, - 245,198,232,212,13,87,107,156,197,101,25,206,228,56,95,2,81,112,115,140,205,201,77,134,180,6,165,195,1,35,167,168, - 118,132,144,120,107,89,33,37,174,14,94,133,0,161,144,182,72,109,74,5,32,37,42,7,77,200,67,71,14,242,91,95, - 249,10,239,186,246,90,148,51,72,163,201,101,78,173,164,248,238,55,190,129,95,248,208,23,104,231,61,100,73,145,89,205, - 231,246,158,225,179,15,157,70,6,37,162,192,243,31,62,242,101,234,53,197,229,27,70,153,61,177,200,153,182,227,145,189, - 79,241,203,191,254,33,182,238,220,205,187,223,253,110,94,253,170,203,8,69,74,107,110,158,197,249,121,42,245,58,245,225, - 97,42,141,6,129,214,184,193,63,194,58,75,106,218,132,21,197,77,183,93,207,171,110,186,154,131,7,14,112,223,221,15, - 243,181,59,247,226,241,148,43,49,46,246,180,187,93,202,141,152,176,20,145,38,9,222,43,2,29,32,101,72,174,37,113, - 92,34,183,112,233,165,87,242,212,83,79,211,107,181,105,14,213,200,242,28,33,130,98,16,237,252,234,155,128,146,18,239, - 92,17,83,173,60,233,128,240,24,230,41,51,51,231,200,243,140,181,211,107,73,251,125,150,151,150,145,82,18,132,30,209, - 233,80,138,75,128,28,180,93,32,69,161,204,119,190,144,204,56,114,188,18,4,82,144,167,25,181,141,155,200,255,201,143, - 173,127,246,183,126,227,246,245,135,142,78,148,97,84,194,157,167,224,224,20,180,215,95,92,144,189,124,1,72,0,121,163, - 194,210,27,174,96,230,138,77,152,177,6,183,106,197,231,119,174,227,183,191,244,56,31,253,218,211,228,105,206,115,89,151, - 127,246,113,20,121,222,55,12,90,176,244,5,122,1,159,5,209,246,190,9,172,173,108,217,212,28,222,52,141,181,6,147, - 119,11,93,151,208,131,135,195,144,244,186,224,236,128,241,60,96,227,14,134,209,120,183,218,126,121,127,1,40,249,194,185, - 112,229,239,32,5,94,120,148,3,229,21,46,138,248,236,19,251,104,150,154,220,182,117,19,89,146,162,51,75,191,103,216, - 56,58,194,119,191,246,10,126,247,11,119,147,57,5,58,35,20,49,24,141,15,114,140,78,57,179,232,249,177,247,127,133, - 225,102,133,110,39,101,177,221,38,115,22,21,132,156,252,218,131,60,242,200,19,188,241,182,27,121,215,59,223,202,174,221, - 59,9,53,244,187,61,58,237,54,81,185,68,115,116,132,70,99,4,175,36,214,219,66,217,142,45,60,138,156,103,199,206, - 75,216,121,217,101,220,254,246,183,240,229,47,124,145,189,247,61,200,236,217,89,134,202,117,92,167,133,75,3,164,183,164, - 38,165,60,52,76,181,90,47,50,169,180,0,231,41,5,17,239,121,199,59,57,124,248,89,158,120,226,9,162,114,137,165, - 229,22,97,28,145,13,88,210,114,16,249,147,101,57,30,79,54,72,96,245,56,58,221,54,181,106,13,99,114,58,221,22, - 229,82,153,229,229,101,148,82,52,135,155,88,107,73,210,148,40,140,7,175,125,209,26,15,56,163,3,141,158,197,11,135, - 247,2,169,21,89,158,32,106,227,200,31,253,137,177,187,255,240,119,94,189,235,129,251,135,214,195,104,15,190,252,42,120, - 236,10,88,72,193,70,23,49,230,229,1,64,57,48,178,123,61,122,231,58,90,151,109,228,245,113,200,201,209,58,34,55, - 8,99,73,115,203,244,112,149,159,255,222,219,248,123,175,187,156,234,151,30,71,126,237,105,236,159,83,17,57,138,16,194, - 179,131,141,215,11,241,118,36,129,118,113,237,81,73,136,245,125,239,119,174,123,219,219,199,100,185,140,233,246,240,46,65, - 137,0,208,197,128,217,249,85,63,100,6,156,151,40,12,137,226,136,86,183,187,26,123,188,34,205,88,253,62,82,146,187, - 65,219,229,61,184,98,107,230,5,228,206,226,60,200,64,243,249,71,246,178,113,120,132,201,106,68,110,122,4,68,180,231, - 123,188,113,247,30,22,151,58,124,244,190,135,16,97,8,34,35,84,93,80,224,92,97,89,177,216,207,152,235,167,68,90, - 34,117,128,34,2,169,209,58,36,113,57,127,252,185,187,249,220,157,143,112,219,173,215,112,199,219,223,192,158,93,91,168, - 148,98,156,49,204,30,63,193,114,121,137,161,137,9,170,181,234,192,243,87,161,131,16,132,162,211,233,179,124,254,12,179, - 199,207,176,182,82,133,117,235,56,221,77,169,135,49,177,82,132,8,186,121,194,162,135,185,153,57,186,75,109,198,54,111, - 33,8,36,105,150,99,109,78,24,106,190,255,251,190,143,143,125,252,227,124,249,43,119,2,30,107,114,180,208,171,131,107, - 103,115,226,48,36,51,6,169,21,74,74,76,150,23,0,222,106,83,12,174,60,83,83,147,68,97,206,242,242,50,14,71, - 115,120,152,74,69,145,101,57,229,178,94,5,33,6,111,16,206,186,98,254,230,67,112,133,246,77,106,79,154,56,74,81, - 157,202,59,223,19,155,55,189,254,234,195,191,248,31,27,91,242,108,196,66,53,132,7,159,130,153,61,96,194,151,216,67, - 191,79,202,213,88,171,111,43,0,74,128,141,19,67,252,236,15,188,129,70,28,98,7,15,85,131,34,139,107,221,244,8, - 86,73,82,99,25,118,30,219,251,250,154,37,51,142,204,164,76,13,87,113,223,123,27,188,238,114,26,95,126,2,113,247, - 62,220,5,64,180,18,45,123,30,88,203,11,231,247,187,242,3,108,65,213,123,191,149,56,222,210,124,219,235,171,18,75, - 150,165,152,220,13,86,236,186,216,222,164,93,178,126,175,24,184,202,66,12,89,138,53,229,114,9,63,200,137,89,1,32, - 107,221,170,254,85,136,98,85,239,133,192,27,139,240,14,137,194,121,143,8,20,210,58,188,55,44,187,156,15,221,123,55, - 223,123,235,45,12,199,18,155,231,160,36,173,185,14,223,121,221,13,44,47,182,248,220,254,131,184,178,4,111,209,54,192, - 88,80,202,18,72,80,14,228,64,29,39,40,252,155,17,16,149,202,248,146,198,163,120,248,209,253,156,58,113,134,93,219, - 54,114,203,205,215,113,217,229,187,24,106,12,145,217,140,133,153,25,210,110,74,165,54,68,218,233,49,115,242,0,199,15, - 28,96,230,228,9,226,126,159,114,98,112,78,210,64,49,57,189,113,176,66,79,200,77,142,202,12,205,80,179,182,92,99, - 46,77,153,57,124,24,61,220,164,50,62,78,230,45,206,11,78,159,62,201,79,252,228,63,33,205,219,124,233,75,119,35, - 69,165,160,38,136,140,40,14,169,196,53,58,221,14,90,10,188,45,242,230,65,160,85,17,1,237,188,35,205,51,150,150, - 150,169,85,235,8,4,189,110,159,48,234,162,164,162,82,9,200,243,156,48,140,6,250,48,199,74,136,136,243,2,114,9, - 42,196,147,35,29,84,194,144,78,107,137,209,106,153,239,251,233,127,166,62,181,110,253,246,189,63,246,99,149,43,186,189, - 138,4,213,129,175,46,195,236,8,188,36,82,88,87,172,69,126,41,8,200,40,66,59,95,241,0,180,178,72,206,128,145, - 177,6,191,250,99,119,176,126,98,168,48,154,186,96,78,99,160,248,92,246,156,115,255,159,91,45,25,7,38,133,225,42, - 35,223,115,43,63,248,218,203,80,95,126,2,238,222,135,72,115,202,20,17,181,103,120,97,27,113,89,128,156,16,48,226, - 96,115,112,217,158,53,205,203,182,8,159,27,112,41,185,145,72,157,82,81,10,188,34,239,247,17,198,34,80,24,28,126, - 197,255,199,56,172,43,66,6,87,164,2,82,62,39,192,47,214,243,190,16,203,242,220,127,5,130,64,72,188,240,56,47, - 201,133,227,208,226,57,62,255,248,227,124,199,245,55,19,136,20,200,201,156,193,119,3,190,247,213,111,96,222,165,220,115, - 228,32,58,172,32,115,65,136,199,34,17,82,16,170,1,120,123,135,240,30,233,50,74,58,100,124,168,73,110,114,132,16, - 140,141,77,17,149,74,156,154,79,249,228,103,239,229,190,251,30,229,170,61,59,216,126,201,70,58,237,22,237,185,46,237, - 217,46,102,185,79,144,101,148,176,172,169,104,148,86,36,78,226,50,75,106,12,221,165,46,206,187,194,31,218,164,69,155, - 3,216,180,79,83,8,106,181,26,11,189,148,238,169,179,232,161,17,42,245,58,231,103,23,233,245,230,249,169,159,252,127, - 88,156,159,101,239,195,71,8,75,101,124,224,41,87,99,66,95,8,116,157,119,3,98,165,34,205,114,50,99,232,167,9, - 121,158,34,148,196,26,75,28,197,76,140,79,33,165,160,221,106,19,4,33,82,104,84,173,134,181,133,231,145,82,43,222, - 73,133,59,54,62,199,32,200,189,65,89,69,37,12,57,53,59,203,235,223,250,90,92,214,229,109,127,255,7,248,125,45, - 215,126,242,239,255,240,107,223,105,221,9,7,79,206,192,124,11,220,139,61,16,18,131,89,232,191,14,67,238,148,154,186, - 51,47,9,81,219,11,10,64,110,0,44,149,102,149,205,175,187,156,137,155,119,225,203,17,157,110,250,252,212,127,3,32, - 154,24,174,97,191,231,86,14,189,254,114,110,253,195,175,177,243,209,195,0,172,249,27,120,1,123,16,28,131,113,11,235, - 135,94,251,186,166,142,171,248,100,25,155,38,120,111,138,76,46,89,100,16,228,121,134,181,69,24,160,29,16,221,60,43, - 186,172,1,24,15,124,130,254,172,90,235,66,113,170,117,5,143,104,69,84,169,156,67,11,137,11,35,30,58,122,144,241, - 198,16,119,92,118,13,174,215,162,143,225,140,93,34,50,1,223,119,213,141,196,157,156,7,79,159,192,198,101,148,15,17, - 214,227,188,199,42,129,86,133,69,170,181,6,231,114,242,212,50,115,110,142,56,148,132,74,50,111,78,49,57,53,65,189, - 90,161,169,20,213,126,206,137,251,31,135,99,103,41,41,133,75,114,74,174,0,70,169,36,198,58,218,185,135,52,71,90, - 135,177,22,99,29,153,207,200,172,41,146,58,132,7,45,80,229,18,149,114,131,70,189,1,65,192,194,177,19,44,204,204, - 34,77,151,233,250,14,36,1,71,143,156,224,250,235,246,240,175,254,229,63,229,39,127,242,223,176,255,192,9,234,67,99, - 52,74,195,88,99,16,84,233,13,50,168,60,158,48,12,81,74,209,207,82,4,144,101,25,222,58,206,156,57,131,115,48, - 58,54,70,104,45,189,118,135,44,203,49,206,80,171,214,169,84,42,171,213,167,247,162,72,232,144,186,48,52,179,69,74, - 108,146,37,84,107,21,46,185,100,43,38,203,9,189,164,50,58,202,130,84,177,178,174,44,64,71,20,113,226,238,69,126, - 208,235,192,191,15,52,127,168,53,53,138,153,226,43,106,6,228,47,120,145,61,69,252,46,59,215,177,118,231,90,198,111, - 217,77,216,168,144,37,25,100,230,121,111,62,141,177,96,44,253,225,58,63,243,67,111,34,253,185,15,242,244,249,165,23, - 244,37,22,131,170,110,73,16,134,158,241,69,88,51,114,235,205,37,133,199,152,12,211,239,34,113,40,21,163,116,128,247, - 22,147,167,5,104,120,135,148,69,128,173,214,130,56,14,87,163,108,87,212,217,95,255,157,10,209,164,64,192,128,211,178, - 242,103,11,41,130,3,225,9,148,66,58,65,174,224,11,143,61,194,80,28,115,203,142,29,200,180,133,72,29,121,218,39, - 182,154,247,190,234,213,52,158,126,156,135,79,31,165,235,10,143,105,97,4,210,41,2,87,172,178,5,158,32,140,40,7, - 33,81,28,83,173,68,140,55,26,76,84,235,76,148,171,76,15,141,80,46,197,200,64,97,133,67,57,143,76,243,130,81, - 237,13,185,243,128,66,234,136,126,55,37,21,150,196,103,232,40,160,50,90,165,54,50,78,169,89,163,57,49,78,117,104, - 136,176,90,163,218,28,162,92,46,83,169,148,209,97,200,77,173,46,79,63,245,12,79,60,246,4,39,143,159,167,22,55, - 57,123,102,134,94,111,43,107,166,70,249,133,127,247,207,249,231,63,253,139,204,205,166,3,110,133,39,75,83,148,146,88, - 231,208,186,104,169,188,119,72,138,100,144,94,210,39,14,66,148,86,44,183,22,169,86,43,40,41,105,181,150,41,85,43, - 69,180,144,43,140,203,74,165,18,74,169,194,187,9,81,196,71,231,14,44,232,72,50,59,115,158,75,182,111,165,222,168, - 97,156,1,169,184,247,11,95,98,71,158,207,122,56,235,161,29,131,123,49,1,200,15,182,191,255,88,7,252,143,64,81, - 161,224,139,188,84,236,102,181,80,223,130,24,65,74,86,254,190,6,42,151,111,66,150,66,244,45,187,177,149,24,49,61, - 194,26,41,241,89,142,233,190,240,236,8,153,229,44,70,1,235,55,79,210,56,191,244,130,127,191,22,240,8,34,2,223, - 12,54,108,104,214,247,236,146,152,156,60,233,99,6,201,12,222,151,65,106,172,205,72,147,94,97,52,54,0,24,231,44, - 74,105,148,214,131,77,23,23,12,161,87,139,157,1,40,13,214,204,95,103,140,54,0,31,239,113,90,32,188,39,180,130, - 80,132,244,69,202,239,63,240,85,114,109,184,117,227,86,84,219,98,8,200,164,71,59,203,219,118,238,225,198,75,182,178, - 104,19,210,126,177,173,114,12,146,36,6,241,205,165,48,42,18,53,148,162,28,86,8,156,34,80,2,103,50,2,97,240, - 89,23,111,53,90,106,188,150,248,40,32,32,66,100,142,126,150,179,220,239,211,241,45,214,111,219,204,216,218,81,202,163, - 21,234,245,10,149,90,140,142,2,84,160,137,74,85,74,213,26,81,185,134,10,162,98,219,132,39,199,211,24,170,115,243, - 173,183,112,243,205,55,113,238,212,57,158,120,252,25,14,60,251,52,135,14,157,96,251,182,141,108,219,182,149,127,243,175, - 127,134,159,255,185,95,98,102,118,17,98,137,212,186,104,193,188,31,204,128,32,12,195,162,133,28,56,34,58,239,73,179, - 156,115,231,207,227,61,108,222,180,165,104,7,251,69,102,189,53,57,173,214,50,206,123,106,213,106,33,135,65,226,173,67, - 73,9,40,156,181,228,54,225,234,107,47,7,60,161,14,217,127,240,8,207,124,252,19,230,125,112,220,194,33,13,75,245, - 193,140,243,197,60,95,144,138,223,213,154,0,255,146,99,106,107,51,119,254,91,40,3,4,56,199,145,127,242,118,110,202, - 51,130,245,227,116,181,42,18,150,60,248,44,255,27,103,67,104,231,217,255,134,43,56,176,247,96,49,176,125,1,223,89, - 98,96,220,251,178,135,145,112,203,214,161,161,169,113,92,178,68,210,235,146,103,25,82,41,52,26,33,4,73,210,37,75, - 250,72,10,73,65,161,245,26,172,214,87,124,120,46,104,189,86,128,198,251,1,39,104,133,22,61,16,78,14,28,134,86, - 127,14,210,121,156,176,24,41,138,12,83,173,233,248,156,143,221,127,15,83,81,149,45,19,83,164,73,15,103,12,185,201, - 136,195,136,102,20,209,240,1,42,168,226,130,128,92,21,32,134,243,152,44,69,82,124,47,233,37,248,140,92,21,98,88, - 165,4,50,0,173,3,194,160,132,150,154,204,89,82,233,88,204,61,243,2,206,217,148,182,75,72,178,46,75,157,121,174, - 10,134,217,50,53,65,92,142,201,242,148,52,201,177,253,20,33,66,234,245,128,72,6,5,209,82,106,172,179,8,169,138, - 170,33,77,16,192,228,218,49,38,55,76,114,211,242,13,28,126,246,32,207,30,58,129,240,134,29,59,118,242,19,63,245, - 15,249,255,126,246,223,178,216,235,145,229,22,41,53,72,129,177,150,64,42,162,168,68,179,57,196,210,114,11,99,115,172, - 241,228,121,78,160,53,173,78,139,243,179,231,24,29,29,195,121,8,130,238,160,237,114,116,41,194,22,203,229,74,97,215, - 33,11,187,146,80,75,206,158,59,195,214,237,91,152,90,55,69,158,166,200,184,194,39,254,248,19,108,63,113,124,110,4, - 158,78,224,72,31,250,127,60,24,246,190,88,51,160,42,240,159,2,205,146,128,202,75,113,13,159,30,125,246,91,255,42, - 227,117,42,66,224,211,28,159,190,184,163,45,151,27,234,27,199,153,188,110,27,203,247,238,127,65,1,40,4,169,165,168, - 230,206,143,235,230,112,69,73,143,119,166,240,44,70,96,156,163,44,11,73,64,175,219,42,230,63,190,40,199,133,4,33, - 10,63,157,80,235,1,25,81,172,90,76,172,180,87,43,230,100,171,237,217,170,107,98,17,203,190,194,158,46,100,98,18, - 163,5,214,21,32,18,137,128,212,102,252,225,125,247,242,206,91,110,102,107,115,24,233,28,38,10,200,180,68,100,14,97, - 5,169,80,120,3,202,22,58,52,37,36,210,5,8,173,87,149,250,198,59,34,33,9,195,34,250,199,8,193,114,158,243, - 236,249,25,90,253,62,105,32,201,227,128,32,174,162,194,26,178,222,164,108,42,212,228,48,253,190,225,206,187,30,224,190, - 251,247,114,249,21,151,177,125,219,54,70,70,134,48,121,70,123,169,67,191,123,140,114,173,70,169,86,163,90,175,161,195, - 16,164,196,123,71,38,61,69,253,97,193,164,196,213,144,61,87,95,193,214,254,37,28,218,255,52,15,61,250,8,227,163, - 99,188,251,59,223,198,175,188,255,183,177,126,32,252,85,1,165,40,70,8,65,158,229,140,141,142,16,232,128,165,165,37, - 210,52,197,25,143,113,142,94,191,207,169,51,103,136,227,18,163,195,99,152,44,167,211,110,175,254,12,236,192,132,191,82, - 41,3,18,233,100,65,127,200,51,110,190,229,70,114,107,64,41,78,159,62,203,227,31,248,160,249,30,56,156,195,227,14, - 78,255,79,48,159,124,177,159,240,32,36,148,138,242,138,156,231,165,6,64,66,61,15,99,32,99,95,244,33,219,215,129, - 131,117,76,188,246,114,166,30,60,64,108,220,11,242,238,179,226,41,52,7,82,128,94,74,83,221,203,218,4,120,18,107, - 81,113,140,116,150,168,84,198,153,140,164,215,43,252,119,156,67,106,133,27,112,160,165,210,132,97,225,197,44,132,94,5, - 155,21,48,130,129,47,180,95,177,140,125,78,167,228,87,53,99,69,236,178,178,128,183,24,105,139,4,119,227,80,50,228, - 88,210,227,255,124,233,203,220,176,105,59,87,109,222,204,84,165,76,32,32,215,6,35,28,194,57,20,30,159,231,132,74, - 227,124,142,14,10,101,184,80,122,80,81,72,156,146,28,95,110,113,236,208,97,150,140,97,161,223,199,5,138,209,169,9, - 26,149,6,54,243,136,92,130,233,17,42,77,164,21,198,42,130,32,102,116,122,10,25,6,28,62,182,200,129,3,119,51, - 49,218,96,207,165,219,88,51,57,140,146,158,206,226,121,58,11,179,180,162,152,82,181,78,181,57,76,185,82,33,212,193, - 192,56,3,44,186,176,6,17,150,168,164,184,236,218,107,217,190,123,55,167,78,28,229,202,252,42,246,92,246,0,247,61, - 240,16,82,69,104,161,73,179,140,56,138,139,193,179,135,225,102,147,114,169,68,183,223,163,221,43,236,102,187,73,31,235, - 28,71,143,29,199,89,201,154,169,73,100,36,105,181,90,24,107,168,84,138,90,83,105,73,92,138,9,101,192,169,83,167, - 216,125,217,78,70,199,70,233,231,125,170,213,33,62,241,177,223,99,253,51,79,204,143,192,83,25,60,149,195,210,20,248, - 247,240,226,144,237,34,224,30,41,57,174,36,218,191,116,73,217,175,72,49,170,207,12,193,166,9,22,174,217,198,254,251, - 159,125,65,128,127,80,1,249,186,243,109,5,199,151,191,248,133,195,31,188,241,117,155,198,234,13,113,166,164,74,205,43, - 246,68,107,174,190,92,236,186,118,13,209,112,25,99,115,220,64,107,36,173,69,200,24,239,51,180,202,10,107,10,21,124, - 67,235,245,28,8,201,193,122,94,2,94,174,12,159,221,215,189,163,121,81,216,189,202,66,201,129,195,227,133,196,121,129, - 208,154,101,39,249,204,254,125,124,245,232,1,118,142,141,115,249,212,90,214,77,140,83,46,151,8,181,38,116,2,97,13, - 206,122,180,214,16,134,244,157,101,169,223,99,118,97,145,99,115,51,156,92,158,39,183,30,21,197,56,161,200,173,165,42, - 171,72,25,98,157,196,107,72,76,78,40,161,84,9,139,217,150,113,24,160,223,206,104,84,98,42,186,142,12,60,231,206, - 156,231,248,241,47,49,52,92,225,138,43,119,179,97,253,52,181,114,136,49,57,11,243,231,105,45,204,17,149,202,148,199, - 70,168,150,107,148,75,53,132,18,88,145,98,189,197,122,143,77,19,164,128,205,219,182,178,105,203,22,174,186,250,58,62, - 251,185,207,243,155,191,245,127,121,252,177,125,120,36,18,79,160,66,150,150,150,72,210,144,48,138,105,54,135,9,162,136, - 126,175,143,71,146,152,148,124,113,158,44,55,244,210,46,107,166,166,136,227,152,165,197,37,242,204,210,28,86,164,73,66, - 24,133,180,250,203,72,13,55,223,124,19,206,90,34,29,115,250,212,121,30,249,205,223,202,239,192,31,204,97,175,135,19, - 215,65,246,134,23,241,25,56,43,4,215,135,209,115,109,250,69,0,250,27,110,197,172,99,232,245,87,176,254,225,67,168, - 220,62,239,85,144,2,22,193,159,132,249,146,20,119,111,74,211,220,61,252,204,6,15,245,10,76,44,127,230,158,201,103, - 66,53,126,248,250,43,71,174,252,169,31,175,142,111,223,36,122,102,22,235,52,113,10,50,116,56,45,64,36,131,97,178, - 64,122,119,129,254,75,174,130,80,209,183,13,124,158,145,69,237,228,60,98,176,13,43,64,106,64,54,241,30,225,124,65, - 58,19,96,241,104,83,36,107,248,80,145,56,203,3,167,143,179,247,212,113,154,97,133,169,70,147,201,161,49,214,84,203, - 12,87,75,212,107,67,100,166,207,241,153,25,78,44,204,114,116,113,150,142,40,134,172,129,40,242,182,116,146,3,25,90, - 41,98,165,48,253,62,11,221,46,94,64,20,197,140,143,143,19,148,11,51,51,75,225,225,147,154,132,133,158,39,10,3, - 164,132,90,115,132,166,30,35,207,83,246,62,116,148,135,246,30,100,227,186,81,118,108,219,88,164,99,152,140,94,119,153, - 243,201,34,101,25,51,90,110,82,30,31,161,92,175,160,148,198,51,240,215,150,146,196,230,72,33,104,140,84,248,222,31, - 248,30,222,126,199,219,248,212,39,63,205,239,254,223,15,242,228,147,251,233,27,139,117,142,118,183,131,214,133,24,182,214, - 168,81,42,149,232,245,122,88,231,48,194,51,215,158,163,125,184,205,252,252,28,155,55,109,97,120,120,152,110,167,131,214, - 138,74,41,70,24,199,233,153,83,188,243,221,239,96,104,164,70,154,100,148,170,53,62,244,187,191,206,182,39,30,62,51, - 10,15,36,240,112,11,22,62,51,40,88,95,140,83,1,126,55,8,56,73,193,253,185,8,64,47,198,201,12,126,227,4, - 242,71,223,202,154,247,127,26,242,231,127,241,216,7,74,208,203,157,223,39,224,140,46,102,126,229,88,48,86,246,172,153, - 202,236,166,252,238,189,59,14,221,255,247,46,219,123,199,235,54,237,252,225,247,68,235,39,183,145,36,139,72,221,66,136, - 18,74,12,161,85,4,184,162,130,17,69,122,198,10,17,110,117,45,63,48,172,119,190,104,187,164,82,95,103,170,190,194, - 7,186,112,139,38,87,62,47,37,129,82,88,99,11,251,213,48,194,11,232,144,115,176,53,195,254,185,211,72,233,9,164, - 36,210,49,74,200,194,188,203,122,172,20,232,56,90,77,39,213,170,200,55,43,151,43,68,113,140,113,150,147,167,79,19, - 199,37,198,199,39,24,105,142,96,115,203,236,204,44,113,28,175,234,245,162,40,30,236,44,86,248,75,57,214,22,60,29, - 173,3,132,16,28,63,50,199,129,103,142,49,60,82,101,231,246,205,108,218,184,150,161,64,98,178,140,179,217,121,92,111, - 137,122,28,81,175,84,24,106,142,16,68,85,242,129,161,91,110,7,196,186,44,71,7,146,239,249,219,223,199,219,223,254, - 46,30,221,251,24,95,251,218,125,124,225,11,95,230,192,161,99,244,147,132,32,10,152,155,93,40,30,0,165,138,156,54, - 239,80,66,225,242,156,153,153,51,100,105,159,203,47,191,156,145,145,113,242,60,163,221,105,211,237,119,216,184,105,3,59, - 119,238,32,207,13,97,24,114,248,196,49,30,248,63,191,145,127,63,236,207,225,254,18,28,59,5,217,223,126,49,239,253, - 48,68,42,93,204,125,46,2,208,139,119,68,146,49,127,249,102,178,31,125,43,27,223,255,105,196,243,12,66,26,232,22, - 221,88,79,67,63,0,150,64,214,60,65,8,165,150,96,88,121,177,109,58,207,110,46,127,248,179,183,126,245,193,71,47, - 189,228,39,126,108,232,134,215,95,67,175,107,7,3,77,129,51,5,229,95,14,252,160,221,138,6,98,208,146,173,216,77, - 92,104,211,186,2,60,43,195,106,121,65,53,116,97,43,183,226,105,227,7,131,43,233,197,170,127,142,212,18,99,45,178, - 172,81,66,32,45,24,36,198,175,204,47,67,74,186,200,143,151,10,226,74,9,111,29,165,114,133,48,138,200,178,12,188, - 39,51,57,213,160,134,150,146,110,167,179,250,61,3,173,139,7,92,22,210,143,64,5,104,45,139,239,53,96,25,39,73, - 138,14,52,113,80,162,57,60,133,195,210,89,94,228,179,95,184,151,102,57,224,150,203,118,49,185,110,140,242,196,8,153, - 23,164,237,54,115,237,22,203,115,115,148,42,13,106,35,35,148,107,197,247,206,93,97,248,111,129,110,183,69,20,135,220, - 124,219,141,188,250,53,175,230,71,254,193,63,224,222,123,31,230,163,127,252,97,238,249,218,221,164,105,70,20,70,196,113, - 68,158,164,244,147,4,231,61,222,21,18,142,86,123,137,125,251,246,177,109,155,97,100,100,140,126,191,199,240,112,131,183, - 189,237,205,224,29,89,106,208,181,144,79,125,224,119,184,250,240,129,99,117,184,191,7,251,2,104,189,19,120,138,63,61, - 243,125,33,225,192,3,35,192,7,148,226,159,43,77,224,95,30,98,124,245,163,111,185,230,149,140,65,200,220,144,172,27, - 163,191,126,140,161,71,14,33,158,71,82,252,50,48,63,88,135,43,10,233,199,97,240,195,96,110,133,36,135,37,7,231, - 114,56,83,130,214,250,229,142,220,255,213,123,26,231,70,199,106,27,47,221,69,232,11,207,228,187,238,126,128,99,39,207, - 34,6,98,157,21,95,232,213,56,154,193,44,200,57,55,208,39,125,189,80,245,27,65,103,229,215,95,71,106,84,18,47, - 7,105,139,198,162,17,84,163,50,177,10,9,133,70,152,66,218,81,12,155,1,45,81,113,128,197,146,216,34,157,162,86, - 169,33,164,32,77,19,58,157,46,253,94,15,132,96,100,120,152,90,165,86,180,70,222,23,219,62,32,138,162,85,66,95, - 1,176,158,104,144,131,22,69,17,66,72,180,214,40,169,176,206,98,156,71,5,17,149,114,141,250,208,48,253,133,101,204, - 233,89,78,31,58,68,167,213,166,17,86,168,13,213,32,16,228,182,24,236,247,151,151,232,245,150,17,18,202,165,26,82, - 72,36,32,10,50,19,198,89,146,44,33,42,133,236,218,189,157,55,191,249,245,220,116,211,171,24,30,110,210,233,180,201, - 147,140,230,240,8,65,16,210,239,245,113,110,197,255,71,18,6,17,173,86,139,209,209,81,192,241,93,127,235,93,76,77, - 142,131,135,40,8,120,250,208,97,238,253,167,255,108,249,245,237,206,87,114,248,84,31,158,222,9,201,8,48,14,140,81, - 144,0,199,6,191,127,161,63,246,42,201,63,14,34,114,254,108,171,97,33,64,13,136,173,43,213,180,82,197,27,66,16, - 40,182,93,178,149,219,110,187,141,64,235,130,157,63,208,38,66,225,101,37,131,129,182,223,63,63,43,39,21,86,95,249, - 0,180,10,66,235,199,72,166,71,105,60,114,248,121,3,161,229,98,11,198,32,114,144,14,133,58,126,18,216,58,184,249, - 142,64,22,193,2,48,99,161,179,49,55,254,236,87,31,168,60,99,178,198,37,55,92,33,165,15,185,235,174,123,57,120, - 248,40,98,0,38,43,244,255,21,32,185,16,100,86,254,255,159,85,13,21,22,18,254,235,51,197,6,21,149,23,69,154, - 59,222,35,7,10,203,220,22,41,167,94,60,247,103,133,150,232,80,23,214,164,120,132,119,104,41,16,174,48,0,203,141, - 25,196,240,20,128,40,133,160,90,173,82,46,149,9,244,192,169,144,130,252,87,42,149,208,90,175,138,58,181,46,182,124, - 5,248,20,198,97,122,224,229,236,188,65,234,34,128,81,8,129,14,66,74,66,161,150,58,12,151,42,204,157,56,203,201, - 253,135,56,183,52,143,174,151,41,85,170,68,74,131,119,164,105,135,110,167,67,191,157,130,49,4,90,19,69,1,171,92, - 5,37,16,194,96,93,15,176,172,93,183,134,155,111,186,145,27,111,184,145,237,219,183,211,239,247,72,146,62,214,153,130, - 57,237,4,90,6,228,198,144,36,61,188,201,121,247,187,223,206,21,87,237,128,65,36,80,88,42,243,191,126,225,23,217, - 114,231,93,7,198,225,179,33,220,181,31,230,126,0,120,255,224,227,127,0,7,129,47,3,159,166,160,95,4,64,243,5, - 186,207,127,58,8,216,43,20,241,159,215,17,92,4,160,23,25,132,54,140,147,172,29,165,241,232,17,132,115,207,27,0, - 137,11,0,168,69,225,57,189,117,101,27,1,124,28,92,0,157,42,204,120,33,102,167,156,203,179,135,159,172,63,124,250, - 196,208,182,215,223,166,31,121,120,31,79,238,219,143,80,23,182,96,69,98,231,133,192,115,97,69,115,97,160,222,133,31, - 127,250,166,27,124,222,249,34,73,85,8,132,82,88,1,70,128,21,2,43,5,97,28,17,14,0,76,10,129,242,130,72, - 40,68,110,136,229,74,52,51,40,165,136,194,16,147,229,148,202,101,132,148,88,99,168,148,43,40,161,80,74,209,104,52, - 40,149,74,88,107,169,84,42,88,235,6,179,30,189,26,127,180,34,176,181,222,129,42,72,131,82,250,2,248,84,64,16, - 134,4,129,98,105,126,150,10,138,166,138,8,132,100,118,97,129,243,11,45,250,25,116,146,156,70,115,132,48,8,144,94, - 144,246,251,180,91,139,116,218,45,156,51,68,81,68,168,117,193,107,18,30,188,45,76,225,140,193,88,203,80,179,206,174, - 221,59,185,245,214,155,217,115,217,110,202,229,98,91,54,55,191,136,16,146,40,10,177,38,225,59,223,115,7,111,127,251, - 27,73,122,11,72,47,168,87,235,220,255,216,227,124,246,103,255,117,255,246,36,185,207,194,231,42,176,223,9,145,255,170, - 82,76,3,63,2,188,9,248,126,224,106,224,243,131,22,105,106,80,17,189,16,231,83,82,241,184,148,127,46,219,249,34, - 0,189,84,64,104,221,74,37,228,94,112,0,154,7,126,163,248,188,123,15,116,219,48,155,75,185,52,226,125,172,159,61, - 54,246,200,153,51,213,67,185,212,199,142,159,64,72,113,65,11,245,167,65,230,27,103,60,23,126,254,194,57,209,133,109, - 218,133,25,90,43,119,97,33,128,245,104,161,80,40,66,161,80,20,159,119,214,19,40,141,68,146,231,150,204,88,156,144, - 196,229,242,64,246,225,168,86,170,200,193,48,58,12,2,130,32,32,142,34,148,146,228,121,70,28,199,212,106,85,140,177, - 3,208,41,230,88,90,7,5,165,96,48,181,16,74,34,6,67,115,41,5,10,77,32,66,156,144,24,239,144,145,66,85, - 35,252,82,155,138,0,161,5,37,17,19,82,97,98,221,86,206,39,57,15,62,254,52,210,72,42,81,68,169,22,162,180, - 36,79,83,146,126,143,246,242,18,38,205,9,132,64,171,16,169,10,223,231,98,192,47,138,65,184,203,144,26,214,111,90, - 203,141,55,189,138,55,221,126,59,91,54,95,194,210,252,34,103,207,158,225,166,87,93,197,143,255,216,15,147,167,139,96, - 115,148,144,232,176,196,175,252,187,255,192,165,15,63,122,116,29,124,33,128,175,61,4,179,191,43,21,135,227,146,248,77, - 107,185,213,123,70,6,85,112,23,248,42,176,133,194,30,230,133,114,230,252,152,122,249,1,208,183,93,44,143,234,38,180, - 174,216,196,241,31,125,11,27,222,255,25,68,254,55,19,168,82,46,64,200,127,12,90,239,113,238,201,28,106,107,2,61, - 162,62,123,119,248,137,122,109,109,80,10,3,147,101,5,176,32,240,190,96,224,202,11,218,178,11,129,71,107,189,170,156, - 255,198,1,245,159,2,222,213,135,188,16,105,226,11,177,176,116,30,133,67,88,135,87,106,85,68,236,115,87,128,3,160, - 116,0,74,174,182,94,74,106,130,32,64,169,34,125,52,75,83,2,29,144,36,9,165,184,132,214,138,52,77,72,211,180, - 16,122,42,133,247,130,44,203,73,146,132,32,8,208,90,19,134,65,241,239,92,105,135,69,49,73,243,78,16,149,34,172, - 183,32,61,149,177,81,146,133,14,121,110,136,69,70,100,37,73,63,99,97,102,158,181,87,238,161,149,24,172,136,176,132, - 60,246,212,126,70,134,26,172,95,55,141,240,130,180,103,88,236,205,210,154,59,79,169,54,68,125,116,146,74,165,178,250, - 58,20,129,140,30,164,163,159,180,208,82,50,54,222,224,123,254,238,119,113,199,187,222,198,125,119,223,69,123,105,142,3, - 71,15,49,82,47,209,172,55,136,202,53,62,240,193,63,66,253,209,71,58,55,192,137,4,142,155,162,186,85,223,139,183, - 239,77,19,191,222,89,186,20,130,207,139,190,172,223,198,91,176,63,31,132,210,191,113,16,26,36,103,240,105,224,59,160, - 229,225,145,60,55,245,105,76,253,54,19,15,237,151,97,83,73,133,244,133,133,201,96,169,245,117,21,205,115,225,133,110, - 117,229,126,97,149,115,33,0,93,88,49,201,65,98,132,148,5,168,136,193,12,200,225,177,24,130,32,40,218,160,193,106, - 57,8,66,178,52,69,7,10,99,114,170,229,18,206,121,50,103,9,162,66,185,111,141,161,221,110,19,40,141,22,10,188, - 164,215,235,83,173,86,17,162,112,23,140,99,63,72,251,240,171,177,67,118,85,205,47,16,190,144,91,40,89,128,159,147, - 30,161,5,46,207,145,74,16,160,9,157,194,78,79,211,59,115,142,97,33,73,69,70,213,90,206,45,156,166,218,94,203, - 214,233,181,180,150,231,217,126,229,53,148,71,154,236,123,252,81,206,157,122,130,169,241,49,214,173,157,70,135,138,126,218, - 162,179,60,71,119,160,120,175,53,139,205,89,16,197,3,6,127,49,124,87,74,226,69,78,158,47,16,215,20,175,127,251, - 107,49,73,194,241,99,199,120,230,137,39,57,113,98,158,196,30,227,127,252,231,255,225,254,89,97,183,90,115,176,205,192, - 242,102,56,42,156,59,231,112,173,164,176,46,243,23,193,231,226,22,236,47,104,199,44,201,250,81,146,117,99,212,31,61, - 140,176,127,245,178,242,155,105,193,78,3,95,24,108,41,174,0,62,3,236,46,90,179,100,20,18,15,147,75,129,222,113, - 79,16,14,173,26,143,249,175,39,25,94,88,201,60,231,25,237,255,84,229,179,82,233,92,88,45,93,248,241,245,105,171, - 98,0,72,2,37,139,217,77,173,86,43,42,22,87,228,198,107,173,6,118,20,121,81,53,88,91,248,47,11,177,202,221, - 41,149,98,164,144,4,65,72,24,22,237,88,173,86,195,24,67,191,223,71,41,73,28,199,197,182,107,144,193,181,178,5, - 91,189,14,85,72,116,133,148,148,162,98,132,170,131,194,196,204,216,156,64,23,100,199,186,214,4,145,38,208,10,149,24, - 178,32,96,100,122,154,110,167,79,88,210,236,220,185,133,53,227,147,52,26,67,156,157,61,207,189,123,31,194,8,207,244, - 154,117,133,87,146,77,201,210,132,94,183,69,175,189,140,201,82,162,149,175,39,20,82,42,112,133,246,12,1,206,228,120, - 111,24,30,29,102,219,246,173,12,53,71,152,157,95,196,40,201,99,179,11,242,72,107,185,46,97,93,19,182,70,176,206, - 64,195,129,232,64,222,1,227,193,141,83,240,197,190,10,108,186,216,130,253,233,25,208,255,243,230,171,191,109,209,87,100, - 134,254,186,49,146,181,99,127,173,153,208,55,3,64,25,133,53,236,235,128,155,128,215,0,87,2,107,192,47,10,161,148, - 16,235,231,2,125,197,93,81,52,94,216,119,20,55,134,251,51,222,63,47,36,27,94,72,58,252,198,13,217,10,224,92, - 184,166,247,43,119,224,5,159,135,98,168,28,4,1,81,84,36,83,224,158,179,170,202,243,252,185,121,141,16,168,129,110, - 80,14,4,158,90,43,226,48,162,92,42,35,101,1,52,65,16,124,29,96,73,41,87,179,207,86,190,215,55,94,183,146, - 18,169,116,145,243,165,53,90,43,172,115,120,201,192,210,86,66,160,49,173,14,195,97,136,245,25,97,102,72,90,61,212, - 88,19,89,169,113,254,236,121,54,78,79,81,27,169,177,216,91,230,247,127,255,35,254,254,223,254,80,254,216,159,124,213, - 30,234,180,148,42,69,76,140,142,82,46,151,17,206,224,242,140,164,215,97,105,126,142,164,215,65,74,77,24,132,133,79, - 211,224,7,106,125,1,150,198,26,28,158,106,181,198,246,93,59,120,211,91,222,44,118,191,229,109,106,118,235,246,210,231, - 218,253,241,175,204,205,111,236,153,108,211,56,108,170,193,100,0,85,1,162,11,121,0,249,44,248,71,128,141,23,1,232, - 79,207,128,38,38,38,94,54,120,241,66,181,212,246,205,55,96,190,244,56,225,190,111,45,174,112,197,34,227,194,27,96, - 35,240,11,23,252,126,199,5,189,239,97,48,161,247,125,19,5,206,13,98,120,86,103,60,74,14,18,82,159,3,20,117, - 1,251,249,194,10,231,66,160,249,70,55,197,231,42,158,194,33,80,12,188,94,87,190,222,74,85,149,37,105,225,43,228, - 45,185,181,196,113,188,250,178,135,97,76,150,37,148,203,17,74,23,132,201,96,112,45,74,235,1,232,20,21,79,24,134, - 69,64,160,16,171,243,22,231,28,229,114,153,52,43,28,33,117,16,20,195,231,193,133,25,87,248,236,228,185,193,5,97, - 209,18,250,34,31,76,42,141,115,144,5,33,182,20,147,246,51,116,172,17,145,167,153,88,22,14,31,165,126,233,165,204, - 182,150,56,126,242,4,179,251,186,252,187,159,248,41,191,227,145,39,91,63,14,103,37,36,119,254,250,31,76,252,247,15, - 126,124,116,244,134,43,131,55,220,254,70,110,188,114,55,99,205,42,206,27,146,52,37,109,119,56,215,61,74,80,174,48, - 52,220,164,54,84,71,69,49,129,150,216,188,216,70,122,33,48,214,147,166,61,132,16,92,178,101,138,75,127,252,135,249, - 161,31,252,62,238,189,255,193,240,19,31,250,232,244,175,126,225,243,19,151,156,56,185,237,38,184,98,2,30,15,96,239, - 89,120,188,15,199,190,23,218,7,94,58,62,96,47,157,25,80,24,134,47,151,107,245,47,220,23,86,200,231,1,212,11, - 65,5,252,44,240,79,225,207,21,2,230,20,65,137,63,225,189,247,96,149,49,70,72,141,25,0,14,23,144,249,86,77, - 199,248,122,210,225,74,43,243,141,159,91,153,15,93,56,59,90,169,128,132,120,78,200,170,68,49,68,214,74,81,173,86, - 87,205,182,210,52,93,5,193,32,8,232,118,187,24,107,193,187,98,230,19,132,8,160,239,60,195,205,38,149,74,5,147, - 23,128,83,46,151,87,1,111,229,250,87,6,214,174,184,217,176,198,224,188,71,5,1,38,207,65,136,2,180,156,37,140, - 66,156,47,172,107,81,2,57,40,216,28,133,206,45,43,149,105,27,199,132,14,232,121,143,207,13,165,249,54,173,83,167, - 104,14,53,249,157,223,251,48,159,253,253,15,154,239,59,63,159,222,10,173,20,142,59,152,191,3,230,111,233,244,183,61, - 244,39,247,142,125,248,43,247,133,31,216,185,69,190,229,29,111,17,55,191,234,106,54,76,142,162,149,34,115,57,73,210, - 102,230,84,155,133,185,136,122,115,152,90,189,73,20,215,48,190,104,73,133,0,169,139,64,73,99,251,216,110,66,41,82, - 220,254,198,27,120,211,235,110,224,208,177,127,170,63,242,161,15,79,126,241,211,159,27,93,247,216,227,151,236,236,116,174, - 24,134,7,26,112,87,0,143,77,194,185,114,81,20,95,60,43,0,228,47,142,202,120,62,94,131,112,48,239,249,183,20, - 100,196,191,236,43,182,1,3,46,4,87,206,140,209,202,96,84,177,14,183,182,80,186,75,33,7,91,46,40,244,97,254, - 235,170,158,11,183,98,43,45,149,187,192,162,99,5,152,164,148,24,91,228,207,23,218,44,177,10,94,206,58,242,126,74, - 189,81,35,12,3,74,165,136,110,183,95,8,73,139,80,44,82,147,19,170,194,5,208,218,132,114,169,76,181,90,98,104, - 104,168,104,159,2,137,28,204,145,86,218,172,149,108,245,149,225,55,23,108,239,140,41,18,73,181,214,104,253,28,123,90, - 74,137,70,144,217,156,168,28,23,222,217,214,96,28,72,47,17,97,192,49,151,33,90,30,180,39,183,57,97,187,205,204, - 99,143,179,254,85,215,81,171,14,83,93,88,238,93,9,157,54,4,22,38,34,8,45,148,70,192,191,13,220,205,198,243, - 208,147,135,236,211,79,254,119,243,133,177,33,185,254,230,107,130,247,220,113,135,216,190,117,35,181,122,165,152,115,101,57, - 115,167,79,51,119,118,134,90,189,201,208,96,104,141,42,108,79,156,181,104,41,7,105,181,134,44,105,225,17,108,89,63, - 198,79,255,212,63,98,246,135,254,142,190,251,203,119,79,28,250,131,15,15,143,125,234,51,211,235,178,108,189,133,225,58, - 124,41,40,110,147,231,221,189,230,132,16,124,94,74,162,151,217,222,77,95,196,224,111,97,144,61,120,1,203,192,239,3, - 191,53,152,3,125,83,253,239,115,173,154,143,140,177,161,247,244,40,188,52,86,30,216,149,42,167,152,191,200,231,82,64, - 47,168,124,86,54,75,23,174,227,197,64,114,113,97,251,182,98,249,90,128,128,194,89,183,250,224,59,239,72,211,148,94, - 175,75,20,133,84,42,101,22,22,22,11,16,9,20,105,154,21,32,87,76,131,190,174,178,202,141,65,34,209,58,88,157, - 37,73,41,139,54,234,2,64,52,198,224,6,243,158,149,107,14,130,160,152,177,24,51,240,20,95,177,25,113,88,99,81, - 97,1,186,89,106,8,101,64,28,71,44,215,107,252,201,221,247,177,165,92,162,84,10,176,222,226,45,124,229,143,62,68, - 180,102,154,242,230,237,165,223,58,125,202,212,148,10,250,121,190,45,200,51,43,173,113,147,222,186,141,144,55,65,93,5, - 193,109,16,204,205,46,229,159,248,227,47,166,31,104,103,225,219,238,120,135,172,5,158,141,155,214,51,50,82,39,10,53, - 185,201,232,46,157,167,187,52,71,189,57,76,99,100,132,82,185,134,212,26,235,5,43,221,110,241,227,114,88,215,199,164, - 142,70,89,241,246,59,222,72,239,246,55,4,15,126,226,115,155,190,248,190,127,216,120,125,167,157,133,112,252,17,152,75, - 161,255,124,62,120,49,240,39,66,114,94,8,94,110,217,244,223,246,0,228,129,72,73,30,84,146,57,254,108,13,205,159, - 247,194,157,165,208,127,245,129,95,229,175,94,91,251,98,162,139,242,222,175,12,7,157,181,88,191,162,118,151,120,111,113, - 206,15,120,65,254,207,229,4,5,90,99,173,35,179,41,184,175,31,151,121,231,86,245,86,197,223,187,160,234,27,128,88, - 154,166,56,103,201,178,12,41,19,194,48,36,205,50,148,86,148,227,24,188,39,233,39,69,72,98,150,17,13,196,168,54, - 55,12,53,134,6,3,242,66,130,177,242,245,86,42,177,114,185,24,82,155,60,95,53,81,211,90,127,93,219,168,180,198, - 91,135,113,133,234,62,237,39,3,43,211,2,124,115,147,161,140,32,170,84,89,123,227,53,36,79,31,163,18,104,84,4, - 65,47,97,107,86,38,157,235,114,199,149,215,4,217,149,215,12,103,70,144,228,150,110,150,144,184,54,39,90,139,254,104, - 55,53,203,115,11,44,206,207,243,182,172,231,95,131,15,255,46,248,47,124,229,158,124,230,242,43,213,134,91,111,208,15, - 238,125,148,102,179,196,174,93,219,25,31,29,198,228,133,60,163,179,180,64,187,181,72,165,58,68,115,100,156,32,174,160, - 244,115,206,141,120,7,162,208,240,121,44,214,244,137,133,226,213,239,125,23,31,255,216,167,135,143,127,248,143,182,109,133, - 53,195,16,206,64,127,246,175,112,175,253,101,167,2,220,163,95,158,143,242,183,61,0,5,74,210,109,117,249,254,133,54, - 135,94,12,0,116,30,161,240,74,73,164,215,224,4,94,184,1,232,20,182,173,5,109,71,252,185,43,120,231,139,249,141, - 240,224,132,28,232,187,184,224,255,23,155,45,53,144,118,172,240,129,164,44,196,160,94,21,153,92,248,162,85,11,130,162, - 98,169,148,203,24,99,200,179,140,74,165,138,119,158,60,45,6,201,231,207,159,103,124,108,12,45,53,253,126,151,56,46, - 97,109,78,191,223,93,173,12,86,218,176,110,183,139,28,180,103,43,109,151,25,16,27,87,255,77,206,225,114,143,213,26, - 179,50,243,202,29,65,24,144,123,67,63,237,145,230,93,84,185,66,88,110,224,119,239,96,254,236,25,154,89,74,179,84, - 163,30,164,88,44,198,88,60,1,78,121,188,4,89,142,208,97,9,53,57,41,188,44,5,29,239,57,221,235,241,216,147, - 143,219,108,255,227,217,171,33,120,131,181,250,171,191,244,203,233,145,74,32,174,127,235,237,234,231,255,213,191,226,212,47, - 189,159,55,191,243,173,220,254,166,55,178,97,106,2,157,165,100,54,161,215,94,162,215,94,34,46,149,169,52,134,9,226, - 50,97,169,134,14,138,71,201,228,30,47,5,194,91,156,203,41,137,136,225,45,27,57,5,149,237,69,66,143,254,183,192, - 195,207,235,122,70,18,73,73,153,151,31,241,241,219,26,128,60,80,137,67,126,243,179,15,114,232,204,220,139,118,25,66, - 12,36,9,185,27,108,127,28,97,20,15,34,101,190,222,110,227,27,231,86,43,15,112,150,21,38,235,74,107,124,158,35, - 7,131,95,9,127,106,118,100,76,65,62,92,221,168,249,98,104,92,138,99,164,145,171,179,155,44,203,138,234,42,12,177, - 206,210,104,52,232,180,59,197,32,217,57,90,157,54,227,163,99,116,58,93,178,44,167,86,171,161,117,80,248,74,43,69, - 167,211,193,90,75,189,94,39,138,99,202,23,108,197,46,188,30,127,129,207,245,133,28,40,147,231,228,89,182,218,190,9, - 20,50,181,132,161,194,106,73,180,118,18,211,110,49,179,208,98,56,44,19,90,139,201,186,8,219,67,9,6,255,254,16, - 155,129,145,2,71,70,37,210,92,90,41,177,254,218,107,212,93,101,229,245,99,143,154,219,156,87,183,122,252,190,255,244, - 43,221,127,241,91,31,168,150,206,204,38,63,236,236,210,131,255,249,183,74,255,243,247,63,86,222,244,246,215,68,183,188, - 245,118,118,109,216,136,179,69,234,109,175,219,163,211,238,34,164,162,92,169,50,52,60,76,92,107,12,6,238,131,159,13, - 197,155,67,150,246,40,13,8,16,226,121,54,42,147,80,252,220,121,121,178,174,181,248,38,6,176,94,136,87,36,0,5, - 74,114,126,169,195,175,124,252,158,23,251,82,68,97,77,33,73,243,108,176,249,178,95,183,126,191,208,120,236,194,141,88, - 33,43,176,72,245,156,220,66,172,204,89,46,96,76,127,35,41,49,207,243,213,25,204,202,124,103,69,201,94,171,213,240, - 222,211,233,116,200,178,98,254,179,242,255,148,86,197,60,202,88,250,189,62,105,154,49,52,52,132,177,197,26,62,8,10, - 131,177,44,203,8,195,112,181,101,76,211,20,165,53,81,20,173,126,223,149,107,88,81,213,139,32,40,18,63,6,169,31, - 22,86,171,55,49,232,29,51,151,97,41,252,137,164,128,160,62,132,13,74,156,57,55,79,61,205,9,130,136,72,43,148, - 183,8,111,139,167,61,136,8,61,4,222,146,134,142,52,55,52,156,224,77,55,222,166,127,119,126,81,76,30,63,154,238, - 128,238,206,126,178,212,56,117,46,105,192,137,38,254,216,110,208,189,211,11,235,246,255,234,71,182,253,218,135,62,191,97, - 252,246,215,69,111,127,215,59,216,181,121,35,18,75,154,116,192,102,244,151,231,232,46,207,19,86,134,168,214,170,84,135, - 234,232,48,196,91,71,47,203,232,236,223,239,47,131,118,6,61,1,246,223,82,240,197,190,85,187,212,50,112,191,84,252, - 162,210,168,151,169,232,67,39,165,242,95,8,60,65,158,17,89,59,88,133,190,114,54,102,43,213,207,175,127,250,254,23, - 179,250,1,16,218,58,167,115,235,173,64,104,165,48,3,34,226,133,91,172,11,43,134,149,7,248,194,85,188,86,186,0, - 145,85,169,131,127,14,136,6,9,15,43,132,192,21,146,224,202,223,245,222,19,68,17,146,194,42,35,77,83,196,96,61, - 190,2,122,121,158,175,242,123,242,44,39,142,34,154,205,38,105,150,50,51,151,16,40,141,51,150,48,140,104,54,203,116, - 187,93,172,181,12,13,13,81,169,20,6,102,43,213,207,115,4,199,231,24,217,43,215,185,250,206,254,13,215,30,234,0, - 165,4,137,183,164,38,69,101,80,139,74,32,53,190,18,163,55,213,233,44,204,211,95,92,32,76,44,85,52,35,213,58, - 145,214,160,52,62,235,19,121,131,18,30,167,138,8,160,82,14,187,119,95,169,62,114,234,36,255,208,26,91,129,100,10, - 191,15,184,179,15,143,74,200,53,172,191,26,174,222,62,223,185,254,238,15,124,124,215,255,252,228,159,76,172,123,211,107, - 195,219,239,120,27,187,119,108,36,150,96,178,132,220,102,244,91,243,116,150,102,40,45,86,89,187,126,19,165,210,16,79, - 28,61,65,250,208,195,189,13,112,58,133,153,12,50,1,12,125,139,55,141,2,122,192,31,234,96,53,212,242,101,9,64, - 139,163,227,127,209,251,50,42,203,16,199,15,83,81,154,106,20,21,171,217,139,213,207,243,141,65,133,127,179,181,200,149, - 182,228,2,87,196,213,85,246,224,172,0,193,202,92,200,88,75,150,103,148,227,210,234,223,231,207,40,201,173,181,95,71, - 62,52,198,20,45,214,160,10,209,58,160,215,235,173,206,110,194,48,252,58,80,200,178,172,112,47,140,99,194,32,192,56, - 135,25,84,72,65,89,19,14,192,107,121,185,181,186,142,95,1,62,231,28,225,192,7,104,5,120,130,32,40,4,173,131, - 86,111,229,123,58,107,49,214,226,173,45,102,71,82,22,57,97,74,17,138,194,167,40,136,53,214,184,194,168,222,56,4, - 158,225,13,27,17,155,54,211,106,183,56,115,226,56,159,190,243,43,92,177,121,11,187,166,167,25,174,213,200,136,145,73, - 6,202,145,75,143,119,41,87,111,216,204,3,155,182,198,31,59,122,176,247,110,107,235,17,76,8,40,171,66,175,119,92, - 192,225,12,14,68,240,212,91,224,154,155,91,189,171,30,253,208,167,182,253,241,231,191,60,246,241,27,175,41,95,255,166, - 215,113,205,158,61,140,52,106,64,27,233,37,189,78,135,94,187,71,80,26,229,253,255,241,151,217,50,191,56,171,225,89, - 3,167,114,72,119,125,139,237,146,167,144,246,252,11,29,240,172,148,148,95,206,0,244,23,201,15,132,16,24,33,216,55, - 119,158,208,123,174,153,156,166,30,69,171,67,194,151,123,245,243,27,159,121,128,163,231,22,94,244,203,177,66,8,39,165, - 80,30,172,53,8,41,86,3,9,87,230,49,43,60,153,11,213,241,43,109,145,16,130,64,7,132,65,56,112,31,20,44, - 181,90,36,105,178,250,103,87,248,54,223,56,83,242,222,147,36,9,161,14,8,148,94,101,91,175,104,192,210,52,45,228, - 11,131,207,25,99,80,90,17,199,49,73,146,32,7,127,206,24,75,187,221,38,73,82,148,210,12,15,15,147,166,41,73, - 146,16,69,17,149,106,117,149,39,116,225,28,107,101,48,141,128,204,24,88,201,70,27,208,10,156,115,88,99,176,74,34, - 188,165,174,52,10,137,183,158,92,128,177,25,101,25,18,7,1,253,110,11,39,5,165,106,137,203,110,188,142,153,229,121, - 62,253,135,31,92,122,168,86,209,217,186,245,213,87,109,187,148,219,54,108,2,219,199,5,142,52,119,228,121,198,27,111, - 121,141,252,108,84,105,250,220,149,166,142,62,91,190,62,239,165,85,88,246,208,139,225,204,60,28,140,97,198,195,254,18, - 60,122,11,92,117,77,171,183,231,233,207,221,181,229,107,95,184,107,242,163,219,54,85,119,220,114,179,184,241,198,43,217, - 186,101,35,81,37,226,248,92,139,255,253,239,126,146,214,7,254,168,117,19,60,154,194,163,17,204,236,1,103,249,214,34, - 186,106,192,71,164,226,215,180,38,126,153,235,237,245,55,243,184,134,74,145,36,9,123,103,206,112,205,196,154,151,61,8, - 5,74,50,187,220,125,137,84,63,224,149,20,102,144,199,190,210,130,173,156,231,136,133,114,53,177,211,185,231,126,191,2, - 64,165,82,9,29,232,213,53,249,138,126,235,194,170,105,5,92,190,145,45,29,199,49,12,86,231,113,28,99,140,89,229, - 243,36,73,66,150,101,171,85,138,16,130,126,82,172,227,123,221,238,115,178,139,82,137,82,41,166,217,28,161,84,42,175, - 126,191,21,64,188,112,139,247,156,164,196,13,218,61,57,248,40,180,95,43,219,58,187,210,98,42,133,196,33,241,244,77, - 94,132,57,170,112,224,68,233,201,92,74,181,86,98,106,106,130,109,27,54,50,57,62,78,185,28,115,229,213,187,249,103, - 143,61,232,174,127,246,96,251,232,179,79,199,159,61,114,84,61,178,126,147,104,148,34,122,121,215,39,121,207,118,50,39, - 95,117,253,205,242,159,252,227,31,86,111,254,142,247,86,62,252,145,79,85,62,243,207,126,252,198,239,94,94,232,89,200, - 186,112,207,56,156,186,15,22,215,64,123,4,78,59,120,42,128,173,87,193,206,43,28,123,142,62,123,116,231,221,207,30, - 93,251,137,15,124,184,220,216,48,173,171,99,195,114,225,216,73,179,246,228,217,243,223,9,15,123,248,140,135,71,66,104, - 111,124,158,238,153,223,209,26,67,65,128,125,133,3,80,49,190,87,82,146,90,251,178,7,161,11,171,159,35,103,231,95, - 2,205,23,3,134,113,225,137,140,179,5,33,111,181,109,242,3,23,65,143,16,138,21,73,156,181,102,181,34,82,74,21, - 51,163,129,190,42,140,34,98,91,72,30,86,102,40,23,146,26,87,102,44,23,182,117,74,107,162,32,92,213,128,93,56, - 35,42,170,167,149,245,127,33,82,93,94,90,34,10,67,70,199,70,49,166,216,144,85,202,85,226,56,94,117,67,92,249, - 58,0,206,219,85,194,30,40,172,117,200,65,108,178,247,14,99,115,132,20,88,87,84,117,129,14,144,206,15,0,78,17, - 73,79,20,72,140,82,244,83,67,158,230,140,12,85,152,94,51,194,182,29,219,216,180,125,51,81,169,136,146,206,109,74, - 47,111,177,110,253,8,59,223,125,199,240,167,254,227,47,219,255,98,77,247,157,182,191,116,239,129,167,105,67,84,3,166, - 192,30,17,68,95,242,95,27,254,251,255,224,45,162,119,226,253,220,241,234,75,248,204,85,219,26,31,253,202,3,55,222, - 1,202,67,156,194,23,119,192,201,113,48,1,44,204,193,114,2,199,203,240,88,14,15,108,133,93,219,96,107,222,239,79, - 183,247,31,26,207,246,67,13,206,85,224,217,12,30,1,30,11,225,204,231,192,206,62,15,131,231,95,15,66,190,58,88, - 187,243,237,0,64,171,55,169,16,47,123,16,10,148,228,196,220,50,255,253,37,80,253,200,1,32,42,231,188,114,6,227, - 37,88,139,210,133,77,134,117,190,16,66,122,0,183,106,82,182,82,65,88,187,226,52,168,233,39,253,213,200,158,114,92, - 194,187,162,154,114,23,180,50,23,174,189,47,156,237,24,99,40,85,170,3,50,227,0,12,7,171,246,48,8,80,170,144, - 216,22,12,103,69,146,244,241,222,19,199,49,253,164,143,247,20,145,205,81,12,136,85,250,192,74,139,24,4,33,73,210, - 71,135,146,56,138,113,206,99,140,69,41,143,84,69,88,99,160,53,121,102,200,93,159,40,10,16,88,130,32,6,95,24, - 154,73,41,233,247,123,116,146,46,211,235,183,113,217,149,87,176,235,210,73,154,67,18,69,72,234,13,137,73,208,94,17, - 34,137,116,128,142,52,239,125,199,155,184,235,127,255,150,56,63,187,112,126,18,238,122,7,156,0,170,22,106,30,26,151, - 122,54,29,62,55,115,233,71,62,252,209,202,143,191,117,138,118,251,52,127,247,125,63,192,151,47,191,97,234,19,239,255, - 213,87,191,57,75,76,6,231,170,5,240,180,119,3,71,192,222,83,84,51,157,75,96,38,135,103,162,194,113,117,172,2, - 99,213,34,63,242,188,129,51,227,48,235,160,253,24,216,127,241,188,220,192,33,82,169,87,4,248,252,149,1,232,149,0, - 66,97,24,240,236,161,67,4,103,231,185,134,23,135,59,145,3,235,10,0,114,30,242,178,148,121,5,225,164,144,82,201, - 16,111,61,94,8,4,69,91,226,188,43,204,213,97,96,105,186,146,152,250,28,49,49,205,178,213,121,141,28,56,24,22, - 182,30,174,72,85,85,10,86,140,205,190,193,95,122,165,82,113,74,81,138,99,122,189,222,160,106,241,180,187,221,162,170, - 137,34,164,42,230,81,73,146,160,6,109,185,119,80,169,214,88,88,88,164,20,198,171,121,101,245,122,189,168,148,150,151, - 7,2,219,18,56,137,53,14,200,9,2,133,195,98,93,78,16,104,164,15,80,65,76,183,215,34,233,165,148,203,133,65, - 126,28,133,244,122,29,146,92,48,181,118,45,183,223,188,155,157,59,182,83,137,99,108,178,64,150,245,232,199,160,100,76, - 77,14,227,115,199,252,249,57,14,30,61,194,211,207,236,231,238,251,31,33,201,145,22,102,45,220,99,225,222,160,160,8, - 197,22,154,33,92,247,247,50,155,254,193,175,255,201,213,223,243,213,241,202,223,249,222,157,124,215,119,220,192,77,215,190, - 153,127,121,238,224,240,129,63,248,244,158,61,112,99,15,22,53,28,59,12,73,21,242,157,144,204,21,233,39,253,95,131, - 126,6,51,215,66,16,13,186,162,37,200,230,32,255,106,16,184,207,72,197,130,27,36,226,126,43,15,171,82,104,165,94, - 81,46,139,127,45,34,226,133,32,116,245,196,20,141,40,126,89,128,144,7,114,60,151,126,97,47,159,132,23,53,182,214, - 3,45,48,61,88,172,88,63,55,153,154,116,127,160,75,2,95,8,30,157,69,42,139,195,226,68,134,20,1,160,159,99, - 15,15,88,109,43,131,97,6,9,170,105,154,210,237,245,208,97,161,100,247,30,114,155,23,22,172,43,149,208,160,197,91, - 5,161,129,236,220,230,134,174,237,98,108,1,50,214,59,116,16,96,156,165,213,237,16,5,69,164,78,16,20,155,42,173, - 52,81,41,38,208,97,177,129,27,172,247,251,253,62,81,20,97,173,45,140,225,195,16,103,60,46,7,235,13,65,168,209, - 129,68,74,141,201,13,89,102,16,164,4,2,130,64,98,93,136,115,138,126,63,37,142,45,219,47,217,202,158,203,47,99, - 106,253,24,97,212,71,164,51,244,211,24,194,18,65,60,74,144,37,156,57,113,130,47,127,249,94,190,116,247,221,28,217, - 255,172,239,159,62,237,242,86,151,27,44,173,239,86,122,46,18,242,73,227,221,193,16,142,29,131,52,2,49,5,97,2, - 179,35,96,126,36,237,155,255,249,196,241,171,14,189,118,199,80,126,250,113,76,247,126,242,236,188,127,6,134,119,194,107, - 203,48,12,28,113,176,32,96,113,35,156,222,10,167,247,194,252,113,72,26,66,184,159,10,163,172,3,249,15,228,153,187, - 196,57,150,148,226,95,198,101,132,41,94,255,146,82,223,242,61,243,74,147,142,255,181,153,208,43,32,244,200,204,89,174, - 126,153,84,66,58,10,88,126,234,56,159,187,247,41,190,213,77,196,183,122,28,176,6,242,6,44,74,239,231,107,34,207, - 188,84,37,107,93,193,109,241,224,68,113,203,121,10,79,26,37,2,172,179,171,36,197,149,70,206,11,6,214,167,197,170, - 60,73,18,170,213,234,64,237,110,10,112,241,30,59,224,232,10,64,12,92,8,205,10,25,208,59,210,204,80,42,151,209, - 50,192,38,253,213,25,146,14,3,74,149,50,194,250,194,170,85,7,104,21,210,168,55,128,149,149,126,78,150,166,212,234, - 117,226,184,96,113,175,172,214,87,54,119,133,252,162,184,0,33,21,94,56,180,10,9,116,76,150,118,73,109,138,195,208, - 79,18,70,170,99,92,190,231,50,118,239,222,196,80,67,131,207,112,189,51,228,46,162,92,170,162,136,56,125,126,129,7, - 31,122,148,135,191,120,15,247,222,251,0,237,67,207,158,127,167,243,226,53,208,108,20,65,145,167,198,224,17,97,205,163, - 25,60,49,139,56,50,142,207,239,4,223,0,95,133,228,237,112,184,13,159,15,32,248,187,80,251,245,223,249,218,149,191, - 184,212,209,239,124,245,110,126,228,123,222,34,62,89,154,174,253,183,15,124,114,247,20,118,203,8,180,154,208,217,2,115, - 163,5,24,61,213,133,189,111,131,103,119,121,191,52,158,103,238,7,117,192,175,232,128,255,145,165,133,252,5,79,252,10, - 5,143,23,21,128,86,64,40,177,150,135,103,206,188,44,64,168,36,37,127,231,143,239,226,99,238,165,113,43,252,12,248, - 119,64,138,16,169,243,194,247,123,125,74,104,130,48,32,80,197,107,233,188,67,136,98,51,229,165,89,29,32,251,129,183, - 143,25,200,46,16,197,0,214,73,48,206,162,164,36,138,35,108,226,209,66,224,6,62,60,43,44,99,49,200,85,151,162, - 152,217,36,64,32,21,153,49,36,105,178,170,176,95,33,51,166,73,2,214,83,138,34,156,43,170,176,44,179,152,60,33, - 77,18,26,245,6,89,150,145,231,249,42,137,113,197,107,202,185,162,133,244,88,16,154,60,55,228,166,88,193,91,45,72, - 83,75,210,79,200,146,62,195,163,13,110,126,245,213,92,118,217,38,234,117,112,121,139,180,231,169,149,27,120,17,178,208, - 106,243,244,147,251,216,251,213,175,241,209,79,126,129,103,79,46,32,109,137,53,19,147,184,205,219,199,190,60,59,107,190, - 103,121,222,173,135,52,135,253,105,225,130,123,95,13,102,103,241,253,35,96,195,193,48,247,35,192,195,144,254,12,28,233, - 195,87,134,96,226,187,22,186,67,255,245,195,15,109,126,253,235,47,83,55,110,232,81,249,225,55,197,15,204,44,199,229, - 205,67,53,35,237,216,253,135,78,241,224,153,37,187,246,224,169,43,47,207,179,107,55,194,14,15,95,217,15,15,237,113, - 238,204,127,201,179,236,45,66,176,3,248,80,209,44,191,92,177,65,92,80,120,189,96,33,175,223,178,22,236,229,2,66, - 229,40,224,158,167,142,241,241,123,247,189,116,230,81,131,159,172,245,222,13,85,70,184,227,134,91,56,127,234,56,39,79, - 157,98,126,113,1,235,28,106,176,90,71,136,162,101,49,22,196,96,51,38,4,114,32,236,92,49,154,95,145,56,204,46, - 204,23,85,135,181,69,5,165,20,62,207,87,239,38,99,12,65,24,174,126,222,172,16,26,173,193,243,28,119,72,43,133, - 183,174,16,60,70,17,245,198,16,189,110,159,40,140,137,194,8,194,152,102,163,73,185,84,194,154,156,94,191,143,181,142, - 40,140,144,82,17,4,186,176,243,144,128,40,130,13,165,16,100,89,138,201,45,222,27,22,151,22,169,148,170,220,122,203, - 205,92,127,243,46,42,117,135,164,143,233,89,170,97,21,33,60,7,159,58,206,99,251,246,99,204,97,166,226,156,93,99, - 53,254,160,157,210,177,33,168,156,222,153,131,84,202,195,34,155,88,23,252,198,248,26,110,60,188,47,122,151,115,53,9, - 210,67,107,45,116,52,69,100,114,95,8,62,161,20,39,164,226,113,224,90,147,39,55,57,119,208,192,87,182,192,212,107, - 114,51,242,192,190,83,195,19,165,53,212,70,207,242,254,127,249,86,198,194,243,184,126,159,115,157,173,60,125,90,168,143, - 124,234,145,225,79,30,57,54,180,235,192,209,137,215,56,214,120,24,202,225,75,175,247,254,68,201,123,115,39,80,113,150, - 205,121,202,17,196,75,118,93,190,220,237,253,69,29,223,243,14,56,207,59,0,125,35,8,93,245,18,157,9,73,41,249, - 111,127,124,23,47,37,3,182,213,85,59,176,102,88,249,31,253,185,31,36,112,158,179,167,207,243,228,190,131,60,241,196, - 1,158,126,250,8,231,206,44,176,208,89,160,155,247,11,195,116,64,106,81,196,15,11,129,148,226,185,8,6,241,220,102, - 107,176,59,195,251,226,123,72,165,80,131,129,179,31,172,236,173,115,152,34,178,162,120,109,132,64,105,133,51,6,41,6, - 18,16,231,7,9,164,125,250,253,136,56,46,209,168,15,13,64,199,144,39,41,222,121,162,168,112,163,9,131,136,36,201, - 16,162,79,181,82,37,10,74,228,62,195,120,135,55,197,32,189,223,239,210,235,181,25,159,104,240,250,107,175,227,154,43, - 119,210,108,150,112,174,143,235,41,194,64,98,179,148,71,246,222,207,222,251,30,65,36,125,214,142,198,92,186,103,148,201, - 24,194,160,201,77,87,93,198,19,159,219,75,32,21,129,14,232,245,251,204,31,120,134,109,59,118,211,122,251,119,213,14, - 127,250,195,155,182,155,124,171,131,198,211,48,127,100,0,250,29,33,120,36,8,87,95,176,223,6,46,201,210,214,4,60, - 147,195,179,187,83,119,205,127,251,181,7,154,187,214,191,87,92,219,60,67,205,159,101,230,76,153,251,246,206,185,110,119, - 33,247,113,69,93,187,103,90,230,175,218,36,79,158,216,61,245,135,191,253,169,215,124,167,65,73,104,117,161,245,155,48, - 255,223,87,122,231,36,1,41,249,86,114,87,180,14,8,165,228,149,120,158,55,53,252,115,32,116,246,37,55,152,126,41, - 86,63,223,136,69,165,190,53,89,43,161,90,215,172,95,223,228,146,109,183,241,29,239,126,35,189,94,198,249,243,203,28, - 58,126,150,199,158,216,199,190,125,207,112,226,212,25,102,103,103,233,116,123,197,170,94,7,40,93,84,24,214,121,148,28, - 172,218,189,31,100,204,131,23,133,95,141,148,10,132,68,249,130,173,236,173,99,121,121,169,168,182,6,51,155,162,109,242, - 148,74,33,194,67,160,20,81,41,38,203,115,148,82,196,113,72,28,5,148,74,49,54,203,11,189,21,80,138,203,68,81, - 145,128,154,229,25,198,228,116,187,109,194,40,164,52,112,56,236,251,156,118,171,205,182,205,235,216,181,115,61,59,118,108, - 64,71,2,159,167,100,253,46,81,88,69,88,120,230,169,103,57,250,204,83,44,159,63,202,166,137,42,215,108,158,102,88, - 65,31,129,109,39,16,119,184,114,235,56,13,105,232,231,21,146,204,80,170,8,94,123,251,237,124,255,223,254,219,56,169, - 120,232,115,31,171,237,52,249,176,134,210,62,144,191,9,174,60,104,9,127,60,77,248,62,10,61,85,213,123,22,138,185, - 156,14,32,90,130,224,53,55,111,23,87,239,18,132,153,225,177,19,146,255,245,191,62,213,25,222,123,236,204,22,108,39, - 131,176,23,4,149,71,26,209,248,219,127,234,7,43,251,191,247,13,245,79,253,223,63,185,246,61,112,220,194,145,119,66, - 235,198,129,230,11,88,245,64,250,235,156,8,120,214,26,126,90,134,175,152,213,251,11,2,64,207,13,166,205,75,111,48, - 45,37,255,249,99,119,243,82,179,159,29,100,71,121,128,48,199,229,169,67,250,12,227,60,173,110,159,178,74,169,6,138, - 242,150,113,182,93,178,134,119,188,241,122,122,153,103,113,185,199,204,217,57,158,126,230,48,143,61,185,159,253,135,79,114, - 244,228,97,58,221,101,146,126,66,55,77,87,13,194,180,214,232,32,64,135,18,231,115,108,238,8,116,132,240,2,155,102, - 140,142,12,163,177,180,59,61,140,19,152,44,47,120,63,130,130,91,100,45,181,106,21,237,61,141,161,38,121,47,1,231, - 10,65,129,205,129,194,30,67,233,0,99,115,66,17,20,148,1,239,168,85,202,131,86,78,146,39,41,189,212,18,84,43, - 252,173,191,251,119,120,253,171,175,98,241,244,179,180,151,207,97,115,11,178,132,14,170,156,61,113,130,3,143,239,133,229, - 57,46,223,56,198,186,29,187,136,108,135,60,239,208,77,5,58,140,144,218,227,130,156,53,235,70,169,197,138,161,250,90, - 110,188,241,90,94,247,218,107,185,100,219,86,166,166,198,217,251,212,126,78,8,74,14,154,6,234,59,65,253,123,112,43, - 117,196,144,115,104,10,81,104,27,8,32,246,176,193,193,182,131,181,234,200,123,223,179,142,178,106,243,248,137,26,63,250, - 51,127,96,222,61,51,127,250,45,112,46,131,57,9,202,230,249,154,225,185,220,63,254,201,47,175,249,225,159,121,79,252, - 75,143,31,31,59,249,216,129,61,83,176,41,132,103,95,15,89,157,111,221,123,85,2,111,177,150,131,210,242,155,175,32, - 254,207,11,2,64,5,8,73,18,107,94,50,51,33,161,36,203,173,46,127,231,240,105,254,22,47,238,234,253,27,183,96, - 235,138,119,224,60,130,190,233,206,219,133,222,105,182,143,94,70,63,53,24,23,16,226,193,165,96,139,253,149,140,37,37, - 37,40,85,42,76,79,87,185,241,150,93,228,230,29,116,251,134,153,185,101,102,231,218,204,205,206,179,180,208,97,110,118, - 145,67,135,15,242,196,83,143,49,59,127,142,94,43,39,75,66,156,205,232,185,148,74,53,30,196,225,8,100,32,105,12, - 213,201,50,7,222,19,69,33,81,20,22,121,240,214,210,235,39,40,175,177,61,195,216,240,36,54,207,81,104,132,83,164, - 73,74,46,28,97,12,113,37,68,40,64,73,74,213,42,30,65,110,44,66,132,76,172,27,231,85,183,188,138,43,174,190, - 154,230,112,19,103,251,184,74,147,172,211,33,10,97,105,126,150,39,31,250,2,233,204,73,182,143,196,108,219,53,68,228, - 123,100,221,54,125,93,69,69,138,168,98,177,193,16,157,4,206,156,237,112,190,167,248,161,31,122,31,59,118,92,205,244, - 250,41,234,83,67,52,27,53,234,181,26,181,99,39,232,70,81,216,79,250,227,33,140,70,16,156,129,188,53,232,82,175, - 133,85,251,210,62,176,4,141,26,108,159,129,45,126,199,198,242,214,181,195,56,99,249,195,63,121,138,205,51,243,11,111, - 132,51,125,184,211,193,163,190,16,171,190,102,23,92,245,216,177,153,106,88,169,197,239,248,225,55,203,131,63,122,112,98, - 26,63,145,64,105,14,90,125,158,31,243,231,18,240,3,38,231,247,47,240,120,186,8,64,47,19,16,82,129,102,249,83, - 247,33,206,46,80,127,137,189,248,75,224,71,160,229,224,240,68,43,61,254,197,159,253,207,99,71,222,246,198,96,237,101, - 151,49,189,101,51,107,38,155,84,130,10,206,148,16,190,87,188,243,187,0,239,37,194,123,92,158,161,165,160,57,164,24, - 25,31,65,134,235,64,86,128,106,241,158,110,61,203,115,243,204,156,159,225,244,241,147,156,59,125,134,133,197,5,22,151, - 22,57,112,240,8,7,15,30,165,223,205,9,196,40,82,25,202,129,193,26,75,185,84,42,152,206,229,10,90,199,248,33, - 65,185,20,161,164,160,217,24,90,181,103,53,38,47,12,208,188,199,102,20,13,12,26,29,133,12,141,55,25,30,31,102, - 199,158,29,236,217,115,41,107,38,199,208,10,200,115,76,190,128,144,154,201,233,13,152,126,151,175,253,201,39,57,247,212, - 35,108,31,42,179,253,146,181,52,117,15,210,22,97,92,33,168,213,105,59,152,79,60,179,11,17,199,206,205,179,212,17, - 120,93,195,196,13,202,205,38,135,15,31,98,219,246,181,172,221,48,129,73,83,114,147,80,174,196,196,113,232,252,50,101, - 89,176,158,245,135,128,227,131,155,94,81,100,116,101,69,155,35,43,208,20,176,105,6,198,235,155,135,85,197,58,206,46, - 88,14,239,61,216,251,91,112,198,195,147,192,231,66,120,58,131,97,15,211,18,182,145,137,94,167,103,217,181,125,130,211, - 235,215,214,237,137,147,227,10,170,15,193,121,247,60,154,143,85,188,231,173,214,240,81,165,137,46,2,208,95,13,132,174, - 154,88,67,227,69,2,161,220,57,54,125,249,209,213,160,192,151,218,121,12,150,22,224,225,245,48,58,250,196,209,185,51, - 79,252,218,244,113,21,12,221,63,61,217,172,110,24,11,118,95,125,169,26,90,187,46,104,108,89,175,171,155,214,211,156, - 154,162,28,7,196,74,128,177,24,11,121,90,184,41,138,164,131,84,41,82,46,35,84,33,157,104,140,72,26,195,35,92, - 178,163,9,110,119,161,53,203,45,75,203,93,14,30,60,202,145,67,39,201,82,79,146,246,73,211,62,46,55,132,81,136, - 7,180,46,17,148,234,228,22,112,14,147,246,65,72,194,40,64,202,98,125,223,235,117,25,30,25,97,253,166,205,148,235, - 85,42,165,50,35,163,195,140,142,14,17,70,65,65,114,204,19,114,103,201,16,132,74,162,163,18,249,82,139,71,239,187, - 135,199,239,254,28,81,119,150,119,92,191,141,122,4,157,158,229,124,94,165,151,151,56,191,208,99,190,183,68,39,243,88, - 57,198,82,94,195,232,26,178,38,112,222,210,179,125,230,22,12,19,149,17,102,230,219,172,179,125,16,69,182,89,179,217, - 192,53,234,42,155,57,95,45,193,120,31,42,191,3,173,234,224,117,207,40,76,193,84,241,95,113,2,2,15,37,1,106, - 98,44,64,100,158,115,231,19,162,153,197,246,58,88,202,225,176,131,19,37,232,100,80,22,144,59,240,125,107,92,102,202, - 212,42,150,160,86,14,129,161,8,74,29,16,191,8,254,249,2,11,1,100,121,14,66,62,151,219,125,17,128,190,89,16, - 58,205,213,19,211,47,26,8,189,148,207,233,98,88,121,80,67,191,12,79,108,133,41,97,243,9,119,226,228,100,126,226, - 100,57,189,251,145,242,18,140,207,73,57,121,118,98,108,124,97,199,182,70,237,242,75,163,137,93,219,88,187,101,3,155, - 54,173,103,120,184,73,41,174,33,133,192,186,20,99,83,242,172,143,115,16,170,24,41,52,74,4,152,172,208,120,153,172, - 131,119,41,91,54,142,178,109,227,40,89,154,145,228,9,72,135,207,13,43,89,238,65,92,103,106,211,118,116,92,1,163, - 193,40,208,2,148,24,176,25,87,212,108,114,208,108,12,118,61,222,227,141,199,153,12,225,138,73,70,16,133,32,115,206, - 30,62,204,157,95,252,10,15,63,242,4,103,142,159,98,251,250,73,154,18,126,251,147,79,208,233,91,90,189,46,34,170, - 224,130,58,34,26,162,52,212,164,57,220,68,42,69,234,50,140,77,17,153,65,24,143,42,135,32,83,122,249,50,139,173, - 5,188,243,120,103,9,116,68,164,20,163,55,222,24,62,113,224,200,228,171,113,219,37,76,157,128,217,93,131,139,156,3, - 190,60,184,242,16,220,24,44,43,56,85,130,229,212,48,153,101,57,11,243,243,100,89,38,6,149,140,5,92,225,51,128, - 22,16,166,160,109,185,92,174,212,170,120,221,193,24,231,11,168,198,103,3,144,123,62,89,64,10,216,232,28,39,165,124, - 197,120,41,235,237,215,125,255,95,250,135,118,190,234,7,94,222,255,202,183,252,244,243,240,22,244,194,16,202,230,193,111, - 129,238,52,28,122,22,78,54,10,141,82,213,65,173,4,97,0,113,21,38,112,110,211,248,217,153,141,253,179,51,107,231, - 190,242,181,169,115,48,186,175,82,26,90,90,51,94,141,47,217,16,213,182,92,34,215,93,186,135,77,91,55,177,110,221, - 52,227,99,163,212,235,53,4,10,172,7,161,81,218,16,153,20,163,20,221,238,50,253,36,37,75,250,56,151,99,173,195, - 24,139,205,179,2,95,148,38,51,125,122,173,46,37,81,65,72,139,84,249,64,28,43,112,214,32,132,71,72,5,126,224, - 130,236,44,48,176,214,208,234,185,192,196,52,229,169,135,30,228,83,159,248,20,159,252,212,167,121,246,192,81,134,134,39, - 153,94,179,129,67,39,159,198,165,9,65,24,144,89,75,158,24,188,235,208,28,73,89,187,62,160,81,30,161,155,229,100, - 157,22,82,116,113,222,19,251,18,37,221,192,102,14,173,61,129,43,234,17,225,11,78,212,137,163,135,57,125,242,60,187, - 174,186,150,15,127,244,19,35,87,183,150,54,150,97,106,1,246,255,22,152,54,69,60,242,123,41,34,109,90,224,247,22, - 18,139,103,134,224,248,249,179,201,150,174,117,186,82,18,68,165,216,38,105,55,174,192,90,9,19,14,18,9,163,10,198, - 150,160,22,143,143,212,167,39,154,28,63,118,142,116,102,174,39,97,182,15,221,119,130,255,199,23,51,247,94,220,10,232, - 226,249,230,78,13,168,131,61,6,189,59,160,167,96,113,22,196,99,32,42,69,193,29,55,160,238,97,36,132,241,13,48, - 181,9,166,124,183,191,38,59,120,124,124,249,224,241,137,51,220,53,118,66,136,230,61,81,84,203,214,175,47,169,177,97, - 61,178,101,61,83,91,215,203,203,118,109,102,108,98,140,198,240,48,205,161,97,170,113,137,122,189,74,181,86,34,203,250, - 180,219,203,244,218,93,132,19,104,237,112,206,14,12,226,193,59,129,24,36,138,131,197,123,135,31,176,154,11,242,163,67, - 72,141,64,22,149,17,142,180,215,102,97,118,142,179,167,207,114,255,67,123,185,239,206,59,217,251,240,227,28,63,187,132, - 138,43,132,229,17,82,99,153,61,123,130,56,138,9,75,53,82,91,200,62,42,245,18,120,139,53,150,180,227,153,63,181, - 136,14,219,68,97,76,88,170,224,194,12,143,32,245,41,65,20,144,91,139,164,132,233,105,78,159,56,195,236,185,25,146, - 36,97,98,108,138,160,52,130,109,14,171,126,107,169,82,134,138,5,245,243,192,177,193,235,254,159,40,24,209,6,248,73, - 232,141,194,177,97,56,80,189,247,153,43,230,111,223,58,62,62,218,160,182,102,72,204,47,117,101,29,46,205,225,53,2, - 142,10,216,162,96,247,41,168,238,186,118,103,60,210,28,227,211,31,250,34,122,105,113,94,192,153,26,180,38,46,42,47, - 46,2,208,203,237,136,193,59,178,2,95,3,255,191,128,219,193,46,64,126,51,116,54,193,57,7,7,90,16,59,168,9, - 104,56,24,26,130,177,49,152,188,202,251,41,155,36,19,201,193,131,163,173,3,126,125,251,158,251,39,62,14,245,135,95, - 123,121,227,150,171,183,115,250,204,25,162,184,74,84,170,17,150,107,140,78,174,97,124,106,13,229,74,153,56,14,8,180, - 164,26,23,170,119,235,61,181,122,131,122,179,129,8,229,192,59,68,130,144,8,28,72,69,183,219,165,215,107,113,234,216, - 9,150,206,157,243,51,39,79,249,7,159,120,74,238,59,112,136,217,147,231,124,127,118,209,170,86,175,119,14,66,83,10, - 227,70,173,76,106,5,88,139,80,14,41,53,94,120,82,239,233,165,93,148,201,176,174,224,135,15,53,74,180,211,37,12, - 61,70,154,67,152,220,226,130,0,85,46,225,28,228,72,172,51,120,145,177,220,159,229,236,188,102,236,116,149,161,230,48, - 59,118,78,17,4,17,227,169,101,253,166,13,162,127,252,72,12,84,5,4,255,230,130,215,219,83,172,225,37,176,17,204, - 83,136,153,53,248,253,147,179,11,39,239,253,227,189,35,111,251,161,215,168,87,191,243,186,177,47,30,254,68,242,174,212, - 6,99,240,118,15,109,15,141,253,48,218,222,62,93,126,243,13,91,229,204,124,143,19,31,185,167,255,42,56,145,195,233, - 16,250,209,197,219,249,34,0,189,220,193,104,69,54,145,20,31,190,10,118,67,145,170,144,92,1,203,17,156,217,14,114, - 166,224,171,149,50,168,43,168,105,239,135,71,97,207,180,144,175,171,70,225,149,207,148,101,245,251,47,27,87,233,166,136, - 158,177,44,165,158,185,36,229,236,217,3,28,58,184,143,249,133,54,70,123,124,32,144,66,210,79,18,148,86,108,222,188, - 133,241,137,137,66,212,42,29,169,21,28,56,126,26,209,109,229,242,228,114,110,103,23,242,74,107,174,107,78,157,79,226, - 229,180,31,56,223,159,0,53,14,98,24,178,33,208,147,80,250,96,40,235,255,7,166,3,11,161,42,106,169,32,44,177, - 156,230,180,230,23,64,158,69,135,33,90,6,196,145,165,189,176,72,167,221,98,114,98,146,198,218,245,244,18,207,240,112, - 132,245,9,190,163,72,178,140,52,77,16,10,194,40,70,14,53,88,78,187,60,240,208,19,32,61,111,122,243,107,216,188, - 97,29,37,229,137,167,70,196,113,24,222,0,19,10,170,18,22,30,24,188,198,155,129,27,7,211,171,57,96,10,191,224, - 225,137,9,120,228,177,47,62,59,253,145,117,83,147,111,189,121,157,154,123,223,237,27,126,227,55,190,84,190,177,151,196, - 101,200,14,197,98,88,93,119,201,200,119,124,231,107,75,91,166,199,248,226,167,191,66,248,232,35,115,21,216,239,225,228, - 83,144,253,48,133,19,217,197,115,17,128,94,17,71,14,192,72,20,115,35,18,240,21,176,91,192,238,131,252,36,116,46, - 133,185,46,200,114,145,139,126,44,241,174,63,148,36,85,113,102,97,108,169,213,85,165,164,77,89,9,226,178,100,114,56, - 226,202,75,154,56,225,49,182,137,203,99,146,158,167,211,109,23,246,24,66,160,116,134,74,79,23,158,212,222,209,11,135, - 249,224,71,190,148,223,126,240,196,177,29,48,43,224,148,132,101,93,16,138,151,129,150,4,35,6,131,88,15,83,33,92, - 95,113,178,57,57,62,65,218,238,98,114,83,240,139,140,65,74,129,86,10,139,193,25,139,5,226,74,141,13,187,47,229, - 240,193,195,156,58,125,134,36,201,24,29,29,195,227,73,211,4,173,53,181,90,13,169,11,211,251,70,163,62,8,69,244, - 116,243,28,235,50,142,30,57,193,214,13,235,9,117,200,229,55,220,200,129,63,250,88,93,88,51,166,160,218,1,121,15, - 184,0,56,5,236,40,218,95,12,176,31,210,237,176,223,193,151,111,117,102,205,199,127,247,206,87,255,210,177,29,181,27, - 110,189,90,92,250,125,183,140,223,249,208,147,195,59,154,147,249,141,215,174,141,174,223,51,42,17,130,15,127,250,65,158, - 250,95,31,105,189,23,30,205,224,33,13,103,95,3,182,126,241,150,189,8,64,175,244,10,105,229,244,6,160,212,25,110, - 250,131,205,134,93,58,63,107,175,109,119,79,84,181,126,56,52,230,138,238,153,214,149,109,162,168,28,22,218,45,105,5, - 34,151,184,229,28,1,4,206,17,200,30,85,105,104,148,12,178,92,48,161,133,112,3,235,12,137,179,146,188,30,115,221, - 134,166,217,112,240,68,47,128,167,172,20,95,180,206,159,116,208,11,161,107,33,233,22,193,208,94,129,80,176,93,194,88, - 207,178,115,253,154,77,196,74,112,244,200,17,58,221,46,89,154,225,133,64,75,13,14,188,5,111,29,175,186,246,122,38, - 39,38,56,127,110,150,164,215,47,116,103,67,67,148,202,21,26,205,26,245,122,131,48,12,240,94,144,101,57,74,6,104, - 21,32,132,70,5,10,111,224,244,233,25,150,91,29,180,244,76,175,89,195,147,97,16,250,190,25,235,67,115,59,232,255, - 8,217,138,51,207,255,11,60,58,248,245,187,192,189,19,22,246,193,131,26,134,223,149,25,185,247,75,79,237,121,252,208, - 252,216,174,107,214,234,155,223,124,165,170,52,135,181,79,13,95,190,251,44,95,123,226,4,242,161,131,203,223,105,204,3, - 17,124,214,194,35,21,104,109,0,54,92,188,69,47,2,208,183,211,113,83,19,44,252,192,247,50,188,126,154,143,252,246, - 31,224,238,123,200,190,93,208,50,208,206,123,89,190,152,27,166,26,49,105,175,143,196,163,40,188,168,133,87,40,43,200, - 148,47,108,223,125,48,136,193,25,152,224,83,248,66,75,29,82,25,169,49,186,99,93,176,240,197,199,101,3,150,188,231, - 96,9,14,244,33,17,224,215,20,196,74,4,48,3,242,68,209,242,204,220,234,205,204,153,78,107,104,242,170,87,149,135, - 170,77,22,22,23,201,77,78,102,114,28,5,243,186,211,110,177,48,187,128,179,142,44,73,217,181,99,7,195,35,163,84, - 42,85,116,80,100,95,25,155,208,79,250,88,55,176,166,149,122,160,247,76,168,86,27,68,165,42,253,196,113,238,252,121, - 238,186,235,46,174,187,250,74,238,191,239,126,150,250,125,37,96,212,193,72,0,186,83,152,205,83,5,222,116,1,0,181, - 128,115,96,99,56,157,195,23,21,44,222,12,87,181,142,159,189,116,230,248,217,173,7,84,80,127,186,81,169,45,90,167, - 77,43,177,219,124,222,121,3,254,145,10,124,34,133,47,215,224,244,221,96,211,65,251,252,170,139,183,229,69,0,250,118, - 168,130,134,223,242,70,26,183,221,76,84,175,97,146,84,76,13,15,249,33,240,206,24,43,133,200,109,175,103,79,37,37, - 174,220,115,9,174,223,66,249,28,235,44,120,135,82,18,229,29,214,131,68,161,181,92,181,0,89,177,252,80,74,33,188, - 70,212,37,211,87,108,211,251,27,149,198,37,203,221,77,185,247,123,114,232,89,56,103,161,55,13,70,2,243,141,42,98, - 215,70,39,239,123,106,209,195,145,117,48,183,113,238,252,154,92,7,229,230,208,48,181,90,157,86,187,77,16,6,131,88, - 159,12,49,54,73,111,178,87,8,95,131,8,173,131,129,149,71,66,150,103,196,113,132,64,144,13,162,154,181,10,16,97, - 225,85,148,36,9,185,113,68,253,132,126,214,102,124,188,193,198,141,27,24,159,152,96,253,244,26,191,8,153,129,146,132, - 178,5,245,143,120,110,19,118,225,249,18,112,5,240,17,72,167,224,168,45,10,203,39,202,176,99,35,92,177,193,230,235, - 174,88,88,26,77,11,32,115,1,28,17,112,103,14,119,213,225,248,207,67,246,137,111,24,114,95,60,23,1,232,149,59, - 164,110,212,217,247,246,55,211,125,235,155,217,150,36,120,239,105,59,207,142,64,115,165,16,116,189,79,74,176,56,109,252, - 242,209,99,167,39,237,27,174,195,7,2,47,13,129,26,228,194,11,240,88,180,1,37,3,132,44,124,36,44,30,55,8, - 6,76,7,126,67,42,207,152,110,14,241,7,245,242,200,174,94,186,125,60,55,42,47,102,185,79,90,56,180,23,206,4, - 208,146,73,154,29,58,122,150,42,180,135,224,128,18,28,191,172,181,188,225,107,231,79,143,150,154,77,149,180,179,65,212, - 50,228,105,74,191,223,39,12,2,192,145,246,83,162,56,162,223,235,145,244,43,69,245,99,12,81,20,144,101,41,2,49, - 8,106,84,244,122,125,230,231,231,209,90,83,42,101,196,177,230,250,235,174,226,134,27,174,102,168,86,248,16,110,219,182, - 149,3,149,170,179,221,142,18,160,67,16,215,1,179,65,72,62,136,164,6,138,106,108,64,146,237,0,219,33,95,128,249, - 47,192,210,142,98,179,245,132,128,33,7,163,162,248,112,18,78,117,225,208,90,56,255,31,33,255,196,197,219,242,34,0, - 125,59,12,163,37,16,215,106,168,95,254,207,44,76,77,48,209,235,147,196,49,86,41,68,171,229,127,231,137,167,57,224, - 61,255,16,250,30,63,55,10,173,39,79,30,243,56,35,164,119,40,99,81,94,22,188,65,4,74,134,69,150,186,51,120, - 81,176,156,189,0,239,192,230,41,161,20,133,133,173,115,108,27,30,97,121,98,93,229,39,23,186,219,94,27,48,246,234, - 212,109,158,118,254,42,233,253,129,4,246,37,240,116,150,230,199,55,156,155,95,152,128,252,12,28,55,158,199,54,165,189, - 109,15,28,124,106,77,239,234,107,170,81,8,214,130,247,57,120,75,165,20,22,238,140,170,204,210,210,18,103,207,158,197, - 218,124,53,39,205,121,71,191,215,45,140,236,189,165,181,188,76,187,221,65,74,77,185,92,102,120,116,140,184,18,115,237, - 181,123,184,241,166,27,8,66,129,119,6,139,103,108,205,26,49,51,54,90,237,119,59,149,10,52,129,248,111,9,217,186, - 87,107,102,133,64,175,12,247,133,160,159,38,171,175,177,162,160,62,255,30,216,159,131,37,15,45,11,50,40,200,161,161, - 7,50,72,246,64,118,28,220,177,139,183,230,69,0,122,37,159,128,98,215,126,28,120,24,248,114,158,19,255,247,247,35, - 173,165,7,188,15,120,167,16,252,215,52,67,29,61,193,247,131,114,208,80,48,18,10,21,157,93,108,139,204,59,148,42, - 30,46,33,61,82,136,194,224,204,155,129,255,52,131,225,115,33,173,112,194,23,90,46,57,176,65,115,158,106,213,115,245, - 149,235,248,204,254,131,165,195,81,163,244,39,50,29,191,50,207,214,223,108,237,37,187,172,189,162,238,121,54,133,71,12, - 236,157,135,163,14,22,44,236,45,121,191,249,182,163,135,71,254,200,166,91,231,155,35,177,203,29,65,16,82,142,202,104, - 37,137,74,37,116,16,225,40,92,18,17,208,238,180,240,120,22,151,150,57,55,115,22,53,240,59,170,84,170,140,143,79, - 48,50,58,86,132,22,106,205,80,189,198,21,151,239,33,12,21,144,35,148,67,0,19,35,77,122,107,55,132,231,142,29, - 107,108,131,181,93,24,218,229,221,236,118,107,253,169,11,42,32,6,32,116,161,101,139,184,0,240,123,224,158,1,183,9, - 204,229,208,203,129,125,192,26,224,244,197,118,235,34,0,189,18,43,29,53,248,200,129,135,128,95,6,142,80,172,143,73, - 18,120,228,177,213,63,191,56,0,169,53,192,111,128,170,195,154,30,220,164,165,186,233,161,90,48,189,239,124,143,133,118, - 194,186,50,248,92,224,165,4,21,129,243,56,145,129,0,233,229,32,56,112,197,5,177,176,129,45,174,199,147,251,24,35, - 36,187,166,107,12,37,22,167,5,115,26,245,105,17,14,127,1,221,188,50,79,166,111,79,211,141,215,122,191,85,194,250, - 30,124,193,22,46,168,135,114,184,115,155,177,35,239,62,121,50,252,23,231,231,182,46,73,45,99,1,101,95,38,172,6, - 4,177,64,26,138,181,251,248,48,97,57,226,158,7,238,69,15,12,243,165,80,12,213,154,140,143,143,179,113,227,70,198, - 199,199,87,141,238,179,44,199,59,75,24,6,104,161,177,54,195,81,68,92,87,171,21,154,235,55,201,199,249,234,208,46, - 216,100,96,179,135,179,151,102,105,251,75,20,86,28,223,76,187,43,191,97,238,118,225,231,46,158,139,0,244,138,57,126, - 240,67,73,6,15,199,255,6,22,6,31,127,217,89,6,222,11,250,16,76,117,224,213,177,16,119,252,65,168,111,254,61, - 236,72,48,55,199,137,83,103,217,176,107,109,49,244,21,133,188,66,10,89,44,204,133,3,235,87,99,148,189,16,72,33, - 46,176,36,47,172,95,173,205,153,152,24,165,82,138,232,11,192,56,34,47,72,201,196,3,81,84,123,84,168,218,219,109, - 191,249,221,150,114,232,92,71,120,206,106,56,105,138,124,244,53,151,24,63,125,117,224,38,254,68,209,200,77,78,223,38, - 116,151,123,164,243,93,34,89,12,154,159,126,118,63,198,89,186,253,30,34,145,40,37,25,106,12,179,118,237,90,38,39, - 39,209,90,51,55,55,143,247,131,156,51,15,222,103,124,228,35,127,204,238,221,151,177,118,237,52,195,35,117,20,160,149, - 230,242,171,46,229,87,62,72,253,102,216,185,6,110,152,131,147,59,224,192,15,22,94,76,95,87,101,30,0,210,139,183, - 225,69,0,250,118,4,30,63,0,158,47,1,63,55,40,241,191,217,179,161,0,160,82,38,196,250,16,110,18,222,191,229, - 127,135,209,109,31,13,228,8,94,146,167,57,39,207,205,195,101,91,16,178,91,0,138,16,43,145,96,224,197,64,219,229, - 7,96,35,193,23,15,183,240,224,10,89,59,206,121,214,173,157,98,100,180,206,177,249,101,2,10,206,144,146,162,136,241, - 9,34,62,150,155,225,237,222,172,189,21,182,58,24,61,11,39,171,112,62,16,60,161,189,191,242,170,220,108,249,114,16, - 52,144,18,239,40,90,60,29,20,154,89,41,56,114,252,88,145,119,95,174,96,237,202,160,92,112,250,244,25,206,156,57, - 75,16,4,40,165,8,195,16,107,29,165,82,76,165,82,103,97,33,225,228,169,5,154,205,50,235,214,79,176,123,247,78, - 166,215,108,224,29,111,124,43,7,126,232,168,254,191,127,248,123,219,222,215,90,190,182,6,15,108,47,218,195,60,185,160, - 146,81,60,71,74,188,216,82,93,4,160,111,139,147,15,110,248,50,80,1,126,1,248,234,224,255,93,251,77,180,6,51, - 192,15,0,187,10,150,239,142,208,251,215,57,120,221,199,75,149,43,63,22,139,17,107,50,148,137,200,172,101,223,193,83, - 184,219,175,47,36,93,66,12,4,254,174,248,74,131,141,216,10,223,90,8,57,120,240,139,100,213,213,105,137,51,148,99, - 69,163,22,194,156,35,80,69,112,33,222,128,213,164,169,231,93,239,253,110,17,156,56,84,239,223,251,181,161,16,234,1, - 168,25,200,182,121,206,59,56,59,105,109,187,12,62,149,66,56,233,240,72,148,10,112,182,224,79,7,90,35,132,196,120, - 143,10,52,214,89,150,150,151,49,253,156,198,80,131,122,189,78,173,86,163,82,169,18,199,37,202,229,50,72,73,84,138, - 209,58,34,77,4,207,62,125,154,82,216,100,114,124,61,165,178,228,231,255,245,207,240,131,7,247,71,199,239,252,210,240, - 229,133,46,76,253,18,112,248,207,120,93,35,224,141,23,31,142,139,0,244,237,112,222,77,33,64,45,1,223,55,248,248, - 171,156,7,11,200,168,44,195,174,42,188,245,172,224,45,255,167,92,218,253,181,32,46,121,103,80,190,224,252,122,1,7, - 14,159,33,51,30,137,7,87,4,31,10,236,32,190,65,32,6,182,26,43,109,13,12,76,237,253,115,21,129,115,142,56, - 150,52,234,49,74,8,130,160,132,183,57,121,238,169,70,37,222,247,227,63,192,123,190,243,187,248,147,127,251,239,195,62, - 68,10,74,77,144,83,133,71,78,23,88,28,242,190,87,177,206,116,33,208,222,226,172,199,75,191,90,69,57,15,222,90, - 164,80,68,81,192,248,240,36,235,166,166,105,84,170,212,107,53,162,184,72,99,245,64,16,4,120,239,72,115,75,24,150, - 80,90,83,175,87,217,118,201,22,182,109,221,194,190,167,158,225,240,145,131,212,155,195,28,59,120,144,184,120,41,228,95, - 84,229,164,192,191,161,96,73,171,139,183,232,69,0,122,41,156,215,189,128,63,0,199,95,221,59,216,82,236,148,255,65, - 193,109,217,80,134,55,158,144,226,237,255,169,84,185,236,105,233,149,50,109,132,139,240,94,35,149,65,4,130,227,39,230, - 152,95,88,102,178,38,138,21,188,119,56,225,138,172,120,231,89,137,133,6,135,144,131,49,235,74,37,228,28,194,21,195, - 233,176,172,24,27,174,17,42,141,183,144,102,25,245,106,147,31,249,123,63,196,59,223,115,19,67,13,205,182,233,233,220, - 20,224,40,50,16,187,129,253,133,139,96,167,38,72,34,103,157,87,69,58,42,20,241,63,198,185,34,181,195,67,41,42, - 209,108,52,217,181,107,23,107,166,214,80,45,87,240,222,145,231,57,214,88,188,240,56,231,177,174,216,118,149,162,18,227, - 19,147,172,89,211,228,234,171,118,35,4,60,187,255,41,102,102,230,168,86,135,248,195,15,255,49,115,167,79,249,38,194, - 88,188,141,192,95,79,225,11,244,103,101,118,61,53,152,7,133,23,111,253,139,0,244,82,56,175,127,137,93,143,27,180, - 108,145,16,101,188,223,217,22,220,242,191,170,181,221,251,4,74,231,30,79,9,43,50,188,43,188,252,132,146,204,156,91, - 224,212,137,51,108,188,98,29,125,91,184,25,22,98,11,177,106,30,38,86,36,175,162,0,31,111,61,110,80,25,121,231, - 81,94,80,14,67,166,166,70,233,118,30,166,20,72,46,221,115,25,87,94,117,25,141,122,141,102,99,132,201,169,113,246, - 251,126,222,43,170,12,57,68,65,238,235,128,40,131,172,120,196,168,208,249,113,124,36,112,72,100,33,173,16,16,232,128, - 209,145,81,46,217,114,9,107,166,166,89,55,189,22,129,160,159,244,73,173,67,106,93,52,141,82,226,115,67,58,96,70, - 215,170,130,13,235,135,184,245,182,155,112,38,231,216,177,147,76,142,79,179,115,199,30,158,120,242,81,190,118,255,221,236, - 12,117,214,200,178,37,160,149,130,249,135,252,249,142,133,154,130,45,109,46,222,250,23,1,232,165,112,174,123,9,94,211, - 192,178,163,166,97,243,211,65,180,249,113,108,232,51,135,245,113,97,24,166,52,94,166,224,21,82,4,36,253,132,19,167, - 206,227,175,90,11,62,7,4,14,3,34,44,160,200,249,1,15,72,172,14,156,157,119,184,66,147,138,214,10,239,53,4, - 33,67,205,58,245,106,153,239,120,247,247,176,126,243,6,114,155,51,185,102,146,161,102,5,103,115,116,92,97,48,85,18, - 150,98,163,103,33,244,66,12,133,80,90,111,93,239,33,29,84,157,7,229,65,120,135,84,69,250,170,86,154,229,229,37, - 146,94,66,187,221,102,168,222,64,107,77,84,142,144,82,16,133,1,214,58,80,138,204,230,56,239,89,106,45,243,232,99, - 251,112,214,176,107,215,22,54,109,154,162,82,174,35,101,196,254,103,75,140,140,76,17,47,119,140,134,89,96,126,25,204, - 201,191,164,197,242,131,121,144,189,120,251,95,4,160,23,251,76,191,4,193,39,7,206,123,31,199,48,124,88,138,70,99, - 98,138,106,59,97,110,118,17,35,250,8,47,145,212,80,58,67,136,132,4,203,211,71,23,200,165,2,215,67,16,23,187, - 103,167,17,94,34,164,29,12,157,45,120,139,16,197,0,88,138,128,48,16,72,37,232,186,58,123,15,180,104,140,172,225, - 167,127,250,199,144,170,142,115,33,213,74,133,52,239,144,89,143,146,30,19,202,192,21,69,141,110,23,12,98,74,5,214, - 196,66,16,189,38,235,157,251,92,216,168,38,65,165,44,179,30,18,139,117,138,229,86,155,36,205,88,88,94,34,77,83, - 180,86,72,45,169,132,49,163,245,33,226,82,137,40,42,81,169,84,137,74,37,26,205,38,205,161,6,22,203,236,242,18, - 159,251,220,253,220,253,149,199,185,100,251,122,118,239,94,207,244,134,53,188,254,246,155,121,231,99,111,227,225,95,248,69, - 43,160,21,66,119,30,236,255,230,185,104,158,63,235,100,20,118,29,53,10,191,160,139,231,34,0,189,168,45,207,75,13, - 128,6,251,43,7,100,77,155,102,54,77,89,183,126,19,235,214,173,167,155,46,49,115,126,129,78,59,37,79,83,84,160, - 80,50,228,233,103,14,147,244,37,129,45,33,209,8,233,80,72,156,8,112,88,36,96,109,62,232,194,4,58,208,132,129, - 166,155,123,14,29,155,227,201,103,102,88,232,69,68,141,105,140,212,68,161,38,75,22,233,46,11,170,149,53,104,145,16, - 136,58,93,21,199,182,88,238,53,60,68,39,161,83,7,35,240,253,204,35,246,120,228,143,244,58,79,254,102,197,93,149, - 196,34,200,19,137,246,197,171,236,125,97,207,90,252,90,224,12,116,178,30,121,63,39,140,66,172,177,32,36,185,177,212, - 235,117,166,38,167,104,12,53,104,14,15,81,111,52,232,119,251,236,123,230,0,135,142,28,96,100,180,206,117,175,186,134, - 207,125,250,19,220,14,139,1,204,247,160,183,13,252,251,191,201,7,164,51,168,148,46,174,230,47,2,208,139,118,142,191, - 196,174,103,133,176,88,21,162,155,195,204,30,47,230,245,226,210,244,227,179,79,210,104,196,76,174,153,100,203,166,75,8, - 180,32,237,119,88,110,167,204,207,44,112,232,232,57,206,47,100,108,24,109,128,237,227,101,134,243,57,194,150,240,214,225, - 144,168,160,76,138,164,159,195,249,249,22,231,102,206,114,236,76,151,197,126,128,46,13,227,43,49,185,146,148,202,101,146, - 52,33,77,36,198,12,102,73,153,7,235,104,197,97,220,130,177,113,216,24,194,104,13,22,13,116,173,231,24,130,115,192, - 206,203,181,72,74,185,205,19,17,7,222,231,120,231,8,163,8,6,22,32,141,70,131,126,63,161,92,174,224,140,69,139, - 194,34,68,135,1,90,43,66,231,201,179,156,131,7,15,161,165,162,82,46,177,231,242,203,24,25,155,64,139,128,44,73, - 8,84,157,51,103,102,88,56,122,156,221,136,89,131,63,13,116,142,81,108,187,196,55,241,58,91,96,248,226,35,112,17, - 128,94,204,243,95,94,98,215,99,128,49,224,31,120,223,13,224,244,136,245,51,147,222,154,185,32,210,237,118,155,229,103, - 59,184,92,80,175,133,76,77,78,176,105,235,86,110,121,245,109,52,68,198,3,79,156,96,97,195,36,181,74,64,84,146, - 4,65,68,137,162,95,234,244,115,206,47,182,57,126,182,197,249,165,140,110,30,96,9,208,165,117,136,90,72,46,13,173, - 222,34,218,164,180,250,45,188,21,144,137,34,129,79,131,166,2,14,108,37,16,167,161,118,21,236,202,96,23,112,62,130, - 94,7,14,43,207,19,61,33,214,253,161,100,251,178,242,101,209,55,132,50,196,169,98,160,12,20,110,137,65,72,110,44, - 105,146,16,71,49,66,20,219,50,173,52,121,110,8,195,16,188,99,180,89,101,120,120,132,201,137,73,74,149,8,169,60, - 206,11,130,82,5,39,52,79,221,247,128,255,206,126,119,121,13,254,132,135,147,25,244,254,3,112,146,111,110,203,213,5, - 110,5,110,227,162,252,226,34,0,189,72,103,221,75,176,37,44,1,11,144,141,195,233,10,226,200,173,214,93,249,180,204, - 71,141,112,88,43,144,66,145,36,41,71,79,156,224,196,185,179,4,58,100,203,212,52,71,142,214,24,170,55,80,90,82, - 46,69,52,135,70,9,17,116,90,139,24,15,72,69,230,4,137,51,232,168,76,165,86,67,137,5,44,65,161,13,243,17, - 206,20,137,24,38,233,19,12,146,127,58,253,46,86,120,2,33,25,91,183,65,252,110,173,217,188,178,189,184,117,28,110, - 238,65,55,128,243,18,154,66,136,94,46,232,156,80,58,244,97,5,37,28,214,22,2,8,235,44,74,42,162,40,38,10, - 2,112,30,225,60,54,55,244,243,156,82,169,132,146,154,168,28,51,49,49,65,189,86,99,168,209,160,217,28,70,75,137, - 193,144,123,67,154,36,212,202,53,70,199,155,44,60,60,107,111,183,98,57,192,207,121,88,60,15,230,125,131,1,243,55, - 219,86,245,41,12,203,236,197,86,236,34,0,189,24,231,255,188,68,175,235,36,228,7,224,140,240,126,223,245,38,191,254, - 163,165,112,244,180,9,16,206,34,149,71,200,128,220,231,228,105,130,49,134,39,158,125,150,103,15,41,130,40,64,133,138, - 90,181,70,37,170,163,162,128,48,10,152,24,159,68,75,133,205,60,90,104,42,101,79,191,221,163,50,236,209,21,141,18, - 17,129,42,33,92,177,150,215,178,80,206,219,204,97,179,4,21,105,142,30,60,76,103,185,207,252,218,13,149,163,207,44, - 70,27,225,218,0,70,92,241,12,107,229,253,90,9,161,206,93,230,227,40,10,171,134,110,167,131,203,139,73,139,117,142, - 126,63,41,248,62,182,32,73,214,42,17,227,35,195,140,142,140,48,54,62,78,185,92,70,8,65,20,69,132,97,136,195, - 97,188,47,88,222,30,134,155,37,94,115,235,141,92,113,217,78,246,239,154,214,159,124,232,222,230,219,230,59,99,14,38, - 214,66,244,86,200,155,127,141,215,123,255,96,30,148,93,4,162,139,0,244,55,121,222,248,18,188,166,21,50,226,251,96, - 217,195,201,9,231,103,174,116,62,61,165,227,72,248,46,206,25,50,35,33,16,8,161,48,153,65,160,232,91,79,47,233, - 33,140,163,211,239,17,171,101,84,84,38,140,42,232,176,74,163,90,71,88,143,12,32,199,18,7,154,82,169,134,14,66, - 132,119,40,85,100,135,57,60,120,133,113,10,37,28,19,195,35,28,56,116,138,167,247,237,227,181,175,187,141,255,241,203, - 129,123,8,22,79,104,61,229,188,92,103,181,150,21,33,92,57,64,46,161,117,59,170,134,161,75,81,222,131,85,56,71, - 225,196,40,11,167,67,147,27,194,32,64,41,73,20,6,84,74,101,134,26,13,162,32,32,237,247,169,54,26,232,64,99, - 173,33,8,227,85,7,199,169,201,9,110,189,237,58,46,217,58,141,20,150,235,111,186,154,167,254,209,251,234,135,126,238, - 63,239,188,4,174,204,225,217,99,112,164,249,215,216,45,236,24,84,159,103,185,200,146,190,8,64,127,131,231,170,151,224, - 53,57,10,95,227,65,10,69,38,4,182,42,165,143,131,136,110,210,41,18,75,157,7,227,16,210,162,101,128,49,133,221, - 134,0,92,46,177,94,18,232,18,181,48,160,18,56,122,243,243,140,148,107,84,26,53,148,10,64,74,226,161,6,42,8, - 200,250,73,33,4,149,26,132,32,8,11,20,244,214,161,132,103,238,252,121,164,150,188,238,117,175,165,90,21,172,153,26, - 13,207,93,115,203,229,95,61,115,60,156,154,92,167,174,189,226,90,230,44,72,161,169,212,74,220,184,116,134,207,124,242, - 19,136,68,18,171,8,21,12,70,194,206,35,4,72,37,49,214,32,148,198,98,49,121,70,175,219,69,107,77,181,90,197, - 230,25,137,183,84,42,101,180,86,244,147,62,151,94,186,155,55,190,225,54,154,67,1,206,119,81,129,32,235,119,120,239, - 251,126,132,223,253,220,87,214,245,239,127,248,234,0,30,109,195,185,195,208,9,254,26,149,140,184,160,45,63,199,75,111, - 67,122,17,128,94,129,231,223,188,68,175,75,22,109,129,159,7,183,224,157,168,199,37,182,148,202,246,169,118,87,9,153, - 35,2,1,46,66,122,131,215,33,66,245,17,89,134,114,154,76,10,82,219,65,228,41,36,26,235,202,172,153,154,64,201, - 152,40,168,34,20,212,26,85,2,93,162,159,244,208,218,33,116,128,84,17,74,122,2,157,17,8,65,154,90,38,39,167, - 216,188,101,29,155,55,77,115,234,244,49,198,71,167,24,25,25,99,120,100,93,105,118,110,158,157,107,215,177,102,184,78, - 47,43,172,99,227,200,147,14,130,14,51,233,49,94,96,242,124,224,69,45,176,214,21,50,11,33,200,83,135,23,109,210, - 180,143,33,35,138,67,74,165,152,80,23,154,176,21,213,126,160,2,170,37,73,179,161,49,166,139,214,18,239,11,185,199, - 80,179,204,238,31,127,95,229,228,119,255,200,206,109,206,93,106,224,169,3,208,221,86,24,63,254,181,78,147,98,25,176, - 27,248,247,20,12,199,139,85,209,69,0,122,65,206,31,189,68,175,203,1,13,176,35,48,223,176,156,152,232,180,58,253, - 114,117,180,26,196,136,32,34,174,134,196,186,138,182,146,118,183,67,43,179,100,42,64,228,154,177,48,227,93,239,184,137, - 237,107,70,233,217,18,103,90,57,194,149,169,54,70,136,75,21,84,160,9,227,152,78,59,33,38,70,0,214,88,140,109, - 81,171,86,24,170,15,17,70,138,93,59,118,16,87,34,230,230,103,249,204,103,238,100,105,97,137,55,189,233,117,100,166, - 207,252,252,28,89,102,9,130,18,201,32,215,203,11,48,182,136,127,86,74,209,79,123,8,61,16,205,14,56,64,98,96, - 134,239,189,39,203,50,242,44,3,231,232,245,82,164,10,112,192,232,200,24,198,58,242,60,3,4,129,214,236,125,248,49, - 214,174,159,224,242,203,183,35,101,177,206,199,65,158,165,92,121,219,109,60,181,115,251,164,219,247,204,118,9,147,33,156, - 121,166,224,115,126,75,175,191,167,16,20,87,46,206,133,46,2,208,11,117,190,239,37,124,109,39,33,63,4,103,34,120, - 102,93,183,119,110,36,10,70,71,118,236,164,147,245,176,174,143,237,59,172,140,73,236,60,86,122,84,73,97,179,14,183, - 223,176,153,159,253,123,155,137,84,10,229,6,169,108,98,41,225,228,24,186,60,73,88,153,192,137,6,157,174,225,247,255, - 224,83,204,205,45,115,242,216,97,254,249,79,255,191,28,58,116,152,251,239,123,136,230,72,147,153,153,51,68,113,68,146, - 88,164,8,145,42,230,240,225,83,44,183,114,218,157,30,149,106,153,82,57,194,59,79,158,231,8,37,145,66,226,133,160, - 214,168,179,116,182,93,180,92,131,217,207,138,53,170,49,6,231,28,222,23,45,89,24,6,24,239,56,122,226,24,75,75, - 75,108,88,191,145,141,27,55,161,117,33,205,16,194,35,68,192,87,239,188,135,233,233,73,214,172,25,193,56,131,24,24, - 240,215,26,13,162,87,93,85,93,220,247,204,244,16,140,151,32,88,15,185,184,120,123,95,4,160,151,250,249,249,29,91, - 191,181,86,73,10,122,189,132,67,199,78,174,38,156,246,6,239,160,1,127,125,23,62,75,145,111,254,67,133,33,226,177, - 181,130,179,99,237,206,142,153,209,80,215,74,17,129,170,16,170,18,105,234,24,31,242,44,247,115,172,208,228,181,30,83, - 163,107,8,114,205,222,199,78,145,5,150,141,107,107,132,13,141,170,70,104,175,200,243,148,74,217,48,180,174,70,179,17, - 240,129,15,126,17,242,148,7,30,188,143,61,151,95,205,210,167,238,164,159,229,180,147,121,42,165,33,182,111,221,77,167, - 187,196,114,107,137,71,31,125,156,115,231,218,68,113,25,17,44,34,148,69,135,33,185,183,164,105,138,146,18,235,29,185, - 177,168,32,192,121,139,214,154,44,203,96,80,25,173,176,161,87,0,41,183,14,235,115,132,23,204,204,207,34,148,164,90, - 171,50,210,28,37,12,61,198,88,148,22,156,57,59,207,222,189,143,243,174,119,223,142,183,14,63,16,211,134,129,100,250, - 150,87,169,153,223,252,192,240,48,212,13,4,107,249,139,229,24,23,207,69,0,122,73,156,31,187,255,179,223,210,223,47, - 151,75,220,119,223,94,110,185,245,157,171,159,251,238,65,217,254,216,96,142,176,226,126,250,87,121,71,94,81,197,183,33, - 13,133,56,27,59,78,78,119,251,189,195,46,173,135,185,32,119,125,124,45,192,235,128,106,125,152,225,177,6,97,92,129, - 60,195,233,46,198,78,112,223,125,207,240,197,131,135,185,100,119,137,218,80,7,212,12,167,207,156,36,77,186,236,216,178, - 129,127,243,255,253,4,27,55,77,49,50,220,96,100,104,156,123,238,185,143,137,137,105,208,37,130,40,166,89,213,156,63, - 187,72,107,185,195,249,185,89,188,128,135,30,121,4,80,236,218,185,147,165,86,225,96,152,231,22,131,35,75,115,178,52, - 37,203,83,180,214,224,41,204,200,212,115,96,99,173,69,74,185,218,142,57,239,87,171,35,231,138,225,250,201,211,167,233, - 245,82,46,191,116,15,235,214,173,71,107,61,168,162,44,173,78,191,176,154,5,148,84,32,37,198,231,108,189,226,82,230, - 154,181,154,91,108,55,83,40,125,165,136,150,126,65,206,27,47,62,54,23,1,232,249,58,85,251,173,237,58,132,117,148, - 221,215,79,8,110,43,230,55,84,129,255,10,156,31,252,186,207,115,62,65,249,55,1,72,10,120,24,76,15,102,180,243, - 135,174,108,47,207,124,117,126,182,174,70,214,160,93,68,63,237,35,101,128,86,101,210,110,70,156,27,226,72,112,170,53, - 71,223,247,152,152,108,32,207,72,74,19,163,76,111,220,76,175,103,57,112,114,14,239,20,79,63,123,134,179,231,186,172, - 157,30,167,94,21,132,186,196,194,210,89,30,122,244,49,78,159,63,199,184,24,98,98,106,140,36,57,195,236,220,89,42, - 149,33,54,109,222,204,179,7,247,243,192,131,247,48,221,29,193,121,69,210,179,40,209,199,88,135,49,22,155,27,112,48, - 212,24,98,126,113,97,80,233,72,130,32,36,203,50,164,44,92,25,165,112,40,165,177,174,168,140,242,60,71,41,85,152, - 232,75,197,242,242,34,243,139,11,76,79,175,41,116,109,58,196,139,136,32,136,17,74,129,43,190,142,160,240,179,30,25, - 109,34,170,149,42,139,237,241,16,42,103,64,156,42,162,164,47,2,208,69,0,122,233,158,11,227,90,254,90,0,228,253, - 159,250,26,43,70,100,43,118,15,45,224,43,3,16,42,81,48,117,71,41,72,111,127,225,215,6,198,192,183,97,209,10, - 177,127,93,150,31,158,154,111,109,156,31,153,10,162,40,34,176,142,146,6,157,27,50,81,168,219,51,23,112,248,196,34, - 39,103,151,216,176,105,8,189,183,69,127,169,11,137,35,150,130,169,225,33,150,206,157,102,235,230,38,190,127,156,114,216, - 163,81,83,216,20,186,189,20,227,44,141,161,26,179,179,51,132,90,18,137,152,245,235,54,80,169,85,185,246,186,203,121, - 226,233,251,184,251,222,47,241,244,211,251,208,170,138,223,185,7,173,53,173,238,50,198,24,194,64,67,110,169,150,203,68, - 113,140,77,0,239,17,12,236,95,61,197,38,204,250,34,169,195,129,212,98,144,146,225,177,206,98,93,138,22,154,118,167, - 77,146,37,4,161,64,168,16,188,98,121,185,75,158,231,32,36,14,129,146,10,165,4,214,89,150,189,11,37,212,98,8, - 143,131,248,217,23,104,118,252,211,23,31,155,191,124,52,113,241,37,120,233,28,65,161,77,154,0,190,8,28,5,182,3, - 123,254,146,143,75,129,203,129,0,223,75,225,217,80,240,192,119,47,47,28,12,14,62,109,246,31,57,202,242,226,18,42, - 112,136,114,142,174,26,116,41,64,135,101,156,141,57,188,255,8,219,71,21,35,21,201,98,199,18,148,170,148,43,37,74, - 33,216,108,129,157,219,198,56,115,232,46,204,242,51,76,52,43,56,159,163,180,160,181,180,204,200,200,16,185,201,72,186, - 125,230,231,150,144,42,100,211,166,9,46,191,98,51,165,82,132,146,101,112,33,206,164,180,58,139,228,89,142,201,114,242, - 44,39,75,51,140,117,40,169,16,222,83,45,151,169,213,106,68,97,56,112,201,231,185,132,14,60,90,235,194,255,200,217, - 255,191,189,55,15,146,44,59,175,251,126,247,222,183,230,90,123,117,109,221,93,189,47,211,131,30,204,210,192,12,177,11, - 6,33,130,32,77,82,166,68,195,33,129,4,69,74,54,35,108,81,98,72,38,195,132,21,150,195,225,176,197,144,130,52, - 29,148,40,155,146,76,64,65,90,129,85,32,9,96,176,204,0,179,47,61,189,77,239,93,189,212,94,149,149,251,91,238, - 226,63,94,246,0,8,1,3,96,134,164,12,76,158,142,138,138,232,204,172,170,124,121,227,188,239,126,247,59,231,96,116, - 94,52,166,17,4,65,136,117,133,43,163,31,4,164,73,74,110,50,150,110,221,228,206,242,90,17,43,141,195,106,7,86, - 160,173,163,107,139,248,69,59,176,224,31,98,72,64,67,124,155,202,104,21,248,220,160,89,125,237,123,32,175,147,14,61, - 226,220,45,141,248,242,209,180,251,213,191,209,106,172,244,182,26,92,190,241,50,23,206,93,228,230,237,37,122,237,109,186, - 93,135,113,154,209,160,196,75,55,218,4,85,159,233,168,205,230,214,38,205,78,147,64,132,4,50,166,229,199,252,238,191, - 127,130,243,151,215,153,240,50,38,188,30,41,45,140,77,8,114,159,74,28,144,226,104,247,52,123,22,231,216,119,116,47, - 111,121,248,1,68,232,168,213,107,56,87,70,250,1,202,47,230,122,250,253,4,147,107,116,154,99,181,195,104,71,41,46, - 19,123,62,229,40,24,156,98,57,130,208,7,97,113,194,96,156,6,225,6,22,172,134,220,228,32,239,58,56,10,148,10, - 25,169,141,81,10,107,24,93,228,153,42,101,200,18,205,210,213,6,74,21,75,92,72,176,100,32,60,66,43,173,43,10, - 75,163,192,149,138,10,242,207,253,107,136,225,22,236,7,186,26,130,194,80,231,171,20,230,245,63,69,113,90,230,190,195, - 157,35,7,222,3,157,147,206,157,239,195,243,7,123,189,147,123,43,229,217,139,8,181,186,177,196,78,179,196,214,102,13, - 188,6,50,72,169,170,58,47,118,251,236,252,181,26,7,22,119,113,231,220,26,221,213,179,116,243,189,140,149,170,148,168, - 48,58,162,8,186,91,160,199,136,199,171,44,63,187,66,185,84,97,125,189,69,73,167,28,61,124,136,249,137,69,14,44, - 78,115,234,129,123,168,213,203,128,102,110,102,2,103,18,162,168,134,114,146,70,99,27,207,11,200,146,12,173,13,189,94, - 15,99,13,158,39,208,218,160,133,37,203,50,58,157,14,8,129,49,166,120,159,178,120,167,58,207,64,184,194,138,213,57, - 36,130,114,185,202,194,204,28,81,24,98,157,197,243,36,82,21,179,205,58,55,220,185,179,140,179,135,94,73,251,80,190, - 162,219,92,102,188,215,105,1,155,29,232,253,44,184,15,51,156,102,30,18,208,16,175,250,33,245,129,255,7,120,43,69, - 148,204,93,147,172,111,70,27,120,59,184,16,58,73,161,60,111,151,132,176,66,250,202,137,30,185,145,180,58,61,172,200, - 208,46,99,211,180,184,157,106,254,241,239,126,145,191,245,254,123,120,231,67,251,161,26,3,77,164,55,193,187,222,249,1, - 22,230,15,50,165,110,178,185,125,145,140,132,67,71,70,153,156,156,68,246,124,42,163,37,198,103,107,236,158,154,224,212, - 91,78,48,49,81,198,217,14,66,195,7,127,252,199,248,228,39,30,229,169,167,159,38,10,2,218,237,22,213,106,141,36, - 73,73,211,140,36,73,16,82,48,57,53,73,84,46,115,103,229,14,150,98,230,199,1,158,231,21,122,48,99,94,177,232, - 16,131,198,51,22,172,113,4,129,79,92,42,84,243,206,26,114,173,145,158,135,64,160,148,160,209,216,38,77,19,124,79, - 96,172,66,18,211,90,90,33,110,117,219,2,182,29,244,119,81,56,30,14,49,36,160,33,190,7,252,52,240,19,192,19, - 131,187,118,192,183,118,80,13,176,14,166,94,88,143,54,234,190,49,70,91,223,19,49,198,129,181,109,180,177,56,23,163, - 2,139,245,53,159,124,244,44,207,188,120,139,221,187,103,56,116,120,140,67,11,83,212,107,109,234,11,33,75,91,207,179, - 122,227,50,89,175,203,242,102,204,244,244,4,181,186,207,248,220,12,165,114,141,217,189,99,220,127,114,150,209,233,58,56, - 9,248,160,51,198,167,39,248,231,255,236,127,229,23,126,254,111,115,249,234,18,189,44,101,187,181,131,29,196,237,36,3, - 151,198,173,157,109,148,231,35,165,194,225,80,210,67,155,98,0,209,31,52,156,139,237,150,43,236,98,1,207,11,144,158, - 164,86,174,18,120,10,37,7,30,214,131,92,69,229,43,132,146,8,225,13,46,142,68,160,145,100,172,222,106,210,3,95, - 64,41,6,191,199,95,156,197,198,232,112,185,14,9,232,135,13,201,96,91,246,78,224,89,96,135,226,196,204,251,166,173, - 89,9,180,131,237,0,54,102,250,173,190,243,227,200,90,129,24,244,85,144,10,103,2,140,235,33,124,31,75,153,91,89, - 206,202,173,45,158,91,234,17,184,171,40,207,65,52,69,165,62,198,226,158,89,142,239,153,39,40,69,108,53,183,88,223, - 218,225,186,189,138,146,17,60,99,248,220,103,29,229,72,49,59,63,203,190,125,139,28,61,122,15,179,51,33,187,15,44, - 242,214,71,30,230,220,203,87,144,73,194,198,214,6,113,24,147,244,19,250,253,62,97,28,209,207,18,154,173,22,210,83, - 131,137,103,129,211,69,211,217,57,135,26,76,71,91,7,74,250,72,36,129,23,18,135,33,161,31,130,83,148,203,37,162, - 56,194,104,135,31,201,98,230,40,213,196,113,140,231,21,77,109,15,9,120,172,145,114,14,198,143,195,180,134,242,93,253, - 214,144,128,134,4,52,196,247,8,67,161,196,126,25,248,53,160,1,108,125,211,227,191,10,246,175,67,223,65,183,158,219, - 76,6,2,161,114,156,17,88,235,33,132,69,73,141,209,6,163,66,156,144,248,57,196,158,163,54,82,161,82,153,97,98, - 215,36,181,177,17,42,21,71,111,167,207,185,11,231,89,93,91,102,179,177,77,179,185,137,116,22,233,43,178,212,130,246, - 17,46,39,174,88,164,231,51,90,155,224,239,254,242,207,243,139,31,249,48,207,61,253,44,22,104,118,90,196,186,68,191, - 215,199,58,135,167,20,221,126,151,92,107,242,60,47,234,27,103,177,182,168,114,140,49,4,65,128,239,251,197,228,52,69, - 142,189,51,130,122,165,198,216,232,24,66,72,74,229,50,81,185,130,148,30,65,24,19,134,1,202,43,198,30,234,245,42, - 158,95,2,231,112,169,98,237,218,10,127,242,249,47,176,0,210,129,151,22,38,144,194,127,229,220,109,136,33,1,13,241, - 61,33,7,222,11,60,10,252,51,96,134,98,34,186,15,28,43,66,119,50,5,189,58,46,19,206,33,132,1,225,144,162, - 140,19,41,214,36,40,1,206,106,164,176,164,38,71,152,18,19,81,133,242,72,68,63,111,177,115,169,69,171,113,135,78, - 163,73,39,181,164,182,143,39,3,112,17,34,16,120,65,113,196,45,194,24,79,122,8,149,224,16,172,110,36,116,58,154, - 151,47,92,228,244,75,103,200,45,228,198,224,229,26,231,123,36,73,31,41,69,17,52,168,53,89,94,76,58,69,81,132, - 49,26,41,213,43,83,208,214,218,34,185,213,82,16,82,224,227,73,15,171,161,82,45,17,132,33,97,28,33,253,0,49, - 232,138,9,225,136,162,144,99,199,143,131,133,139,231,175,114,250,249,179,156,127,249,44,243,147,7,153,226,139,29,96,51, - 130,238,24,184,128,161,136,116,72,64,67,188,38,56,138,38,234,223,1,62,62,40,251,19,32,130,158,7,235,39,181,219, - 156,205,211,217,155,24,229,91,64,152,65,12,188,68,8,131,20,26,235,4,82,56,66,149,147,52,239,208,182,101,178,92, - 225,76,137,82,181,74,125,122,138,78,71,226,59,77,57,14,112,78,17,198,49,35,99,163,148,226,16,63,18,84,226,49, - 38,198,166,200,109,70,189,50,202,47,254,194,127,193,191,253,131,255,131,237,198,54,65,101,12,144,228,90,19,197,33,214, - 26,180,30,68,66,15,100,22,206,21,249,207,190,31,144,164,41,97,24,17,69,33,58,215,69,106,171,18,4,65,64,41, - 42,225,6,178,140,60,211,4,126,81,37,1,120,126,64,181,90,193,138,132,82,20,209,106,237,240,135,31,251,18,215,175, - 44,225,203,136,95,252,165,95,224,137,175,127,157,165,223,163,237,96,93,65,183,207,95,156,187,225,196,112,121,14,9,232, - 141,64,64,119,19,50,182,128,83,192,20,112,186,24,31,218,30,15,131,246,131,165,48,189,209,77,74,86,170,162,242,81, - 69,195,215,90,240,60,31,79,80,104,165,140,132,176,140,8,170,76,78,140,16,71,49,129,31,82,42,151,145,162,208,89, - 5,161,162,94,169,50,179,107,134,137,137,73,28,14,39,13,158,240,80,8,226,146,224,145,135,239,71,216,46,173,110,78, - 92,25,33,51,133,61,172,181,57,73,226,80,170,176,227,112,20,138,119,156,35,80,30,105,47,65,248,30,126,20,227,71, - 49,206,8,20,130,114,88,34,183,57,185,179,36,58,167,28,151,145,30,72,233,104,55,155,148,226,152,82,165,130,51,57, - 59,141,62,78,100,228,229,140,79,253,135,79,83,138,75,188,253,221,239,226,161,83,135,9,227,18,238,209,62,1,100,18, - 82,13,230,189,124,247,25,171,215,243,217,12,49,36,160,55,84,37,180,14,236,20,125,213,178,47,68,252,114,158,151,190, - 214,151,37,127,208,233,16,66,97,140,123,197,248,235,174,221,133,4,130,80,224,156,161,92,41,225,123,146,40,10,8,131, - 128,192,87,72,169,136,162,144,74,165,68,224,251,197,105,150,148,120,74,18,68,49,161,10,169,87,75,28,62,62,77,37, - 86,124,229,203,79,178,111,225,94,222,254,240,187,121,244,241,79,225,251,1,86,23,106,119,165,84,49,84,168,53,82,74, - 164,82,228,70,227,121,62,115,51,211,136,129,126,203,24,131,53,134,192,15,232,38,224,140,38,12,67,170,213,26,213,82, - 137,145,250,40,56,208,58,71,98,73,91,77,16,29,250,253,62,219,166,207,187,223,243,54,62,240,193,247,49,58,85,197, - 101,109,176,134,104,106,156,185,169,41,161,215,215,221,247,18,203,51,196,144,128,222,208,149,141,25,124,72,187,40,74,154, - 18,223,26,21,156,2,71,65,156,7,239,33,8,182,161,156,20,102,91,71,34,231,30,74,60,127,98,203,6,56,12,190, - 39,9,195,136,110,183,251,138,202,28,4,214,22,19,200,89,146,208,100,7,33,4,181,106,141,44,203,25,31,31,35,46, - 197,72,225,176,78,179,211,106,80,142,74,4,126,128,53,154,137,169,41,132,130,169,201,136,131,251,22,200,82,201,179,79, - 159,69,103,57,247,221,119,148,185,133,159,231,133,211,143,227,132,36,85,26,1,36,73,242,202,239,191,75,132,206,83,164, - 24,86,183,214,241,157,0,235,240,252,16,148,96,164,28,226,17,146,181,13,58,213,244,58,29,226,32,160,213,106,146,166, - 41,165,94,137,76,103,88,44,113,24,80,45,141,16,71,117,118,205,206,50,58,91,67,247,183,49,82,32,156,34,8,66, - 162,169,113,225,214,215,69,34,165,192,14,71,16,135,4,52,68,209,60,29,144,75,31,216,11,140,23,167,234,126,8,234, - 223,12,134,159,75,224,54,192,104,208,17,216,117,80,83,66,212,183,157,219,19,192,108,9,102,29,28,234,195,177,203,176, - 248,25,231,38,115,44,146,162,250,81,74,49,49,49,65,154,166,228,121,142,181,208,235,246,72,242,12,223,243,200,179,46, - 253,110,74,171,212,33,10,183,185,117,243,22,190,239,227,251,62,113,92,98,116,108,132,133,185,57,234,181,58,155,91,107, - 204,206,142,112,248,224,62,230,231,75,52,183,55,184,118,169,199,72,117,146,227,199,15,82,29,243,216,189,56,202,169,251, - 30,225,107,79,63,131,31,22,39,89,189,94,239,149,247,92,88,108,0,72,20,2,157,102,120,126,0,14,242,44,67,42, - 133,116,146,241,145,17,118,207,237,197,89,139,201,52,82,120,40,165,216,181,107,154,241,137,9,132,242,176,194,81,41,133, - 72,25,163,115,88,222,218,192,184,62,218,43,92,151,60,167,88,156,159,231,214,160,240,169,84,171,194,53,155,195,133,55, - 36,160,97,181,3,133,26,126,180,56,30,142,238,133,154,129,81,11,147,41,212,227,193,103,101,192,106,232,118,97,219,66, - 170,160,228,57,119,208,194,67,43,112,20,41,199,111,213,170,187,26,39,79,142,239,126,251,59,188,195,205,166,252,242,239, - 253,139,65,165,99,233,118,187,56,231,136,227,152,169,169,105,70,71,198,169,86,43,180,90,109,182,54,55,201,210,28,165, - 36,198,88,38,38,38,25,31,31,71,8,193,216,232,56,165,82,137,145,209,58,66,8,210,44,195,152,140,118,103,155,61, - 123,223,74,175,189,77,210,117,28,62,186,64,165,86,193,201,140,92,167,148,234,227,156,58,245,16,143,62,246,85,124,79, - 210,75,122,56,91,88,108,216,111,138,98,86,8,164,149,248,161,95,24,145,57,135,181,14,207,8,154,107,155,244,194,62, - 211,115,62,115,51,187,144,82,226,43,69,16,248,148,43,101,164,82,224,64,105,200,123,25,81,92,194,23,10,229,2,164, - 243,9,188,24,145,129,240,4,183,175,95,38,105,236,184,0,108,144,36,246,16,223,16,1,15,49,36,160,55,20,238,78, - 50,123,192,75,224,111,195,136,15,115,33,44,90,88,20,176,96,96,174,11,99,41,120,10,80,96,21,180,125,216,12,5, - 105,28,69,229,164,159,204,239,204,206,28,204,254,171,159,155,147,11,123,228,76,125,130,189,229,50,89,175,203,187,75,49, - 31,255,216,199,217,222,217,65,74,133,49,150,110,183,83,184,4,58,75,158,231,248,254,60,167,30,58,69,165,92,45,44, - 44,40,230,112,188,193,132,178,214,26,157,21,196,36,164,194,247,124,114,33,209,54,225,220,185,11,28,63,190,159,131,139, - 123,153,158,142,192,43,38,108,180,201,10,159,103,107,185,255,161,147,148,75,1,137,205,209,90,23,91,75,99,64,12,200, - 71,41,180,115,168,200,43,172,93,179,194,55,8,41,200,76,142,31,68,196,165,128,208,247,233,247,250,196,97,132,147,10, - 223,47,114,226,115,173,9,130,8,63,10,81,190,135,23,23,199,249,189,180,79,175,101,72,147,46,43,55,110,112,231,153, - 103,89,253,253,63,104,237,190,179,114,221,192,182,78,83,253,171,195,101,56,36,160,55,114,229,51,11,226,131,80,217,130, - 61,62,220,39,225,254,46,28,219,169,148,23,178,67,123,199,163,251,78,148,107,71,78,4,37,63,166,84,46,145,246,58, - 180,87,238,216,213,149,101,221,104,181,92,98,80,87,111,222,82,135,222,247,62,239,248,219,222,33,150,87,183,105,111,236, - 208,189,122,19,155,167,228,121,70,28,149,193,53,6,149,5,24,171,139,74,8,65,224,71,92,191,126,157,213,149,85,14, - 29,60,196,209,163,71,41,87,202,164,105,97,155,161,117,142,231,121,248,129,196,247,138,35,115,132,67,121,1,121,98,232, - 39,9,207,60,119,150,253,123,23,8,60,176,178,136,242,81,158,194,232,156,76,119,57,118,124,15,19,83,35,92,188,118, - 3,103,45,131,248,46,148,87,84,65,74,41,100,16,98,125,15,145,101,28,83,158,59,172,84,190,183,84,182,143,26,237, - 223,240,148,10,203,17,74,74,60,169,16,82,14,12,235,65,121,1,129,167,240,124,69,169,82,65,202,0,47,240,137,3, - 159,180,159,240,167,159,254,18,219,43,55,104,127,245,139,122,241,241,39,239,236,109,182,159,5,254,204,193,21,32,29,97, - 120,90,53,36,160,55,68,185,227,8,162,144,221,129,79,158,229,76,2,199,65,25,152,84,112,111,0,111,111,194,195,75, - 243,147,71,43,63,243,51,19,199,62,248,99,222,222,147,135,9,203,21,154,205,14,237,141,6,59,155,29,182,219,93,58, - 51,123,81,38,15,246,197,37,158,126,242,41,174,108,231,196,205,62,222,197,139,120,94,21,163,193,58,133,242,3,74,149, - 18,83,227,19,220,188,121,3,161,36,32,145,72,148,80,69,206,86,210,197,26,135,53,134,75,151,47,210,238,180,216,189, - 123,55,51,51,51,175,24,201,131,64,9,137,177,57,18,133,117,96,140,35,240,67,242,76,115,229,210,45,110,222,92,230, - 208,225,5,64,224,164,196,57,81,168,218,173,101,116,162,194,193,67,123,57,127,249,26,129,167,200,180,198,9,65,113,16, - 47,113,210,99,26,120,176,215,79,222,150,235,205,195,206,173,214,178,180,17,109,111,143,236,175,215,247,255,47,229,242,88, - 224,251,228,14,82,163,137,131,10,202,247,17,74,81,169,214,112,56,2,79,17,74,69,88,170,224,132,38,105,174,177,249, - 242,6,249,205,149,124,242,210,153,237,61,27,203,87,74,198,60,101,225,177,28,94,168,192,74,2,230,129,225,202,28,18, - 208,27,130,127,146,132,99,15,156,100,233,63,123,23,55,63,243,103,92,6,21,192,116,14,143,4,240,254,51,146,71,58, - 31,120,239,222,247,127,244,127,8,14,221,123,47,141,173,45,46,157,187,204,213,203,55,105,108,247,72,181,33,213,144,234, - 62,89,102,168,84,66,46,95,188,204,167,62,249,71,244,186,9,187,23,231,241,164,34,112,32,68,76,238,43,82,154,8, - 153,48,59,51,70,240,66,128,243,4,185,51,4,25,72,2,82,211,39,239,25,98,47,194,218,20,227,52,102,217,176,181, - 189,77,179,217,100,110,110,142,122,189,142,239,251,72,63,196,106,31,163,53,224,240,132,197,104,141,211,150,220,120,156,63, - 127,135,253,7,23,17,50,47,230,145,133,4,5,78,88,188,48,228,240,225,227,216,79,125,1,35,61,82,37,177,18,170, - 6,142,89,97,223,150,233,230,3,253,254,157,133,60,187,162,224,98,238,220,149,20,26,26,246,239,233,245,126,236,17,193, - 67,87,54,55,162,242,174,24,105,37,189,230,54,196,49,165,145,81,68,183,139,236,103,208,107,131,238,89,215,221,209,213, - 205,181,254,194,214,102,123,180,211,109,84,90,173,59,10,46,89,56,173,225,180,129,107,93,104,229,96,134,42,248,33,1, - 253,224,117,138,95,243,235,29,202,247,249,92,24,112,95,241,63,117,3,15,89,248,169,143,73,222,51,246,119,126,105,242, - 239,255,227,223,164,219,94,231,11,159,253,20,55,110,238,208,110,129,192,129,44,178,176,76,174,89,95,95,35,138,74,108, - 110,44,243,248,227,143,209,235,167,56,41,217,105,117,200,115,69,224,28,34,239,80,246,60,2,127,140,52,239,179,231,224, - 49,68,240,53,210,212,224,2,129,81,6,231,122,88,13,89,174,49,174,77,20,248,104,13,89,154,211,15,19,148,148,180, - 90,45,198,199,199,25,31,31,167,62,50,74,28,151,17,66,160,117,142,186,187,205,234,91,148,15,75,55,111,209,108,118, - 168,215,67,44,22,196,55,196,165,8,193,201,55,221,67,232,41,166,149,112,187,16,118,183,148,233,35,90,111,28,205,147, - 235,37,99,46,230,112,33,131,139,22,150,20,108,196,144,165,112,201,215,58,255,112,171,125,167,215,237,207,245,183,215,199, - 76,24,134,185,16,194,58,135,148,210,73,132,8,172,37,74,211,60,72,211,166,103,244,154,7,235,2,86,44,172,89,184, - 237,224,102,14,203,211,176,179,1,217,39,128,95,228,91,199,25,134,24,18,208,255,175,33,74,175,207,182,92,4,62,171, - 183,111,243,123,79,61,207,63,128,192,135,125,62,188,235,179,240,246,234,223,251,149,201,127,240,27,191,202,141,171,215,248, - 202,87,94,164,223,55,40,95,96,85,134,115,18,97,171,24,151,147,230,109,234,213,10,198,88,46,156,63,67,171,221,64, - 170,8,139,230,250,205,37,238,187,255,17,212,104,153,40,48,4,34,197,237,180,8,101,64,109,126,150,127,244,143,254,59, - 158,121,254,12,159,250,211,79,225,2,1,58,71,80,38,10,21,34,75,200,50,131,211,125,4,105,97,16,102,52,173,86, - 139,157,157,29,58,157,14,225,218,26,181,106,157,90,181,74,185,92,70,122,10,43,0,89,184,43,110,108,111,177,190,182, - 201,216,216,158,226,116,203,13,196,163,88,208,154,197,253,251,248,201,35,135,242,159,184,177,212,155,108,119,151,125,99,206, - 225,220,121,13,47,167,112,217,192,114,79,136,102,197,247,147,11,158,111,30,74,250,108,88,123,117,196,185,158,112,238,217, - 178,205,166,43,121,54,37,122,189,210,160,133,228,238,222,23,92,209,208,207,5,108,3,171,6,182,51,104,4,208,201,161, - 215,133,254,4,216,125,224,250,3,226,17,195,222,207,144,128,126,160,8,40,42,189,190,31,32,235,4,255,242,119,249,123, - 183,151,69,6,19,62,220,127,11,30,156,248,200,223,156,254,165,223,252,135,60,245,245,103,121,233,165,203,116,123,25,16, - 162,240,16,50,68,231,25,142,46,97,232,97,173,67,9,201,157,59,183,232,118,59,100,38,67,170,0,33,12,155,55,175, - 163,154,219,16,180,192,53,168,69,41,39,142,204,51,191,231,0,99,115,135,136,199,39,105,172,174,242,147,63,185,204,51, - 103,95,194,151,96,16,56,151,83,169,84,49,214,145,155,188,232,7,89,203,206,206,78,49,115,99,12,198,24,194,32,228, - 70,118,3,107,45,227,227,227,76,79,79,179,123,247,110,194,40,34,205,50,250,73,206,202,234,38,135,143,238,25,76,88, - 187,66,115,38,36,96,217,53,62,198,125,202,211,83,141,237,29,7,143,167,240,105,13,23,34,216,172,67,247,113,200,43, - 74,33,222,249,30,236,252,110,158,250,250,99,212,94,62,223,115,112,195,193,173,42,132,14,162,154,84,190,21,66,8,163, - 95,225,15,1,244,193,88,72,51,72,98,208,135,193,252,11,112,15,243,141,184,35,201,55,38,159,135,228,51,36,160,31, - 44,200,215,227,242,235,179,178,118,147,223,252,151,255,154,143,64,148,192,225,28,30,217,60,116,226,224,207,253,198,175,169, - 39,190,246,36,79,62,113,13,99,115,60,15,132,208,88,171,112,70,32,148,68,121,61,44,22,129,160,219,233,210,106,183, - 104,236,52,0,131,167,124,156,235,48,26,231,132,233,69,222,60,57,202,190,153,128,241,218,24,206,131,157,214,13,46,175, - 53,104,232,29,30,126,211,65,254,218,143,190,135,231,94,58,143,47,125,172,211,72,207,32,125,159,192,243,169,40,0,73, - 224,135,180,90,173,87,44,82,181,214,68,81,52,240,232,129,181,181,53,54,54,54,72,210,148,137,201,73,162,40,6,33, - 88,91,109,96,173,3,103,80,210,199,57,112,206,98,141,198,143,61,250,187,38,252,68,200,173,192,217,23,36,60,51,15, - 107,255,70,74,247,246,19,111,102,227,194,75,200,44,163,49,62,65,82,171,211,154,156,98,230,229,243,220,4,115,13,204, - 135,32,107,67,251,183,172,161,193,55,220,32,7,213,15,191,9,116,129,167,129,69,224,71,128,165,193,247,97,94,251,144, - 128,126,240,241,75,31,121,29,87,217,99,102,117,157,95,185,179,194,29,24,173,194,61,107,130,19,39,63,250,235,99,171, - 235,91,156,63,123,155,94,218,163,20,71,248,170,168,180,172,203,208,166,141,18,10,167,61,228,192,21,48,73,50,218,221, - 30,105,102,200,116,70,73,194,104,181,198,63,252,200,125,188,247,68,149,216,211,108,172,246,249,202,217,62,59,193,4,170, - 94,193,90,203,243,47,60,198,98,188,195,91,222,188,143,145,145,17,250,205,62,82,21,199,234,89,174,169,214,106,72,9, - 158,244,81,202,43,60,155,141,161,84,46,83,169,86,201,178,194,203,89,12,254,85,171,85,60,63,32,207,53,206,245,9, - 188,136,173,237,54,105,146,17,132,114,64,62,174,16,171,90,240,163,0,87,45,75,131,107,201,162,55,211,254,223,193,157, - 149,146,131,135,142,32,174,188,12,89,134,52,6,97,12,106,144,29,47,191,169,202,113,20,105,33,235,223,230,18,255,253, - 193,115,135,194,138,33,1,253,112,226,247,254,245,235,122,121,90,220,161,131,16,22,82,184,71,189,255,253,187,71,238,63, - 36,31,251,15,143,210,235,121,120,94,136,39,61,28,26,156,5,103,17,214,67,103,96,156,198,247,36,78,56,180,161,232, - 215,72,69,20,251,216,118,198,252,212,40,15,28,153,227,230,245,13,158,191,154,144,149,246,50,119,244,65,14,223,115,148, - 201,93,19,40,4,43,43,151,184,126,229,22,15,190,243,4,123,15,236,225,236,51,103,65,130,176,30,54,203,6,166,96, - 150,192,131,206,118,131,44,203,16,66,20,67,130,90,227,28,248,97,80,36,150,122,133,29,71,165,82,193,247,124,156,133, - 208,143,104,182,123,36,105,70,169,84,193,9,133,47,60,172,21,24,157,162,100,64,85,6,22,231,114,1,89,2,246,143, - 40,28,29,255,122,145,4,246,231,178,45,26,138,75,135,4,244,67,137,207,190,206,215,59,160,4,245,16,142,174,195,137, - 221,63,255,145,145,243,23,174,176,182,182,142,241,71,16,66,33,149,162,82,138,241,148,44,242,175,140,64,27,75,175,155, - 146,154,46,73,218,167,221,237,98,17,56,1,163,99,227,32,2,116,154,16,171,132,229,118,74,26,31,225,3,127,243,151, - 153,152,170,145,247,91,172,173,109,114,230,250,50,141,164,204,198,250,50,129,159,115,242,205,39,120,230,241,39,9,85,5, - 157,75,172,72,104,54,27,4,65,72,71,119,208,218,226,73,133,239,251,84,42,85,148,146,148,203,17,189,94,15,207,243, - 8,195,152,153,153,57,42,229,10,121,166,65,129,182,119,27,207,170,16,183,74,139,115,2,41,68,161,118,247,21,42,146, - 78,64,238,64,43,112,31,2,82,99,153,121,246,73,110,165,9,211,98,72,31,67,2,26,226,219,226,208,235,40,239,5, - 144,129,216,134,154,133,197,246,145,195,123,153,159,147,207,127,246,243,100,198,225,185,14,190,95,71,201,136,114,80,101,106, - 87,141,133,221,147,84,106,33,89,63,163,185,222,226,233,211,231,232,119,83,180,211,168,80,129,113,84,188,93,152,216,177, - 222,91,166,35,160,62,86,97,178,60,143,114,25,79,61,253,12,91,43,13,178,84,210,74,250,84,203,147,92,93,185,68, - 111,189,203,123,31,184,151,127,229,123,224,4,78,40,180,215,67,153,14,42,23,244,122,61,130,32,68,72,69,181,90,29, - 28,187,27,164,204,240,60,143,192,47,51,55,187,155,122,173,74,150,247,7,114,10,31,129,193,23,6,231,2,140,5,165, - 114,44,2,105,65,24,131,72,19,166,186,253,60,42,52,108,205,25,48,255,19,69,143,40,185,126,153,7,128,138,148,124, - 42,8,96,72,68,67,2,26,226,91,209,150,30,145,213,175,137,132,4,133,133,170,145,66,9,235,194,185,201,73,121,249, - 226,101,218,237,30,113,20,160,164,135,179,41,190,215,231,192,161,69,142,31,219,207,200,120,25,235,108,145,242,112,104,158, - 202,68,137,63,250,227,47,83,142,74,96,53,213,74,181,176,39,45,89,214,150,187,108,54,20,123,38,234,92,249,234,139, - 180,31,155,165,39,186,132,186,77,144,135,104,171,241,71,3,150,238,40,206,45,189,192,209,153,58,227,19,85,150,119,114, - 202,153,198,225,145,43,3,54,37,8,2,106,181,26,97,24,99,140,193,247,139,192,192,66,51,22,16,199,49,99,99,99, - 120,158,79,174,19,242,92,35,16,228,66,17,87,71,40,197,37,148,76,144,194,34,40,60,125,208,22,157,58,242,141,173, - 84,194,70,10,59,189,66,209,143,30,92,159,10,69,21,53,255,212,19,44,191,239,175,146,6,193,240,164,106,72,64,67, - 220,197,71,103,142,243,179,27,151,25,207,122,175,105,128,45,7,234,8,36,14,175,211,211,87,94,190,140,242,60,156,53, - 88,28,81,232,113,207,241,67,156,122,232,40,82,229,8,50,24,52,114,51,221,231,240,161,93,28,59,184,200,234,202,50, - 165,56,160,94,171,162,148,32,247,12,73,174,185,178,180,197,131,239,62,73,125,116,25,151,165,140,150,43,180,123,29,124, - 153,178,103,102,140,23,47,95,66,101,227,184,102,29,229,239,112,96,62,230,246,198,38,130,26,46,47,99,92,15,200,145, - 210,209,233,116,169,84,106,232,220,144,231,57,165,82,209,24,15,195,136,133,133,57,170,213,50,89,150,98,29,88,235,8, - 67,137,231,251,76,78,77,17,4,62,66,244,193,89,156,182,197,73,158,12,57,119,254,69,154,171,171,122,15,244,203,144, - 254,54,216,63,248,118,100,125,229,18,251,148,226,64,171,201,189,195,101,55,36,160,33,6,8,74,188,48,58,207,149,181, - 75,223,119,163,51,5,126,6,152,118,206,51,16,172,151,170,126,203,130,176,22,169,20,2,69,28,150,89,92,88,196,147, - 138,60,239,35,144,40,21,35,164,35,211,41,130,156,131,251,23,248,202,87,193,87,18,223,243,208,38,35,55,61,146,212, - 240,153,39,110,241,115,63,254,22,222,245,224,28,143,95,110,211,82,146,204,102,216,238,37,222,250,222,15,178,123,254,24, - 51,174,71,232,174,225,162,113,142,239,61,193,19,79,223,194,85,115,112,10,165,21,8,131,82,138,56,138,209,185,70,8, - 73,28,199,4,65,64,28,151,168,86,107,212,106,181,65,83,218,97,140,197,243,124,162,40,70,231,25,83,211,35,8,101, - 192,88,76,63,3,17,129,11,56,123,238,34,127,252,241,63,230,100,179,149,0,125,3,250,167,129,3,128,255,31,53,203, - 28,189,151,207,51,201,127,156,121,54,196,144,128,222,176,240,157,229,98,105,148,207,188,198,215,63,2,226,158,194,178,198, - 107,132,161,159,106,13,121,70,218,207,81,194,35,80,62,206,88,176,14,233,192,100,6,252,194,172,171,72,123,176,108,53, - 54,177,54,71,56,65,154,100,180,123,13,182,183,54,8,163,18,207,157,89,225,242,218,14,71,78,236,99,185,213,97,114, - 143,100,241,222,119,176,122,166,194,242,165,47,242,230,135,238,33,223,184,205,234,166,225,143,255,244,28,159,127,236,121,202, - 126,133,220,119,8,145,160,80,4,65,9,223,247,9,163,176,120,207,190,55,248,30,16,69,37,198,199,39,8,163,0,173, - 53,214,25,148,44,30,215,58,103,98,178,198,225,67,243,96,179,226,125,8,159,44,151,156,62,125,142,47,125,245,113,242, - 181,6,211,189,254,182,133,13,160,87,5,222,253,29,8,70,80,184,63,150,135,203,110,72,64,67,20,208,206,176,55,30, - 99,79,101,130,165,206,230,247,253,122,67,49,16,103,64,110,6,177,111,173,5,147,145,166,9,158,12,105,119,119,184,185, - 124,131,197,197,147,56,99,16,202,2,41,166,216,231,208,234,102,188,248,210,121,12,154,94,191,152,201,105,181,154,228,185, - 197,154,156,181,141,156,63,250,183,79,242,235,127,171,205,59,102,203,4,113,139,252,230,13,246,250,9,155,145,229,147,159, - 252,18,95,127,106,155,11,75,61,158,56,127,150,70,99,135,48,10,144,89,140,144,2,233,65,24,132,32,10,151,194,32, - 14,176,214,81,42,69,212,235,35,76,78,78,83,173,86,48,38,35,203,82,130,32,66,160,240,124,31,107,53,7,22,23, - 152,26,175,14,124,131,34,214,55,119,120,241,197,23,120,252,107,95,39,40,133,252,149,83,15,57,62,247,39,77,7,155, - 10,146,79,83,196,75,203,87,185,102,18,24,3,194,225,242,27,18,208,27,29,119,239,212,247,141,237,125,77,4,212,150, - 66,72,207,19,46,203,197,213,141,77,185,92,190,78,144,118,209,14,202,229,49,114,157,240,252,139,167,57,126,104,31,147, - 99,37,12,125,4,6,97,4,206,40,190,254,245,115,92,190,118,131,219,43,183,105,52,91,108,109,55,232,180,91,8,2, - 156,53,136,32,231,183,63,251,20,126,205,240,142,251,247,145,52,250,60,250,244,10,103,111,238,32,130,58,126,181,66,101, - 98,23,227,251,29,51,59,107,52,90,25,125,155,225,153,140,216,31,108,245,242,140,177,209,113,2,63,196,31,196,221,140, - 140,140,50,54,54,70,20,21,113,58,214,25,60,95,146,101,41,190,23,99,173,102,100,180,206,187,222,241,118,60,20,91, - 141,38,75,183,87,57,247,242,117,158,121,246,52,229,146,207,135,62,252,55,184,244,135,31,179,94,150,165,2,210,14,152, - 127,69,49,3,244,221,16,1,31,102,56,205,60,36,160,55,56,4,144,59,195,92,121,244,53,85,65,117,235,156,201,114, - 235,131,243,251,61,179,182,182,78,217,246,201,140,99,107,171,205,158,189,123,184,112,225,26,159,253,220,151,248,233,159,248, - 81,170,181,10,189,78,151,141,141,109,158,127,238,28,159,249,179,175,113,107,229,14,107,27,183,89,91,109,97,140,69,72, - 137,213,2,132,69,90,65,187,175,248,39,255,215,83,252,206,39,47,209,111,182,89,152,223,195,254,163,199,40,141,132,220, - 92,90,162,183,233,216,53,61,195,177,197,7,89,187,149,176,153,172,128,167,208,46,67,106,139,26,184,31,214,106,117,162, - 40,38,12,66,198,199,199,41,151,43,120,202,199,216,188,200,228,114,142,48,12,177,6,42,149,42,239,127,255,251,201,211, - 148,39,191,118,158,229,149,117,94,190,188,196,205,213,6,251,14,237,227,167,254,243,247,49,187,48,198,153,141,85,83,118, - 100,14,242,17,112,255,61,133,116,226,187,85,64,171,131,94,208,80,185,62,36,160,33,28,56,241,218,171,160,65,126,151, - 213,155,183,76,143,24,191,18,211,75,183,72,251,45,148,39,152,156,28,231,209,199,30,231,197,179,103,88,152,159,195,88, - 199,141,155,183,89,89,91,163,213,110,115,231,206,29,26,141,6,157,78,7,59,176,50,13,35,133,144,30,253,110,15,207, - 179,24,171,216,218,106,33,149,32,26,169,241,210,153,23,185,179,124,7,173,29,199,143,159,96,114,98,158,218,68,153,217, - 221,19,108,159,93,69,249,22,141,69,225,35,132,71,28,151,136,162,136,145,122,141,106,165,78,41,174,32,133,135,0,66, - 63,160,223,55,132,97,136,195,17,197,30,71,14,29,100,109,121,153,23,159,221,102,117,117,149,102,227,38,211,149,113,254, - 202,187,223,197,125,111,59,202,254,185,17,154,253,148,222,157,213,108,10,183,165,97,167,14,230,191,230,123,107,48,219,193, - 86,109,133,225,148,243,144,128,134,64,91,195,76,121,148,71,38,247,115,102,227,234,171,222,193,239,162,75,113,218,35,192, - 74,208,213,118,91,175,244,175,194,238,41,106,35,37,180,150,108,110,110,209,237,182,153,155,153,97,103,167,193,213,107,87, - 11,77,86,146,113,103,101,149,126,210,39,75,83,180,214,133,68,98,16,103,227,7,1,8,247,74,198,151,64,32,85,113, - 124,255,252,115,207,17,4,1,74,42,74,213,152,245,245,117,54,183,182,152,155,157,225,200,145,35,220,190,125,155,86,171, - 53,168,164,44,190,231,177,111,223,62,74,113,76,20,132,248,42,0,109,169,148,35,74,213,18,142,194,204,222,58,135,242, - 37,83,19,147,52,26,219,92,188,116,145,94,179,195,228,216,24,111,122,211,73,14,29,63,192,209,147,71,168,151,75,144, - 229,228,105,134,235,119,50,96,83,194,78,0,38,227,123,27,236,20,131,30,208,20,176,54,92,176,67,2,26,2,180,115, - 220,63,50,207,135,118,150,17,121,255,187,222,201,45,80,5,215,131,36,130,230,92,24,245,140,203,217,106,111,178,211,131, - 188,229,33,21,212,70,98,110,175,88,202,113,17,63,188,177,177,78,179,221,38,73,179,194,28,62,207,49,198,224,156,195, - 243,60,162,40,34,240,125,210,44,41,102,114,156,0,44,14,144,74,18,122,17,224,176,214,96,172,161,84,142,73,146,62, - 253,126,194,216,232,4,15,191,245,17,190,252,229,175,208,75,250,68,129,79,173,82,163,215,233,161,211,156,190,239,83,171, - 86,193,194,86,150,97,221,24,86,138,66,32,170,36,129,10,216,220,220,66,231,154,90,173,198,248,200,24,7,247,204,114, - 228,196,62,118,31,95,68,8,135,236,39,133,177,124,150,35,114,99,92,97,149,145,255,83,176,191,13,196,223,207,53,167, - 80,185,247,134,203,111,72,64,111,248,126,144,179,180,252,144,237,209,5,126,118,253,210,119,37,32,1,164,224,214,161,99, - 97,61,180,174,147,27,77,214,234,99,243,12,151,6,8,37,72,117,200,214,214,22,58,47,140,224,173,45,146,33,140,27, - 164,82,72,31,165,160,84,42,17,197,49,74,41,90,173,29,250,73,31,107,45,82,202,226,53,20,61,154,48,12,105,53, - 119,144,82,146,235,156,102,163,133,153,53,248,190,143,231,121,204,207,47,176,127,255,126,110,221,188,197,161,195,135,11,31, - 232,48,26,228,128,5,148,75,49,149,114,25,37,20,81,169,140,23,12,166,118,132,32,215,57,253,94,239,149,252,46,229, - 251,220,243,192,125,28,56,92,39,205,83,252,220,71,56,139,139,28,237,126,15,63,147,133,64,30,92,62,184,46,253,239, - 243,186,95,26,46,189,33,1,13,81,64,89,67,119,100,134,79,55,151,185,152,118,94,245,148,198,0,19,192,143,66,106, - 160,61,233,92,111,97,124,146,43,171,55,9,125,129,13,44,214,64,183,219,5,1,149,82,25,231,138,237,158,213,182,72, - 14,117,16,199,17,97,24,146,231,57,253,126,31,173,53,89,158,14,162,142,93,33,6,149,30,142,194,72,172,215,235,97, - 29,8,91,184,19,250,158,143,148,146,36,73,104,54,155,128,96,223,226,62,78,61,120,10,223,247,209,86,147,231,154,36, - 77,17,206,20,166,241,82,18,148,98,130,48,192,243,10,2,202,117,142,195,225,251,62,130,66,49,47,156,164,159,228,128, - 195,211,57,82,75,50,15,124,17,177,121,233,26,193,173,149,190,131,158,6,243,87,129,105,190,255,44,174,187,150,28,191, - 51,232,9,13,49,36,160,55,46,1,57,199,154,10,185,49,115,148,201,27,207,188,106,63,227,110,254,87,12,166,11,201, - 136,54,253,227,243,115,110,105,107,83,88,157,0,69,76,177,67,22,238,126,73,70,24,68,248,94,128,117,22,207,83,8, - 100,97,113,234,28,217,192,62,35,205,138,78,138,214,69,190,123,81,156,200,65,85,82,228,122,149,226,26,221,110,151,90, - 173,198,236,204,44,35,35,163,120,158,95,228,171,87,171,56,99,144,82,208,107,119,48,206,21,141,114,229,21,57,91,65, - 132,19,18,173,13,46,24,100,121,13,72,64,73,137,118,20,118,28,56,242,164,199,250,237,219,184,227,51,8,153,162,189, - 132,160,84,231,198,229,43,172,254,246,239,247,38,175,93,61,99,224,106,94,84,129,188,214,52,10,31,248,101,224,183,248, - 222,142,241,135,24,18,208,15,45,164,213,148,227,17,62,84,153,228,129,206,198,119,125,254,121,208,109,216,246,250,189,141, - 55,151,131,188,245,35,111,15,190,252,165,47,225,97,145,24,156,28,156,147,185,98,186,56,8,130,34,59,29,135,20,96, - 156,165,215,110,99,181,65,15,178,213,7,188,131,148,2,73,17,117,46,165,71,28,197,120,94,192,248,248,36,211,187,118, - 177,184,103,145,106,173,74,28,71,228,70,147,38,9,206,90,130,48,64,122,62,141,78,151,181,149,85,70,171,53,198,198, - 199,169,212,234,120,190,87,152,207,75,85,228,120,41,129,16,2,147,229,131,0,67,135,144,5,225,41,223,103,121,109,21, - 157,38,248,165,0,43,224,153,207,127,145,139,191,250,209,230,220,153,243,79,1,159,13,224,89,160,125,138,215,55,229,252, - 163,192,28,240,145,225,18,28,18,208,27,186,23,52,168,110,62,62,190,135,127,223,217,224,213,82,198,51,224,199,32,159, - 133,213,28,174,30,184,117,103,123,249,173,239,216,181,118,239,253,92,60,127,6,169,187,8,43,144,74,34,165,122,133,124, - 172,213,3,55,68,65,158,166,224,28,218,232,34,81,75,74,140,45,26,195,175,40,207,157,96,126,126,158,125,251,15,48, - 57,53,205,232,232,24,113,24,163,60,143,164,159,144,101,26,135,165,86,175,129,20,116,27,219,52,207,158,177,245,151,47, - 232,122,187,205,246,169,183,121,106,106,90,226,64,56,1,6,226,56,36,14,35,180,213,131,30,147,64,121,170,56,113,19, - 18,103,45,206,15,176,113,136,240,28,55,207,94,224,201,223,255,152,238,254,223,255,110,101,177,217,121,86,194,159,120,240, - 165,18,220,250,29,200,99,160,198,107,183,55,137,40,172,87,135,24,18,208,112,43,102,13,155,165,81,110,76,29,224,193, - 245,43,40,190,253,124,75,6,204,20,237,160,181,12,206,238,186,113,237,202,200,129,197,169,83,15,63,40,199,106,37,46, - 157,62,77,171,213,66,10,65,185,84,166,90,175,131,128,78,167,69,174,51,148,49,248,214,129,47,65,72,242,60,43,42, - 16,107,200,179,12,68,153,61,187,15,240,240,155,223,204,222,61,11,88,9,61,155,163,60,15,172,165,151,116,169,142,84, - 9,2,159,78,179,73,114,237,101,166,175,93,237,239,191,116,121,115,87,171,181,58,225,156,150,48,243,137,222,214,252,86, - 104,101,28,9,130,48,64,57,137,22,142,204,104,140,209,24,35,193,249,4,94,72,106,83,148,7,81,57,70,167,9,165, - 235,55,220,215,255,155,207,247,150,63,241,137,173,250,230,246,245,89,120,30,120,76,195,243,22,86,62,10,217,39,135,75, - 102,136,33,1,253,249,193,1,129,53,28,157,56,192,223,238,53,57,248,42,91,177,12,120,17,90,192,185,32,201,158,59, - 113,230,194,190,47,76,239,157,61,114,252,30,118,239,154,225,133,211,47,176,116,115,169,200,80,239,52,177,198,224,156,69, - 231,57,218,128,239,135,4,202,199,26,73,166,29,58,207,41,197,101,14,239,187,135,99,71,143,113,248,240,65,194,48,164, - 211,238,224,210,28,101,12,81,217,71,196,33,213,168,130,202,53,205,103,158,118,19,47,189,212,222,187,124,123,121,38,77, - 46,120,112,94,195,245,4,144,112,106,223,203,23,223,219,169,141,237,73,246,29,19,65,77,225,252,16,89,13,113,78,160, - 6,65,131,214,9,116,214,39,72,122,148,117,134,60,123,75,215,158,125,170,25,94,187,182,154,102,217,149,121,56,235,224, - 124,14,23,114,184,49,2,173,223,2,51,36,159,33,134,4,244,250,118,92,238,59,61,208,119,134,127,55,177,200,111,188, - 10,1,5,69,21,148,95,133,27,26,158,88,88,186,113,240,216,153,211,245,211,39,223,84,246,75,1,15,63,242,86,22, - 118,47,176,178,186,70,191,215,67,8,65,191,223,163,223,235,97,133,71,169,82,67,73,1,90,83,158,171,48,63,191,192, - 145,35,71,153,158,222,5,194,144,244,59,244,186,93,132,148,152,80,225,171,128,40,12,72,218,93,242,243,215,221,244,11, - 207,108,159,188,117,243,70,93,235,139,14,94,178,240,146,129,107,1,108,38,224,57,88,58,218,106,53,103,190,252,232,91, - 239,60,245,244,108,30,70,126,88,42,17,150,203,104,157,129,49,88,231,112,206,162,180,182,113,158,217,82,146,228,81,187, - 181,86,178,246,162,131,11,182,248,186,146,193,198,94,232,124,5,242,39,249,54,182,27,67,12,49,36,160,239,187,216,121, - 213,7,79,116,183,190,235,15,89,0,82,216,185,3,207,9,152,185,247,185,167,107,237,170,255,192,141,125,135,35,95,120, - 220,115,248,24,39,142,221,75,158,229,104,173,49,185,38,244,3,180,40,82,48,42,81,137,122,181,74,185,84,38,42,197, - 244,147,132,84,247,49,182,56,202,15,189,128,220,106,188,56,198,96,216,57,119,134,125,47,157,110,237,191,181,116,173,154, - 36,207,105,120,206,193,121,3,75,26,54,28,244,207,130,253,47,129,23,32,233,67,163,174,243,211,99,237,198,140,107,23, - 39,229,118,160,130,184,27,6,248,205,217,90,6,50,1,43,6,174,8,184,133,16,59,35,74,245,207,104,109,223,9,156, - 7,110,48,148,81,12,49,36,160,191,80,24,227,136,59,13,150,10,130,121,213,50,202,130,25,131,91,91,240,133,216,104, - 255,109,95,121,204,69,205,238,125,183,79,190,165,98,29,120,198,17,120,1,97,84,122,101,32,209,15,36,206,228,131,19, - 41,73,187,219,161,213,239,224,135,33,42,240,240,157,79,53,174,128,146,100,121,74,239,218,117,70,95,120,186,127,224,252, - 217,165,201,110,247,37,11,79,25,120,38,134,43,171,208,168,64,58,3,238,14,112,109,240,119,37,208,156,135,179,55,225, - 90,9,226,210,64,132,110,41,28,29,131,111,67,36,61,48,9,244,35,33,186,7,14,29,200,211,195,251,221,212,196,8, - 75,95,250,26,246,250,173,225,194,24,98,72,64,127,225,228,99,29,251,234,17,215,30,121,136,23,146,14,82,124,103,133, - 152,39,37,75,221,46,201,115,207,166,191,226,220,149,77,248,211,64,91,115,234,217,231,146,169,102,251,77,23,223,252,224, - 164,155,157,23,65,232,147,27,141,118,14,43,101,17,113,227,10,162,19,18,148,23,225,5,138,32,80,68,113,132,148,18, - 50,141,185,190,68,233,233,39,251,251,47,156,185,189,171,213,56,39,29,207,26,120,110,16,129,188,118,24,250,159,6,142, - 81,72,27,238,18,138,1,38,129,189,144,158,133,116,22,26,255,219,128,120,74,158,98,97,116,140,155,141,6,169,214,175, - 156,254,5,20,121,92,231,129,119,252,200,91,168,253,212,143,99,146,62,38,246,169,47,175,13,9,104,136,33,1,253,101, - 32,183,150,15,28,159,231,161,125,179,69,64,240,171,118,146,4,120,30,239,217,217,225,127,190,114,57,249,187,112,169,15, - 105,136,219,58,116,249,226,234,200,157,219,167,206,47,238,95,216,62,113,50,142,23,22,240,3,133,242,61,60,21,160,42, - 101,132,44,68,167,65,224,19,122,30,158,16,36,157,54,237,75,231,92,240,228,83,189,189,55,174,223,158,236,118,206,75, - 120,206,192,139,249,128,120,22,161,87,3,187,243,77,149,216,119,130,164,104,152,127,124,64,64,191,246,158,119,114,100,113, - 47,255,227,255,249,251,223,242,188,24,248,111,7,63,75,249,62,86,128,233,37,72,5,54,207,135,219,174,33,134,4,244, - 151,5,37,4,89,154,146,234,239,238,92,83,141,34,170,74,241,135,192,12,36,31,129,171,13,104,229,176,58,213,235,222, - 24,63,247,210,253,203,183,150,14,95,157,157,223,149,238,222,29,245,162,72,154,56,22,34,12,113,206,81,169,85,104,182, - 90,168,141,117,29,111,108,234,218,198,122,251,158,181,181,149,145,52,189,12,60,111,224,197,92,138,75,210,186,85,191,176, - 63,181,21,10,85,249,119,83,239,127,59,210,24,13,124,198,148,122,245,215,56,203,43,83,145,67,12,49,36,160,191,92, - 184,239,247,201,119,165,19,64,21,244,255,11,107,143,192,19,10,150,4,188,176,187,213,188,103,161,213,60,144,93,186,48, - 154,64,156,249,126,77,123,94,221,89,43,124,104,187,60,111,199,90,247,98,104,43,88,6,174,89,196,229,28,119,57,129, - 245,178,117,189,17,176,222,224,215,189,158,106,196,216,194,132,108,136,33,134,4,244,195,86,57,1,91,192,117,176,191,14, - 173,231,161,155,192,178,134,211,22,166,34,107,43,1,132,54,77,71,101,154,78,57,80,18,54,44,108,73,72,53,244,50, - 216,150,176,237,227,218,14,250,115,96,253,111,170,78,134,110,130,67,12,9,104,136,87,45,136,238,110,112,170,96,34,104, - 93,131,206,12,220,186,13,106,18,68,25,162,118,209,118,17,9,244,125,72,19,48,62,216,147,160,159,6,171,129,121,94, - 187,196,97,136,33,254,178,33,220,176,180,30,98,136,33,254,19,65,14,47,193,16,67,12,241,159,10,255,31,228,61,54, - 41,71,79,28,213,0,0,0,0,73,69,78,68,174,66,96,130, -}; - -}; diff --git a/target-loki/resource/resource.hpp b/target-loki/resource/resource.hpp deleted file mode 100644 index a665316a..00000000 --- a/target-loki/resource/resource.hpp +++ /dev/null @@ -1,3 +0,0 @@ -namespace resource { - extern const uint8_t loki[121905]; -}; diff --git a/target-loki/settings/settings.cpp b/target-loki/settings/settings.cpp deleted file mode 100644 index 6a067be1..00000000 --- a/target-loki/settings/settings.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "../loki.hpp" -Settings* settings = nullptr; - -Settings::Settings() { - settings = this; - - video.append(video.driver = ruby::video.optimalDriver(), "Driver"); - video.append(video.synchronize = false, "Synchronize"); - append(video, "Video"); - - audio.append(audio.driver = ruby::audio.optimalDriver(), "Driver"); - audio.append(audio.synchronize = true, "Synchronize"); - audio.append(audio.mute = false, "Mute"); - append(audio, "Audio"); - - input.append(input.driver = ruby::input.optimalDriver(), "Driver"); - append(input, "Input"); - - terminal.append(terminal.backgroundColor = 0x481818, "BackgroundColor"); - terminal.append(terminal.foregroundColor = 0xffffff, "ForegroundColor"); - append(terminal, "Terminal"); - - geometry.append(geometry.presentation = "", "Presentation"); - geometry.append(geometry.terminal = "", "Terminal"); - append(geometry, "Geometry"); - - load(); -} - -void Settings::load() { - Configuration::Document::load(program->path("settings.bml")); - Configuration::Document::save(program->path("settings.bml")); -} - -void Settings::unload() { - //remember window geometry for next run - geometry.presentation = presentation->geometry().text(); - geometry.terminal = ::terminal->geometry().text(); - - Configuration::Document::save(program->path("settings.bml")); -} - -void Settings::command(string s, lstring args) { - unsigned argc = args.size(); - s.ltrim<1>("settings."); - - if(s == "video.driver" && argc == 1) { video.driver = args[0]; return; } - if(s == "video.synchronize" && argc == 1) { video.synchronize = args[0] != "false"; ruby::video.set(ruby::Video::Synchronize, video.synchronize); return; } - if(s == "audio.driver" && argc == 1) { audio.driver = args[0]; return; } - if(s == "audio.synchronize" && argc == 1) { audio.synchronize = args[0] != "false"; ruby::audio.set(ruby::Audio::Synchronize, audio.synchronize); return; } - if(s == "audio.mute" && argc == 1) { audio.mute = args[0] != "false"; return; } - if(s == "input.driver" && argc == 1) { input.driver = args[0]; return; } - if(s == "terminal.background-color" && argc == 1) { terminal.backgroundColor = hex(args[0]); ::terminal->setColors(); return; } - if(s == "terminal.foreground-color" && argc == 1) { terminal.foregroundColor = hex(args[0]); ::terminal->setColors(); return; } - - echo("Error: unrecognized setting: ", s, "\n"); -} diff --git a/target-loki/settings/settings.hpp b/target-loki/settings/settings.hpp deleted file mode 100644 index 68bd5de1..00000000 --- a/target-loki/settings/settings.hpp +++ /dev/null @@ -1,34 +0,0 @@ -struct Settings : Configuration::Document { - struct Video : Configuration::Node { - string driver; - bool synchronize; - } video; - - struct Audio : Configuration::Node { - string driver; - bool synchronize; - bool mute; - } audio; - - struct Input : Configuration::Node { - string driver; - } input; - - struct Terminal : Configuration::Node { - unsigned backgroundColor; - unsigned foregroundColor; - } terminal; - - struct Geometry : Configuration::Node { - string presentation; - string terminal; - } geometry; - - Settings(); - void load(); - void unload(); - - void command(string s, lstring args); -}; - -extern Settings* settings; diff --git a/target-loki/terminal/terminal.cpp b/target-loki/terminal/terminal.cpp deleted file mode 100644 index 18fd0213..00000000 --- a/target-loki/terminal/terminal.cpp +++ /dev/null @@ -1,384 +0,0 @@ -#include "../loki.hpp" -Terminal* terminal = nullptr; - -Terminal::Terminal() { - terminal = this; - if(settings->geometry.terminal.empty()) { - unsigned y = 64 + presentation->geometry().height + presentation->frameMargin().height; - settings->geometry.terminal = {"64,", y, ",800,480"}; - } - - setTitle({"loki v", Emulator::Version}); - setGeometry(settings->geometry.terminal); - - console.setFont(Font::monospace(8)); - console.setPrompt("$ "); - setColors(); - - layout.append(console, {~0, ~0}); - append(layout); - - onClose = &Application::quit; - console.onActivate = {&Terminal::command, this}; -} - -void Terminal::load() { - if(file::exists(program->path("aliases.cfg"))) { - string filedata = file::read(program->path("aliases.cfg")); - lstring lines = filedata.split("\n"); - for(auto& line : lines) { - lstring part = line.split<1>(" => "); - if(part.size() != 2) continue; - aliases.append({part[0], part[1]}); - } - } - - if(file::exists(program->path("hotkeys.cfg"))) { - string filedata = file::read(program->path("hotkeys.cfg")); - lstring lines = filedata.split("\n"); - for(auto& line : lines) { - lstring part = line.split<1>(" => "); - if(part.size() != 2) continue; - hotkeys.append({part[0], part[1]}); - } - } -} - -void Terminal::unload() { - file fp; - if(fp.open(program->path("aliases.cfg"), file::mode::write)) { - for(auto& alias : aliases) fp.print(alias.name, " => ", alias.mapping, "\n"); - fp.close(); - } - if(fp.open(program->path("hotkeys.cfg"), file::mode::write)) { - for(auto& hotkey : hotkeys) fp.print(hotkey.name, " => ", hotkey.mapping, "\n"); - fp.close(); - } -} - -void Terminal::command(string t) { - for(auto& alias : aliases) { - lstring tokens; - if(tokenize(tokens, t, alias.name) == false) continue; - string output = alias.mapping; - for(unsigned n = 0; n < tokens.size(); n++) { - output.replace(string{"{", 1 + n, "}"}, tokens[n]); - } - t = output; - break; - } - - auto source = Debugger::Source::CPU; - if(t.beginsWith("cpu/" )) { source = Debugger::Source::CPU; t.ltrim<1>("cpu/" ); } - if(t.beginsWith("smp/" )) { source = Debugger::Source::SMP; t.ltrim<1>("smp/" ); } - if(t.beginsWith("ppu/" )) { source = Debugger::Source::PPU; t.ltrim<1>("ppu/" ); } - if(t.beginsWith("dsp/" )) { source = Debugger::Source::DSP; t.ltrim<1>("dsp/" ); } - if(t.beginsWith("apu/" )) { source = Debugger::Source::APU; t.ltrim<1>("apu/" ); } - if(t.beginsWith("wram/" )) { source = Debugger::Source::WRAM; t.ltrim<1>("wram/" ); } - if(t.beginsWith("vram/" )) { source = Debugger::Source::VRAM; t.ltrim<1>("vram/" ); } - if(t.beginsWith("oam/" )) { source = Debugger::Source::OAM; t.ltrim<1>("oam/" ); } - if(t.beginsWith("cgram/")) { source = Debugger::Source::CGRAM; t.ltrim<1>("cgram/"); } - - if(source == Debugger::Source::CPU) t.replace("$", hex(SFC::cpu.regs.pc)); - if(source == Debugger::Source::SMP) t.replace("$", hex(SFC::smp.regs.pc)); - - lstring part = t.strip().split<1>(" "), args; - string s = part(0); - string p = part(1); - if(p) args = p.qsplit(" ").strip(); - unsigned argc = args.size(); - - if(s.empty()) return; - - if(s.beginsWith("settings.")) return settings->command(s, args); - - if(s == "aliases") { - echoAliases(); - return; - } - - if(s == "aliases.append") { - lstring part = p.qsplit<1>("=>").strip(); - if(part.size() == 2) aliases.append({part[0], part[1]}); - echoAliases(); - return; - } - - if(s == "aliases.remove" && argc == 1) { - unsigned n = decimal(args[0]); - if(n < aliases.size()) aliases.remove(n); - echoAliases(); - return; - } - - if(s == "aliases.reset") { - aliases.reset(); - echo("All aliases removed\n"); - return; - } - - if(s == "break") { - debugger->stop(); - return; - } - - if(s == "breakpoints") { - debugger->echoBreakpoints(); - return; - } - - if(s == "breakpoints.append" && argc >= 2 && argc <= 3) { - Debugger::Breakpoint bp; - bp.source = source; - if(args[0] == "read" ) bp.mode = Debugger::Breakpoint::Mode::Read; - if(args[0] == "write" ) bp.mode = Debugger::Breakpoint::Mode::Write; - if(args[0] == "execute") bp.mode = Debugger::Breakpoint::Mode::Execute; - bp.addr = hex(args[1]); - if(argc >= 3) bp.data = (uint8_t)hex(args[2]); - debugger->breakpoints.append(bp); - debugger->echoBreakpoints(); - return; - } - - if(s == "breakpoints.remove" && argc == 1) { - unsigned n = decimal(args[0]); - if(n < debugger->breakpoints.size()) { - debugger->breakpoints.remove(n); - } - debugger->echoBreakpoints(); - return; - } - - if(s == "breakpoints.reset") { - debugger->breakpoints.reset(); - echo("All breakpoints removed\n"); - return; - } - - if(s == "clear") { - reset(); - return; - } - - if(s == "counter") { - if(source == Debugger::Source::CPU) echo("CPU instructions executed: ", debugger->cpuInstructionCounter, "\n"); - if(source == Debugger::Source::SMP) echo("SMP instructions executed: ", debugger->smpInstructionCounter, "\n"); - return; - } - - if(s == "counter.reset") { - if(source == Debugger::Source::CPU) { echo("CPU instruction counter reset\n"); debugger->cpuInstructionCounter = 0; } - if(source == Debugger::Source::SMP) { echo("SMP instruction counter reset\n"); debugger->smpInstructionCounter = 0; } - return; - } - - if(s == "disassemble" && argc >= 1 && argc <= 2) { - debugger->echoDisassemble(source, hex(args[0]), argc == 2 ? decimal(args[1]) : 16); - return; - } - - if(s == "export" && argc <= 1) { - string filename = {debugger->sourceName(source), "-", string::datetime().transform(" :", "--"), ".ram"}; - if(argc >= 1) filename = args[0]; - string pathname = {interface->pathname, "loki/", filename}; - debugger->memoryExport(source, pathname); - return; - } - - if(s == "hex" && argc >= 1 && argc <= 2) { - debugger->echoHex(source, hex(args[0]), argc == 2 ? decimal(args[1]) : 256); - return; - } - - if(s == "hotkeys") { - echoHotkeys(); - return; - } - - if(s == "hotkeys.append") { - lstring part = p.qsplit<1>("=>").strip(); - if(part.size() == 2) hotkeys.append({part[0], part[1]}); - echoHotkeys(); - return; - } - - if(s == "hotkeys.remove" && argc == 1) { - unsigned n = decimal(args[0]); - if(n < hotkeys.size()) hotkeys.remove(n); - echoHotkeys(); - return; - } - - if(s == "hotkeys.reset") { - hotkeys.reset(); - echo("All hotkeys removed\n"); - return; - } - - if(s == "power") { - emulator->power(); - echo("System has been power cycled\n"); - return; - } - - if(s == "quit") { - Application::quit(); - return; - } - - if(s == "read" && argc == 1) { - unsigned addr = hex(args[0]); - uint8_t data = debugger->memoryRead(source, addr); - echo(debugger->sourceName(source), "/", hex<6>(addr), " = ", hex<2>(data), "\n"); - return; - } - - if(s == "reset") { - emulator->reset(); - echo("System has been reset\n"); - return; - } - - if(s == "run" && argc == 0) { - debugger->run(); - return; - } - - if(s == "run.for" && argc == 1) { - debugger->run(); - if(source == Debugger::Source::CPU) debugger->cpuRunFor = (unsigned)decimal(args[0]); - if(source == Debugger::Source::SMP) debugger->smpRunFor = (unsigned)decimal(args[0]); - return; - } - - if(s == "run.to" && argc == 1) { - debugger->run(); - if(source == Debugger::Source::CPU) debugger->cpuRunTo = (unsigned)hex(args[0]); - if(source == Debugger::Source::SMP) debugger->smpRunTo = (unsigned)hex(args[0]); - return; - } - - if(s == "state.load" && argc == 1) { - string pathname = {interface->pathname, "loki/state-", args[0], ".bst"}; - debugger->stateLoad(pathname); - return; - } - - if(s == "state.save" && argc == 1) { - string pathname = {interface->pathname, "loki/state-", args[0], ".bst"}; - debugger->stateSave(pathname); - return; - } - - if(s == "step" && argc == 0) { - debugger->run(); - if(source == Debugger::Source::CPU) debugger->cpuStepFor = 1u; - if(source == Debugger::Source::SMP) debugger->smpStepFor = 1u; - return; - } - - if(s == "step.for" && argc == 1) { - debugger->run(); - if(source == Debugger::Source::CPU) debugger->cpuStepFor = (unsigned)decimal(args[0]); - if(source == Debugger::Source::SMP) debugger->smpStepFor = (unsigned)decimal(args[0]); - return; - } - - if(s == "step.to" && argc == 1) { - debugger->run(); - if(source == Debugger::Source::CPU) debugger->cpuStepTo = (unsigned)hex(args[0]); - if(source == Debugger::Source::SMP) debugger->smpStepTo = (unsigned)hex(args[0]); - return; - } - - if(s == "tracer.enable" && argc <= 1) { - string filename = {debugger->sourceName(source), "-trace-", string::datetime().transform(" :", "--"), ".log"}; - if(argc >= 1) filename = args[0]; - string pathname = {interface->pathname, "loki/", filename}; - debugger->tracerEnable(source, pathname); - return; - } - - if(s == "tracer.disable") { - debugger->tracerDisable(source); - return; - } - - if(s == "tracer.mask.enable") { - debugger->tracerMaskEnable(source); - return; - } - - if(s == "tracer.mask.disable") { - debugger->tracerMaskDisable(source); - return; - } - - if(s == "usage.reset") { - if(source == Debugger::Source::CPU) memset(debugger->cpuUsage, 0x00, 0x1000000); - if(source == Debugger::Source::APU) memset(debugger->apuUsage, 0x00, 0x10000); - return; - } - - if(s == "write" && argc == 2) { - unsigned addr = hex(args[0]); - uint8 data = hex(args[1]); - debugger->memoryWrite(source, addr, data); - echo(debugger->sourceName(source), "/", hex<6>(addr), " = ", hex<2>(data), "\n"); - return; - } - - echo("Error: unrecognized command: ", s, "\n"); -} - -void Terminal::echoAliases() { - if(aliases.size() == 0) return echo("No aliases defined\n"); - echo("# alias\n"); - echo("--- -----\n"); - for(unsigned n = 0; n < aliases.size(); n++) { - echo(format<-3>(n), " ", aliases[n].name, " => ", aliases[n].mapping, "\n"); - } -} - -void Terminal::echoHotkeys() { - if(hotkeys.size() == 0) return echo("No hotkeys defined\n"); - echo("# hotkey\n"); - echo("--- ------\n"); - for(unsigned n = 0; n < hotkeys.size(); n++) { - echo(format<-3>(n), " ", hotkeys[n].name, " => ", hotkeys[n].mapping, "\n"); - } -} - -void Terminal::inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue) { - if(focused() == false) return; - if(device.isKeyboard() == false) return; //only capture keyboard events - if(oldValue != 0 || newValue != 1) return; //only capture key down events - string name = device.group[group].input[input].name; - - for(auto& hotkey : hotkeys) { - if(name != hotkey.name) continue; - command(hotkey.mapping); - } -} - -void Terminal::reset() { - console.reset(); -} - -void Terminal::print(const string& text) { - console.print(text); -} - -void Terminal::setColors() { - console.setBackgroundColor({ - (uint8)(settings->terminal.backgroundColor >> 16), - (uint8)(settings->terminal.backgroundColor >> 8), - (uint8)(settings->terminal.backgroundColor >> 0) - }); - - console.setForegroundColor({ - (uint8)(settings->terminal.foregroundColor >> 16), - (uint8)(settings->terminal.foregroundColor >> 8), - (uint8)(settings->terminal.foregroundColor >> 0) - }); -} diff --git a/target-loki/terminal/terminal.hpp b/target-loki/terminal/terminal.hpp deleted file mode 100644 index 93f05460..00000000 --- a/target-loki/terminal/terminal.hpp +++ /dev/null @@ -1,31 +0,0 @@ -struct Terminal : Window { - struct Alias { - string name; - string mapping; - }; - - struct Hotkey { - string name; - string mapping; - }; - - Terminal(); - void load(); - void unload(); - - void command(string s); - void echoAliases(); - void echoHotkeys(); - void inputEvent(HID::Device& device, unsigned group, unsigned input, int16_t oldValue, int16_t newValue); - void reset(); - void print(const string& text); - void setColors(); - - VerticalLayout layout; - Console console; - - vector aliases; - vector hotkeys; -}; - -extern Terminal* terminal;