From da448cdfc6022aaaef4114b9602f76092c74a2dd Mon Sep 17 00:00:00 2001 From: Morten Delenk Date: Sun, 15 May 2016 12:45:15 +0200 Subject: [PATCH] Initial commit --- GNUmakefile | 47 + cocoa/action/action.cpp | 25 + cocoa/action/action.hpp | 16 + cocoa/action/menu-check-item.cpp | 56 + cocoa/action/menu-check-item.hpp | 24 + cocoa/action/menu-item.cpp | 53 + cocoa/action/menu-item.hpp | 24 + cocoa/action/menu-radio-item.cpp | 68 + cocoa/action/menu-radio-item.hpp | 25 + cocoa/action/menu-separator.cpp | 20 + cocoa/action/menu-separator.hpp | 13 + cocoa/action/menu.cpp | 72 + cocoa/action/menu.hpp | 27 + cocoa/application.cpp | 93 + cocoa/application.hpp | 24 + cocoa/browser-window.cpp | 73 + cocoa/browser-window.hpp | 13 + cocoa/desktop.cpp | 22 + cocoa/desktop.hpp | 12 + cocoa/font.cpp | 51 + cocoa/font.hpp | 14 + cocoa/group.cpp | 13 + cocoa/group.hpp | 11 + cocoa/header.hpp | 6 + cocoa/keyboard.cpp | 16 + cocoa/keyboard.hpp | 12 + cocoa/layout.cpp | 33 + cocoa/layout.hpp | 15 + cocoa/menu-bar.cpp | 40 + cocoa/menu-bar.hpp | 16 + cocoa/message-window.cpp | 83 + cocoa/message-window.hpp | 14 + cocoa/monitor.cpp | 25 + cocoa/monitor.hpp | 13 + cocoa/mouse.cpp | 15 + cocoa/mouse.hpp | 12 + cocoa/object.cpp | 35 + cocoa/object.hpp | 31 + cocoa/platform.cpp | 60 + cocoa/platform.hpp | 74 + cocoa/popup-menu.cpp | 22 + cocoa/popup-menu.hpp | 15 + cocoa/sizable.cpp | 20 + cocoa/sizable.hpp | 14 + cocoa/status-bar.cpp | 53 + cocoa/status-bar.hpp | 18 + cocoa/timer.cpp | 67 + cocoa/timer.hpp | 27 + cocoa/utility.cpp | 48 + cocoa/widget/button.cpp | 90 + cocoa/widget/button.hpp | 28 + cocoa/widget/canvas.cpp | 208 +++ cocoa/widget/canvas.hpp | 48 + cocoa/widget/check-button.cpp | 99 + cocoa/widget/check-button.hpp | 29 + cocoa/widget/check-label.cpp | 68 + cocoa/widget/check-label.hpp | 26 + cocoa/widget/combo-button-item.cpp | 39 + cocoa/widget/combo-button-item.hpp | 17 + cocoa/widget/combo-button.cpp | 81 + cocoa/widget/combo-button.hpp | 29 + cocoa/widget/console.cpp | 46 + cocoa/widget/console.hpp | 29 + cocoa/widget/frame.cpp | 87 + cocoa/widget/frame.hpp | 30 + cocoa/widget/hex-edit.cpp | 52 + cocoa/widget/hex-edit.hpp | 31 + cocoa/widget/horizontal-scroll-bar.cpp | 94 + cocoa/widget/horizontal-scroll-bar.hpp | 26 + cocoa/widget/horizontal-slider.cpp | 67 + cocoa/widget/horizontal-slider.hpp | 26 + cocoa/widget/label.cpp | 77 + cocoa/widget/label.hpp | 25 + cocoa/widget/line-edit.cpp | 83 + cocoa/widget/line-edit.hpp | 28 + cocoa/widget/list-view-cell.cpp | 50 + cocoa/widget/list-view-cell.hpp | 22 + cocoa/widget/list-view-column.cpp | 87 + cocoa/widget/list-view-column.hpp | 30 + cocoa/widget/list-view-header.cpp | 38 + cocoa/widget/list-view-header.hpp | 17 + cocoa/widget/list-view-item.cpp | 51 + cocoa/widget/list-view-item.hpp | 21 + cocoa/widget/list-view.cpp | 455 +++++ cocoa/widget/list-view.hpp | 71 + cocoa/widget/progress-bar.cpp | 48 + cocoa/widget/progress-bar.hpp | 23 + cocoa/widget/radio-button.cpp | 114 ++ cocoa/widget/radio-button.hpp | 30 + cocoa/widget/radio-label.cpp | 82 + cocoa/widget/radio-label.hpp | 27 + cocoa/widget/tab-frame-item.cpp | 49 + cocoa/widget/tab-frame-item.hpp | 23 + cocoa/widget/tab-frame.cpp | 166 ++ cocoa/widget/tab-frame.hpp | 42 + cocoa/widget/text-edit.cpp | 119 ++ cocoa/widget/text-edit.hpp | 34 + cocoa/widget/vertical-scroll-bar.cpp | 94 + cocoa/widget/vertical-scroll-bar.hpp | 26 + cocoa/widget/vertical-slider.cpp | 67 + cocoa/widget/vertical-slider.hpp | 26 + cocoa/widget/viewport.cpp | 72 + cocoa/widget/viewport.hpp | 29 + cocoa/widget/widget.cpp | 78 + cocoa/widget/widget.hpp | 21 + cocoa/window.cpp | 418 +++++ cocoa/window.hpp | 65 + components.hpp | 98 + core/action/action.cpp | 18 + core/action/menu-check-item.cpp | 38 + core/action/menu-item.cpp | 38 + core/action/menu-radio-item.cpp | 57 + core/action/menu-separator.cpp | 7 + core/action/menu.cpp | 78 + core/alignment.cpp | 44 + core/application.cpp | 103 ++ core/browser-window.cpp | 35 + core/color.cpp | 79 + core/core.cpp | 108 ++ core/core.hpp | 1916 ++++++++++++++++++++ core/cursor.cpp | 43 + core/desktop.cpp | 11 + core/font.cpp | 74 + core/geometry.cpp | 112 ++ core/gradient.cpp | 37 + core/group.cpp | 51 + core/hotkey.cpp | 62 + core/keyboard.cpp | 79 + core/layout.cpp | 70 + core/menu-bar.cpp | 64 + core/message-window.cpp | 42 + core/monitor.cpp | 15 + core/mouse.cpp | 15 + core/object.cpp | 331 ++++ core/popup-menu.cpp | 64 + core/position.cpp | 55 + core/property.cpp | 29 + core/shared.hpp | 942 ++++++++++ core/sizable.cpp | 21 + core/size.cpp | 55 + core/status-bar.cpp | 24 + core/timer.cpp | 28 + core/widget/button.cpp | 58 + core/widget/canvas.cpp | 113 ++ core/widget/check-button.cpp | 68 + core/widget/check-label.cpp | 38 + core/widget/combo-button-item.cpp | 47 + core/widget/combo-button.cpp | 77 + core/widget/console.cpp | 58 + core/widget/frame.cpp | 55 + core/widget/hex-edit.cpp | 93 + core/widget/horizontal-scroll-bar.cpp | 38 + core/widget/horizontal-slider.cpp | 38 + core/widget/icon-view-item.cpp | 44 + core/widget/icon-view.cpp | 165 ++ core/widget/label.cpp | 29 + core/widget/line-edit.cpp | 67 + core/widget/list-view-cell.cpp | 148 ++ core/widget/list-view-column.cpp | 153 ++ core/widget/list-view-header.cpp | 53 + core/widget/list-view-item.cpp | 98 + core/widget/list-view.cpp | 205 +++ core/widget/progress-bar.cpp | 19 + core/widget/radio-button.cpp | 87 + core/widget/radio-label.cpp | 57 + core/widget/source-edit.cpp | 47 + core/widget/tab-frame-item.cpp | 103 ++ core/widget/tab-frame.cpp | 104 ++ core/widget/text-edit.cpp | 87 + core/widget/tree-view-item.cpp | 167 ++ core/widget/tree-view.cpp | 123 ++ core/widget/vertical-scroll-bar.cpp | 38 + core/widget/vertical-slider.cpp | 38 + core/widget/viewport.cpp | 68 + core/widget/widget.cpp | 24 + core/window.cpp | 278 +++ extension/browser-dialog.cpp | 261 +++ extension/browser-dialog.hpp | 34 + extension/extension.cpp | 11 + extension/extension.hpp | 9 + extension/fixed-layout.cpp | 63 + extension/fixed-layout.hpp | 23 + extension/horizontal-layout.cpp | 141 ++ extension/horizontal-layout.hpp | 35 + extension/message-dialog.cpp | 81 + extension/message-dialog.hpp | 28 + extension/shared.hpp | 35 + extension/vertical-layout.cpp | 141 ++ extension/vertical-layout.hpp | 35 + gtk/action/action.cpp | 35 + gtk/action/action.hpp | 19 + gtk/action/menu-check-item.cpp | 38 + gtk/action/menu-check-item.hpp | 15 + gtk/action/menu-item.cpp | 35 + gtk/action/menu-item.hpp | 14 + gtk/action/menu-radio-item.cpp | 78 + gtk/action/menu-radio-item.hpp | 22 + gtk/action/menu-separator.cpp | 15 + gtk/action/menu-separator.hpp | 11 + gtk/action/menu.cpp | 53 + gtk/action/menu.hpp | 19 + gtk/application.cpp | 112 ++ gtk/application.hpp | 20 + gtk/browser-window.cpp | 92 + gtk/browser-window.hpp | 13 + gtk/desktop.cpp | 52 + gtk/desktop.hpp | 12 + gtk/font.cpp | 68 + gtk/font.hpp | 17 + gtk/group.cpp | 13 + gtk/group.hpp | 11 + gtk/header.hpp | 47 + gtk/keyboard.cpp | 251 +++ gtk/keyboard.hpp | 17 + gtk/layout.cpp | 33 + gtk/layout.hpp | 15 + gtk/menu-bar.cpp | 49 + gtk/menu-bar.hpp | 19 + gtk/message-window.cpp | 64 + gtk/message-window.hpp | 14 + gtk/monitor.cpp | 21 + gtk/monitor.hpp | 13 + gtk/mouse.cpp | 47 + gtk/mouse.hpp | 12 + gtk/object.cpp | 35 + gtk/object.hpp | 31 + gtk/platform.cpp | 66 + gtk/platform.hpp | 79 + gtk/popup-menu.cpp | 36 + gtk/popup-menu.hpp | 18 + gtk/settings.cpp | 26 + gtk/settings.hpp | 26 + gtk/sizable.cpp | 20 + gtk/sizable.hpp | 14 + gtk/status-bar.cpp | 42 + gtk/status-bar.hpp | 18 + gtk/timer.cpp | 35 + gtk/timer.hpp | 14 + gtk/utility.cpp | 58 + gtk/widget/button.cpp | 72 + gtk/widget/button.hpp | 21 + gtk/widget/canvas.cpp | 196 ++ gtk/widget/canvas.hpp | 28 + gtk/widget/check-button.cpp | 77 + gtk/widget/check-button.hpp | 18 + gtk/widget/check-label.cpp | 43 + gtk/widget/check-label.hpp | 15 + gtk/widget/combo-button-item.cpp | 40 + gtk/widget/combo-button-item.hpp | 19 + gtk/widget/combo-button.cpp | 91 + gtk/widget/combo-button.hpp | 25 + gtk/widget/console.cpp | 189 ++ gtk/widget/console.hpp | 27 + gtk/widget/frame.cpp | 70 + gtk/widget/frame.hpp | 24 + gtk/widget/hex-edit.cpp | 313 ++++ gtk/widget/hex-edit.hpp | 35 + gtk/widget/horizontal-scroll-bar.cpp | 45 + gtk/widget/horizontal-scroll-bar.hpp | 15 + gtk/widget/horizontal-slider.cpp | 44 + gtk/widget/horizontal-slider.hpp | 15 + gtk/widget/icon-view-item.cpp | 36 + gtk/widget/icon-view-item.hpp | 17 + gtk/widget/icon-view.cpp | 228 +++ gtk/widget/icon-view.hpp | 33 + gtk/widget/label.cpp | 38 + gtk/widget/label.hpp | 15 + gtk/widget/line-edit.cpp | 59 + gtk/widget/line-edit.hpp | 17 + gtk/widget/list-view-cell.cpp | 62 + gtk/widget/list-view-cell.hpp | 23 + gtk/widget/list-view-column.cpp | 138 ++ gtk/widget/list-view-column.hpp | 39 + gtk/widget/list-view-header.cpp | 41 + gtk/widget/list-view-header.hpp | 18 + gtk/widget/list-view-item.cpp | 76 + gtk/widget/list-view-item.hpp | 24 + gtk/widget/list-view.cpp | 421 +++++ gtk/widget/list-view.hpp | 49 + gtk/widget/progress-bar.cpp | 28 + gtk/widget/progress-bar.hpp | 14 + gtk/widget/radio-button.cpp | 116 ++ gtk/widget/radio-button.hpp | 21 + gtk/widget/radio-label.cpp | 82 + gtk/widget/radio-label.hpp | 21 + gtk/widget/source-edit.cpp | 146 ++ gtk/widget/source-edit.hpp | 28 + gtk/widget/tab-frame-item.cpp | 56 + gtk/widget/tab-frame-item.hpp | 21 + gtk/widget/tab-frame.cpp | 285 +++ gtk/widget/tab-frame.hpp | 43 + gtk/widget/text-edit.cpp | 112 ++ gtk/widget/text-edit.hpp | 24 + gtk/widget/tree-view-item.cpp | 111 ++ gtk/widget/tree-view-item.hpp | 28 + gtk/widget/tree-view.cpp | 193 ++ gtk/widget/tree-view.hpp | 34 + gtk/widget/vertical-scroll-bar.cpp | 45 + gtk/widget/vertical-scroll-bar.hpp | 15 + gtk/widget/vertical-slider.cpp | 44 + gtk/widget/vertical-slider.hpp | 15 + gtk/widget/viewport.cpp | 88 + gtk/widget/viewport.hpp | 14 + gtk/widget/widget.cpp | 55 + gtk/widget/widget.hpp | 22 + gtk/window.cpp | 422 +++++ gtk/window.hpp | 53 + hiro.cpp | 8 + hiro.hpp | 21 + platform/windows/keyboard.hpp | 119 ++ platform/xorg/keyboard.hpp | 119 ++ qt/action/action.cpp | 49 + qt/action/action.hpp | 20 + qt/action/menu-check-item.cpp | 46 + qt/action/menu-check-item.hpp | 18 + qt/action/menu-item.cpp | 44 + qt/action/menu-item.hpp | 18 + qt/action/menu-radio-item.cpp | 78 + qt/action/menu-radio-item.hpp | 20 + qt/action/menu-separator.cpp | 25 + qt/action/menu-separator.hpp | 13 + qt/action/menu.cpp | 58 + qt/action/menu.hpp | 20 + qt/application.cpp | 59 + qt/application.hpp | 21 + qt/browser-window.cpp | 64 + qt/browser-window.hpp | 13 + qt/desktop.cpp | 17 + qt/desktop.hpp | 12 + qt/font.cpp | 37 + qt/font.hpp | 14 + qt/group.cpp | 13 + qt/group.hpp | 11 + qt/header.hpp | 16 + qt/keyboard.cpp | 47 + qt/keyboard.hpp | 16 + qt/layout.cpp | 19 + qt/layout.hpp | 13 + qt/menu-bar.cpp | 46 + qt/menu-bar.hpp | 20 + qt/message-window.cpp | 59 + qt/message-window.hpp | 14 + qt/monitor.cpp | 20 + qt/monitor.hpp | 13 + qt/mouse.cpp | 22 + qt/mouse.hpp | 12 + qt/object.cpp | 35 + qt/object.hpp | 31 + qt/platform.cpp | 65 + qt/platform.hpp | 136 ++ qt/popup-menu.cpp | 40 + qt/popup-menu.hpp | 20 + qt/qt.hpp | 303 ++++ qt/qt.moc | 1624 +++++++++++++++++ qt/settings.cpp | 26 + qt/settings.hpp | 20 + qt/sizable.cpp | 20 + qt/sizable.hpp | 14 + qt/status-bar.cpp | 45 + qt/status-bar.hpp | 19 + qt/timer.cpp | 33 + qt/timer.hpp | 16 + qt/utility.cpp | 260 +++ qt/widget/button.cpp | 66 + qt/widget/button.hpp | 19 + qt/widget/canvas.cpp | 160 ++ qt/widget/canvas.hpp | 27 + qt/widget/check-button.cpp | 78 + qt/widget/check-button.hpp | 22 + qt/widget/check-label.cpp | 45 + qt/widget/check-label.hpp | 19 + qt/widget/combo-button-item.cpp | 51 + qt/widget/combo-button-item.hpp | 18 + qt/widget/combo-button.cpp | 50 + qt/widget/combo-button.hpp | 18 + qt/widget/console.cpp | 56 + qt/widget/frame.cpp | 64 + qt/widget/frame.hpp | 22 + qt/widget/hex-edit.cpp | 307 ++++ qt/widget/hex-edit.hpp | 29 + qt/widget/horizontal-scroll-bar.cpp | 46 + qt/widget/horizontal-scroll-bar.hpp | 19 + qt/widget/horizontal-slider.cpp | 46 + qt/widget/horizontal-slider.hpp | 19 + qt/widget/icon-view.cpp | 152 ++ qt/widget/label.cpp | 35 + qt/widget/label.hpp | 17 + qt/widget/line-edit.cpp | 71 + qt/widget/line-edit.hpp | 21 + qt/widget/list-view-cell.cpp | 73 + qt/widget/list-view-cell.hpp | 23 + qt/widget/list-view-column.cpp | 99 + qt/widget/list-view-column.hpp | 30 + qt/widget/list-view-header.cpp | 43 + qt/widget/list-view-header.hpp | 18 + qt/widget/list-view-item.cpp | 64 + qt/widget/list-view-item.hpp | 24 + qt/widget/list-view.cpp | 256 +++ qt/widget/list-view.hpp | 30 + qt/widget/progress-bar.cpp | 33 + qt/widget/progress-bar.hpp | 18 + qt/widget/radio-button.cpp | 110 ++ qt/widget/radio-button.hpp | 23 + qt/widget/radio-label.cpp | 80 + qt/widget/radio-label.hpp | 20 + qt/widget/tab-frame-item.cpp | 82 + qt/widget/tab-frame-item.hpp | 26 + qt/widget/tab-frame.cpp | 66 + qt/widget/tab-frame.hpp | 20 + qt/widget/text-edit.cpp | 83 + qt/widget/text-edit.hpp | 23 + qt/widget/vertical-scroll-bar.cpp | 46 + qt/widget/vertical-scroll-bar.hpp | 19 + qt/widget/vertical-slider.cpp | 47 + qt/widget/vertical-slider.hpp | 19 + qt/widget/viewport.cpp | 68 + qt/widget/viewport.hpp | 18 + qt/widget/widget.cpp | 77 + qt/widget/widget.hpp | 20 + qt/window.cpp | 315 ++++ qt/window.hpp | 42 + reference/action/action.cpp | 15 + reference/action/action.hpp | 14 + reference/action/check-item.cpp | 15 + reference/action/check-item.hpp | 14 + reference/action/item.cpp | 15 + reference/action/item.hpp | 14 + reference/action/menu.cpp | 21 + reference/action/menu.hpp | 16 + reference/action/radio-item.cpp | 18 + reference/action/radio-item.hpp | 15 + reference/action/separator.cpp | 9 + reference/action/separator.hpp | 11 + reference/application.cpp | 19 + reference/application.hpp | 12 + reference/browser-window.cpp | 15 + reference/browser-window.hpp | 9 + reference/desktop.cpp | 11 + reference/desktop.hpp | 8 + reference/font.cpp | 19 + reference/font.hpp | 10 + reference/header.hpp | 0 reference/keyboard.cpp | 14 + reference/keyboard.hpp | 8 + reference/message-window.cpp | 19 + reference/message-window.hpp | 10 + reference/monitor.cpp | 15 + reference/monitor.hpp | 9 + reference/mouse.cpp | 11 + reference/mouse.hpp | 8 + reference/object.cpp | 9 + reference/object.hpp | 14 + reference/platform.cpp | 45 + reference/platform.hpp | 53 + reference/popup-menu.cpp | 18 + reference/popup-menu.hpp | 15 + reference/timer.cpp | 15 + reference/timer.hpp | 14 + reference/widget/button.cpp | 18 + reference/widget/button.hpp | 15 + reference/widget/canvas.cpp | 18 + reference/widget/canvas.hpp | 15 + reference/widget/check-button.cpp | 18 + reference/widget/check-button.hpp | 15 + reference/widget/check-label.cpp | 15 + reference/widget/check-label.hpp | 14 + reference/widget/combo-button.cpp | 24 + reference/widget/combo-button.hpp | 17 + reference/widget/console.cpp | 24 + reference/widget/console.hpp | 17 + reference/widget/frame.cpp | 12 + reference/widget/frame.hpp | 13 + reference/widget/hex-edit.cpp | 30 + reference/widget/hex-edit.hpp | 19 + reference/widget/horizontal-scroller.cpp | 15 + reference/widget/horizontal-scroller.hpp | 14 + reference/widget/horizontal-slider.cpp | 15 + reference/widget/horizontal-slider.hpp | 14 + reference/widget/label.cpp | 12 + reference/widget/label.hpp | 13 + reference/widget/layout.hpp | 9 + reference/widget/line-edit.cpp | 24 + reference/widget/line-edit.hpp | 17 + reference/widget/list-view.cpp | 69 + reference/widget/list-view.hpp | 32 + reference/widget/progress-bar.cpp | 12 + reference/widget/progress-bar.hpp | 13 + reference/widget/radio-button.cpp | 21 + reference/widget/radio-button.hpp | 16 + reference/widget/radio-label.cpp | 18 + reference/widget/radio-label.hpp | 15 + reference/widget/sizable.hpp | 9 + reference/widget/tab-frame.cpp | 24 + reference/widget/tab-frame.hpp | 17 + reference/widget/text-edit.cpp | 30 + reference/widget/text-edit.hpp | 19 + reference/widget/vertical-scroller.cpp | 15 + reference/widget/vertical-scroller.hpp | 14 + reference/widget/vertical-slider.cpp | 15 + reference/widget/vertical-slider.hpp | 14 + reference/widget/viewport.cpp | 16 + reference/widget/viewport.hpp | 14 + reference/widget/widget.cpp | 36 + reference/widget/widget.hpp | 20 + reference/window.cpp | 86 + reference/window.hpp | 37 + resource/GNUmakefile | 13 + resource/icon/action/add.png | Bin 0 -> 323 bytes resource/icon/action/attach.png | Bin 0 -> 649 bytes resource/icon/action/bookmark.png | Bin 0 -> 686 bytes resource/icon/action/full-screen.png | Bin 0 -> 650 bytes resource/icon/action/mute.png | Bin 0 -> 632 bytes resource/icon/action/new.png | Bin 0 -> 477 bytes resource/icon/action/open.png | Bin 0 -> 672 bytes resource/icon/action/properties.png | Bin 0 -> 464 bytes resource/icon/action/quit.png | Bin 0 -> 799 bytes resource/icon/action/refresh.png | Bin 0 -> 912 bytes resource/icon/action/remove.png | Bin 0 -> 247 bytes resource/icon/action/save.png | Bin 0 -> 911 bytes resource/icon/action/search.png | Bin 0 -> 935 bytes resource/icon/action/settings.png | Bin 0 -> 611 bytes resource/icon/action/stop.png | Bin 0 -> 820 bytes resource/icon/application/browser.png | Bin 0 -> 928 bytes resource/icon/application/calculator.png | Bin 0 -> 686 bytes resource/icon/application/calendar.png | Bin 0 -> 603 bytes resource/icon/application/chat.png | Bin 0 -> 422 bytes resource/icon/application/file-manager.png | Bin 0 -> 378 bytes resource/icon/application/mail.png | Bin 0 -> 550 bytes resource/icon/application/monitor.png | Bin 0 -> 611 bytes 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 0 -> 897 bytes resource/icon/device/display.png | Bin 0 -> 662 bytes resource/icon/device/joypad.png | Bin 0 -> 812 bytes resource/icon/device/keyboard.png | Bin 0 -> 587 bytes resource/icon/device/microphone.png | Bin 0 -> 703 bytes resource/icon/device/mouse.png | Bin 0 -> 720 bytes resource/icon/device/network.png | Bin 0 -> 408 bytes resource/icon/device/optical.png | Bin 0 -> 720 bytes resource/icon/device/printer.png | Bin 0 -> 481 bytes resource/icon/device/speaker.png | Bin 0 -> 592 bytes resource/icon/device/storage.png | Bin 0 -> 603 bytes resource/icon/edit/clear.png | Bin 0 -> 773 bytes resource/icon/edit/copy.png | Bin 0 -> 498 bytes resource/icon/edit/cut.png | Bin 0 -> 807 bytes resource/icon/edit/delete.png | Bin 0 -> 680 bytes resource/icon/edit/find.png | Bin 0 -> 617 bytes resource/icon/edit/paste.png | Bin 0 -> 561 bytes resource/icon/edit/redo.png | Bin 0 -> 591 bytes resource/icon/edit/replace.png | Bin 0 -> 776 bytes resource/icon/edit/undo.png | Bin 0 -> 650 bytes resource/icon/emblem/archive.png | Bin 0 -> 540 bytes resource/icon/emblem/audio.png | Bin 0 -> 688 bytes resource/icon/emblem/binary.png | Bin 0 -> 560 bytes resource/icon/emblem/file.png | Bin 0 -> 741 bytes resource/icon/emblem/folder.png | Bin 0 -> 581 bytes resource/icon/emblem/font.png | Bin 0 -> 627 bytes resource/icon/emblem/image.png | Bin 0 -> 558 bytes resource/icon/emblem/markup.png | Bin 0 -> 709 bytes resource/icon/emblem/program.png | Bin 0 -> 609 bytes resource/icon/emblem/script.png | Bin 0 -> 516 bytes resource/icon/emblem/text.png | Bin 0 -> 333 bytes resource/icon/emblem/video.png | Bin 0 -> 592 bytes resource/icon/go/down.png | Bin 0 -> 683 bytes resource/icon/go/home.png | Bin 0 -> 606 bytes resource/icon/go/left.png | Bin 0 -> 655 bytes resource/icon/go/right.png | Bin 0 -> 676 bytes resource/icon/go/up.png | Bin 0 -> 652 bytes resource/icon/media/back.png | Bin 0 -> 770 bytes resource/icon/media/eject.png | Bin 0 -> 628 bytes resource/icon/media/flash.png | Bin 0 -> 607 bytes resource/icon/media/floppy.png | Bin 0 -> 561 bytes resource/icon/media/next.png | Bin 0 -> 771 bytes resource/icon/media/optical.png | Bin 0 -> 931 bytes resource/icon/media/pause.png | Bin 0 -> 464 bytes resource/icon/media/play.png | Bin 0 -> 660 bytes resource/icon/media/record.png | Bin 0 -> 653 bytes resource/icon/media/rewind.png | Bin 0 -> 764 bytes resource/icon/media/skip.png | Bin 0 -> 782 bytes resource/icon/media/stop.png | Bin 0 -> 429 bytes resource/icon/place/bookmarks.png | Bin 0 -> 753 bytes resource/icon/place/desktop.png | Bin 0 -> 722 bytes resource/icon/place/home.png | Bin 0 -> 679 bytes resource/icon/place/server.png | Bin 0 -> 642 bytes resource/icon/place/share.png | Bin 0 -> 697 bytes resource/icon/prompt/error.png | Bin 0 -> 653 bytes resource/icon/prompt/information.png | Bin 0 -> 863 bytes resource/icon/prompt/question.png | Bin 0 -> 932 bytes resource/icon/prompt/warning.png | Bin 0 -> 603 bytes resource/resource.bml | 92 + resource/resource.cpp | 1891 +++++++++++++++++++ resource/resource.hpp | 102 ++ windows/action/action.cpp | 46 + windows/action/action.hpp | 21 + windows/action/menu-check-item.cpp | 29 + windows/action/menu-check-item.hpp | 16 + windows/action/menu-item.cpp | 38 + windows/action/menu-item.hpp | 20 + windows/action/menu-radio-item.cpp | 64 + windows/action/menu-radio-item.hpp | 17 + windows/action/menu-separator.cpp | 13 + windows/action/menu-separator.hpp | 11 + windows/action/menu.cpp | 123 ++ windows/action/menu.hpp | 22 + windows/application.cpp | 261 +++ windows/application.hpp | 16 + windows/browser-window.cpp | 109 ++ windows/browser-window.hpp | 13 + windows/desktop.cpp | 17 + windows/desktop.hpp | 12 + windows/font.cpp | 42 + windows/font.hpp | 15 + windows/group.cpp | 13 + windows/group.hpp | 11 + windows/header.hpp | 82 + windows/hiro.Manifest | 14 + windows/hiro.rc | 1 + windows/keyboard.cpp | 99 + windows/keyboard.hpp | 18 + windows/layout.cpp | 31 + windows/layout.hpp | 15 + windows/menu-bar.cpp | 83 + windows/menu-bar.hpp | 23 + windows/message-window.cpp | 58 + windows/message-window.hpp | 14 + windows/monitor.cpp | 47 + windows/monitor.hpp | 13 + windows/mouse.cpp | 22 + windows/mouse.hpp | 12 + windows/object.cpp | 41 + windows/object.hpp | 31 + windows/platform.cpp | 59 + windows/platform.hpp | 90 + windows/popup-menu.cpp | 109 ++ windows/popup-menu.hpp | 19 + windows/sizable.cpp | 20 + windows/sizable.hpp | 14 + windows/status-bar.cpp | 54 + windows/status-bar.hpp | 21 + windows/timer.cpp | 39 + windows/timer.hpp | 16 + windows/utility.cpp | 397 ++++ windows/widget/button.cpp | 184 ++ windows/widget/button.hpp | 26 + windows/widget/canvas.cpp | 176 ++ windows/widget/canvas.hpp | 27 + windows/widget/check-button.cpp | 100 + windows/widget/check-button.hpp | 27 + windows/widget/check-label.cpp | 42 + windows/widget/check-label.hpp | 17 + windows/widget/combo-button-item.cpp | 42 + windows/widget/combo-button-item.hpp | 17 + windows/widget/combo-button.cpp | 67 + windows/widget/combo-button.hpp | 19 + windows/widget/frame.cpp | 60 + windows/widget/frame.hpp | 18 + windows/widget/hex-edit.cpp | 258 +++ windows/widget/hex-edit.hpp | 29 + windows/widget/horizontal-scroll-bar.cpp | 42 + windows/widget/horizontal-scroll-bar.hpp | 17 + windows/widget/horizontal-slider.cpp | 43 + windows/widget/horizontal-slider.hpp | 17 + windows/widget/label.cpp | 70 + windows/widget/label.hpp | 15 + windows/widget/line-edit.cpp | 61 + windows/widget/line-edit.hpp | 23 + windows/widget/list-view-cell.cpp | 72 + windows/widget/list-view-cell.hpp | 23 + windows/widget/list-view-column.cpp | 109 ++ windows/widget/list-view-column.hpp | 31 + windows/widget/list-view-header.cpp | 42 + windows/widget/list-view-header.hpp | 18 + windows/widget/list-view-item.cpp | 75 + windows/widget/list-view-item.hpp | 22 + windows/widget/list-view.cpp | 440 +++++ windows/widget/list-view.hpp | 43 + windows/widget/progress-bar.cpp | 30 + windows/widget/progress-bar.hpp | 14 + windows/widget/radio-button.cpp | 126 ++ windows/widget/radio-button.hpp | 28 + windows/widget/radio-label.cpp | 67 + windows/widget/radio-label.hpp | 18 + windows/widget/tab-frame-item.cpp | 63 + windows/widget/tab-frame-item.hpp | 21 + windows/widget/tab-frame.cpp | 149 ++ windows/widget/tab-frame.hpp | 27 + windows/widget/text-edit.cpp | 75 + windows/widget/text-edit.hpp | 23 + windows/widget/vertical-scroll-bar.cpp | 42 + windows/widget/vertical-scroll-bar.hpp | 17 + windows/widget/vertical-slider.cpp | 43 + windows/widget/vertical-slider.hpp | 17 + windows/widget/viewport.cpp | 72 + windows/widget/viewport.hpp | 14 + windows/widget/widget.cpp | 93 + windows/widget/widget.hpp | 28 + windows/window.cpp | 281 +++ windows/window.hpp | 50 + 698 files changed, 37867 insertions(+) create mode 100644 GNUmakefile create mode 100644 cocoa/action/action.cpp create mode 100644 cocoa/action/action.hpp create mode 100644 cocoa/action/menu-check-item.cpp create mode 100644 cocoa/action/menu-check-item.hpp create mode 100644 cocoa/action/menu-item.cpp create mode 100644 cocoa/action/menu-item.hpp create mode 100644 cocoa/action/menu-radio-item.cpp create mode 100644 cocoa/action/menu-radio-item.hpp create mode 100644 cocoa/action/menu-separator.cpp create mode 100644 cocoa/action/menu-separator.hpp create mode 100644 cocoa/action/menu.cpp create mode 100644 cocoa/action/menu.hpp create mode 100644 cocoa/application.cpp create mode 100644 cocoa/application.hpp create mode 100644 cocoa/browser-window.cpp create mode 100644 cocoa/browser-window.hpp create mode 100644 cocoa/desktop.cpp create mode 100644 cocoa/desktop.hpp create mode 100644 cocoa/font.cpp create mode 100644 cocoa/font.hpp create mode 100644 cocoa/group.cpp create mode 100644 cocoa/group.hpp create mode 100644 cocoa/header.hpp create mode 100644 cocoa/keyboard.cpp create mode 100644 cocoa/keyboard.hpp create mode 100644 cocoa/layout.cpp create mode 100644 cocoa/layout.hpp create mode 100644 cocoa/menu-bar.cpp create mode 100644 cocoa/menu-bar.hpp create mode 100644 cocoa/message-window.cpp create mode 100644 cocoa/message-window.hpp create mode 100644 cocoa/monitor.cpp create mode 100644 cocoa/monitor.hpp create mode 100644 cocoa/mouse.cpp create mode 100644 cocoa/mouse.hpp create mode 100644 cocoa/object.cpp create mode 100644 cocoa/object.hpp create mode 100644 cocoa/platform.cpp create mode 100644 cocoa/platform.hpp create mode 100644 cocoa/popup-menu.cpp create mode 100644 cocoa/popup-menu.hpp create mode 100644 cocoa/sizable.cpp create mode 100644 cocoa/sizable.hpp create mode 100644 cocoa/status-bar.cpp create mode 100644 cocoa/status-bar.hpp create mode 100644 cocoa/timer.cpp create mode 100644 cocoa/timer.hpp create mode 100644 cocoa/utility.cpp create mode 100644 cocoa/widget/button.cpp create mode 100644 cocoa/widget/button.hpp create mode 100644 cocoa/widget/canvas.cpp create mode 100644 cocoa/widget/canvas.hpp create mode 100644 cocoa/widget/check-button.cpp create mode 100644 cocoa/widget/check-button.hpp create mode 100644 cocoa/widget/check-label.cpp create mode 100644 cocoa/widget/check-label.hpp create mode 100644 cocoa/widget/combo-button-item.cpp create mode 100644 cocoa/widget/combo-button-item.hpp create mode 100644 cocoa/widget/combo-button.cpp create mode 100644 cocoa/widget/combo-button.hpp create mode 100644 cocoa/widget/console.cpp create mode 100644 cocoa/widget/console.hpp create mode 100644 cocoa/widget/frame.cpp create mode 100644 cocoa/widget/frame.hpp create mode 100644 cocoa/widget/hex-edit.cpp create mode 100644 cocoa/widget/hex-edit.hpp create mode 100644 cocoa/widget/horizontal-scroll-bar.cpp create mode 100644 cocoa/widget/horizontal-scroll-bar.hpp create mode 100644 cocoa/widget/horizontal-slider.cpp create mode 100644 cocoa/widget/horizontal-slider.hpp create mode 100644 cocoa/widget/label.cpp create mode 100644 cocoa/widget/label.hpp create mode 100644 cocoa/widget/line-edit.cpp create mode 100644 cocoa/widget/line-edit.hpp create mode 100644 cocoa/widget/list-view-cell.cpp create mode 100644 cocoa/widget/list-view-cell.hpp create mode 100644 cocoa/widget/list-view-column.cpp create mode 100644 cocoa/widget/list-view-column.hpp create mode 100644 cocoa/widget/list-view-header.cpp create mode 100644 cocoa/widget/list-view-header.hpp create mode 100644 cocoa/widget/list-view-item.cpp create mode 100644 cocoa/widget/list-view-item.hpp create mode 100644 cocoa/widget/list-view.cpp create mode 100644 cocoa/widget/list-view.hpp create mode 100644 cocoa/widget/progress-bar.cpp create mode 100644 cocoa/widget/progress-bar.hpp create mode 100644 cocoa/widget/radio-button.cpp create mode 100644 cocoa/widget/radio-button.hpp create mode 100644 cocoa/widget/radio-label.cpp create mode 100644 cocoa/widget/radio-label.hpp create mode 100644 cocoa/widget/tab-frame-item.cpp create mode 100644 cocoa/widget/tab-frame-item.hpp create mode 100644 cocoa/widget/tab-frame.cpp create mode 100644 cocoa/widget/tab-frame.hpp create mode 100644 cocoa/widget/text-edit.cpp create mode 100644 cocoa/widget/text-edit.hpp create mode 100644 cocoa/widget/vertical-scroll-bar.cpp create mode 100644 cocoa/widget/vertical-scroll-bar.hpp create mode 100644 cocoa/widget/vertical-slider.cpp create mode 100644 cocoa/widget/vertical-slider.hpp create mode 100644 cocoa/widget/viewport.cpp create mode 100644 cocoa/widget/viewport.hpp create mode 100644 cocoa/widget/widget.cpp create mode 100644 cocoa/widget/widget.hpp create mode 100644 cocoa/window.cpp create mode 100644 cocoa/window.hpp create mode 100644 components.hpp create mode 100644 core/action/action.cpp create mode 100644 core/action/menu-check-item.cpp create mode 100644 core/action/menu-item.cpp create mode 100644 core/action/menu-radio-item.cpp create mode 100644 core/action/menu-separator.cpp create mode 100644 core/action/menu.cpp create mode 100644 core/alignment.cpp create mode 100644 core/application.cpp create mode 100644 core/browser-window.cpp create mode 100644 core/color.cpp create mode 100644 core/core.cpp create mode 100644 core/core.hpp create mode 100644 core/cursor.cpp create mode 100644 core/desktop.cpp create mode 100644 core/font.cpp create mode 100644 core/geometry.cpp create mode 100644 core/gradient.cpp create mode 100644 core/group.cpp create mode 100644 core/hotkey.cpp create mode 100644 core/keyboard.cpp create mode 100644 core/layout.cpp create mode 100644 core/menu-bar.cpp create mode 100644 core/message-window.cpp create mode 100644 core/monitor.cpp create mode 100644 core/mouse.cpp create mode 100644 core/object.cpp create mode 100644 core/popup-menu.cpp create mode 100644 core/position.cpp create mode 100644 core/property.cpp create mode 100644 core/shared.hpp create mode 100644 core/sizable.cpp create mode 100644 core/size.cpp create mode 100644 core/status-bar.cpp create mode 100644 core/timer.cpp create mode 100644 core/widget/button.cpp create mode 100644 core/widget/canvas.cpp create mode 100644 core/widget/check-button.cpp create mode 100644 core/widget/check-label.cpp create mode 100644 core/widget/combo-button-item.cpp create mode 100644 core/widget/combo-button.cpp create mode 100644 core/widget/console.cpp create mode 100644 core/widget/frame.cpp create mode 100644 core/widget/hex-edit.cpp create mode 100644 core/widget/horizontal-scroll-bar.cpp create mode 100644 core/widget/horizontal-slider.cpp create mode 100644 core/widget/icon-view-item.cpp create mode 100644 core/widget/icon-view.cpp create mode 100644 core/widget/label.cpp create mode 100644 core/widget/line-edit.cpp create mode 100644 core/widget/list-view-cell.cpp create mode 100644 core/widget/list-view-column.cpp create mode 100644 core/widget/list-view-header.cpp create mode 100644 core/widget/list-view-item.cpp create mode 100644 core/widget/list-view.cpp create mode 100644 core/widget/progress-bar.cpp create mode 100644 core/widget/radio-button.cpp create mode 100644 core/widget/radio-label.cpp create mode 100644 core/widget/source-edit.cpp create mode 100644 core/widget/tab-frame-item.cpp create mode 100644 core/widget/tab-frame.cpp create mode 100644 core/widget/text-edit.cpp create mode 100644 core/widget/tree-view-item.cpp create mode 100644 core/widget/tree-view.cpp create mode 100644 core/widget/vertical-scroll-bar.cpp create mode 100644 core/widget/vertical-slider.cpp create mode 100644 core/widget/viewport.cpp create mode 100644 core/widget/widget.cpp create mode 100644 core/window.cpp create mode 100644 extension/browser-dialog.cpp create mode 100644 extension/browser-dialog.hpp create mode 100644 extension/extension.cpp create mode 100644 extension/extension.hpp create mode 100644 extension/fixed-layout.cpp create mode 100644 extension/fixed-layout.hpp create mode 100644 extension/horizontal-layout.cpp create mode 100644 extension/horizontal-layout.hpp create mode 100644 extension/message-dialog.cpp create mode 100644 extension/message-dialog.hpp create mode 100644 extension/shared.hpp create mode 100644 extension/vertical-layout.cpp create mode 100644 extension/vertical-layout.hpp create mode 100644 gtk/action/action.cpp create mode 100644 gtk/action/action.hpp create mode 100644 gtk/action/menu-check-item.cpp create mode 100644 gtk/action/menu-check-item.hpp create mode 100644 gtk/action/menu-item.cpp create mode 100644 gtk/action/menu-item.hpp create mode 100644 gtk/action/menu-radio-item.cpp create mode 100644 gtk/action/menu-radio-item.hpp create mode 100644 gtk/action/menu-separator.cpp create mode 100644 gtk/action/menu-separator.hpp create mode 100644 gtk/action/menu.cpp create mode 100644 gtk/action/menu.hpp create mode 100644 gtk/application.cpp create mode 100644 gtk/application.hpp create mode 100644 gtk/browser-window.cpp create mode 100644 gtk/browser-window.hpp create mode 100644 gtk/desktop.cpp create mode 100644 gtk/desktop.hpp create mode 100644 gtk/font.cpp create mode 100644 gtk/font.hpp create mode 100644 gtk/group.cpp create mode 100644 gtk/group.hpp create mode 100644 gtk/header.hpp create mode 100644 gtk/keyboard.cpp create mode 100644 gtk/keyboard.hpp create mode 100644 gtk/layout.cpp create mode 100644 gtk/layout.hpp create mode 100644 gtk/menu-bar.cpp create mode 100644 gtk/menu-bar.hpp create mode 100644 gtk/message-window.cpp create mode 100644 gtk/message-window.hpp create mode 100644 gtk/monitor.cpp create mode 100644 gtk/monitor.hpp create mode 100644 gtk/mouse.cpp create mode 100644 gtk/mouse.hpp create mode 100644 gtk/object.cpp create mode 100644 gtk/object.hpp create mode 100644 gtk/platform.cpp create mode 100644 gtk/platform.hpp create mode 100644 gtk/popup-menu.cpp create mode 100644 gtk/popup-menu.hpp create mode 100644 gtk/settings.cpp create mode 100644 gtk/settings.hpp create mode 100644 gtk/sizable.cpp create mode 100644 gtk/sizable.hpp create mode 100644 gtk/status-bar.cpp create mode 100644 gtk/status-bar.hpp create mode 100644 gtk/timer.cpp create mode 100644 gtk/timer.hpp create mode 100644 gtk/utility.cpp create mode 100644 gtk/widget/button.cpp create mode 100644 gtk/widget/button.hpp create mode 100644 gtk/widget/canvas.cpp create mode 100644 gtk/widget/canvas.hpp create mode 100644 gtk/widget/check-button.cpp create mode 100644 gtk/widget/check-button.hpp create mode 100644 gtk/widget/check-label.cpp create mode 100644 gtk/widget/check-label.hpp create mode 100644 gtk/widget/combo-button-item.cpp create mode 100644 gtk/widget/combo-button-item.hpp create mode 100644 gtk/widget/combo-button.cpp create mode 100644 gtk/widget/combo-button.hpp create mode 100644 gtk/widget/console.cpp create mode 100644 gtk/widget/console.hpp create mode 100644 gtk/widget/frame.cpp create mode 100644 gtk/widget/frame.hpp create mode 100644 gtk/widget/hex-edit.cpp create mode 100644 gtk/widget/hex-edit.hpp create mode 100644 gtk/widget/horizontal-scroll-bar.cpp create mode 100644 gtk/widget/horizontal-scroll-bar.hpp create mode 100644 gtk/widget/horizontal-slider.cpp create mode 100644 gtk/widget/horizontal-slider.hpp create mode 100644 gtk/widget/icon-view-item.cpp create mode 100644 gtk/widget/icon-view-item.hpp create mode 100644 gtk/widget/icon-view.cpp create mode 100644 gtk/widget/icon-view.hpp create mode 100644 gtk/widget/label.cpp create mode 100644 gtk/widget/label.hpp create mode 100644 gtk/widget/line-edit.cpp create mode 100644 gtk/widget/line-edit.hpp create mode 100644 gtk/widget/list-view-cell.cpp create mode 100644 gtk/widget/list-view-cell.hpp create mode 100644 gtk/widget/list-view-column.cpp create mode 100644 gtk/widget/list-view-column.hpp create mode 100644 gtk/widget/list-view-header.cpp create mode 100644 gtk/widget/list-view-header.hpp create mode 100644 gtk/widget/list-view-item.cpp create mode 100644 gtk/widget/list-view-item.hpp create mode 100644 gtk/widget/list-view.cpp create mode 100644 gtk/widget/list-view.hpp create mode 100644 gtk/widget/progress-bar.cpp create mode 100644 gtk/widget/progress-bar.hpp create mode 100644 gtk/widget/radio-button.cpp create mode 100644 gtk/widget/radio-button.hpp create mode 100644 gtk/widget/radio-label.cpp create mode 100644 gtk/widget/radio-label.hpp create mode 100644 gtk/widget/source-edit.cpp create mode 100644 gtk/widget/source-edit.hpp create mode 100644 gtk/widget/tab-frame-item.cpp create mode 100644 gtk/widget/tab-frame-item.hpp create mode 100644 gtk/widget/tab-frame.cpp create mode 100644 gtk/widget/tab-frame.hpp create mode 100644 gtk/widget/text-edit.cpp create mode 100644 gtk/widget/text-edit.hpp create mode 100644 gtk/widget/tree-view-item.cpp create mode 100644 gtk/widget/tree-view-item.hpp create mode 100644 gtk/widget/tree-view.cpp create mode 100644 gtk/widget/tree-view.hpp create mode 100644 gtk/widget/vertical-scroll-bar.cpp create mode 100644 gtk/widget/vertical-scroll-bar.hpp create mode 100644 gtk/widget/vertical-slider.cpp create mode 100644 gtk/widget/vertical-slider.hpp create mode 100644 gtk/widget/viewport.cpp create mode 100644 gtk/widget/viewport.hpp create mode 100644 gtk/widget/widget.cpp create mode 100644 gtk/widget/widget.hpp create mode 100644 gtk/window.cpp create mode 100644 gtk/window.hpp create mode 100644 hiro.cpp create mode 100644 hiro.hpp create mode 100644 platform/windows/keyboard.hpp create mode 100644 platform/xorg/keyboard.hpp create mode 100644 qt/action/action.cpp create mode 100644 qt/action/action.hpp create mode 100644 qt/action/menu-check-item.cpp create mode 100644 qt/action/menu-check-item.hpp create mode 100644 qt/action/menu-item.cpp create mode 100644 qt/action/menu-item.hpp create mode 100644 qt/action/menu-radio-item.cpp create mode 100644 qt/action/menu-radio-item.hpp create mode 100644 qt/action/menu-separator.cpp create mode 100644 qt/action/menu-separator.hpp create mode 100644 qt/action/menu.cpp create mode 100644 qt/action/menu.hpp create mode 100644 qt/application.cpp create mode 100644 qt/application.hpp create mode 100644 qt/browser-window.cpp create mode 100644 qt/browser-window.hpp create mode 100644 qt/desktop.cpp create mode 100644 qt/desktop.hpp create mode 100644 qt/font.cpp create mode 100644 qt/font.hpp create mode 100644 qt/group.cpp create mode 100644 qt/group.hpp create mode 100644 qt/header.hpp create mode 100644 qt/keyboard.cpp create mode 100644 qt/keyboard.hpp create mode 100644 qt/layout.cpp create mode 100644 qt/layout.hpp create mode 100644 qt/menu-bar.cpp create mode 100644 qt/menu-bar.hpp create mode 100644 qt/message-window.cpp create mode 100644 qt/message-window.hpp create mode 100644 qt/monitor.cpp create mode 100644 qt/monitor.hpp create mode 100644 qt/mouse.cpp create mode 100644 qt/mouse.hpp create mode 100644 qt/object.cpp create mode 100644 qt/object.hpp create mode 100644 qt/platform.cpp create mode 100644 qt/platform.hpp create mode 100644 qt/popup-menu.cpp create mode 100644 qt/popup-menu.hpp create mode 100644 qt/qt.hpp create mode 100644 qt/qt.moc create mode 100644 qt/settings.cpp create mode 100644 qt/settings.hpp create mode 100644 qt/sizable.cpp create mode 100644 qt/sizable.hpp create mode 100644 qt/status-bar.cpp create mode 100644 qt/status-bar.hpp create mode 100644 qt/timer.cpp create mode 100644 qt/timer.hpp create mode 100644 qt/utility.cpp create mode 100644 qt/widget/button.cpp create mode 100644 qt/widget/button.hpp create mode 100644 qt/widget/canvas.cpp create mode 100644 qt/widget/canvas.hpp create mode 100644 qt/widget/check-button.cpp create mode 100644 qt/widget/check-button.hpp create mode 100644 qt/widget/check-label.cpp create mode 100644 qt/widget/check-label.hpp create mode 100644 qt/widget/combo-button-item.cpp create mode 100644 qt/widget/combo-button-item.hpp create mode 100644 qt/widget/combo-button.cpp create mode 100644 qt/widget/combo-button.hpp create mode 100644 qt/widget/console.cpp create mode 100644 qt/widget/frame.cpp create mode 100644 qt/widget/frame.hpp create mode 100644 qt/widget/hex-edit.cpp create mode 100644 qt/widget/hex-edit.hpp create mode 100644 qt/widget/horizontal-scroll-bar.cpp create mode 100644 qt/widget/horizontal-scroll-bar.hpp create mode 100644 qt/widget/horizontal-slider.cpp create mode 100644 qt/widget/horizontal-slider.hpp create mode 100644 qt/widget/icon-view.cpp create mode 100644 qt/widget/label.cpp create mode 100644 qt/widget/label.hpp create mode 100644 qt/widget/line-edit.cpp create mode 100644 qt/widget/line-edit.hpp create mode 100644 qt/widget/list-view-cell.cpp create mode 100644 qt/widget/list-view-cell.hpp create mode 100644 qt/widget/list-view-column.cpp create mode 100644 qt/widget/list-view-column.hpp create mode 100644 qt/widget/list-view-header.cpp create mode 100644 qt/widget/list-view-header.hpp create mode 100644 qt/widget/list-view-item.cpp create mode 100644 qt/widget/list-view-item.hpp create mode 100644 qt/widget/list-view.cpp create mode 100644 qt/widget/list-view.hpp create mode 100644 qt/widget/progress-bar.cpp create mode 100644 qt/widget/progress-bar.hpp create mode 100644 qt/widget/radio-button.cpp create mode 100644 qt/widget/radio-button.hpp create mode 100644 qt/widget/radio-label.cpp create mode 100644 qt/widget/radio-label.hpp create mode 100644 qt/widget/tab-frame-item.cpp create mode 100644 qt/widget/tab-frame-item.hpp create mode 100644 qt/widget/tab-frame.cpp create mode 100644 qt/widget/tab-frame.hpp create mode 100644 qt/widget/text-edit.cpp create mode 100644 qt/widget/text-edit.hpp create mode 100644 qt/widget/vertical-scroll-bar.cpp create mode 100644 qt/widget/vertical-scroll-bar.hpp create mode 100644 qt/widget/vertical-slider.cpp create mode 100644 qt/widget/vertical-slider.hpp create mode 100644 qt/widget/viewport.cpp create mode 100644 qt/widget/viewport.hpp create mode 100644 qt/widget/widget.cpp create mode 100644 qt/widget/widget.hpp create mode 100644 qt/window.cpp create mode 100644 qt/window.hpp create mode 100644 reference/action/action.cpp create mode 100644 reference/action/action.hpp create mode 100644 reference/action/check-item.cpp create mode 100644 reference/action/check-item.hpp create mode 100644 reference/action/item.cpp create mode 100644 reference/action/item.hpp create mode 100644 reference/action/menu.cpp create mode 100644 reference/action/menu.hpp create mode 100644 reference/action/radio-item.cpp create mode 100644 reference/action/radio-item.hpp create mode 100644 reference/action/separator.cpp create mode 100644 reference/action/separator.hpp create mode 100644 reference/application.cpp create mode 100644 reference/application.hpp create mode 100644 reference/browser-window.cpp create mode 100644 reference/browser-window.hpp create mode 100644 reference/desktop.cpp create mode 100644 reference/desktop.hpp create mode 100644 reference/font.cpp create mode 100644 reference/font.hpp create mode 100644 reference/header.hpp create mode 100644 reference/keyboard.cpp create mode 100644 reference/keyboard.hpp create mode 100644 reference/message-window.cpp create mode 100644 reference/message-window.hpp create mode 100644 reference/monitor.cpp create mode 100644 reference/monitor.hpp create mode 100644 reference/mouse.cpp create mode 100644 reference/mouse.hpp create mode 100644 reference/object.cpp create mode 100644 reference/object.hpp create mode 100644 reference/platform.cpp create mode 100644 reference/platform.hpp create mode 100644 reference/popup-menu.cpp create mode 100644 reference/popup-menu.hpp create mode 100644 reference/timer.cpp create mode 100644 reference/timer.hpp create mode 100644 reference/widget/button.cpp create mode 100644 reference/widget/button.hpp create mode 100644 reference/widget/canvas.cpp create mode 100644 reference/widget/canvas.hpp create mode 100644 reference/widget/check-button.cpp create mode 100644 reference/widget/check-button.hpp create mode 100644 reference/widget/check-label.cpp create mode 100644 reference/widget/check-label.hpp create mode 100644 reference/widget/combo-button.cpp create mode 100644 reference/widget/combo-button.hpp create mode 100644 reference/widget/console.cpp create mode 100644 reference/widget/console.hpp create mode 100644 reference/widget/frame.cpp create mode 100644 reference/widget/frame.hpp create mode 100644 reference/widget/hex-edit.cpp create mode 100644 reference/widget/hex-edit.hpp create mode 100644 reference/widget/horizontal-scroller.cpp create mode 100644 reference/widget/horizontal-scroller.hpp create mode 100644 reference/widget/horizontal-slider.cpp create mode 100644 reference/widget/horizontal-slider.hpp create mode 100644 reference/widget/label.cpp create mode 100644 reference/widget/label.hpp create mode 100644 reference/widget/layout.hpp create mode 100644 reference/widget/line-edit.cpp create mode 100644 reference/widget/line-edit.hpp create mode 100644 reference/widget/list-view.cpp create mode 100644 reference/widget/list-view.hpp create mode 100644 reference/widget/progress-bar.cpp create mode 100644 reference/widget/progress-bar.hpp create mode 100644 reference/widget/radio-button.cpp create mode 100644 reference/widget/radio-button.hpp create mode 100644 reference/widget/radio-label.cpp create mode 100644 reference/widget/radio-label.hpp create mode 100644 reference/widget/sizable.hpp create mode 100644 reference/widget/tab-frame.cpp create mode 100644 reference/widget/tab-frame.hpp create mode 100644 reference/widget/text-edit.cpp create mode 100644 reference/widget/text-edit.hpp create mode 100644 reference/widget/vertical-scroller.cpp create mode 100644 reference/widget/vertical-scroller.hpp create mode 100644 reference/widget/vertical-slider.cpp create mode 100644 reference/widget/vertical-slider.hpp create mode 100644 reference/widget/viewport.cpp create mode 100644 reference/widget/viewport.hpp create mode 100644 reference/widget/widget.cpp create mode 100644 reference/widget/widget.hpp create mode 100644 reference/window.cpp create mode 100644 reference/window.hpp create mode 100644 resource/GNUmakefile create mode 100644 resource/icon/action/add.png create mode 100644 resource/icon/action/attach.png create mode 100644 resource/icon/action/bookmark.png create mode 100644 resource/icon/action/full-screen.png create mode 100644 resource/icon/action/mute.png create mode 100644 resource/icon/action/new.png create mode 100644 resource/icon/action/open.png create mode 100644 resource/icon/action/properties.png create mode 100644 resource/icon/action/quit.png create mode 100644 resource/icon/action/refresh.png create mode 100644 resource/icon/action/remove.png create mode 100644 resource/icon/action/save.png create mode 100644 resource/icon/action/search.png create mode 100644 resource/icon/action/settings.png create mode 100644 resource/icon/action/stop.png create mode 100644 resource/icon/application/browser.png create mode 100644 resource/icon/application/calculator.png create mode 100644 resource/icon/application/calendar.png create mode 100644 resource/icon/application/chat.png create mode 100644 resource/icon/application/file-manager.png create mode 100644 resource/icon/application/mail.png create mode 100644 resource/icon/application/monitor.png create mode 100644 resource/icon/application/terminal.png create mode 100644 resource/icon/application/text-editor.png create mode 100644 resource/icon/device/clock.png create mode 100644 resource/icon/device/display.png create mode 100644 resource/icon/device/joypad.png create mode 100644 resource/icon/device/keyboard.png create mode 100644 resource/icon/device/microphone.png create mode 100644 resource/icon/device/mouse.png create mode 100644 resource/icon/device/network.png create mode 100644 resource/icon/device/optical.png create mode 100644 resource/icon/device/printer.png create mode 100644 resource/icon/device/speaker.png create mode 100644 resource/icon/device/storage.png create mode 100644 resource/icon/edit/clear.png create mode 100644 resource/icon/edit/copy.png create mode 100644 resource/icon/edit/cut.png create mode 100644 resource/icon/edit/delete.png create mode 100644 resource/icon/edit/find.png create mode 100644 resource/icon/edit/paste.png create mode 100644 resource/icon/edit/redo.png create mode 100644 resource/icon/edit/replace.png create mode 100644 resource/icon/edit/undo.png create mode 100644 resource/icon/emblem/archive.png create mode 100644 resource/icon/emblem/audio.png create mode 100644 resource/icon/emblem/binary.png create mode 100644 resource/icon/emblem/file.png create mode 100644 resource/icon/emblem/folder.png create mode 100644 resource/icon/emblem/font.png create mode 100644 resource/icon/emblem/image.png create mode 100644 resource/icon/emblem/markup.png create mode 100644 resource/icon/emblem/program.png create mode 100644 resource/icon/emblem/script.png create mode 100644 resource/icon/emblem/text.png create mode 100644 resource/icon/emblem/video.png create mode 100644 resource/icon/go/down.png create mode 100644 resource/icon/go/home.png create mode 100644 resource/icon/go/left.png create mode 100644 resource/icon/go/right.png create mode 100644 resource/icon/go/up.png create mode 100644 resource/icon/media/back.png create mode 100644 resource/icon/media/eject.png create mode 100644 resource/icon/media/flash.png create mode 100644 resource/icon/media/floppy.png create mode 100644 resource/icon/media/next.png create mode 100644 resource/icon/media/optical.png create mode 100644 resource/icon/media/pause.png create mode 100644 resource/icon/media/play.png create mode 100644 resource/icon/media/record.png create mode 100644 resource/icon/media/rewind.png create mode 100644 resource/icon/media/skip.png create mode 100644 resource/icon/media/stop.png create mode 100644 resource/icon/place/bookmarks.png create mode 100644 resource/icon/place/desktop.png create mode 100644 resource/icon/place/home.png create mode 100644 resource/icon/place/server.png create mode 100644 resource/icon/place/share.png create mode 100644 resource/icon/prompt/error.png create mode 100644 resource/icon/prompt/information.png create mode 100644 resource/icon/prompt/question.png create mode 100644 resource/icon/prompt/warning.png create mode 100644 resource/resource.bml create mode 100644 resource/resource.cpp create mode 100644 resource/resource.hpp create mode 100644 windows/action/action.cpp create mode 100644 windows/action/action.hpp create mode 100644 windows/action/menu-check-item.cpp create mode 100644 windows/action/menu-check-item.hpp create mode 100644 windows/action/menu-item.cpp create mode 100644 windows/action/menu-item.hpp create mode 100644 windows/action/menu-radio-item.cpp create mode 100644 windows/action/menu-radio-item.hpp create mode 100644 windows/action/menu-separator.cpp create mode 100644 windows/action/menu-separator.hpp create mode 100644 windows/action/menu.cpp create mode 100644 windows/action/menu.hpp create mode 100644 windows/application.cpp create mode 100644 windows/application.hpp create mode 100644 windows/browser-window.cpp create mode 100644 windows/browser-window.hpp create mode 100644 windows/desktop.cpp create mode 100644 windows/desktop.hpp create mode 100644 windows/font.cpp create mode 100644 windows/font.hpp create mode 100644 windows/group.cpp create mode 100644 windows/group.hpp create mode 100644 windows/header.hpp create mode 100644 windows/hiro.Manifest create mode 100644 windows/hiro.rc create mode 100644 windows/keyboard.cpp create mode 100644 windows/keyboard.hpp create mode 100644 windows/layout.cpp create mode 100644 windows/layout.hpp create mode 100644 windows/menu-bar.cpp create mode 100644 windows/menu-bar.hpp create mode 100644 windows/message-window.cpp create mode 100644 windows/message-window.hpp create mode 100644 windows/monitor.cpp create mode 100644 windows/monitor.hpp create mode 100644 windows/mouse.cpp create mode 100644 windows/mouse.hpp create mode 100644 windows/object.cpp create mode 100644 windows/object.hpp create mode 100644 windows/platform.cpp create mode 100644 windows/platform.hpp create mode 100644 windows/popup-menu.cpp create mode 100644 windows/popup-menu.hpp create mode 100644 windows/sizable.cpp create mode 100644 windows/sizable.hpp create mode 100644 windows/status-bar.cpp create mode 100644 windows/status-bar.hpp create mode 100644 windows/timer.cpp create mode 100644 windows/timer.hpp create mode 100644 windows/utility.cpp create mode 100644 windows/widget/button.cpp create mode 100644 windows/widget/button.hpp create mode 100644 windows/widget/canvas.cpp create mode 100644 windows/widget/canvas.hpp create mode 100644 windows/widget/check-button.cpp create mode 100644 windows/widget/check-button.hpp create mode 100644 windows/widget/check-label.cpp create mode 100644 windows/widget/check-label.hpp create mode 100644 windows/widget/combo-button-item.cpp create mode 100644 windows/widget/combo-button-item.hpp create mode 100644 windows/widget/combo-button.cpp create mode 100644 windows/widget/combo-button.hpp create mode 100644 windows/widget/frame.cpp create mode 100644 windows/widget/frame.hpp create mode 100644 windows/widget/hex-edit.cpp create mode 100644 windows/widget/hex-edit.hpp create mode 100644 windows/widget/horizontal-scroll-bar.cpp create mode 100644 windows/widget/horizontal-scroll-bar.hpp create mode 100644 windows/widget/horizontal-slider.cpp create mode 100644 windows/widget/horizontal-slider.hpp create mode 100644 windows/widget/label.cpp create mode 100644 windows/widget/label.hpp create mode 100644 windows/widget/line-edit.cpp create mode 100644 windows/widget/line-edit.hpp create mode 100644 windows/widget/list-view-cell.cpp create mode 100644 windows/widget/list-view-cell.hpp create mode 100644 windows/widget/list-view-column.cpp create mode 100644 windows/widget/list-view-column.hpp create mode 100644 windows/widget/list-view-header.cpp create mode 100644 windows/widget/list-view-header.hpp create mode 100644 windows/widget/list-view-item.cpp create mode 100644 windows/widget/list-view-item.hpp create mode 100644 windows/widget/list-view.cpp create mode 100644 windows/widget/list-view.hpp create mode 100644 windows/widget/progress-bar.cpp create mode 100644 windows/widget/progress-bar.hpp create mode 100644 windows/widget/radio-button.cpp create mode 100644 windows/widget/radio-button.hpp create mode 100644 windows/widget/radio-label.cpp create mode 100644 windows/widget/radio-label.hpp create mode 100644 windows/widget/tab-frame-item.cpp create mode 100644 windows/widget/tab-frame-item.hpp create mode 100644 windows/widget/tab-frame.cpp create mode 100644 windows/widget/tab-frame.hpp create mode 100644 windows/widget/text-edit.cpp create mode 100644 windows/widget/text-edit.hpp create mode 100644 windows/widget/vertical-scroll-bar.cpp create mode 100644 windows/widget/vertical-scroll-bar.hpp create mode 100644 windows/widget/vertical-slider.cpp create mode 100644 windows/widget/vertical-slider.hpp create mode 100644 windows/widget/viewport.cpp create mode 100644 windows/widget/viewport.hpp create mode 100644 windows/widget/widget.cpp create mode 100644 windows/widget/widget.hpp create mode 100644 windows/window.cpp create mode 100644 windows/window.hpp diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..ac6f28b --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,47 @@ +ifeq ($(platform),) + hiroflags = $(cppflags) $(flags) -DHIRO_REFERENCE + hirolink = +endif + +ifeq ($(platform),windows) + ifeq ($(hiro),) + hiro := windows + endif + + ifeq ($(hiro),windows) + hiroflags = $(cppflags) $(flags) -DHIRO_WINDOWS + hirolink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi + endif + + ifeq ($(hiro),gtk) + hiroflags = $(cppflags) $(flags) -DHIRO_GTK $(shell pkg-config --cflags gtk+-2.0 gtksourceview-2.0) + hirolink = $(shell pkg-config --libs gtk+-2.0 gtksourceview-2.0) + endif +endif + +ifeq ($(platform),macosx) + ifeq ($(hiro),) + hiro := cocoa + endif + + ifeq ($(hiro),cocoa) + hiroflags = $(objcppflags) $(flags) -w -DHIRO_COCOA + hirolink = -framework Cocoa -framework Carbon + endif +endif + +ifneq ($(filter $(platform),linux bsd),) + ifeq ($(hiro),) + hiro := gtk + endif + + ifeq ($(hiro),gtk) + hiroflags = $(cppflags) $(flags) -DHIRO_GTK $(shell pkg-config --cflags gtk+-2.0 gtksourceview-2.0) + hirolink = -lX11 $(shell pkg-config --libs gtk+-2.0 gtksourceview-2.0) + endif + + ifeq ($(hiro),qt) + hiroflags = $(cppflags) $(flags) -DHIRO_QT $(shell pkg-config --cflags QtCore QtGui) + hirolink = -lX11 $(shell pkg-config --libs QtCore QtGui) + endif +endif diff --git a/cocoa/action/action.cpp b/cocoa/action/action.cpp new file mode 100644 index 0000000..a71477e --- /dev/null +++ b/cocoa/action/action.cpp @@ -0,0 +1,25 @@ +#if defined(Hiro_Action) + +namespace hiro { + +auto pAction::construct() -> void { +} + +auto pAction::destruct() -> void { +} + +auto pAction::setEnabled(bool enabled) -> void { + @autoreleasepool { + [cocoaAction setEnabled:enabled]; + } +} + +auto pAction::setVisible(bool visible) -> void { + @autoreleasepool { + [cocoaAction setHidden:!visible]; + } +} + +} + +#endif diff --git a/cocoa/action/action.hpp b/cocoa/action/action.hpp new file mode 100644 index 0000000..c870bfe --- /dev/null +++ b/cocoa/action/action.hpp @@ -0,0 +1,16 @@ +#if defined(Hiro_Action) + +namespace hiro { + +struct pAction : pObject { + Declare(Action, Object) + + auto setEnabled(bool enabled) -> void override; + auto setVisible(bool visible) -> void override; + + NSMenuItem* cocoaAction = nullptr; +}; + +} + +#endif diff --git a/cocoa/action/menu-check-item.cpp b/cocoa/action/menu-check-item.cpp new file mode 100644 index 0000000..308ac53 --- /dev/null +++ b/cocoa/action/menu-check-item.cpp @@ -0,0 +1,56 @@ +#if defined(Hiro_MenuCheckItem) + +@implementation CocoaMenuCheckItem : NSMenuItem + +-(id) initWith:(hiro::mMenuCheckItem&)menuCheckItemReference { + if(self = [super initWithTitle:@"" action:@selector(activate) keyEquivalent:@""]) { + menuCheckItem = &menuCheckItemReference; + + [self setTarget:self]; + } + return self; +} + +-(void) activate { + menuCheckItem->state.checked = !menuCheckItem->state.checked; + auto state = menuCheckItem->state.checked ? NSOnState : NSOffState; + [self setState:state]; + menuCheckItem->doToggle(); +} + +@end + +namespace hiro { + +auto pMenuCheckItem::construct() -> void { + @autoreleasepool { + cocoaAction = cocoaMenuCheckItem = [[CocoaMenuCheckItem alloc] initWith:self()]; + pAction::construct(); + + setChecked(state().checked); + setText(state().text); + } +} + +auto pMenuCheckItem::destruct() -> void { + @autoreleasepool { + [cocoaAction release]; + } +} + +auto pMenuCheckItem::setChecked(bool checked) -> void { + @autoreleasepool { + auto state = checked ? NSOnState : NSOffState; + [cocoaAction setState:state]; + } +} + +auto pMenuCheckItem::setText(const string& text) -> void { + @autoreleasepool { + [cocoaAction setTitle:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/action/menu-check-item.hpp b/cocoa/action/menu-check-item.hpp new file mode 100644 index 0000000..8352821 --- /dev/null +++ b/cocoa/action/menu-check-item.hpp @@ -0,0 +1,24 @@ +#if defined(Hiro_MenuCheckItem) + +@interface CocoaMenuCheckItem : NSMenuItem { +@public + hiro::mMenuCheckItem* menuCheckItem; +} +-(id) initWith:(hiro::mMenuCheckItem&)checkItem; +-(void) activate; +@end + +namespace hiro { + +struct pMenuCheckItem : pAction { + Declare(MenuCheckItem, Action) + + auto setChecked(bool checked) -> void; + auto setText(const string& text) -> void; + + CocoaMenuCheckItem* cocoaMenuCheckItem = nullptr; +}; + +} + +#endif diff --git a/cocoa/action/menu-item.cpp b/cocoa/action/menu-item.cpp new file mode 100644 index 0000000..10335e6 --- /dev/null +++ b/cocoa/action/menu-item.cpp @@ -0,0 +1,53 @@ +#if defined(Hiro_MenuItem) + +@implementation CocoaMenuItem : NSMenuItem + +-(id) initWith:(hiro::mMenuItem&)menuItemReference { + if(self = [super initWithTitle:@"" action:@selector(activate) keyEquivalent:@""]) { + menuItem = &menuItemReference; + + [self setTarget:self]; + } + return self; +} + +-(void) activate { + menuItem->doActivate(); +} + +@end + +namespace hiro { + +auto pMenuItem::construct() -> void { + @autoreleasepool { + cocoaAction = cocoaMenuItem = [[CocoaMenuItem alloc] initWith:self()]; + pAction::construct(); + + setIcon(state().icon); + setText(state().text); + } +} + +auto pMenuItem::destruct() -> void { + @autoreleasepool { + [cocoaAction release]; + } +} + +auto pMenuItem::setIcon(const image& icon) -> void { + @autoreleasepool { + uint size = 15; //there is no API to retrieve the optimal size + [cocoaAction setImage:NSMakeImage(icon, size, size)]; + } +} + +auto pMenuItem::setText(const string& text) -> void { + @autoreleasepool { + [cocoaAction setTitle:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/action/menu-item.hpp b/cocoa/action/menu-item.hpp new file mode 100644 index 0000000..12dba02 --- /dev/null +++ b/cocoa/action/menu-item.hpp @@ -0,0 +1,24 @@ +#if defined(Hiro_MenuItem) + +@interface CocoaMenuItem : NSMenuItem { +@public + hiro::mMenuItem* menuItem; +} +-(id) initWith:(hiro::mMenuItem&)menuItem; +-(void) activate; +@end + +namespace hiro { + +struct pMenuItem : pAction { + Declare(MenuItem, Action) + + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + CocoaMenuItem* cocoaMenuItem = nullptr; +}; + +} + +#endif diff --git a/cocoa/action/menu-radio-item.cpp b/cocoa/action/menu-radio-item.cpp new file mode 100644 index 0000000..a1fa773 --- /dev/null +++ b/cocoa/action/menu-radio-item.cpp @@ -0,0 +1,68 @@ +#if defined(Hiro_MenuRadioItem) + +@implementation CocoaMenuRadioItem : NSMenuItem + +-(id) initWith:(hiro::mMenuRadioItem&)menuRadioItemReference { + if(self = [super initWithTitle:@"" action:@selector(activate) keyEquivalent:@""]) { + menuRadioItem = &menuRadioItemReference; + + [self setTarget:self]; + [self setOnStateImage:[NSImage imageNamed:@"NSMenuRadio"]]; + } + return self; +} + +-(void) activate { + menuRadioItem->setChecked(); + menuRadioItem->doActivate(); +} + +@end + +namespace hiro { + +auto pMenuRadioItem::construct() -> void { + @autoreleasepool { + cocoaAction = cocoaMenuRadioItem = [[CocoaMenuRadioItem alloc] initWith:self()]; + pAction::construct(); + + if(state().checked) setChecked(); + setText(state().text); + } +} + +auto pMenuRadioItem::destruct() -> void { + @autoreleasepool { + [cocoaAction release]; + } +} + +auto pMenuRadioItem::setChecked() -> void { + @autoreleasepool { + if(auto group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto self = object->self()) { + if(auto p = dynamic_cast(self)) { + auto state = this == p ? NSOnState : NSOffState; + [p->cocoaAction setState:state]; + } + } + } + } + } + } +} + +auto pMenuRadioItem::setGroup(sGroup group) -> void { +} + +auto pMenuRadioItem::setText(const string& text) -> void { + @autoreleasepool { + [cocoaAction setTitle:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/action/menu-radio-item.hpp b/cocoa/action/menu-radio-item.hpp new file mode 100644 index 0000000..681b79d --- /dev/null +++ b/cocoa/action/menu-radio-item.hpp @@ -0,0 +1,25 @@ +#if defined(Hiro_MenuRadioItem) + +@interface CocoaMenuRadioItem : NSMenuItem { +@public + hiro::mMenuRadioItem* menuRadioItem; +} +-(id) initWith:(hiro::mMenuRadioItem&)menuRadioItem; +-(void) activate; +@end + +namespace hiro { + +struct pMenuRadioItem : pAction { + Declare(MenuRadioItem, Action) + + auto setChecked() -> void; + auto setGroup(sGroup group) -> void; + auto setText(const string& text) -> void; + + CocoaMenuRadioItem* cocoaMenuRadioItem = nullptr; +}; + +} + +#endif diff --git a/cocoa/action/menu-separator.cpp b/cocoa/action/menu-separator.cpp new file mode 100644 index 0000000..9ecf9b8 --- /dev/null +++ b/cocoa/action/menu-separator.cpp @@ -0,0 +1,20 @@ +#if defined(Hiro_MenuSeparator) + +namespace hiro { + +auto pMenuSeparator::construct() -> void { + @autoreleasepool { + cocoaAction = cocoaSeparator = [[NSMenuItem separatorItem] retain]; + pAction::construct(); + } +} + +auto pMenuSeparator::destruct() -> void { + @autoreleasepool { + [cocoaAction release]; + } +} + +} + +#endif diff --git a/cocoa/action/menu-separator.hpp b/cocoa/action/menu-separator.hpp new file mode 100644 index 0000000..2fa46b4 --- /dev/null +++ b/cocoa/action/menu-separator.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_MenuSeparator) + +namespace hiro { + +struct pMenuSeparator : pAction { + Declare(MenuSeparator, Action) + + NSMenuItem* cocoaSeparator = nullptr; +}; + +} + +#endif diff --git a/cocoa/action/menu.cpp b/cocoa/action/menu.cpp new file mode 100644 index 0000000..7f23b19 --- /dev/null +++ b/cocoa/action/menu.cpp @@ -0,0 +1,72 @@ +#if defined(Hiro_Menu) + +@implementation CocoaMenu : NSMenuItem + +-(id) initWith:(hiro::mMenu&)menuReference { + if(self = [super initWithTitle:@"" action:nil keyEquivalent:@""]) { + menu = &menuReference; + + cocoaMenu = [[NSMenu alloc] initWithTitle:@""]; + [self setSubmenu:cocoaMenu]; + } + return self; +} + +-(NSMenu*) cocoaMenu { + return cocoaMenu; +} + +@end + +namespace hiro { + +auto pMenu::construct() -> void { + @autoreleasepool { + cocoaAction = cocoaMenu = [[CocoaMenu alloc] initWith:self()]; + pAction::construct(); + + setIcon(state().icon); + setText(state().text); + } +} + +auto pMenu::destruct() -> void { + @autoreleasepool { + [[cocoaAction cocoaMenu] release]; + [cocoaAction release]; + } +} + +auto pMenu::append(sAction action) -> void { + @autoreleasepool { + if(auto pAction = action->self()) { + [[cocoaAction cocoaMenu] addItem:pAction->cocoaAction]; + } + } +} + +auto pMenu::remove(sAction action) -> void { + @autoreleasepool { + if(auto pAction = action->self()) { + [[cocoaAction cocoaMenu] removeItem:pAction->cocoaAction]; + } + } +} + +auto pMenu::setIcon(const image& icon) -> void { + @autoreleasepool { + uint size = 15; //there is no API to retrieve the optimal size + [cocoaAction setImage:NSMakeImage(icon, size, size)]; + } +} + +auto pMenu::setText(const string& text) -> void { + @autoreleasepool { + [[cocoaAction cocoaMenu] setTitle:[NSString stringWithUTF8String:text]]; + [cocoaAction setTitle:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/action/menu.hpp b/cocoa/action/menu.hpp new file mode 100644 index 0000000..d608062 --- /dev/null +++ b/cocoa/action/menu.hpp @@ -0,0 +1,27 @@ +#if defined(Hiro_Menu) + +@interface CocoaMenu : NSMenuItem { +@public + hiro::mMenu* menu; + NSMenu* cocoaMenu; +} +-(id) initWith:(hiro::mMenu&)menu; +-(NSMenu*) cocoaMenu; +@end + +namespace hiro { + +struct pMenu : pAction { + Declare(Menu, Action) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + CocoaMenu* cocoaMenu = nullptr; +}; + +} + +#endif diff --git a/cocoa/application.cpp b/cocoa/application.cpp new file mode 100644 index 0000000..7cc054f --- /dev/null +++ b/cocoa/application.cpp @@ -0,0 +1,93 @@ +#if defined(Hiro_Application) + +@implementation CocoaDelegate : NSObject + +-(NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender { + using hiro::Application; + if(Application::state.cocoa.onQuit) Application::Cocoa::doQuit(); + else Application::quit(); + return NSTerminateCancel; +} + +-(BOOL) applicationShouldHandleReopen:(NSApplication*)application hasVisibleWindows:(BOOL)flag { + using hiro::Application; + if(Application::state.cocoa.onActivate) Application::Cocoa::doActivate(); + return NO; +} + +-(void) run:(NSTimer*)timer { + using hiro::Application; + if(Application::state.onMain) Application::doMain(); +} + +-(void) updateInDock:(NSTimer*)timer { + NSArray* windows = [NSApp windows]; + for(uint n = 0; n < [windows count]; n++) { + NSWindow* window = [windows objectAtIndex:n]; + if([window isMiniaturized]) { + [window updateInDock]; + } + } +} + +@end + +CocoaDelegate* cocoaDelegate = nullptr; + +namespace hiro { + +auto pApplication::run() -> void { +//NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:0.1667 target:cocoaDelegate selector:@selector(updateInDock:) userInfo:nil repeats:YES]; + + if(Application::state.onMain) { + NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:0.0 target:cocoaDelegate selector:@selector(run:) userInfo:nil repeats:YES]; + + //below line is needed to run application during window resize; however it has a large performance penalty on the resize smoothness + //[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode]; + } + + @autoreleasepool { + [NSApp run]; + } +} + +auto pApplication::pendingEvents() -> bool { + bool result = false; + @autoreleasepool { + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:NO]; + if(event != nil) result = true; + } + return result; +} + +auto pApplication::processEvents() -> void { + @autoreleasepool { + while(!Application::state.quit) { + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + if(event == nil) break; + [event retain]; + [NSApp sendEvent:event]; + [event release]; + } + } +} + +auto pApplication::quit() -> void { + @autoreleasepool { + [NSApp stop:nil]; + NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0]; + [NSApp postEvent:event atStart:true]; + } +} + +auto pApplication::initialize() -> void { + @autoreleasepool { + [NSApplication sharedApplication]; + cocoaDelegate = [[CocoaDelegate alloc] init]; + [NSApp setDelegate:cocoaDelegate]; + } +} + +} + +#endif diff --git a/cocoa/application.hpp b/cocoa/application.hpp new file mode 100644 index 0000000..b697311 --- /dev/null +++ b/cocoa/application.hpp @@ -0,0 +1,24 @@ +#if defined(Hiro_Application) + +@interface CocoaDelegate : NSObject { +} +-(NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender; +-(BOOL) applicationShouldHandleReopen:(NSApplication*)application hasVisibleWindows:(BOOL)flag; +-(void) run:(NSTimer*)timer; +-(void) updateInDock:(NSTimer*)timer; +@end + +namespace hiro { + +struct pApplication { + static auto run() -> void; + static auto pendingEvents() -> bool; + static auto processEvents() -> void; + static auto quit() -> void; + + static auto initialize() -> void; +}; + +} + +#endif diff --git a/cocoa/browser-window.cpp b/cocoa/browser-window.cpp new file mode 100644 index 0000000..e2e5429 --- /dev/null +++ b/cocoa/browser-window.cpp @@ -0,0 +1,73 @@ +#if defined(Hiro_BrowserWindow) + +namespace hiro { + +auto pBrowserWindow::directory(BrowserWindow::State& state) -> string { + string result; + + @autoreleasepool { + NSOpenPanel* panel = [NSOpenPanel openPanel]; + if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]]; + [panel setCanChooseDirectories:YES]; + [panel setCanChooseFiles:NO]; + if([panel runModalForDirectory:[NSString stringWithUTF8String:state.path] file:nil] == NSOKButton) { + NSArray* names = [panel filenames]; + const char* name = [[names objectAtIndex:0] UTF8String]; + if(name) result = name; + } + } + + return result; +} + +auto pBrowserWindow::open(BrowserWindow::State& state) -> string { + string result; + + @autoreleasepool { + NSMutableArray* filters = [[NSMutableArray alloc] init]; + for(auto& rule : state.filters) { + string pattern = rule.split("(", 1L)(1).rtrim(")", 1L); + if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]]; + } + NSOpenPanel* panel = [NSOpenPanel openPanel]; + if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]]; + [panel setCanChooseDirectories:NO]; + [panel setCanChooseFiles:YES]; + [panel setAllowedFileTypes:filters]; + if([panel runModalForDirectory:[NSString stringWithUTF8String:state.path] file:nil] == NSOKButton) { + NSArray* names = [panel filenames]; + const char* name = [[names objectAtIndex:0] UTF8String]; + if(name) result = name; + } + [filters release]; + } + + return result; +} + +auto pBrowserWindow::save(BrowserWindow::State& state) -> string { + string result; + + @autoreleasepool { + NSMutableArray* filters = [[NSMutableArray alloc] init]; + for(auto& rule : state.filters) { + string pattern = rule.split("(", 1L)(1).rtrim(")", 1L); + if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]]; + } + NSSavePanel* panel = [NSSavePanel savePanel]; + if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]]; + [panel setAllowedFileTypes:filters]; + if([panel runModalForDirectory:[NSString stringWithUTF8String:state.path] file:nil] == NSOKButton) { + NSArray* names = [panel filenames]; + const char* name = [[names objectAtIndex:0] UTF8String]; + if(name) result = name; + } + [filters release]; + } + + return result; +} + +} + +#endif diff --git a/cocoa/browser-window.hpp b/cocoa/browser-window.hpp new file mode 100644 index 0000000..80e561b --- /dev/null +++ b/cocoa/browser-window.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_BrowserWindow) + +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; +}; + +} + +#endif diff --git a/cocoa/desktop.cpp b/cocoa/desktop.cpp new file mode 100644 index 0000000..083c702 --- /dev/null +++ b/cocoa/desktop.cpp @@ -0,0 +1,22 @@ +#if defined(Hiro_Desktop) + +namespace hiro { + +auto pDesktop::size() -> Size { + @autoreleasepool { + NSRect primary = [[[NSScreen screens] objectAtIndex:0] frame]; + return {(int)primary.size.width, (int)primary.size.height}; + } +} + +auto pDesktop::workspace() -> Geometry { + @autoreleasepool { + auto screen = Desktop::size(); + NSRect area = [[[NSScreen screens] objectAtIndex:0] visibleFrame]; + return {(int)area.origin.x, (int)(screen.height() - area.size.height - area.origin.y), (int)area.size.width, (int)area.size.height}; + } +} + +} + +#endif diff --git a/cocoa/desktop.hpp b/cocoa/desktop.hpp new file mode 100644 index 0000000..2c179b6 --- /dev/null +++ b/cocoa/desktop.hpp @@ -0,0 +1,12 @@ +#if defined(Hiro_Desktop) + +namespace hiro { + +struct pDesktop { + static auto size() -> Size; + static auto workspace() -> Geometry; +}; + +} + +#endif diff --git a/cocoa/font.cpp b/cocoa/font.cpp new file mode 100644 index 0000000..9807189 --- /dev/null +++ b/cocoa/font.cpp @@ -0,0 +1,51 @@ +#if defined(Hiro_Font) + +namespace hiro { + +auto pFont::size(const Font& font, const string& text) -> Size { + @autoreleasepool { + if(NSFont* nsFont = create(font)) { + return size(nsFont, text); + } + } + return {0, 0}; +} + +auto pFont::size(NSFont* font, const string& text) -> Size { + @autoreleasepool { + NSString* cocoaText = [NSString stringWithUTF8String:text]; + NSDictionary* fontAttributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]; + NSSize size = [cocoaText sizeWithAttributes:fontAttributes]; + return {(int)size.width, (int)size.height}; + } +} + +auto pFont::family(const string& family) -> string { + if(family == Font::Sans ) return "Lucida Grande"; + if(family == Font::Serif) return "Georgia"; + if(family == Font::Mono ) return "Menlo"; + return "Lucida Grande"; +} + +auto pFont::create(const Font& font) -> NSFont* { + auto fontName = family(font.family()); + NSString* family = [NSString stringWithUTF8String:fontName]; + CGFloat size = (float)(font.size() ? font.size() : 8); + NSFontTraitMask traits = 0; + + if(font.bold()) traits |= NSBoldFontMask; + if(font.italic()) traits |= NSItalicFontMask; + +//note: below properties are not exposed by hiro::Font; traits are saved here for possible future use +//if(font.narrow()) traits |= NSNarrowFontMask; +//if(font.expanded()) traits |= NSExpandedFontMask; +//if(font.condensed()) traits |= NSCondensedFontMask; +//if(font.smallCaps()) traits |= NSSmallCapsFontMask; + + size *= 1.5; //scale to point sizes (for consistency with other operating systems) + return [[NSFontManager sharedFontManager] fontWithFamily:family traits:traits weight:5 size:size]; +} + +} + +#endif diff --git a/cocoa/font.hpp b/cocoa/font.hpp new file mode 100644 index 0000000..67f2596 --- /dev/null +++ b/cocoa/font.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_Font) + +namespace hiro { + +struct pFont { + static auto size(const Font& font, const string& text) -> Size; + static auto size(NSFont* font, const string& text) -> Size; + static auto family(const string& family) -> string; + static auto create(const Font& font) -> NSFont*; +}; + +} + +#endif diff --git a/cocoa/group.cpp b/cocoa/group.cpp new file mode 100644 index 0000000..cbf387f --- /dev/null +++ b/cocoa/group.cpp @@ -0,0 +1,13 @@ +#if defined(Hiro_Group) + +namespace hiro { + +auto pGroup::construct() -> void { +} + +auto pGroup::destruct() -> void { +} + +} + +#endif diff --git a/cocoa/group.hpp b/cocoa/group.hpp new file mode 100644 index 0000000..fe22c50 --- /dev/null +++ b/cocoa/group.hpp @@ -0,0 +1,11 @@ +#if defined(Hiro_Group) + +namespace hiro { + +struct pGroup : pObject { + Declare(Group, Object); +}; + +} + +#endif diff --git a/cocoa/header.hpp b/cocoa/header.hpp new file mode 100644 index 0000000..776e1d6 --- /dev/null +++ b/cocoa/header.hpp @@ -0,0 +1,6 @@ +#define decimal CocoaDecimal +#import +#import +#undef decimal + +#include diff --git a/cocoa/keyboard.cpp b/cocoa/keyboard.cpp new file mode 100644 index 0000000..46647e2 --- /dev/null +++ b/cocoa/keyboard.cpp @@ -0,0 +1,16 @@ +#if defined(Hiro_Keyboard) + +namespace hiro { + +auto pKeyboard::poll() -> vector { + vector result; + return result; +} + +auto pKeyboard::pressed(uint code) -> bool { + return false; +} + +} + +#endif diff --git a/cocoa/keyboard.hpp b/cocoa/keyboard.hpp new file mode 100644 index 0000000..e8b8d40 --- /dev/null +++ b/cocoa/keyboard.hpp @@ -0,0 +1,12 @@ +#if defined(Hiro_Keyboard) + +namespace hiro { + +struct pKeyboard { + static auto poll() -> vector; + static auto pressed(uint code) -> bool; +}; + +} + +#endif diff --git a/cocoa/layout.cpp b/cocoa/layout.cpp new file mode 100644 index 0000000..0412e00 --- /dev/null +++ b/cocoa/layout.cpp @@ -0,0 +1,33 @@ +#if defined(Hiro_Layout) + +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(auto self = sizable->self()) self->setEnabled(enabled && sizable->enabled(true)); + } +} + +auto pLayout::setFont(const Font& font) -> void { + for(auto& sizable : state().sizables) { + if(auto self = sizable->self()) self->setFont(font ? font : sizable->font(true)); + } +} + +auto pLayout::setVisible(bool visible) -> void { + for(auto& sizable : state().sizables) { + if(auto self = sizable->self()) self->setVisible(visible && sizable->visible(true)); + } +} + +} + +#endif diff --git a/cocoa/layout.hpp b/cocoa/layout.hpp new file mode 100644 index 0000000..fc2e550 --- /dev/null +++ b/cocoa/layout.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_Layout) + +namespace hiro { + +struct pLayout : pSizable { + Declare(Layout, Sizable); + + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; +}; + +} + +#endif diff --git a/cocoa/menu-bar.cpp b/cocoa/menu-bar.cpp new file mode 100644 index 0000000..bbe65b4 --- /dev/null +++ b/cocoa/menu-bar.cpp @@ -0,0 +1,40 @@ +#if defined(Hiro_MenuBar) + +namespace hiro { + +auto pMenuBar::construct() -> void { +} + +auto pMenuBar::destruct() -> void { +} + +auto pMenuBar::append(sMenu menu) -> void { + @autoreleasepool { + if(auto parent = _parent()) { + if(auto pMenu = menu->self()) { + [[parent->cocoaWindow menuBar] addItem:pMenu->cocoaAction]; + } + } + } +} + +auto pMenuBar::remove(sMenu menu) -> void { + @autoreleasepool { + if(auto parent = _parent()) { + if(auto pMenu = menu->self()) { + [[parent->cocoaWindow menuBar] removeItem:pMenu->cocoaAction]; + } + } + } +} + +auto pMenuBar::_parent() -> maybe { + if(auto parent = self().parentWindow()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/cocoa/menu-bar.hpp b/cocoa/menu-bar.hpp new file mode 100644 index 0000000..3d7c44d --- /dev/null +++ b/cocoa/menu-bar.hpp @@ -0,0 +1,16 @@ +#if defined(Hiro_MenuBar) + +namespace hiro { + +struct pMenuBar : pObject { + Declare(MenuBar, Object) + + auto append(sMenu menu) -> void; + auto remove(sMenu menu) -> void; + + auto _parent() -> maybe; +}; + +} + +#endif diff --git a/cocoa/message-window.cpp b/cocoa/message-window.cpp new file mode 100644 index 0000000..a85e0ce --- /dev/null +++ b/cocoa/message-window.cpp @@ -0,0 +1,83 @@ +#if defined(Hiro_MessageWindow) + +namespace hiro { + +enum class MessageWindowType : uint { Error, Information, Question, Warning }; + +auto MessageWindow_dialog(MessageWindow::State& state, MessageWindowType type) -> MessageWindow::Response { + @autoreleasepool { + NSAlert* alert = [[[NSAlert alloc] init] autorelease]; + if(state.title) [alert setMessageText:[NSString stringWithUTF8String:state.title]]; + [alert setInformativeText:[NSString stringWithUTF8String:state.text]]; + + switch(state.buttons) { + case MessageWindow::Buttons::Ok: + [alert addButtonWithTitle:@"Ok"]; + break; + case MessageWindow::Buttons::OkCancel: + [alert addButtonWithTitle:@"Ok"]; + [alert addButtonWithTitle:@"Cancel"]; + break; + case MessageWindow::Buttons::YesNo: + [alert addButtonWithTitle:@"Yes"]; + [alert addButtonWithTitle:@"No"]; + break; + case MessageWindow::Buttons::YesNoCancel: + [alert addButtonWithTitle:@"Yes"]; + [alert addButtonWithTitle:@"No"]; + [alert addButtonWithTitle:@"Cancel"]; + break; + } + + switch(type) { + case MessageWindowType::Error: [alert setAlertStyle:NSCriticalAlertStyle]; break; + case MessageWindowType::Information: [alert setAlertStyle:NSInformationalAlertStyle]; break; + case MessageWindowType::Question: [alert setAlertStyle:NSInformationalAlertStyle]; break; + case MessageWindowType::Warning: [alert setAlertStyle:NSWarningAlertStyle]; break; + } + + NSInteger response = [alert runModal]; + //[alert beginSheetModalForWindow:parent.p.cocoaWindow modalDelegate:self didEndSelector:@selector(...) contextInfo:nil]; + + switch(state.buttons) { + case MessageWindow::Buttons::Ok: + if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Ok; + break; + case MessageWindow::Buttons::OkCancel: + if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Ok; + if(response == NSAlertSecondButtonReturn) return MessageWindow::Response::Cancel; + break; + case MessageWindow::Buttons::YesNo: + if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Yes; + if(response == NSAlertSecondButtonReturn) return MessageWindow::Response::No; + break; + case MessageWindow::Buttons::YesNoCancel: + if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Yes; + if(response == NSAlertSecondButtonReturn) return MessageWindow::Response::No; + if(response == NSAlertThirdButtonReturn) return MessageWindow::Response::Cancel; + break; + } + } + + throw; +} + +auto pMessageWindow::error(MessageWindow::State& state) -> MessageWindow::Response { + return MessageWindow_dialog(state, MessageWindowType::Error); +} + +auto pMessageWindow::information(MessageWindow::State& state) -> MessageWindow::Response { + return MessageWindow_dialog(state, MessageWindowType::Information); +} + +auto pMessageWindow::question(MessageWindow::State& state) -> MessageWindow::Response { + return MessageWindow_dialog(state, MessageWindowType::Question); +} + +auto pMessageWindow::warning(MessageWindow::State& state) -> MessageWindow::Response { + return MessageWindow_dialog(state, MessageWindowType::Warning); +} + +} + +#endif diff --git a/cocoa/message-window.hpp b/cocoa/message-window.hpp new file mode 100644 index 0000000..b8b26af --- /dev/null +++ b/cocoa/message-window.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_MessageWindow) + +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; +}; + +} + +#endif diff --git a/cocoa/monitor.cpp b/cocoa/monitor.cpp new file mode 100644 index 0000000..f6799db --- /dev/null +++ b/cocoa/monitor.cpp @@ -0,0 +1,25 @@ +#if defined(Hiro_Monitor) + +namespace hiro { + +auto pMonitor::count() -> uint { + @autoreleasepool { + return [[NSScreen screens] count]; + } +} + +auto pMonitor::geometry(uint monitor) -> Geometry { + @autoreleasepool { + NSRect rectangle = [[[NSScreen screens] objectAtIndex:monitor] frame]; + return {(int)rectangle.origin.x, (int)rectangle.origin.y, (int)rectangle.size.width, (int)rectangle.size.height}; + } +} + +auto pMonitor::primary() -> uint { + //on OS X, the primary monitor is always the first monitor + return 0; +} + +} + +#endif diff --git a/cocoa/monitor.hpp b/cocoa/monitor.hpp new file mode 100644 index 0000000..b41ab72 --- /dev/null +++ b/cocoa/monitor.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_Monitor) + +namespace hiro { + +struct pMonitor { + static auto count() -> uint; + static auto geometry(uint monitor) -> Geometry; + static auto primary() -> uint; +}; + +} + +#endif diff --git a/cocoa/mouse.cpp b/cocoa/mouse.cpp new file mode 100644 index 0000000..5bf9f38 --- /dev/null +++ b/cocoa/mouse.cpp @@ -0,0 +1,15 @@ +#if defined(Hiro_Mouse) + +namespace hiro { + +auto pMouse::position() -> Position { + return {0, 0}; +} + +auto pMouse::pressed(Mouse::Button button) -> bool { + return false; +} + +} + +#endif diff --git a/cocoa/mouse.hpp b/cocoa/mouse.hpp new file mode 100644 index 0000000..72a5605 --- /dev/null +++ b/cocoa/mouse.hpp @@ -0,0 +1,12 @@ +#if defined(Hiro_Mouse) + +namespace hiro { + +struct pMouse { + static auto position() -> Position; + static auto pressed(Mouse::Button button) -> bool; +}; + +} + +#endif diff --git a/cocoa/object.cpp b/cocoa/object.cpp new file mode 100644 index 0000000..3c6ac44 --- /dev/null +++ b/cocoa/object.cpp @@ -0,0 +1,35 @@ +#if defined(Hiro_Object) + +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 Font& font) -> void { +} + +auto pObject::setVisible(bool visible) -> void { +} + +} + +#endif diff --git a/cocoa/object.hpp b/cocoa/object.hpp new file mode 100644 index 0000000..056ed0b --- /dev/null +++ b/cocoa/object.hpp @@ -0,0 +1,31 @@ +#if defined(Hiro_Object) + +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 Font& 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; +}; + +} + +#endif diff --git a/cocoa/platform.cpp b/cocoa/platform.cpp new file mode 100644 index 0000000..1da4474 --- /dev/null +++ b/cocoa/platform.cpp @@ -0,0 +1,60 @@ +#include "platform.hpp" +#include "utility.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 "group.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-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/list-view-header.cpp" +#include "widget/list-view-column.cpp" +#include "widget/list-view-item.cpp" +#include "widget/list-view-cell.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-button.cpp" +#include "widget/radio-label.cpp" +#include "widget/tab-frame.cpp" +#include "widget/tab-frame-item.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +#include "application.cpp" diff --git a/cocoa/platform.hpp b/cocoa/platform.hpp new file mode 100644 index 0000000..324d6c0 --- /dev/null +++ b/cocoa/platform.hpp @@ -0,0 +1,74 @@ +namespace hiro { + struct pFont; + 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 "group.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-scroll-bar.hpp" +#include "widget/horizontal-slider.hpp" +#include "widget/label.hpp" +#include "widget/line-edit.hpp" +#include "widget/list-view.hpp" +#include "widget/list-view-header.hpp" +#include "widget/list-view-column.hpp" +#include "widget/list-view-item.hpp" +#include "widget/list-view-cell.hpp" +#include "widget/progress-bar.hpp" +#include "widget/radio-button.hpp" +#include "widget/radio-label.hpp" +#include "widget/tab-frame.hpp" +#include "widget/tab-frame-item.hpp" +#include "widget/text-edit.hpp" +#include "widget/vertical-scroll-bar.hpp" +#include "widget/vertical-slider.hpp" +#include "widget/viewport.hpp" + +#undef Declare + +#include "application.hpp" diff --git a/cocoa/popup-menu.cpp b/cocoa/popup-menu.cpp new file mode 100644 index 0000000..fa8c197 --- /dev/null +++ b/cocoa/popup-menu.cpp @@ -0,0 +1,22 @@ +#if defined(Hiro_PopupMenu) + +namespace hiro { + +auto pPopupMenu::construct() -> void { +} + +auto pPopupMenu::destruct() -> void { +} + +auto pPopupMenu::append(sAction action) -> void { +} + +auto pPopupMenu::remove(sAction action) -> void { +} + +auto pPopupMenu::setVisible(bool visible) -> void { +} + +} + +#endif diff --git a/cocoa/popup-menu.hpp b/cocoa/popup-menu.hpp new file mode 100644 index 0000000..4b692ce --- /dev/null +++ b/cocoa/popup-menu.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_PopupMenu) + +namespace hiro { + +struct pPopupMenu : pObject { + Declare(PopupMenu, Object) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setVisible(bool visible) -> void; +}; + +} + +#endif diff --git a/cocoa/sizable.cpp b/cocoa/sizable.cpp new file mode 100644 index 0000000..4e793ab --- /dev/null +++ b/cocoa/sizable.cpp @@ -0,0 +1,20 @@ +#if defined(Hiro_Sizable) + +namespace hiro { + +auto pSizable::construct() -> void { +} + +auto pSizable::destruct() -> void { +} + +auto pSizable::minimumSize() const -> Size { + return {0, 0}; +} + +auto pSizable::setGeometry(Geometry geometry) -> void { +} + +} + +#endif diff --git a/cocoa/sizable.hpp b/cocoa/sizable.hpp new file mode 100644 index 0000000..5270283 --- /dev/null +++ b/cocoa/sizable.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_Sizable) + +namespace hiro { + +struct pSizable : pObject { + Declare(Sizable, Object) + + virtual auto minimumSize() const -> Size; + virtual auto setGeometry(Geometry geometry) -> void; +}; + +} + +#endif diff --git a/cocoa/status-bar.cpp b/cocoa/status-bar.cpp new file mode 100644 index 0000000..b2678df --- /dev/null +++ b/cocoa/status-bar.cpp @@ -0,0 +1,53 @@ +#if defined(Hiro_StatusBar) + +namespace hiro { + +auto pStatusBar::construct() -> void { +} + +auto pStatusBar::destruct() -> void { +} + +auto pStatusBar::setEnabled(bool enabled) -> void { + @autoreleasepool { + if(auto parent = _parent()) { + [[parent->cocoaWindow statusBar] setEnabled:enabled]; + } + } +} + +auto pStatusBar::setFont(const Font& font) -> void { + @autoreleasepool { + if(auto parent = _parent()) { + [[parent->cocoaWindow statusBar] setFont:pFont::create(font)]; + } + } +} + +auto pStatusBar::setText(const string& text) -> void { + @autoreleasepool { + if(auto parent = _parent()) { + [[parent->cocoaWindow statusBar] setStringValue:[NSString stringWithUTF8String:state().text]]; + } + } +} + +auto pStatusBar::setVisible(bool visible) -> void { + @autoreleasepool { + if(auto parent = _parent()) { + [[parent->cocoaWindow statusBar] setHidden:!visible]; + parent->setGeometry(parent->state().geometry); + } + } +} + +auto pStatusBar::_parent() -> maybe { + if(auto parent = self().parentWindow()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/cocoa/status-bar.hpp b/cocoa/status-bar.hpp new file mode 100644 index 0000000..aed5cc9 --- /dev/null +++ b/cocoa/status-bar.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_StatusBar) + +namespace hiro { + +struct pStatusBar : pObject { + Declare(StatusBar, Object) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; +}; + +} + +#endif diff --git a/cocoa/timer.cpp b/cocoa/timer.cpp new file mode 100644 index 0000000..91de054 --- /dev/null +++ b/cocoa/timer.cpp @@ -0,0 +1,67 @@ +#if defined(Hiro_Timer) + +@implementation CocoaTimer : NSObject + +-(id) initWith:(hiro::mTimer&)timerReference { + if(self = [super init]) { + timer = &timerReference; + instance = nil; + } + return self; +} + +-(NSTimer*) instance { + return instance; +} + +-(void) update { + if(instance) { + [instance invalidate]; + instance = nil; + } + if(timer->enabled()) { + instance = [NSTimer + scheduledTimerWithTimeInterval:timer->state.interval / 1000.0 + target:self selector:@selector(run:) userInfo:nil repeats:YES + ]; + } +} + +-(void) run:(NSTimer*)instance { + if(timer->enabled()) { + timer->doActivate(); + } +} + +@end + +namespace hiro { + +auto pTimer::construct() -> void { + @autoreleasepool { + cocoaTimer = [[CocoaTimer alloc] initWith:self()]; + } +} + +auto pTimer::destruct() -> void { + @autoreleasepool { + if([cocoaTimer instance]) [[cocoaTimer instance] invalidate]; + [cocoaTimer release]; + } +} + +auto pTimer::setEnabled(bool enabled) -> void { + @autoreleasepool { + [cocoaTimer update]; + } +} + +auto pTimer::setInterval(uint interval) -> void { + @autoreleasepool { + [cocoaTimer update]; + } +} + +} + +#endif diff --git a/cocoa/timer.hpp b/cocoa/timer.hpp new file mode 100644 index 0000000..d8fd337 --- /dev/null +++ b/cocoa/timer.hpp @@ -0,0 +1,27 @@ +#if defined(Hiro_Timer) + +@interface CocoaTimer : NSObject { +@public + hiro::mTimer* timer; + NSTimer* instance; +} +-(id) initWith:(hiro::mTimer&)timer; +-(NSTimer*) instance; +-(void) update; +-(void) run:(NSTimer*)instance; +@end + +namespace hiro { + +struct pTimer : pObject { + Declare(Timer, Object) + + auto setEnabled(bool enabled) -> void; + auto setInterval(uint interval) -> void; + + CocoaTimer* cocoaTimer = nullptr; +}; + +} + +#endif diff --git a/cocoa/utility.cpp b/cocoa/utility.cpp new file mode 100644 index 0000000..cc35dbd --- /dev/null +++ b/cocoa/utility.cpp @@ -0,0 +1,48 @@ +auto NSMakeColor(const hiro::Color& color) -> NSColor* { + return [NSColor colorWithRed:(color.red() / 255.0) green:(color.green() / 255.0) blue:(color.blue() / 255.0) alpha:(color.alpha() / 255.0)]; +} + +auto NSMakeImage(image icon, uint scaleWidth = 0, uint scaleHeight = 0) -> NSImage* { + if(!icon) return nil; + + if(scaleWidth && scaleHeight) icon.scale(scaleWidth, scaleHeight); + icon.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); //Cocoa stores images in ABGR format + + //create NSImage from memory + NSImage* cocoaImage = [[[NSImage alloc] initWithSize:NSMakeSize(icon.width(), icon.height())] autorelease]; + NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:nil + pixelsWide:icon.width() pixelsHigh:icon.height() + bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES + isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace + bitmapFormat:NSAlphaNonpremultipliedBitmapFormat + bytesPerRow:(4 * icon.width()) bitsPerPixel:32 + ] autorelease]; + memory::copy([bitmap bitmapData], icon.data(), 4 * icon.width() * icon.height()); + [cocoaImage addRepresentation:bitmap]; + return cocoaImage; +} + +auto DropPathsOperation(id sender) -> NSDragOperation { + NSPasteboard* pboard = [sender draggingPasteboard]; + if([[pboard types] containsObject:NSFilenamesPboardType]) { + if([sender draggingSourceOperationMask] & NSDragOperationGeneric) { + return NSDragOperationGeneric; + } + } + return NSDragOperationNone; +} + +auto DropPaths(id sender) -> lstring { + lstring paths; + NSPasteboard* pboard = [sender draggingPasteboard]; + if([[pboard types] containsObject:NSFilenamesPboardType]) { + NSArray* files = [pboard propertyListForType:NSFilenamesPboardType]; + for(uint n = 0; n < [files count]; n++) { + string path = [[files objectAtIndex:n] UTF8String]; + if(directory::exists(path) && !path.endsWith("/")) path.append("/"); + paths.append(path); + } + } + return paths; +} diff --git a/cocoa/widget/button.cpp b/cocoa/widget/button.cpp new file mode 100644 index 0000000..9b82e97 --- /dev/null +++ b/cocoa/widget/button.cpp @@ -0,0 +1,90 @@ +#if defined(Hiro_Button) + +@implementation CocoaButton : NSButton + +-(id) initWith:(hiro::mButton&)buttonReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + button = &buttonReference; + [self setTarget:self]; + [self setAction:@selector(activate:)]; + //NSRoundedBezelStyle has a fixed height; which breaks both icons and larger/smaller text + [self setBezelStyle:NSRegularSquareBezelStyle]; + } + return self; +} + +-(IBAction) activate:(id)sender { + button->doActivate(); +} + +@end + +namespace hiro { + +auto pButton::construct() -> void { + @autoreleasepool { + cocoaView = cocoaButton = [[CocoaButton alloc] initWith:self()]; + pWidget::construct(); + + setBordered(state().bordered); + setIcon(state().icon); + setOrientation(state().orientation); + setText(state().text); + } +} + +auto pButton::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +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 ? 20 : 8), size.height() + 8}; +} + +auto pButton::setBordered(bool bordered) -> void { +} + +auto pButton::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry({ + geometry.x() - 2, geometry.y() - 2, + geometry.width() + 4, geometry.height() + 4 + }); +} + +auto pButton::setIcon(const image& icon) -> void { + @autoreleasepool { + [cocoaView setImage:NSMakeImage(icon)]; + } +} + +auto pButton::setOrientation(Orientation orientation) -> void { + @autoreleasepool { + if(orientation == Orientation::Horizontal) [cocoaView setImagePosition:NSImageLeft]; + if(orientation == Orientation::Vertical ) [cocoaView setImagePosition:NSImageAbove]; + } +} + +auto pButton::setText(const string& text) -> void { + @autoreleasepool { + [cocoaView setTitle:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/widget/button.hpp b/cocoa/widget/button.hpp new file mode 100644 index 0000000..98028e8 --- /dev/null +++ b/cocoa/widget/button.hpp @@ -0,0 +1,28 @@ +#if defined(Hiro_Button) + +@interface CocoaButton : NSButton { +@public + hiro::mButton* button; +} +-(id) initWith:(hiro::mButton&)button; +-(IBAction) activate:(id)sender; +@end + +namespace hiro { + +struct pButton : pWidget { + Declare(Button, Widget) + + auto minimumSize() const -> Size override; + auto setBordered(bool bordered) -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + + CocoaButton* cocoaButton = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/canvas.cpp b/cocoa/widget/canvas.cpp new file mode 100644 index 0000000..6f2730e --- /dev/null +++ b/cocoa/widget/canvas.cpp @@ -0,0 +1,208 @@ +#if defined(Hiro_Canvas) + +@implementation CocoaCanvas : NSImageView + +-(id) initWith:(hiro::mCanvas&)canvasReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + canvas = &canvasReference; + [self setEditable:NO]; //disable image drag-and-drop functionality + NSTrackingArea* area = [[[NSTrackingArea alloc] initWithRect:[self frame] + options:NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect + owner:self userInfo:nil + ] autorelease]; + [self addTrackingArea:area]; + } + return self; +} + +-(NSDragOperation) draggingEntered:(id)sender { + return DropPathsOperation(sender); +} + +-(BOOL) performDragOperation:(id)sender { + lstring paths = DropPaths(sender); + if(paths.empty()) return NO; + canvas->doDrop(paths); + return YES; +} + +-(void) mouseButton:(NSEvent*)event down:(BOOL)isDown { + if(isDown) { + switch([event buttonNumber]) { + case 0: return canvas->doMousePress(hiro::Mouse::Button::Left); + case 1: return canvas->doMousePress(hiro::Mouse::Button::Right); + case 2: return canvas->doMousePress(hiro::Mouse::Button::Middle); + } + } else { + switch([event buttonNumber]) { + case 0: return canvas->doMouseRelease(hiro::Mouse::Button::Left); + case 1: return canvas->doMouseRelease(hiro::Mouse::Button::Right); + case 2: return canvas->doMouseRelease(hiro::Mouse::Button::Middle); + } + } +} + +-(void) mouseExited:(NSEvent*)event { + canvas->doMouseLeave(); +} + +-(void) mouseMove:(NSEvent*)event { + if([event window] == nil) return; + NSPoint location = [self convertPoint:[event locationInWindow] fromView:nil]; + canvas->doMouseMove({(int)location.x, (int)([self frame].size.height - 1 - location.y)}); +} + +-(void) mouseDown:(NSEvent*)event { + [self mouseButton:event down:YES]; +} + +-(void) mouseUp:(NSEvent*)event { + [self mouseButton:event down:NO]; +} + +-(void) mouseDragged:(NSEvent*)event { + [self mouseMove:event]; +} + +-(void) rightMouseDown:(NSEvent*)event { + [self mouseButton:event down:YES]; +} + +-(void) rightMouseUp:(NSEvent*)event { + [self mouseButton:event down:NO]; +} + +-(void) rightMouseDragged:(NSEvent*)event { + [self mouseMove:event]; +} + +-(void) otherMouseDown:(NSEvent*)event { + [self mouseButton:event down:YES]; +} + +-(void) otherMouseUp:(NSEvent*)event { + [self mouseButton:event down:NO]; +} + +-(void) otherMouseDragged:(NSEvent*)event { + [self mouseMove:event]; +} + +@end + +namespace hiro { + +auto pCanvas::construct() -> void { + @autoreleasepool { + cocoaView = cocoaCanvas = [[CocoaCanvas alloc] initWith:self()]; + pWidget::construct(); + + setDroppable(state().droppable); + } +} + +auto pCanvas::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pCanvas::minimumSize() const -> Size { + if(auto& icon = state().icon) return {(int)icon.width(), (int)icon.height()}; + return {0, 0}; +} + +auto pCanvas::setColor(Color color) -> void { + update(); +} + +auto pCanvas::setDroppable(bool droppable) -> void { + @autoreleasepool { + if(droppable) { + [cocoaCanvas registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]]; + } else { + [cocoaCanvas unregisterDraggedTypes]; + } + } +} + +auto pCanvas::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + update(); +} + +auto pCanvas::setGradient(Gradient gradient) -> void { + update(); +} + +auto pCanvas::setIcon(const image& icon) -> void { + update(); +} + +auto pCanvas::update() -> void { + _rasterize(); + @autoreleasepool { + [cocoaView setNeedsDisplay:YES]; + } +} + +auto pCanvas::_rasterize() -> void { + @autoreleasepool { + int width = 0; + int height = 0; + + if(auto& icon = state().icon) { + width = icon.width(); + height = icon.height(); + } else { + width = pSizable::state().geometry.width(); + height = pSizable::state().geometry.height(); + } + if(width <= 0 || height <= 0) return; + + if(width != surfaceWidth || height != surfaceHeight) { + [cocoaView setImage:nil]; + [surface release]; + surface = nullptr; + bitmap = nullptr; + } + + surfaceWidth = width; + surfaceHeight = height; + + if(!surface) { + surface = [[[NSImage alloc] initWithSize:NSMakeSize(width, height)] autorelease]; + bitmap = [[[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:nil + pixelsWide:width pixelsHigh:height + bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES + isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace + bitmapFormat:NSAlphaNonpremultipliedBitmapFormat + bytesPerRow:(width * 4) bitsPerPixel:32 + ] autorelease]; + [surface addRepresentation:bitmap]; + [cocoaView setImage:surface]; + } + + auto target = (uint32*)[bitmap bitmapData]; + + if(auto icon = state().icon) { + icon.transform(); + memory::copy(target, icon.data(), icon.size()); + } else if(auto& gradient = state().gradient) { + auto& colors = gradient.state.colors; + image fill; + fill.allocate(width, height); + fill.gradient(colors[0].value(), colors[1].value(), colors[2].value(), colors[3].value()); + memory::copy(target, fill.data(), fill.size()); + } else { + uint32 color = state().color.value(); + for(auto n : range(width * height)) target[n] = color; + } + } +} + +} + +#endif diff --git a/cocoa/widget/canvas.hpp b/cocoa/widget/canvas.hpp new file mode 100644 index 0000000..64f77f1 --- /dev/null +++ b/cocoa/widget/canvas.hpp @@ -0,0 +1,48 @@ +#if defined(Hiro_Canvas) + +@interface CocoaCanvas : NSImageView { +@public + hiro::mCanvas* canvas; +} +-(id) initWith:(hiro::mCanvas&)canvas; +-(NSDragOperation) draggingEntered:(id)sender; +-(BOOL) performDragOperation:(id)sender; +-(void) mouseButton:(NSEvent*)event down:(BOOL)isDown; +-(void) mouseExited:(NSEvent*)event; +-(void) mouseMove:(NSEvent*)event; +-(void) mouseDown:(NSEvent*)event; +-(void) mouseUp:(NSEvent*)event; +-(void) mouseDragged:(NSEvent*)event; +-(void) rightMouseDown:(NSEvent*)event; +-(void) rightMouseUp:(NSEvent*)event; +-(void) rightMouseDragged:(NSEvent*)event; +-(void) otherMouseDown:(NSEvent*)event; +-(void) otherMouseUp:(NSEvent*)event; +-(void) otherMouseDragged:(NSEvent*)event; +@end + +namespace hiro { + +struct pCanvas : pWidget { + Declare(Canvas, Widget) + + auto minimumSize() const -> Size; + auto setColor(Color color) -> void; + auto setDroppable(bool droppable) -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setGradient(Gradient gradient) -> void; + auto setIcon(const image& icon) -> void; + auto update() -> void; + + auto _rasterize() -> void; + + CocoaCanvas* cocoaCanvas = nullptr; + NSImage* surface = nullptr; + NSBitmapImageRep* bitmap = nullptr; + uint surfaceWidth = 0; + uint surfaceHeight = 0; +}; + +} + +#endif diff --git a/cocoa/widget/check-button.cpp b/cocoa/widget/check-button.cpp new file mode 100644 index 0000000..96a3edc --- /dev/null +++ b/cocoa/widget/check-button.cpp @@ -0,0 +1,99 @@ +#if defined(Hiro_CheckButton) + +@implementation CocoaCheckButton : NSButton + +-(id) initWith:(hiro::mCheckButton&)checkButtonReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + checkButton = &checkButtonReference; + + [self setTarget:self]; + [self setAction:@selector(activate:)]; + [self setBezelStyle:NSRegularSquareBezelStyle]; + [self setButtonType:NSOnOffButton]; + } + return self; +} + +-(IBAction) activate:(id)sender { + checkButton->state.checked = [self state] != NSOffState; + checkButton->doToggle(); +} + +@end + +namespace hiro { + +auto pCheckButton::construct() -> void { + @autoreleasepool { + cocoaView = cocoaCheckButton = [[CocoaCheckButton alloc] initWith:self()]; + pWidget::construct(); + + setBordered(state().bordered); + setChecked(state().checked); + setIcon(state().icon); + setOrientation(state().orientation); + setText(state().text); + } +} + +auto pCheckButton::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +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() + (state().text ? 20 : 8), size.height() + 8}; +} + +auto pCheckButton::setBordered(bool bordered) -> void { +} + +auto pCheckButton::setChecked(bool checked) -> void { + @autoreleasepool { + [cocoaView setState:checked ? NSOnState : NSOffState]; + } +} + +auto pCheckButton::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry({ + geometry.x() - 2, geometry.y() - 2, + geometry.width() + 4, geometry.height() + 4 + }); +} + +auto pCheckButton::setIcon(const image& icon) -> void { + @autoreleasepool { + [cocoaView setImage:NSMakeImage(icon)]; + } +} + +auto pCheckButton::setOrientation(Orientation orientation) -> void { + @autoreleasepool { + if(orientation == Orientation::Horizontal) [cocoaView setImagePosition:NSImageLeft]; + if(orientation == Orientation::Vertical ) [cocoaView setImagePosition:NSImageAbove]; + } +} + +auto pCheckButton::setText(const string& text) -> void { + @autoreleasepool { + [cocoaView setTitle:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/widget/check-button.hpp b/cocoa/widget/check-button.hpp new file mode 100644 index 0000000..6c3d478 --- /dev/null +++ b/cocoa/widget/check-button.hpp @@ -0,0 +1,29 @@ +#if defined(Hiro_CheckButton) + +@interface CocoaCheckButton : NSButton { +@public + hiro::mCheckButton* checkButton; +} +-(id) initWith:(hiro::mCheckButton&)checkButton; +-(IBAction) activate:(id)sender; +@end + +namespace hiro { + +struct pCheckButton : pWidget { + Declare(CheckButton, Widget) + + auto minimumSize() const -> Size override; + auto setBordered(bool bordered) -> void; + auto setChecked(bool checked) -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + + CocoaCheckButton* cocoaCheckButton = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/check-label.cpp b/cocoa/widget/check-label.cpp new file mode 100644 index 0000000..2810216 --- /dev/null +++ b/cocoa/widget/check-label.cpp @@ -0,0 +1,68 @@ +#if defined(Hiro_CheckLabel) + +@implementation CocoaCheckLabel : NSButton + +-(id) initWith:(hiro::mCheckLabel&)checkLabelReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + checkLabel = &checkLabelReference; + + [self setTarget:self]; + [self setAction:@selector(activate:)]; + [self setButtonType:NSSwitchButton]; + } + return self; +} + +-(IBAction) activate:(id)sender { + checkLabel->state.checked = [self state] != NSOffState; + checkLabel->doToggle(); +} + +@end + +namespace hiro { + +auto pCheckLabel::construct() -> void { + @autoreleasepool { + cocoaView = cocoaCheckLabel = [[CocoaCheckLabel alloc] initWith:self()]; + pWidget::construct(); + + setChecked(state().checked); + setText(state().text); + } +} + +auto pCheckLabel::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pCheckLabel::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + return {size.width() + 20, size.height()}; +} + +auto pCheckLabel::setChecked(bool checked) -> void { + @autoreleasepool { + [cocoaView setState:checked ? NSOnState : NSOffState]; + } +} + +auto pCheckLabel::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry({ + geometry.x() - 2, geometry.y(), + geometry.width() + 4, geometry.height() + }); +} + +auto pCheckLabel::setText(const string& text) -> void { + @autoreleasepool { + [cocoaView setTitle:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/widget/check-label.hpp b/cocoa/widget/check-label.hpp new file mode 100644 index 0000000..2f8f2d3 --- /dev/null +++ b/cocoa/widget/check-label.hpp @@ -0,0 +1,26 @@ +#if defined(Hiro_CheckLabel) + +@interface CocoaCheckLabel : NSButton { +@public + hiro::mCheckLabel* checkLabel; +} +-(id) initWith:(hiro::mCheckLabel&)checkLabel; +-(IBAction) activate:(id)sender; +@end + +namespace hiro { + +struct pCheckLabel : pWidget { + Declare(CheckLabel, Widget) + + auto minimumSize() const -> Size override; + auto setChecked(bool checked) -> void; + auto setGeometry(Geometry geometry) -> void; + auto setText(const string& text) -> void; + + CocoaCheckLabel* cocoaCheckLabel = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/combo-button-item.cpp b/cocoa/widget/combo-button-item.cpp new file mode 100644 index 0000000..881f996 --- /dev/null +++ b/cocoa/widget/combo-button-item.cpp @@ -0,0 +1,39 @@ +#if defined(Hiro_ComboButton) + +namespace hiro { + +auto pComboButtonItem::construct() -> void { +} + +auto pComboButtonItem::destruct() -> void { +} + +auto pComboButtonItem::setIcon(const image& icon) -> void { +} + +auto pComboButtonItem::setSelected() -> void { + @autoreleasepool { + if(auto parent = _parent()) { + [parent->cocoaView selectItemAtIndex:self().offset()]; + } + } +} + +auto pComboButtonItem::setText(const string& text) -> void { + @autoreleasepool { + if(auto parent = _parent()) { + [[parent->cocoaView itemAtIndex:self().offset()] setTitle:[NSString stringWithUTF8String:text]]; + } + } +} + +auto pComboButtonItem::_parent() -> maybe { + if(auto parent = self().parentComboButton()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/cocoa/widget/combo-button-item.hpp b/cocoa/widget/combo-button-item.hpp new file mode 100644 index 0000000..335e489 --- /dev/null +++ b/cocoa/widget/combo-button-item.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_ComboButton) + +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() -> maybe; +}; + +} + +#endif diff --git a/cocoa/widget/combo-button.cpp b/cocoa/widget/combo-button.cpp new file mode 100644 index 0000000..b6ac1d4 --- /dev/null +++ b/cocoa/widget/combo-button.cpp @@ -0,0 +1,81 @@ +#if defined(Hiro_ComboButton) + +@implementation CocoaComboButton : NSPopUpButton + +-(id) initWith:(hiro::mComboButton&)comboButtonReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0) pullsDown:NO]) { + comboButton = &comboButtonReference; + + [self setTarget:self]; + [self setAction:@selector(activate:)]; + } + return self; +} + +-(IBAction) activate:(id)sender { + if(auto p = comboButton->self()) p->_updateSelected([self indexOfSelectedItem]); + comboButton->doChange(); +} + +@end + +namespace hiro { + +auto pComboButton::construct() -> void { + @autoreleasepool { + cocoaView = cocoaComboButton = [[CocoaComboButton alloc] initWith:self()]; + pWidget::construct(); + } +} + +auto pComboButton::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pComboButton::append(sComboButtonItem item) -> void { + @autoreleasepool { + [cocoaView addItemWithTitle:[NSString stringWithUTF8String:item->text()]]; + } +} + +auto pComboButton::minimumSize() const -> Size { + auto font = self().font(true); + int maximumWidth = 0; + for(auto& item : state().items) { + maximumWidth = max(maximumWidth, pFont::size(font, item->state.text).width()); + } + Size size = pFont::size(font, " "); + return {maximumWidth + 36, size.height() + 6}; +} + +auto pComboButton::remove(sComboButtonItem item) -> void { + @autoreleasepool { + [cocoaView removeItemAtIndex:item->offset()]; + } +} + +auto pComboButton::reset() -> void { + @autoreleasepool { + [cocoaView removeAllItems]; + } +} + +auto pComboButton::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry({ + geometry.x() - 2, geometry.y(), + geometry.width() + 4, geometry.height() + }); +} + +auto pComboButton::_updateSelected(signed selected) -> void { + for(auto& item : state().items) { + item->state.selected = item->offset() == selected; + } +} + +} + +#endif diff --git a/cocoa/widget/combo-button.hpp b/cocoa/widget/combo-button.hpp new file mode 100644 index 0000000..042de0c --- /dev/null +++ b/cocoa/widget/combo-button.hpp @@ -0,0 +1,29 @@ +#if defined(Hiro_ComboButton) + +@interface CocoaComboButton : NSPopUpButton { +@public + hiro::mComboButton* comboButton; +} +-(id) initWith:(hiro::mComboButton&)comboButton; +-(IBAction) activate:(id)sender; +@end + +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 setGeometry(Geometry geometry) -> void override; + + auto _updateSelected(signed selected) -> void; + + CocoaComboButton* cocoaComboButton = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/console.cpp b/cocoa/widget/console.cpp new file mode 100644 index 0000000..4a5f186 --- /dev/null +++ b/cocoa/widget/console.cpp @@ -0,0 +1,46 @@ +#if defined(Hiro_Console) + +@implementation CocoaConsole : NSScrollView + +-(id) initWith:(phoenix::Console&)consoleReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + console = &consoleReference; + } + return self; +} + +@end + +namespace hiro { + +void pConsole::print(string text) { +} + +void pConsole::reset() { +} + +void pConsole::setBackgroundColor(Color color) { +} + +void pConsole::setForegroundColor(Color color) { +} + +void pConsole::setPrompt(string prompt) { +} + +void pConsole::constructor() { + @autoreleasepool { + cocoaView = cocoaConsole = [[CocoaConsole alloc] initWith:console]; + } +} + +void pConsole::destructor() { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +} + +#endif diff --git a/cocoa/widget/console.hpp b/cocoa/widget/console.hpp new file mode 100644 index 0000000..fa42a99 --- /dev/null +++ b/cocoa/widget/console.hpp @@ -0,0 +1,29 @@ +#if defined(Hiro_Console) + +@interface CocoaConsole : NSScrollView { +@public + phoenix::Console* console; +} +-(id) initWith:(phoenix::Console&)console; +@end + +namespace hiro { + +struct pConsole : public pWidget { + Console& console; + CocoaConsole* cocoaConsole = nullptr; + + 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(); +}; + +} + +#endif diff --git a/cocoa/widget/frame.cpp b/cocoa/widget/frame.cpp new file mode 100644 index 0000000..6460e1b --- /dev/null +++ b/cocoa/widget/frame.cpp @@ -0,0 +1,87 @@ +#if defined(Hiro_Frame) + +@implementation CocoaFrame : NSBox + +-(id) initWith:(hiro::mFrame&)frameReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + frame = &frameReference; + + [self setTitle:@""]; + } + return self; +} + +@end + +namespace hiro { + +auto pFrame::construct() -> void { + @autoreleasepool { + cocoaView = cocoaFrame = [[CocoaFrame alloc] initWith:self()]; + pWidget::construct(); + + setText(state().text); + } +} + +auto pFrame::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pFrame::append(sLayout layout) -> void { +} + +auto pFrame::remove(sLayout layout) -> void { +} + +auto pFrame::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + if(auto layout = _layout()) layout->setEnabled(layout->self().enabled(true)); +} + +auto pFrame::setFont(const Font& font) -> void { + @autoreleasepool { + [cocoaView setTitleFont:pFont::create(font)]; + } + if(auto layout = _layout()) layout->setFont(layout->self().font(true)); +} + +auto pFrame::setGeometry(Geometry geometry) -> void { + bool empty = !state().text; + Size size = pFont::size(self().font(true), state().text); + pWidget::setGeometry({ + geometry.x() - 3, geometry.y() - (empty ? size.height() - 2 : 1), + geometry.width() + 6, geometry.height() + (empty ? size.height() + 2 : 5) + }); + if(auto layout = state().layout) { + layout->setGeometry({ + geometry.x() + 1, geometry.y() + (empty ? 1 : size.height() - 2), + geometry.width() - 2, geometry.height() - (empty ? 1 : size.height() - 1) + }); + } +} + +auto pFrame::setText(const string& text) -> void { + @autoreleasepool { + [cocoaView setTitle:[NSString stringWithUTF8String:text]]; + } +} + +auto pFrame::setVisible(bool visible) -> void { + pWidget::setVisible(visible); + if(auto layout = _layout()) layout->setVisible(layout->self().visible(true)); +} + +auto pFrame::_layout() -> maybe { + if(auto layout = state().layout) { + if(auto self = layout->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/cocoa/widget/frame.hpp b/cocoa/widget/frame.hpp new file mode 100644 index 0000000..13335f9 --- /dev/null +++ b/cocoa/widget/frame.hpp @@ -0,0 +1,30 @@ +#if defined(Hiro_Frame) + +@interface CocoaFrame : NSBox { +@public + hiro::mFrame* frame; +} +-(id) initWith:(hiro::mFrame&)frame; +@end + +namespace hiro { + +struct pFrame : pWidget { + Declare(Frame, Widget) + + auto append(sLayout layout) -> void; + auto remove(sLayout layout) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _layout() -> maybe; + + CocoaFrame* cocoaFrame = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/hex-edit.cpp b/cocoa/widget/hex-edit.cpp new file mode 100644 index 0000000..22f772f --- /dev/null +++ b/cocoa/widget/hex-edit.cpp @@ -0,0 +1,52 @@ +#if defined(Hiro_HexEdit) + +@implementation CocoaHexEdit : NSScrollView + +-(id) initWith:(phoenix::HexEdit&)hexEditReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + hexEdit = &hexEditReference; + } + return self; +} + +@end + +namespace hiro { + +void pHexEdit::setBackgroundColor(Color color) { +} + +void pHexEdit::setColumns(unsigned columns) { +} + +void pHexEdit::setForegroundColor(Color color) { +} + +void pHexEdit::setLength(unsigned length) { +} + +void pHexEdit::setOffset(unsigned offset) { +} + +void pHexEdit::setRows(unsigned rows) { +} + +void pHexEdit::update() { +} + +void pHexEdit::constructor() { + @autoreleasepool { + cocoaView = cocoaHexEdit = [[CocoaHexEdit alloc] initWith:hexEdit]; + } +} + +void pHexEdit::destructor() { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +} + +#endif diff --git a/cocoa/widget/hex-edit.hpp b/cocoa/widget/hex-edit.hpp new file mode 100644 index 0000000..b78755e --- /dev/null +++ b/cocoa/widget/hex-edit.hpp @@ -0,0 +1,31 @@ +#if defined(Hiro_HexEdit) + +@interface CocoaHexEdit : NSScrollView { +@public + phoenix::HexEdit* hexEdit; +} +-(id) initWith:(phoenix::HexEdit&)hexEdit; +@end + +namespace hiro { + +struct pHexEdit : public pWidget { + HexEdit& hexEdit; + CocoaHexEdit* cocoaHexEdit = nullptr; + + 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(); +}; + +} + +#endif diff --git a/cocoa/widget/horizontal-scroll-bar.cpp b/cocoa/widget/horizontal-scroll-bar.cpp new file mode 100644 index 0000000..f1672f5 --- /dev/null +++ b/cocoa/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,94 @@ +#if defined(Hiro_HorizontalScrollBar) + +@implementation CocoaHorizontalScrollBar : NSScroller + +-(id) initWith:(hiro::mHorizontalScrollBar&)horizontalScrollBarReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 1, 0)]) { + horizontalScrollBar = &horizontalScrollBarReference; + + [self setTarget:self]; + [self setAction:@selector(scroll:)]; + + [self setControlSize:NSRegularControlSize]; + [self setScrollerStyle:NSScrollerStyleLegacy]; + [self setEnabled:YES]; + + [self update]; + } + return self; +} + +-(void) update { + double d = 1.0 / horizontalScrollBar->state.length; + double f = d * horizontalScrollBar->state.position; + + [self setDoubleValue:f]; + [self setKnobProportion:d]; +} + +-(IBAction) scroll:(id)sender { + auto& state = horizontalScrollBar->state; + + switch([self hitPart]) { + case NSScrollerIncrementLine: + case NSScrollerIncrementPage: + if(state.position < state.length - 1) state.position++; + [self update]; + break; + + case NSScrollerDecrementLine: + case NSScrollerDecrementPage: + if(state.position) state.position--; + [self update]; + break; + + case NSScrollerKnob: + state.position = [self doubleValue] * state.length; + break; + } + + horizontalScrollBar->doChange(); +} + +@end + +namespace hiro { + +auto pHorizontalScrollBar::construct() -> void { + @autoreleasepool { + cocoaView = cocoaHorizontalScrollBar = [[CocoaHorizontalScrollBar alloc] initWith:self()]; + pWidget::construct(); + + setLength(state().length); + setPosition(state().position); + } +} + +auto pHorizontalScrollBar::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pHorizontalScrollBar::minimumSize() const -> Size { + @autoreleasepool { + return {32, (int)[NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy]}; + } +} + +auto pHorizontalScrollBar::setLength(uint length) -> void { + @autoreleasepool { + [cocoaView update]; + } +} + +auto pHorizontalScrollBar::setPosition(uint position) -> void { + @autoreleasepool { + [cocoaView update]; + } +} + +} + +#endif diff --git a/cocoa/widget/horizontal-scroll-bar.hpp b/cocoa/widget/horizontal-scroll-bar.hpp new file mode 100644 index 0000000..b80cc64 --- /dev/null +++ b/cocoa/widget/horizontal-scroll-bar.hpp @@ -0,0 +1,26 @@ +#if defined(Hiro_HorizontalScrollBar) + +@interface CocoaHorizontalScrollBar : NSScroller { +@public + hiro::mHorizontalScrollBar* horizontalScrollBar; +} +-(id) initWith:(hiro::mHorizontalScrollBar&)horizontalScrollBar; +-(void) update; +-(IBAction) scroll:(id)sender; +@end + +namespace hiro { + +struct pHorizontalScrollBar : pWidget { + Declare(HorizontalScrollBar, Widget) + + auto minimumSize() const -> Size override; + auto setLength(uint length) -> void; + auto setPosition(uint position) -> void; + + CocoaHorizontalScrollBar* cocoaHorizontalScrollBar = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/horizontal-slider.cpp b/cocoa/widget/horizontal-slider.cpp new file mode 100644 index 0000000..7878d6f --- /dev/null +++ b/cocoa/widget/horizontal-slider.cpp @@ -0,0 +1,67 @@ +#if defined(Hiro_HorizontalSlider) + +@implementation CocoaHorizontalSlider : NSSlider + +-(id) initWith:(hiro::mHorizontalSlider&)horizontalSliderReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 1, 0)]) { + horizontalSlider = &horizontalSliderReference; + + [self setTarget:self]; + [self setAction:@selector(activate:)]; + [self setMinValue:0]; + } + return self; +} + +-(IBAction) activate:(id)sender { + horizontalSlider->state.position = [self doubleValue]; + horizontalSlider->doChange(); +} + +@end + +namespace hiro { + +auto pHorizontalSlider::construct() -> void { + @autoreleasepool { + cocoaView = cocoaHorizontalSlider = [[CocoaHorizontalSlider alloc] initWith:self()]; + pWidget::construct(); + + setLength(state().length); + setPosition(state().position); + } +} + +auto pHorizontalSlider::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pHorizontalSlider::minimumSize() const -> Size { + return {48, 20}; +} + +auto pHorizontalSlider::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry({ + geometry.x() - 2, geometry.y(), + geometry.width() + 4, geometry.height() + }); +} + +auto pHorizontalSlider::setLength(uint length) -> void { + @autoreleasepool { + [cocoaView setMaxValue:length]; + } +} + +auto pHorizontalSlider::setPosition(uint position) -> void { + @autoreleasepool { + [cocoaView setDoubleValue:position]; + } +} + +} + +#endif diff --git a/cocoa/widget/horizontal-slider.hpp b/cocoa/widget/horizontal-slider.hpp new file mode 100644 index 0000000..b8d4b0d --- /dev/null +++ b/cocoa/widget/horizontal-slider.hpp @@ -0,0 +1,26 @@ +#if defined(Hiro_HorizontalSlider) + +@interface CocoaHorizontalSlider : NSSlider { +@public + hiro::mHorizontalSlider* horizontalSlider; +} +-(id) initWith:(hiro::mHorizontalSlider&)horizontalSlider; +-(IBAction) activate:(id)sender; +@end + +namespace hiro { + +struct pHorizontalSlider : pWidget { + Declare(HorizontalSlider, Widget) + + auto minimumSize() const -> Size override; + auto setGeometry(Geometry geometry) -> void; + auto setLength(uint length) -> void; + auto setPosition(uint position) -> void; + + CocoaHorizontalSlider* cocoaHorizontalSlider = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/label.cpp b/cocoa/widget/label.cpp new file mode 100644 index 0000000..7f2ebf7 --- /dev/null +++ b/cocoa/widget/label.cpp @@ -0,0 +1,77 @@ +#if defined(Hiro_Label) + +@implementation CocoaLabel : NSTextView + +-(id) initWith:(hiro::mLabel&)labelReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + label = &labelReference; + + [self setDrawsBackground:NO]; + [self setEditable:NO]; + [self setRichText:NO]; + } + return self; +} + +@end + +namespace hiro { + +auto pLabel::construct() -> void { + @autoreleasepool { + cocoaView = cocoaLabel = [[CocoaLabel alloc] initWith:self()]; + pWidget::construct(); + + setAlignment(state().alignment); + setText(state().text); + } +} + +auto pLabel::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pLabel::minimumSize() const -> Size { + return pFont::size(self().font(true), state().text); +} + +auto pLabel::setAlignment(Alignment alignment) -> void { + @autoreleasepool { + NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + paragraphStyle.alignment = NSTextAlignmentCenter; + if(alignment.horizontal() < 0.333) paragraphStyle.alignment = NSTextAlignmentLeft; + if(alignment.horizontal() > 0.666) paragraphStyle.alignment = NSTextAlignmentRight; + [cocoaView setDefaultParagraphStyle:paragraphStyle]; + } +} + +auto pLabel::setGeometry(Geometry geometry) -> void { + //NSTextView does not support vertical text centering: + //simulate this by adjusting the geometry placement (reduce height, move view down) + uint height = pFont::size(self().font(true), state().text).height(); + auto offset = geometry; + + if(geometry.height() > height) { + uint diff = geometry.height() - height; + offset.setY(offset.y() + (diff >> 1)); + offset.setHeight(offset.height() - (diff >> 1)); + } + + pWidget::setGeometry({ + offset.x() - 6, offset.y(), + offset.width() + 12, offset.height() + }); +} + +auto pLabel::setText(const string& text) -> void { + @autoreleasepool { + [cocoaView setString:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/widget/label.hpp b/cocoa/widget/label.hpp new file mode 100644 index 0000000..56df8f4 --- /dev/null +++ b/cocoa/widget/label.hpp @@ -0,0 +1,25 @@ +#if defined(Hiro_Label) + +@interface CocoaLabel : NSTextView { +@public + hiro::mLabel* label; +} +-(id) initWith:(hiro::mLabel&)label; +@end + +namespace hiro { + +struct pLabel : pWidget { + Declare(Label, Widget) + + auto minimumSize() const -> Size override; + auto setAlignment(Alignment alignment) -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setText(const string& text) -> void; + + CocoaLabel* cocoaLabel = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/line-edit.cpp b/cocoa/widget/line-edit.cpp new file mode 100644 index 0000000..145bdfe --- /dev/null +++ b/cocoa/widget/line-edit.cpp @@ -0,0 +1,83 @@ +#if defined(Hiro_LineEdit) + +@implementation CocoaLineEdit : NSTextField + +-(id) initWith:(hiro::mLineEdit&)lineEditReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + lineEdit = &lineEditReference; + + [self setDelegate:self]; + [self setTarget:self]; + [self setAction:@selector(activate:)]; + + //prevent focus changes from generating activate event + [[self cell] setSendsActionOnEndEditing:NO]; + } + return self; +} + +-(void) textDidChange:(NSNotification*)n { + lineEdit->doChange(); +} + +-(IBAction) activate:(id)sender { + lineEdit->doActivate(); +} + +@end + +namespace hiro { + +auto pLineEdit::construct() -> void { + @autoreleasepool { + cocoaView = cocoaLineEdit = [[CocoaLineEdit alloc] initWith:self()]; + pWidget::construct(); + + setBackgroundColor(state().backgroundColor); + setEditable(state().editable); + setForegroundColor(state().foregroundColor); + setText(state().text); + } +} + +auto pLineEdit::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pLineEdit::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + return {size.width() + 10, size.height() + 8}; +} + +auto pLineEdit::setBackgroundColor(Color color) -> void { +} + +auto pLineEdit::setEditable(bool editable) -> void { + @autoreleasepool { + [cocoaView setEditable:editable]; + } +} + +auto pLineEdit::setForegroundColor(Color color) -> void { +} + +auto pLineEdit::setText(const string& text) -> void { + @autoreleasepool { + [cocoaView setStringValue:[NSString stringWithUTF8String:text]]; + } +} + +/* +auto pLineEdit::text() const -> string { + @autoreleasepool { + return [[cocoaView stringValue] UTF8String]; + } +} +*/ + +} + +#endif diff --git a/cocoa/widget/line-edit.hpp b/cocoa/widget/line-edit.hpp new file mode 100644 index 0000000..c3fec79 --- /dev/null +++ b/cocoa/widget/line-edit.hpp @@ -0,0 +1,28 @@ +#if defined(Hiro_LineEdit) + +@interface CocoaLineEdit : NSTextField { +@public + hiro::mLineEdit* lineEdit; +} +-(id) initWith:(hiro::mLineEdit&)lineEdit; +-(void) textDidChange:(NSNotification*)n; +-(IBAction) activate:(id)sender; +@end + +namespace hiro { + +struct pLineEdit : pWidget { + Declare(LineEdit, Widget) + + auto minimumSize() const -> Size override; + auto setBackgroundColor(Color color) -> void; + auto setEditable(bool editable) -> void; + auto setForegroundColor(Color color) -> void; + auto setText(const string& text) -> void; + + CocoaLineEdit* cocoaLineEdit = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/list-view-cell.cpp b/cocoa/widget/list-view-cell.cpp new file mode 100644 index 0000000..ef43ced --- /dev/null +++ b/cocoa/widget/list-view-cell.cpp @@ -0,0 +1,50 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewCell::construct() -> void { +} + +auto pListViewCell::destruct() -> void { +} + +auto pListViewCell::setAlignment(Alignment alignment) -> void { +} + +auto pListViewCell::setBackgroundColor(Color color) -> void { +} + +auto pListViewCell::setCheckable(bool checkable) -> void { +} + +auto pListViewCell::setChecked(bool checked) -> void { +} + +auto pListViewCell::setForegroundColor(Color color) -> void { +} + +auto pListViewCell::setIcon(const image& icon) -> void { +} + +auto pListViewCell::setText(const string& text) -> void { + @autoreleasepool { + if(auto pListView = _grandparent()) { + [[pListView->cocoaView content] reloadData]; + } + } +} + +auto pListViewCell::_grandparent() -> maybe { + if(auto parent = _parent()) return parent->_parent(); +} + +auto pListViewCell::_parent() -> maybe { + if(auto parent = self().parentListViewItem()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/cocoa/widget/list-view-cell.hpp b/cocoa/widget/list-view-cell.hpp new file mode 100644 index 0000000..33b33f3 --- /dev/null +++ b/cocoa/widget/list-view-cell.hpp @@ -0,0 +1,22 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewCell : pObject { + Declare(ListViewCell, Object) + + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; + auto setChecked(bool checked) -> void; + auto setForegroundColor(Color color) -> void; + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + auto _grandparent() -> maybe; + auto _parent() -> maybe; +}; + +} + +#endif diff --git a/cocoa/widget/list-view-column.cpp b/cocoa/widget/list-view-column.cpp new file mode 100644 index 0000000..a2016c1 --- /dev/null +++ b/cocoa/widget/list-view-column.cpp @@ -0,0 +1,87 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewColumn::construct() -> void { + @autoreleasepool { + if(auto listView = _grandparent()) { + [listView->cocoaView reloadColumns]; + } + } +} + +auto pListViewColumn::destruct() -> void { + @autoreleasepool { + if(auto listView = _grandparent()) { + [listView->cocoaView reloadColumns]; + } + } +} + +auto pListViewColumn::setActive() -> void { +} + +auto pListViewColumn::setAlignment(Alignment alignment) -> void { +} + +auto pListViewColumn::setBackgroundColor(Color color) -> void { +} + +auto pListViewColumn::setEditable(bool editable) -> void { +} + +auto pListViewColumn::setExpandable(bool expandable) -> void { +} + +auto pListViewColumn::setFont(const Font& font) -> void { +} + +auto pListViewColumn::setForegroundColor(Color color) -> void { +} + +auto pListViewColumn::setHorizontalAlignment(double alignment) -> void { +} + +auto pListViewColumn::setIcon(const image& icon) -> void { +} + +auto pListViewColumn::setResizable(bool resizable) -> void { +} + +auto pListViewColumn::setSortable(bool sortable) -> void { +} + +auto pListViewColumn::setText(const string& text) -> void { + @autoreleasepool { + if(auto pListView = _grandparent()) { + NSTableColumn* tableColumn = [[pListView->cocoaView content] tableColumnWithIdentifier:[[NSNumber numberWithInteger:self().offset()] stringValue]]; + [[tableColumn headerCell] setStringValue:[NSString stringWithUTF8STring:text]]; + [[pListView->cocoaView headerView] setNeedsDisplay:YES]; + } + } +} + +auto pListViewColumn::setVerticalAlignment(double alignment) -> void { +} + +auto pListViewColumn::setVisible(bool visible) -> void { +} + +auto pListViewColumn::setWidth(signed width) -> void { +} + +auto pListViewColumn::_grandparent() -> maybe { + if(auto parent = _parent()) return parent->_parent(); + return nothing; +} + +auto pListViewColumn::_parent() -> maybe { + if(auto parent = self().parentListViewHeader()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/cocoa/widget/list-view-column.hpp b/cocoa/widget/list-view-column.hpp new file mode 100644 index 0000000..59b4528 --- /dev/null +++ b/cocoa/widget/list-view-column.hpp @@ -0,0 +1,30 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewColumn : pObject { + Declare(ListViewColumn, Object) + + auto setActive() -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setEditable(bool editable) -> void; + auto setExpandable(bool expandable) -> void; + auto setFont(const Font& font) -> void override; + auto setForegroundColor(Color color) -> void; + auto setHorizontalAlignment(double) -> 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) -> void; + auto setVisible(bool visible) -> void override; + auto setWidth(signed width) -> void; + + auto _grandparent() -> maybe; + auto _parent() -> maybe; +}; + +} + +#endif diff --git a/cocoa/widget/list-view-header.cpp b/cocoa/widget/list-view-header.cpp new file mode 100644 index 0000000..2b2756a --- /dev/null +++ b/cocoa/widget/list-view-header.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewHeader::construct() -> void { +} + +auto pListViewHeader::destruct() -> void { +} + +auto pListViewHeader::append(sListViewColumn column) -> void { +} + +auto pListViewHeader::remove(sListViewColumn column) -> void { +} + +auto pListViewHeader::setVisible(bool visible) -> void { + @autoreleasepool { + if(auto pListView = _parent()) { + if(visible) { + [[pListView->cocoaView content] setHeaderView:[[[NSTableHeaderView alloc] init] autorelease]]; + } else { + [[pListView->cocoaView content] setHeaderView:nil]; + } + } + } +} + +auto pListViewHeader::_parent() -> maybe { + if(auto parent = self().parentListView()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/cocoa/widget/list-view-header.hpp b/cocoa/widget/list-view-header.hpp new file mode 100644 index 0000000..b2c1aa8 --- /dev/null +++ b/cocoa/widget/list-view-header.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewHeader : pObject { + Declare(ListViewHeader, Object) + + auto append(sListViewColumn column) -> void; + auto remove(sListViewColumn column) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; +}; + +} + +#endif diff --git a/cocoa/widget/list-view-item.cpp b/cocoa/widget/list-view-item.cpp new file mode 100644 index 0000000..0f04387 --- /dev/null +++ b/cocoa/widget/list-view-item.cpp @@ -0,0 +1,51 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewItem::construct() -> void { +} + +auto pListViewItem::destruct() -> void { +} + +auto pListViewItem::append(sListViewCell cell) -> void { + @autoreleasepool { + if(auto listView = _parent()) { + [[listView->cocoaView content] reloadData]; + } + } +} + +auto pListViewItem::remove(sListViewCell cell) -> void { + @autoreleasepool { + if(auto listView = _parent()) { + [[listView->cocoaView content] reloadData]; + } + } +} + +auto pListViewItem::setAlignment(Alignment alignment) -> void { +} + +auto pListViewItem::setBackgroundColor(Color color) -> void { +} + +auto pListViewItem::setFocused() -> void { +} + +auto pListViewItem::setForegroundColor(Color color) -> void { +} + +auto pListViewItem::setSelected(bool selected) -> void { +} + +auto pListViewItem::_parent() -> maybe { + if(auto parent = self().parentListView()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/cocoa/widget/list-view-item.hpp b/cocoa/widget/list-view-item.hpp new file mode 100644 index 0000000..c95ff09 --- /dev/null +++ b/cocoa/widget/list-view-item.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewItem : pObject { + Declare(ListViewItem, Object) + + auto append(sListViewCell cell) -> void; + auto remove(sListViewCell cell) -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setFocused() -> void; + auto setForegroundColor(Color color) -> void; + auto setSelected(bool selected) -> void; + + auto _parent() -> maybe; +}; + +} + +#endif diff --git a/cocoa/widget/list-view.cpp b/cocoa/widget/list-view.cpp new file mode 100644 index 0000000..987f549 --- /dev/null +++ b/cocoa/widget/list-view.cpp @@ -0,0 +1,455 @@ +#if defined(Hiro_ListView) + +@implementation CocoaListView : NSScrollView + +-(id) initWith:(hiro::mListView&)listViewReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + listView = &listViewReference; + content = [[CocoaListViewContent alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]; + + [self setDocumentView:content]; + [self setBorderType:NSBezelBorder]; + [self setHasVerticalScroller:YES]; + + [content setDataSource:self]; + [content setDelegate:self]; + [content setTarget:self]; + [content setDoubleAction:@selector(doubleAction:)]; + + [content setAllowsColumnReordering:NO]; + [content setAllowsColumnResizing:YES]; + [content setAllowsColumnSelection:NO]; + [content setAllowsEmptySelection:YES]; + [content setColumnAutoresizingStyle:NSTableViewLastColumnOnlyAutoresizingStyle]; + + font = nil; + [self setFont:nil]; + } + return self; +} + +-(void) dealloc { + [content release]; + [font release]; + [super dealloc]; +} + +-(CocoaListViewContent*) content { + return content; +} + +-(NSFont*) font { + return font; +} + +-(void) setFont:(NSFont*)fontPointer { + if(!fontPointer) fontPointer = [NSFont systemFontOfSize:12]; + [fontPointer retain]; + if(font) [font release]; + font = fontPointer; + + uint fontHeight = hiro::pFont::size(font, " ").height(); + [content setFont:font]; + [content setRowHeight:fontHeight]; + [self reloadColumns]; +} + +-(void) reloadColumns { + while([[content tableColumns] count]) { + [content removeTableColumn:[[content tableColumns] lastObject]]; + } + + if(auto listViewHeader = listView->state.header) { + for(auto& listViewColumn : listViewHeader->state.columns) { + auto column = listViewColumn->offset(); + + NSTableColumn* tableColumn = [[NSTableColumn alloc] initWithIdentifier:[[NSNumber numberWithInteger:column] stringValue]]; + NSTableHeaderCell* headerCell = [[NSTableHeaderCell alloc] initTextCell:[NSString stringWithUTF8String:listViewColumn->state.text]]; + CocoaListViewCell* dataCell = [[CocoaListViewCell alloc] initWith:*listView]; + + [dataCell setEditable:NO]; + + [tableColumn setResizingMask:NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask]; + [tableColumn setHeaderCell:headerCell]; + [tableColumn setDataCell:dataCell]; + + [content addTableColumn:tableColumn]; + } + } +} + +-(NSInteger) numberOfRowsInTableView:(NSTableView*)table { + return listView->state.items.size(); +} + +-(id) tableView:(NSTableView*)table objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row { + if(auto listViewItem = listView->item(row)) { + if(auto listViewCell = listViewItem->cell([[tableColumn identifier] integerValue])) { + NSString* text = [NSString stringWithUTF8String:listViewCell->state.text]; + return @{ @"text":text }; //used by type-ahead + } + } + return @{}; +} + +-(BOOL) tableView:(NSTableView*)table shouldShowCellExpansionForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row { + return NO; +} + +-(NSString*) tableView:(NSTableView*)table toolTipForCell:(NSCell*)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation { + return nil; +} + +-(void) tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row { + [cell setFont:[self font]]; +} + +-(void) tableViewSelectionDidChange:(NSNotification*)notification { + for(auto& listViewItem : listView->state.items) { + listViewItem->state.selected = listViewItem->offset() == [content selectedRow]; + } + listView->doChange(); +} + +-(IBAction) activate:(id)sender { + listView->doActivate(); +} + +-(IBAction) doubleAction:(id)sender { + if([content clickedRow] >= 0) { + [self activate:self]; + } +} + +@end + +@implementation CocoaListViewContent : NSTableView + +-(void) keyDown:(NSEvent*)event { + auto character = [[event characters] characterAtIndex:0]; + if(character == NSEnterCharacter || character == NSCarriageReturnCharacter) { + if([self selectedRow] >= 0) { + [[self delegate] activate:self]; + return; + } + } + + [super keyDown:event]; +} + +@end + +@implementation CocoaListViewCell : NSCell + +-(id) initWith:(hiro::mListView&)listViewReference { + if(self = [super initTextCell:@""]) { + listView = &listViewReference; + buttonCell = [[NSButtonCell alloc] initTextCell:@""]; + [buttonCell setButtonType:NSSwitchButton]; + [buttonCell setControlSize:NSSmallControlSize]; + [buttonCell setRefusesFirstResponder:YES]; + [buttonCell setTarget:self]; + } + return self; +} + +//used by type-ahead +-(NSString*) stringValue { + return [[self objectValue] objectForKey:@"text"]; +} + +-(void) drawWithFrame:(NSRect)frame inView:(NSView*)view { + if(auto listViewItem = listView->item([view rowAtPoint:frame.origin])) { + if(auto listViewCell = listViewItem->cell([view columnAtPoint:frame.origin])) { + NSColor* backgroundColor = nil; + if([self isHighlighted]) backgroundColor = [NSColor alternateSelectedControlColor]; + else if(!listView->enabled(true)) backgroundColor = [NSColor controlBackgroundColor]; + else if(auto color = listViewCell->state.backgroundColor) backgroundColor = NSMakeColor(color); + else backgroundColor = [NSColor controlBackgroundColor]; + + [backgroundColor set]; + [NSBezierPath fillRect:frame]; + + if(listViewCell->state.checkable) { + [buttonCell setHighlighted:YES]; + [buttonCell setState:(listViewCell->state.checked ? NSOnState : NSOffState)]; + [buttonCell drawWithFrame:frame inView:view]; + frame.origin.x += frame.size.height + 2; + frame.size.width -= frame.size.height + 2; + } + + if(listViewCell->state.icon) { + NSImage* image = NSMakeImage(listViewCell->state.icon, frame.size.height, frame.size.height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRect targetRect = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.height, frame.size.height); + NSRect sourceRect = NSMakeRect(0, 0, [image size].width, [image size].height); + [image drawInRect:targetRect fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil]; + [[NSGraphicsContext currentContext] restoreGraphicsState]; + frame.origin.x += frame.size.height + 2; + frame.size.width -= frame.size.height + 2; + } + + if(listViewCell->state.text) { + NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + paragraphStyle.alignment = NSTextAlignmentCenter; + if(listViewCell->state.alignment.horizontal() < 0.333) paragraphStyle.alignment = NSTextAlignmentLeft; + if(listViewCell->state.alignment.horizontal() > 0.666) paragraphStyle.alignment = NSTextAlignmentRight; + NSColor* foregroundColor = nil; + if([self isHighlighted]) foregroundColor = [NSColor alternateSelectedControlTextColor]; + else if(!listView->enabled(true)) foregroundColor = [NSColor disabledControlTextColor]; + else if(auto color = listViewCell->state.foregroundColor) foregroundColor = NSMakeColor(color); + else foregroundColor = [NSColor textColor]; + NSString* text = [NSString stringWithUTF8String:listViewCell->state.text]; + [text drawInRect:frame withAttributes:@{ + NSBackgroundColorAttributeName:backgroundColor, + NSForegroundColorAttributeName:foregroundColor, + NSFontAttributeName:hiro::pFont::create(listViewCell->font(true)), + NSParagraphStyleAttributeName:paragraphStyle + }]; + } + } + } +} + +//needed to trigger trackMouse events +-(NSUInteger) hitTestForEvent:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view { + NSUInteger hitTest = [super hitTestForEvent:event inRect:frame ofView:view]; + NSPoint point = [view convertPointFromBase:[event locationInWindow]]; + NSRect rect = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.height, frame.size.height); + if(NSMouseInRect(point, rect, [view isFlipped])) { + hitTest |= NSCellHitTrackableArea; + } + return hitTest; +} + +//I am unable to get startTrackingAt:, continueTracking:, stopTracking: to work +//so instead, I have to run a modal loop on events until the mouse button is released +-(BOOL) trackMouse:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view untilMouseUp:(BOOL)flag { + if([event type] == NSLeftMouseDown) { + NSWindow* window = [view window]; + NSEvent* nextEvent; + while((nextEvent = [window nextEventMatchingMask:(NSLeftMouseDragged | NSLeftMouseUp)])) { + if([nextEvent type] == NSLeftMouseUp) { + NSPoint point = [view convertPointFromBase:[nextEvent locationInWindow]]; + NSRect rect = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.height, frame.size.height); + if(NSMouseInRect(point, rect, [view isFlipped])) { + if(auto listViewItem = listView->item([view rowAtPoint:point])) { + if(auto listViewCell = listViewItem->cell([view columnAtPoint:point])) { + listViewCell->state.checked = !listViewCell->state.checked; + listView->doToggle(listViewCell->instance); + } + } + } + break; + } + } + } + return YES; +} + ++(BOOL) prefersTrackingUntilMouseUp { + return YES; +} + +@end + +namespace hiro { + +auto pListView::construct() -> void { + @autoreleasepool { + cocoaView = cocoaListView = [[CocoaListView alloc] initWith:self()]; + pWidget::construct(); + + setAlignment(state().alignment); + setBackgroundColor(state().backgroundColor); + setBatchable(state().batchable); + setBordered(state().bordered); + setFont(self().font(true)); + setForegroundColor(state().foregroundColor); + } +} + +auto pListView::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pListView::append(sListViewHeader header) -> void { + @autoreleasepool { + [cocoaView reloadColumns]; + + header->setVisible(header->visible()); + } +} + +auto pListView::append(sListViewItem item) -> void { + @autoreleasepool { + [[cocoaView content] reloadData]; + } +} + +auto pListView::remove(sListViewHeader header) -> void { + @autoreleasepool { + [cocoaView reloadColumns]; + } +} + +auto pListView::remove(sListViewItem item) -> void { + @autoreleasepool { + [[cocoaView content] reloadData]; + } +} + +auto pListView::resizeColumns() -> void { + @autoreleasepool { + if(auto& header = state().header) { + vector widths; + int minimumWidth = 0; + int expandable = 0; + for(auto column : range(header->columnCount())) { + int width = _width(column); + widths.append(width); + minimumWidth += width; + if(header->column(column).expandable()) expandable++; + } + + int maximumWidth = self().geometry().width() - 18; //include margin for vertical scroll bar + int expandWidth = 0; + if(expandable && maximumWidth > minimumWidth) { + expandWidth = (maximumWidth - minimumWidth) / expandable; + } + + for(auto column : range(header->columnCount())) { + if(auto self = header->state.columns[column]->self()) { + int width = widths[column]; + if(self->state().expandable) width += expandWidth; + NSTableColumn* tableColumn = [[cocoaView content] tableColumnWithIdentifier:[[NSNumber numberWithInteger:column] stringValue]]; + [tableColumn setWidth:width]; + } + } + } + } +} + +auto pListView::setAlignment(Alignment alignment) -> void { +} + +auto pListView::setBackgroundColor(Color color) -> void { +} + +auto pListView::setBatchable(bool batchable) -> void { + @autoreleasepool { + [[cocoaView content] setAllowsMultipleSelection:(batchable ? YES : NO)]; + } +} + +auto pListView::setBordered(bool bordered) -> void { +} + +auto pListView::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + @autoreleasepool { + [[cocoaView content] setEnabled:enabled]; + } +} + +auto pListView::setFont(const Font& font) -> void { + @autoreleasepool { + [cocoaView setFont:pFont::create(font)]; + } +} + +auto pListView::setForegroundColor(Color color) -> void { +} + +auto pListView::_cellWidth(uint row, uint column) -> uint { + uint width = 8; + if(auto pListViewItem = self().item(row)) { + if(auto pListViewCell = pListViewItem->cell(column)) { + if(pListViewCell->state.checkable) { + width += 24; + } + if(auto& icon = pListViewCell->state.icon) { + width += icon.width() + 2; + } + if(auto& text = pListViewCell->state.text) { + width += pFont::size(pListViewCell->font(true), text).width(); + } + } + } + return width; +} + +auto pListView::_columnWidth(uint column) -> uint { + uint width = 8; + if(auto& header = state().header) { + if(auto pListViewColumn = header->column(column)) { + if(auto& icon = pListViewColumn->state.icon) { + width += icon.width() + 2; + } + if(auto& text = pListViewColumn->state.text) { + width += pFont::size(pListViewColumn->font(true), text).width(); + } + } + } + return width; +} + +auto pListView::_width(uint column) -> uint { + if(auto& header = state().header) { + if(auto width = header->column(column).width()) return width; + uint width = 1; + if(!header->column(column).visible()) return width; + if(header->visible()) width = max(width, _columnWidth(column)); + for(auto row : range(state().items)) { + width = max(width, _cellWidth(row, column)); + } + return width; + } + return 1; +} + +/* +auto pListView::autoSizeColumns() -> void { + @autoreleasepool { + if(listView.state.checkable) { + NSTableColumn* tableColumn = [[cocoaView content] tableColumnWithIdentifier:@"check"]; + [tableColumn setWidth:20.0]; + } + + unsigned height = [[cocoaView content] rowHeight]; + for(unsigned column = 0; column < max(1u, listView.state.headerText.size()); column++) { + NSTableColumn* tableColumn = [[cocoaView content] tableColumnWithIdentifier:[[NSNumber numberWithInteger:column] stringValue]]; + unsigned minimumWidth = pFont::size([[tableColumn headerCell] font], listView.state.headerText(column)).width + 4; + for(unsigned row = 0; row < listView.state.text.size(); row++) { + unsigned width = pFont::size([cocoaView font], listView.state.text(row)(column)).width + 2; + if(listView.state.image(row)(height).empty() == false) width += height + 2; + if(width > minimumWidth) minimumWidth = width; + } + [tableColumn setWidth:minimumWidth]; + } + + [[cocoaView content] sizeLastColumnToFit]; + } +} + +auto pListView::setSelected(bool selected) -> void { + @autoreleasepool { + if(selected == false) { + [[cocoaView content] deselectAll:nil]; + } + } +} + +auto pListView::setSelection(unsigned selection) -> void { + @autoreleasepool { + [[cocoaView content] selectRowIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(selection, 1)] byExtendingSelection:NO]; + } +} +*/ + +} + +#endif diff --git a/cocoa/widget/list-view.hpp b/cocoa/widget/list-view.hpp new file mode 100644 index 0000000..e1f3fba --- /dev/null +++ b/cocoa/widget/list-view.hpp @@ -0,0 +1,71 @@ +#if defined(Hiro_ListView) + +@class CocoaListViewContent; + +@interface CocoaListView : NSScrollView { +@public + hiro::mListView* listView; + CocoaListViewContent* content; + NSFont* font; +} +-(id) initWith:(hiro::mListView&)listView; +-(void) dealloc; +-(CocoaListViewContent*) content; +-(NSFont*) font; +-(void) setFont:(NSFont*)font; +-(void) reloadColumns; +-(NSInteger) numberOfRowsInTableView:(NSTableView*)table; +-(id) tableView:(NSTableView*)table objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row; +-(BOOL) tableView:(NSTableView*)table shouldShowCellExpansionForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row; +-(NSString*) tableView:(NSTableView*)table toolTipForCell:(NSCell*)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation; +-(void) tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row; +-(void) tableViewSelectionDidChange:(NSNotification*)notification; +-(IBAction) activate:(id)sender; +-(IBAction) doubleAction:(id)sender; +@end + +@interface CocoaListViewContent : NSTableView { +} +-(void) keyDown:(NSEvent*)event; +@end + +@interface CocoaListViewCell : NSCell { + hiro::mListView* listView; + NSButtonCell* buttonCell; +} +-(id) initWith:(hiro::mListView&)listViewReference; +-(NSString*) stringValue; +-(void) drawWithFrame:(NSRect)frame inView:(NSView*)view; +-(NSUInteger) hitTestForEvent:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view; +-(BOOL) trackMouse:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view untilMouseUp:(BOOL)flag; ++(BOOL) prefersTrackingUntilMouseUp; +@end + +namespace hiro { + +struct pListView : pWidget { + Declare(ListView, Widget) + + auto append(sListViewHeader header) -> void; + auto append(sListViewItem item) -> void; + auto remove(sListViewHeader header) -> void; + auto remove(sListViewItem item) -> void; + auto resizeColumns() -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setBatchable(bool batchable) -> void; + auto setBordered(bool bordered) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setForegroundColor(Color color) -> void; + + auto _cellWidth(uint row, uint column) -> uint; + auto _columnWidth(uint column) -> uint; + auto _width(uint column) -> uint; + + CocoaListView* cocoaListView = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/progress-bar.cpp b/cocoa/widget/progress-bar.cpp new file mode 100644 index 0000000..4afe7ed --- /dev/null +++ b/cocoa/widget/progress-bar.cpp @@ -0,0 +1,48 @@ +#if defined(Hiro_ProgressBar) + +@implementation CocoaProgressBar : NSProgressIndicator + +-(id) initWith:(hiro::mProgressBar&)progressBarReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + progressBar = &progressBarReference; + + [self setIndeterminate:NO]; + [self setMinValue:0.0]; + [self setMaxValue:100.0]; + } + return self; +} + +@end + +namespace hiro { + +auto pProgressBar::construct() -> void { + @autoreleasepool { + cocoaView = cocoaProgressBar = [[CocoaProgressBar alloc] initWith:self()]; + pWidget::construct(); + + setPosition(state().position); + } +} + +auto pProgressBar::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pProgressBar::minimumSize() const -> Size { + return {0, 12}; +} + +auto pProgressBar::setPosition(uint position) -> void { + @autoreleasepool { + [cocoaView setDoubleValue:position]; + } +} + +} + +#endif diff --git a/cocoa/widget/progress-bar.hpp b/cocoa/widget/progress-bar.hpp new file mode 100644 index 0000000..0369156 --- /dev/null +++ b/cocoa/widget/progress-bar.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_ProgressBar) + +@interface CocoaProgressBar : NSProgressIndicator { +@public + hiro::mProgressBar* progressBar; +} +-(id) initWith:(hiro::mProgressBar&)progressBar; +@end + +namespace hiro { + +struct pProgressBar : pWidget { + Declare(ProgressBar, Widget) + + auto minimumSize() const -> Size override; + auto setPosition(uint position) -> void; + + CocoaProgressBar* cocoaProgressBar = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/radio-button.cpp b/cocoa/widget/radio-button.cpp new file mode 100644 index 0000000..e60ab37 --- /dev/null +++ b/cocoa/widget/radio-button.cpp @@ -0,0 +1,114 @@ +#if defined(Hiro_RadioButton) + +@implementation CocoaRadioButton : NSButton + +-(id) initWith:(hiro::mRadioButton&)radioButtonReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + radioButton = &radioButtonReference; + + [self setTarget:self]; + [self setAction:@selector(activate:)]; + [self setBezelStyle:NSRegularSquareBezelStyle]; + [self setButtonType:NSOnOffButton]; + } + return self; +} + +-(IBAction) activate:(id)sender { + bool wasChecked = radioButton->state.checked; + radioButton->setChecked(); + if(!wasChecked) radioButton->doActivate(); +} + +@end + +namespace hiro { + +auto pRadioButton::construct() -> void { + @autoreleasepool { + cocoaView = cocoaRadioButton = [[CocoaRadioButton alloc] initWith:self()]; + pWidget::construct(); + + setBordered(state().bordered); + if(state().checked) setChecked(); + setIcon(state().icon); + setOrientation(state().orientation); + setText(state().text); + } +} + +auto pRadioButton::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +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() + (state().text ? 20 : 8), size.height() + 8}; +} + +auto pRadioButton::setBordered(bool bordered) -> void { +} + +auto pRadioButton::setChecked() -> void { + @autoreleasepool { + if(auto group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto self = object->self()) { + if(auto p = dynamic_cast(self)) { + auto state = this == p ? NSOnState : NSOffState; + [p->cocoaView setState:state]; + } + } + } + } + } + } +} + +auto pRadioButton::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry({ + geometry.x() - 2, geometry.y() - 2, + geometry.width() + 4, geometry.height() + 4 + }); +} + +auto pRadioButton::setGroup(sGroup group) -> void { +} + +auto pRadioButton::setIcon(const image& icon) -> void { + @autoreleasepool { + [cocoaView setImage:NSMakeImage(icon)]; + } +} + +auto pRadioButton::setOrientation(Orientation orientation) -> void { + @autoreleasepool { + if(orientation == Orientation::Horizontal) [cocoaView setImagePosition:NSImageLeft]; + if(orientation == Orientation::Vertical ) [cocoaView setImagePosition:NSImageAbove]; + } +} + +auto pRadioButton::setText(const string& text) -> void { + @autoreleasepool { + [cocoaView setTitle:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/widget/radio-button.hpp b/cocoa/widget/radio-button.hpp new file mode 100644 index 0000000..30848e3 --- /dev/null +++ b/cocoa/widget/radio-button.hpp @@ -0,0 +1,30 @@ +#if defined(Hiro_RadioButton) + +@interface CocoaRadioButton : NSButton { +@public + hiro::mRadioButton* radioButton; +} +-(id) initWith:(hiro::mRadioButton&)radioButton; +-(IBAction) activate:(id)sender; +@end + +namespace hiro { + +struct pRadioButton : pWidget { + Declare(RadioButton, Widget) + + auto minimumSize() const -> Size override; + auto setBordered(bool bordered) -> void; + auto setChecked() -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setGroup(sGroup group) -> void; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + + CocoaRadioButton* cocoaRadioButton = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/radio-label.cpp b/cocoa/widget/radio-label.cpp new file mode 100644 index 0000000..aa5dd94 --- /dev/null +++ b/cocoa/widget/radio-label.cpp @@ -0,0 +1,82 @@ +#if defined(Hiro_RadioLabel) + +@implementation CocoaRadioLabel : NSButton + +-(id) initWith:(hiro::mRadioLabel&)radioLabelReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + radioLabel = &radioLabelReference; + + [self setTarget:self]; + [self setAction:@selector(activate:)]; + [self setButtonType:NSRadioButton]; + } + return self; +} + +-(IBAction) activate:(id)sender { + radioLabel->setChecked(); + radioLabel->doActivate(); +} + +@end + +namespace hiro { + +auto pRadioLabel::construct() -> void { + @autoreleasepool { + cocoaView = cocoaRadioLabel = [[CocoaRadioLabel alloc] initWith:self()]; + pWidget::construct(); + + if(state().checked) setChecked(); + setText(state().text); + } +} + +auto pRadioLabel::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pRadioLabel::minimumSize() const -> Size { + Size size = pFont::size(self().font(true), state().text); + return {size.width() + 22, size.height()}; +} + +auto pRadioLabel::setChecked() -> void { + @autoreleasepool { + if(auto group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto self = object->self()) { + if(auto p = dynamic_cast(self)) { + auto state = this == p ? NSOnState : NSOffState; + [p->cocoaView setState:state]; + } + } + } + } + } + } +} + +auto pRadioLabel::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry({ + geometry.x() - 1, geometry.y(), + geometry.width() + 2, geometry.height() + }); +} + +auto pRadioLabel::setGroup(sGroup group) -> void { +} + +auto pRadioLabel::setText(const string& text) -> void { + @autoreleasepool { + [cocoaView setTitle:[NSString stringWithUTF8String:text]]; + } +} + +} + +#endif diff --git a/cocoa/widget/radio-label.hpp b/cocoa/widget/radio-label.hpp new file mode 100644 index 0000000..c064f86 --- /dev/null +++ b/cocoa/widget/radio-label.hpp @@ -0,0 +1,27 @@ +#if defined(Hiro_RadioLabel) + +@interface CocoaRadioLabel : NSButton { +@public + hiro::mRadioLabel* radioLabel; +} +-(id) initWith:(hiro::mRadioLabel&)radioLabel; +-(IBAction) activate:(id)sender; +@end + +namespace hiro { + +struct pRadioLabel : pWidget { + Declare(RadioLabel, Widget) + + auto minimumSize() const -> Size override; + auto setChecked() -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setGroup(sGroup group) -> void; + auto setText(const string& text) -> void; + + CocoaRadioLabel* cocoaRadioLabel = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/tab-frame-item.cpp b/cocoa/widget/tab-frame-item.cpp new file mode 100644 index 0000000..96616a8 --- /dev/null +++ b/cocoa/widget/tab-frame-item.cpp @@ -0,0 +1,49 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +auto pTabFrameItem::construct() -> void { +} + +auto pTabFrameItem::destruct() -> void { +} + +auto pTabFrameItem::append(sLayout layout) -> void { +} + +auto pTabFrameItem::remove(sLayout layout) -> void { +} + +auto pTabFrameItem::setClosable(bool closable) -> void { +} + +auto pTabFrameItem::setIcon(const image& icon) -> void { +} + +auto pTabFrameItem::setMovable(bool movable) -> void { +} + +auto pTabFrameItem::setSelected() -> void { + @autoreleasepool { + if(auto parent = _parent()) { + [parent->cocoaView selectTabViewItem:cocoaTabFrameItem]; + } + } +} + +auto pTabFrameItem::setText(const string& text) -> void { + @autoreleasepool { + [cocoaTabFrameItem setLabel:[NSString stringWithUTF8String:state().text]]; + } +} + +auto pTabFrameItem::_parent() -> maybe { + if(auto parent = self().parentTabFrame()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/cocoa/widget/tab-frame-item.hpp b/cocoa/widget/tab-frame-item.hpp new file mode 100644 index 0000000..ede2333 --- /dev/null +++ b/cocoa/widget/tab-frame-item.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +struct pTabFrameItem : pObject { + Declare(TabFrameItem, Object) + + auto append(sLayout layout) -> void; + auto remove(sLayout layout) -> void; + 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; + + CocoaTabFrameItem* cocoaTabFrameItem = nullptr; + + auto _parent() -> maybe; +}; + +} + +#endif diff --git a/cocoa/widget/tab-frame.cpp b/cocoa/widget/tab-frame.cpp new file mode 100644 index 0000000..3449051 --- /dev/null +++ b/cocoa/widget/tab-frame.cpp @@ -0,0 +1,166 @@ +#if defined(Hiro_TabFrame) + +@implementation CocoaTabFrame : NSTabView + +-(id) initWith:(hiro::mTabFrame&)tabFrameReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + tabFrame = &tabFrameReference; + + [self setDelegate:self]; + } + return self; +} + +-(void) tabView:(NSTabView*)tabView didSelectTabViewItem:(NSTabViewItem*)tabViewItem { + tabFrame->self()->_synchronizeLayout(); + tabFrame->doChange(); +} + +@end + +@implementation CocoaTabFrameItem : NSTabViewItem + +-(id) initWith:(hiro::mTabFrame&)tabFrameReference { + if(self = [super initWithIdentifier:nil]) { + tabFrame = &tabFrameReference; + cocoaTabFrame = tabFrame->self()->cocoaTabFrame; + } + return self; +} + +-(NSSize) sizeOfLabel:(BOOL)shouldTruncateLabel { + NSSize sizeOfLabel = [super sizeOfLabel:shouldTruncateLabel]; + int selection = [cocoaTabFrame indexOfTabViewItem:self]; + if(selection >= 0) { + if(auto item = tabFrame->item(selection)) { + if(item->state.icon) { + uint iconSize = hiro::pFont::size(tabFrame->font(true), " ").height(); + sizeOfLabel.width += iconSize + 2; + } + } + } + return sizeOfLabel; +} + +-(void) drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)tabRect { + int selection = [cocoaTabFrame indexOfTabViewItem:self]; + if(selection >= 0) { + if(auto item = tabFrame->item(selection)) { + if(item->state.icon) { + uint iconSize = hiro::pFont::size(tabFrame->font(true), " ").height(); + NSImage* image = NSMakeImage(item->state.icon); + + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRect targetRect = NSMakeRect(tabRect.origin.x, tabRect.origin.y + 2, iconSize, iconSize); + [image drawInRect:targetRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil]; + [[NSGraphicsContext currentContext] restoreGraphicsState]; + + tabRect.origin.x += iconSize + 2; + tabRect.size.width -= iconSize + 2; + } + } + } + [super drawLabel:shouldTruncateLabel inRect:tabRect]; +} + +@end + +namespace hiro { + +auto pTabFrame::construct() -> void { + @autoreleasepool { + cocoaView = cocoaTabFrame = [[CocoaTabFrame alloc] initWith:self()]; + pWidget::construct(); + + setNavigation(state().navigation); + } +} + +auto pTabFrame::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pTabFrame::append(sTabFrameItem item) -> void { + @autoreleasepool { + if(auto p = item->self()) { + p->cocoaTabFrameItem = [[CocoaTabFrameItem alloc] initWith:self()]; + [p->cocoaTabFrameItem setLabel:[NSString stringWithUTF8String:item->state.text]]; + [cocoaView addTabViewItem:p->cocoaTabFrameItem]; + } + } +} + +auto pTabFrame::remove(sTabFrameItem item) -> void { + @autoreleasepool { + if(auto p = item->self()) { + [cocoaView removeTabViewItem:p->cocoaTabFrameItem]; + } + } +} + +auto pTabFrame::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + for(auto& item : state().items) { + if(auto& layout = item->state.layout) { + if(auto self = layout->self()) self->setEnabled(layout->enabled(true)); + } + } +} + +auto pTabFrame::setFont(const Font& font) -> void { + pWidget::setFont(font); + for(auto& item : state().items) { + if(auto& layout = item->state.layout) { + if(auto self = layout->self()) self->setFont(layout->font(true)); + } + } +} + +auto pTabFrame::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry({ + geometry.x() - 7, geometry.y() - 5, + geometry.width() + 14, geometry.height() + 6 + }); + geometry.setGeometry({ + geometry.x() + 1, geometry.y() + 22, + geometry.width() - 2, geometry.height() - 32 + }); + for(auto& item : state().items) { + if(auto& layout = item->state.layout) { + layout->setGeometry(geometry); + } + } + _synchronizeLayout(); +} + +auto pTabFrame::setNavigation(Navigation navigation) -> void { +} + +auto pTabFrame::setVisible(bool visible) -> void { + pWidget::setVisible(visible); + for(auto& item : state().items) { + if(auto& layout = item->state.layout) { + if(auto self = layout->self()) self->setVisible(layout->visible(true)); + } + } +} + +auto pTabFrame::_synchronizeLayout() -> void { + @autoreleasepool { + NSTabViewItem* tabViewItem = [cocoaView selectedTabViewItem]; + int selected = tabViewItem ? [cocoaView indexOfTabViewItem:tabViewItem] : -1; + for(auto& item : state().items) { + item->state.selected = item->offset() == selected; + if(auto& layout = item->state.layout) { + if(auto self = layout->self()) self->setVisible(layout->visible(true) && item->selected()); + } + } + } +} + +} + +#endif diff --git a/cocoa/widget/tab-frame.hpp b/cocoa/widget/tab-frame.hpp new file mode 100644 index 0000000..531e056 --- /dev/null +++ b/cocoa/widget/tab-frame.hpp @@ -0,0 +1,42 @@ +#if defined(Hiro_TabFrame) + +@interface CocoaTabFrame : NSTabView { +@public + hiro::mTabFrame* tabFrame; +} +-(id) initWith:(hiro::mTabFrame&)tabFrame; +-(void) tabView:(NSTabView*)tabView didSelectTabViewItem:(NSTabViewItem*)tabViewItem; +@end + +@interface CocoaTabFrameItem : NSTabViewItem { +@public + hiro::mTabFrame* tabFrame; + CocoaTabFrame* cocoaTabFrame; +} +-(id) initWith:(hiro::mTabFrame&)tabFrame; +-(NSSize) sizeOfLabel:(BOOL)shouldTruncateLabel; +-(void) drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)tabRect; +@end + +namespace hiro { + +struct pTabFrame : pWidget { + Declare(TabFrame, Widget) + + auto append(sTabFrameItem item) -> void; + auto remove(sTabFrameItem item) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setNavigation(Navigation navigation) -> void; + auto setVisible(bool visible) -> void override; + + auto _synchronizeLayout() -> void; + + CocoaTabFrame* cocoaTabFrame = nullptr; + vector tabs; +}; + +} + +#endif diff --git a/cocoa/widget/text-edit.cpp b/cocoa/widget/text-edit.cpp new file mode 100644 index 0000000..3b18ed5 --- /dev/null +++ b/cocoa/widget/text-edit.cpp @@ -0,0 +1,119 @@ +#if defined(Hiro_TextEdit) + +@implementation CocoaTextEdit : NSScrollView + +-(id) initWith:(hiro::mTextEdit&)textEditReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + textEdit = &textEditReference; + + content = [[[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease]; + [content setDelegate:self]; + [content setRichText:NO]; + + [self setBorderType:NSBezelBorder]; + [self setDocumentView:content]; + [self configure]; + } + return self; +} + +-(NSTextView*) content { + return content; +} + +-(void) configure { + [content setMinSize:NSMakeSize(0, 0)]; + [content setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; + + [[content textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)]; + [[content textContainer] setWidthTracksTextView:textEdit->wordWrap()]; + + [content setHorizontallyResizable:YES]; + [content setVerticallyResizable:YES]; + [content setAutoresizingMask:NSViewNotSizable]; + + [self setHasHorizontalScroller:!textEdit->wordWrap()]; + [self setHasVerticalScroller:YES]; +} + +-(void) textDidChange:(NSNotification*)notification { + textEdit->state.text = [[content string] UTF8String]; + textEdit->doChange(); +} + +@end + +namespace hiro { + +auto pTextEdit::construct() -> void { + @autoreleasepool { + cocoaView = cocoaTextEdit = [[CocoaTextEdit alloc] initWith:self()]; + pWidget::construct(); + + setEditable(state().editable); + setWordWrap(state().wordWrap); + setText(state().text); + setCursor(state().cursor); + } +} + +auto pTextEdit::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pTextEdit::setBackgroundColor(Color color) -> void { +} + +auto pTextEdit::setCursor(Cursor cursor) -> void { + @autoreleasepool { + //todo: handle text selection (cursor.length()) + string text = [[[cocoaView content] string] UTF8String]; + auto offset = min(cursor.offset(), text.length()); + [[cocoaView content] setSelectedRange:NSMakeRange(offset, 0)]; + } +} + +auto pTextEdit::setEditable(bool editable) -> void { + @autoreleasepool { + [[cocoaView content] setEditable:(editable && self().enabled(true))]; + } +} + +auto pTextEdit::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + setEditable(state().editable); //Cocoa lacks NSTextView::setEnabled; simulate via setEnabled() +} + +auto pTextEdit::setFont(const Font& font) -> void { + @autoreleasepool { + [[cocoaView content] setFont:pFont::create(font)]; + } +} + +auto pTextEdit::setForegroundColor(Color color) -> void { +} + +auto pTextEdit::setText(const string& text) -> void { + @autoreleasepool { + [[cocoaView content] setString:[NSString stringWithUTF8String:text]]; + } +} + +auto pTextEdit::setWordWrap(bool wordWrap) -> void { + @autoreleasepool { + [cocoaView configure]; + } +} + +auto pTextEdit::text() const -> string { + @autoreleasepool { + return [[[cocoaView content] string] UTF8String]; + } +} + +} + +#endif diff --git a/cocoa/widget/text-edit.hpp b/cocoa/widget/text-edit.hpp new file mode 100644 index 0000000..745784e --- /dev/null +++ b/cocoa/widget/text-edit.hpp @@ -0,0 +1,34 @@ +#if defined(Hiro_TextEdit) + +@interface CocoaTextEdit : NSScrollView { +@public + hiro::mTextEdit* textEdit; + NSTextView* content; +} +-(id) initWith:(hiro::mTextEdit&)textEdit; +-(NSTextView*) content; +-(void) configure; +-(void) textDidChange:(NSNotification*)notification; +@end + +namespace hiro { + +struct pTextEdit : pWidget { + Declare(TextEdit, Widget) + + auto setBackgroundColor(Color color) -> void; + auto setCursor(Cursor cursor) -> void; + auto setEditable(bool editable) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setForegroundColor(Color color) -> void; + auto setText(const string& text) -> void; + auto setWordWrap(bool wordWrap) -> void; + auto text() const -> string; + + CocoaTextEdit* cocoaTextEdit = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/vertical-scroll-bar.cpp b/cocoa/widget/vertical-scroll-bar.cpp new file mode 100644 index 0000000..db8bc41 --- /dev/null +++ b/cocoa/widget/vertical-scroll-bar.cpp @@ -0,0 +1,94 @@ +#if defined(Hiro_VerticalScrollBar) + +@implementation CocoaVerticalScrollBar : NSScroller + +-(id) initWith:(hiro::mVerticalScrollBar&)verticalScrollBarReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 1)]) { + verticalScrollBar = &verticalScrollBarReference; + + [self setTarget:self]; + [self setAction:@selector(scroll:)]; + + [self setControlSize:NSRegularControlSize]; + [self setScrollerStyle:NSScrollerStyleLegacy]; + [self setEnabled:YES]; + + [self update]; + } + return self; +} + +-(void) update { + double d = 1.0 / verticalScrollBar->state.length; + double f = d * verticalScrollBar->state.position; + + [self setDoubleValue:f]; + [self setKnobProportion:d]; +} + +-(IBAction) scroll:(id)sender { + auto& state = verticalScrollBar->state; + + switch([self hitPart]) { + case NSScrollerIncrementLine: + case NSScrollerIncrementPage: + if(state.position < state.length - 1) state.position++; + [self update]; + break; + + case NSScrollerDecrementLine: + case NSScrollerDecrementPage: + if(state.position) state.position--; + [self update]; + break; + + case NSScrollerKnob: + state.position = [self doubleValue] * state.length; + break; + } + + verticalScrollBar->doChange(); +} + +@end + +namespace hiro { + +auto pVerticalScrollBar::construct() -> void { + @autoreleasepool { + cocoaView = cocoaVerticalScrollBar = [[CocoaVerticalScrollBar alloc] initWith:self()]; + pWidget::construct(); + + setLength(state().length); + setPosition(state().position); + } +} + +auto pVerticalScrollBar::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pVerticalScrollBar::minimumSize() const -> Size { + @autoreleasepool { + return {(int)[NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy], 32}; + } +} + +auto pVerticalScrollBar::setLength(uint length) -> void { + @autoreleasepool { + [cocoaView update]; + } +} + +auto pVerticalScrollBar::setPosition(uint position) -> void { + @autoreleasepool { + [cocoaView update]; + } +} + +} + +#endif diff --git a/cocoa/widget/vertical-scroll-bar.hpp b/cocoa/widget/vertical-scroll-bar.hpp new file mode 100644 index 0000000..22e232b --- /dev/null +++ b/cocoa/widget/vertical-scroll-bar.hpp @@ -0,0 +1,26 @@ +#if defined(Hiro_VerticalScrollBar) + +@interface CocoaVerticalScrollBar : NSScroller { +@public + hiro::mVerticalScrollBar* verticalScrollBar; +} +-(id) initWith:(hiro::mVerticalScrollBar&)verticalScrollBar; +-(void) update; +-(IBAction) scroll:(id)sender; +@end + +namespace hiro { + +struct pVerticalScrollBar : pWidget { + Declare(VerticalScrollBar, Widget) + + auto minimumSize() const -> Size override; + auto setLength(uint length) -> void; + auto setPosition(uint position) -> void; + + CocoaVerticalScrollBar* cocoaVerticalScrollBar = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/vertical-slider.cpp b/cocoa/widget/vertical-slider.cpp new file mode 100644 index 0000000..12cd401 --- /dev/null +++ b/cocoa/widget/vertical-slider.cpp @@ -0,0 +1,67 @@ +#if defined(Hiro_VerticalSlider) + +@implementation CocoaVerticalSlider : NSSlider + +-(id) initWith:(hiro::mVerticalSlider&)verticalSliderReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 1)]) { + verticalSlider = &verticalSliderReference; + + [self setTarget:self]; + [self setAction:@selector(activate:)]; + [self setMinValue:0]; + } + return self; +} + +-(IBAction) activate:(id)sender { + verticalSlider->state.position = [self doubleValue]; + verticalSlider->doChange(); +} + +@end + +namespace hiro { + +auto pVerticalSlider::construct() -> void { + @autoreleasepool { + cocoaView = cocoaVerticalSlider = [[CocoaVerticalSlider alloc] initWith:self()]; + pWidget::construct(); + + setLength(state().length); + setPosition(state().position); + } +} + +auto pVerticalSlider::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pVerticalSlider::minimumSize() const -> Size { + return {20, 48}; +} + +auto pVerticalSlider::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry({ + geometry.x(), geometry.y() - 2, + geometry.width(), geometry.height() + 4 + }); +} + +auto pVerticalSlider::setLength(uint length) -> void { + @autoreleasepool { + [cocoaView setMaxValue:length]; + } +} + +auto pVerticalSlider::setPosition(uint position) -> void { + @autoreleasepool { + [cocoaView setDoubleValue:position]; + } +} + +} + +#endif diff --git a/cocoa/widget/vertical-slider.hpp b/cocoa/widget/vertical-slider.hpp new file mode 100644 index 0000000..a8b2c1e --- /dev/null +++ b/cocoa/widget/vertical-slider.hpp @@ -0,0 +1,26 @@ +#if defined(Hiro_VerticalSlider) + +@interface CocoaVerticalSlider : NSSlider { +@public + hiro::mVerticalSlider* verticalSlider; +} +-(id) initWith:(hiro::mVerticalSlider&)verticalSlider; +-(IBAction) activate:(id)sender; +@end + +namespace hiro { + +struct pVerticalSlider : pWidget { + Declare(VerticalSlider, Widget) + + auto minimumSize() const -> Size override; + auto setGeometry(Geometry geometry) -> void override; + auto setLength(uint length) -> void; + auto setPosition(uint position) -> void; + + CocoaVerticalSlider* cocoaVerticalSlider = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/viewport.cpp b/cocoa/widget/viewport.cpp new file mode 100644 index 0000000..c03202d --- /dev/null +++ b/cocoa/widget/viewport.cpp @@ -0,0 +1,72 @@ +#if defined(Hiro_Viewport) + +@implementation CocoaViewport : NSView + +-(id) initWith:(hiro::mViewport&)viewportReference { + if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) { + viewport = &viewportReference; + } + return self; +} + +-(void) drawRect:(NSRect)rect { + [[NSColor blackColor] setFill]; + NSRectFillUsingOperation(rect, NSCompositeSourceOver); +} + +-(BOOL) acceptsFirstResponder { + return YES; +} + +-(NSDragOperation) draggingEntered:(id)sender { + return DropPathsOperation(sender); +} + +-(BOOL) performDragOperation:(id)sender { + lstring paths = DropPaths(sender); + if(paths.empty()) return NO; + viewport->doDrop(paths); + return YES; +} + +-(void) keyDown:(NSEvent*)event { +} + +-(void) keyUp:(NSEvent*)event { +} + +@end + +namespace hiro { + +auto pViewport::construct() -> void { + @autoreleasepool { + cocoaView = cocoaViewport = [[CocoaViewport alloc] initWith:self()]; + pWidget::construct(); + } +} + +auto pViewport::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pViewport::handle() const -> uintptr { + return (uintptr)cocoaViewport; +} + +auto pViewport::setDroppable(bool droppable) -> void { + @autoreleasepool { + if(droppable) { + [cocoaViewport registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]]; + } else { + [cocoaViewport unregisterDraggedTypes]; + } + } +} + +} + +#endif diff --git a/cocoa/widget/viewport.hpp b/cocoa/widget/viewport.hpp new file mode 100644 index 0000000..36a93ee --- /dev/null +++ b/cocoa/widget/viewport.hpp @@ -0,0 +1,29 @@ +#if defined(Hiro_Viewport) + +@interface CocoaViewport : NSView { +@public + hiro::mViewport* viewport; +} +-(id) initWith:(hiro::mViewport&)viewport; +-(void) drawRect:(NSRect)rect; +-(BOOL) acceptsFirstResponder; +-(NSDragOperation) draggingEntered:(id)sender; +-(BOOL) performDragOperation:(id)sender; +-(void) keyDown:(NSEvent*)event; +-(void) keyUp:(NSEvent*)event; +@end + +namespace hiro { + +struct pViewport : pWidget { + Declare(Viewport, Widget) + + auto handle() const -> uintptr; + auto setDroppable(bool droppable) -> void; + + CocoaViewport* cocoaViewport = nullptr; +}; + +} + +#endif diff --git a/cocoa/widget/widget.cpp b/cocoa/widget/widget.cpp new file mode 100644 index 0000000..0d0357d --- /dev/null +++ b/cocoa/widget/widget.cpp @@ -0,0 +1,78 @@ +#if defined(Hiro_Widget) + +namespace hiro { + +auto pWidget::construct() -> void { + @autoreleasepool { + if(!cocoaView) { + abstract = true; + cocoaView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]; + [cocoaView setHidden:true]; + } + + if(auto window = self().parentWindow(true)) { + if(auto p = window->self()) p->_append(self()); + setEnabled(self().enabled(true)); + setFont(self().font(true)); + setVisible(self().visible(true)); + } + } +} + +auto pWidget::destruct() -> void { + @autoreleasepool { + [cocoaView removeFromSuperview]; + [cocoaView release]; + } +} + +auto pWidget::focused() const -> bool { + @autoreleasepool { + return cocoaView == [[cocoaView window] firstResponder]; + } +} + +auto pWidget::setEnabled(bool enabled) -> void { + if(abstract) enabled = false; + + @autoreleasepool { + if([cocoaView respondsToSelector:@selector(setEnabled:)]) { + [cocoaView setEnabled:enabled]; + } + } +} + +auto pWidget::setFocused() -> void { + @autoreleasepool { + [[cocoaView window] makeFirstResponder:cocoaView]; + } +} + +auto pWidget::setFont(const Font& font) -> void { + @autoreleasepool { + if([cocoaView respondsToSelector:@selector(setFont:)]) { + [cocoaView setFont:pFont::create(font)]; + } + } +} + +auto pWidget::setGeometry(Geometry geometry) -> void { + @autoreleasepool { + CGFloat windowHeight = [[cocoaView superview] frame].size.height; + [cocoaView setFrame:NSMakeRect(geometry.x(), windowHeight - geometry.y() - geometry.height(), geometry.width(), geometry.height())]; + [[cocoaView superview] setNeedsDisplay:YES]; + } + self().doSize(); +} + +auto pWidget::setVisible(bool visible) -> void { + if(abstract) visible = false; + + @autoreleasepool { + [cocoaView setHidden:!visible]; + } +} + +} + +#endif diff --git a/cocoa/widget/widget.hpp b/cocoa/widget/widget.hpp new file mode 100644 index 0000000..ca5e48e --- /dev/null +++ b/cocoa/widget/widget.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_Widget) + +namespace hiro { + +struct pWidget : pSizable { + Declare(Widget, Sizable) + + auto focused() const -> bool; + auto setEnabled(bool enabled) -> void override; + auto setFocused() -> void override; + auto setFont(const Font& font) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setVisible(bool visible) -> void override; + + NSView* cocoaView = nullptr; + bool abstract = false; +}; + +} + +#endif diff --git a/cocoa/window.cpp b/cocoa/window.cpp new file mode 100644 index 0000000..0debae8 --- /dev/null +++ b/cocoa/window.cpp @@ -0,0 +1,418 @@ +#if defined(Hiro_Window) + +@implementation CocoaWindow : NSWindow + +-(id) initWith:(hiro::mWindow&)windowReference { + window = &windowReference; + + NSUInteger style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; + if(window->state.resizable) style |= NSResizableWindowMask; + + if(self = [super initWithContentRect:NSMakeRect(0, 0, 640, 480) styleMask:style backing:NSBackingStoreBuffered defer:YES]) { + [self setDelegate:self]; + [self setReleasedWhenClosed:NO]; + [self setAcceptsMouseMovedEvents:YES]; + [self setTitle:@""]; + + NSBundle* bundle = [NSBundle mainBundle]; + NSDictionary* dictionary = [bundle infoDictionary]; + NSString* applicationName = [dictionary objectForKey:@"CFBundleDisplayName"]; + if(applicationName == nil) applicationName = [NSString stringWithUTF8String:hiro::Application::state.name]; + + menuBar = [[NSMenu alloc] init]; + + NSMenuItem* item; + string text; + + rootMenu = [[NSMenu alloc] init]; + item = [[[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""] autorelease]; + [item setSubmenu:rootMenu]; + [menuBar addItem:item]; + + item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"About %@ ...", applicationName] action:@selector(menuAbout) keyEquivalent:@""] autorelease]; + [item setTarget:self]; + [rootMenu addItem:item]; + [rootMenu addItem:[NSMenuItem separatorItem]]; + + item = [[[NSMenuItem alloc] initWithTitle:@"Preferences ..." action:@selector(menuPreferences) keyEquivalent:@""] autorelease]; + [item setTarget:self]; + [rootMenu addItem:item]; + + string result = nall::execute("defaults", "read", "/Library/Preferences/com.apple.security", "GKAutoRearm").strip(); + if(result != "0") { + disableGatekeeperAutoRearm = [[[NSMenuItem alloc] initWithTitle:@"Disable Gatekeeper Auto-Rearm" action:@selector(menuDisableGatekeeperAutoRearm) keyEquivalent:@""] autorelease]; + [disableGatekeeperAutoRearm setTarget:self]; + [rootMenu addItem:disableGatekeeperAutoRearm]; + } + + [rootMenu addItem:[NSMenuItem separatorItem]]; + + NSMenu* servicesMenu = [[[NSMenu alloc] initWithTitle:@"Services"] autorelease]; + item = [[[NSMenuItem alloc] initWithTitle:@"Services" action:nil keyEquivalent:@""] autorelease]; + [item setTarget:self]; + [item setSubmenu:servicesMenu]; + [rootMenu addItem:item]; + [rootMenu addItem:[NSMenuItem separatorItem]]; + [NSApp setServicesMenu:servicesMenu]; + + item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Hide %@", applicationName] action:@selector(hide:) keyEquivalent:@""] autorelease]; + [item setTarget:NSApp]; + [rootMenu addItem:item]; + + item = [[[NSMenuItem alloc] initWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@""] autorelease]; + [item setTarget:NSApp]; + [rootMenu addItem:item]; + + item = [[[NSMenuItem alloc] initWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""] autorelease]; + [item setTarget:NSApp]; + [rootMenu addItem:item]; + + [rootMenu addItem:[NSMenuItem separatorItem]]; + + item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Quit %@", applicationName] action:@selector(menuQuit) keyEquivalent:@""] autorelease]; + [item setTarget:self]; + [rootMenu addItem:item]; + + statusBar = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]; + [statusBar setAlignment:NSLeftTextAlignment]; + [statusBar setBordered:YES]; + [statusBar setBezeled:YES]; + [statusBar setBezelStyle:NSTextFieldSquareBezel]; + [statusBar setEditable:NO]; + [statusBar setHidden:YES]; + + [[self contentView] addSubview:statusBar positioned:NSWindowBelow relativeTo:nil]; + } + + return self; +} + +-(BOOL) canBecomeKeyWindow { + return YES; +} + +-(BOOL) canBecomeMainWindow { + return YES; +} + +-(void) windowDidBecomeMain:(NSNotification*)notification { + if(window->state.menuBar) { + [NSApp setMainMenu:menuBar]; + } +} + +-(void) windowDidMove:(NSNotification*)notification { + if(auto p = window->self()) p->moveEvent(); +} + +-(void) windowDidResize:(NSNotification*)notification { + if(auto p = window->self()) p->sizeEvent(); +} + +-(BOOL) windowShouldClose:(id)sender { + if(window->state.onClose) window->doClose(); + else window->setVisible(false); + if(window->state.modal && !window->visible()) window->setModal(false); + return NO; +} + +-(NSDragOperation) draggingEntered:(id)sender { + return DropPathsOperation(sender); +} + +-(BOOL) performDragOperation:(id)sender { + lstring paths = DropPaths(sender); + if(paths.empty()) return NO; + window->doDrop(paths); + return YES; +} + +-(NSMenu*) menuBar { + return menuBar; +} + +-(void) menuAbout { + hiro::Application::Cocoa::doAbout(); +} + +-(void) menuPreferences { + hiro::Application::Cocoa::doPreferences(); +} + +-(void) menuDisableGatekeeperAutoRearm { + NSAlert* alert = [[[NSAlert alloc] init] autorelease]; + [alert setMessageText:@"Disable Gatekeeper Auto-Rearm"]; + + nall::execute("sudo", "defaults", "write", "/Library/Preferences/com.apple.security", "GKAutoRearm", "-bool", "NO"); + if(nall::execute("defaults", "read", "/Library/Preferences/com.apple.security", "GKAutoRearm").strip() == "0") { + [alert setAlertStyle:NSInformationalAlertStyle]; + [alert setInformativeText:@"Gatekeeper's automatic 30-day rearm behavior has been disabled successfully."]; + [disableGatekeeperAutoRearm setHidden:YES]; + } else { + [alert setAlertStyle:NSWarningAlertStyle]; + [alert setInformativeText:@"Error: failed to disable Gatekeeper's automatic rearm behavior."]; + } + + [alert addButtonWithTitle:@"Ok"]; + [alert runModal]; +} + +-(void) menuQuit { + hiro::Application::Cocoa::doQuit(); +} + +-(NSTextField*) statusBar { + return statusBar; +} + +@end + +namespace hiro { + +auto pWindow::construct() -> void { + @autoreleasepool { + cocoaWindow = [[CocoaWindow alloc] initWith:self()]; + + static bool once = true; + if(once) { + once = false; + [NSApp setMainMenu:[cocoaWindow menuBar]]; + } + } +} + +auto pWindow::destruct() -> void { + @autoreleasepool { + [cocoaWindow release]; + } +} + +auto pWindow::append(sLayout layout) -> void { + layout->setGeometry(self().geometry().setPosition(0, 0)); + statusBarReposition(); +} + +auto pWindow::append(sMenuBar menuBar) -> void { +} + +auto pWindow::append(sStatusBar statusBar) -> void { + statusBar->setEnabled(statusBar->enabled(true)); + statusBar->setFont(statusBar->font(true)); + statusBar->setText(statusBar->text()); + statusBar->setVisible(statusBar->visible(true)); +} + +auto pWindow::focused() const -> bool { + @autoreleasepool { + return [cocoaWindow isMainWindow] == YES; + } +} + +auto pWindow::frameMargin() const -> Geometry { + @autoreleasepool { + NSRect frame = [cocoaWindow frameRectForContentRect:NSMakeRect(0, 0, 640, 480)]; + return {abs(frame.origin.x), (int)(frame.size.height - 480), (int)(frame.size.width - 640), abs(frame.origin.y)}; + } +} + +auto pWindow::remove(sLayout layout) -> void { + @autoreleasepool { + [[cocoaWindow contentView] setNeedsDisplay:YES]; + } +} + +auto pWindow::remove(sMenuBar menuBar) -> void { +} + +auto pWindow::remove(sStatusBar statusBar) -> void { + @autoreleasepool { + [[cocoaWindow statusBar] setHidden:YES]; + } +} + +auto pWindow::setBackgroundColor(Color color) -> void { + @autoreleasepool { + [cocoaWindow + setBackgroundColor:[NSColor + colorWithCalibratedRed:color.red() / 255.0 + green:color.green() / 255.0 + blue:color.blue() / 255.0 + alpha:color.alpha() / 255.0 + ] + ]; + } +} + +auto pWindow::setDroppable(bool droppable) -> void { + @autoreleasepool { + if(droppable) { + [cocoaWindow registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]]; + } else { + [cocoaWindow unregisterDraggedTypes]; + } + } +} + +auto pWindow::setFocused() -> void { + @autoreleasepool { + [cocoaWindow makeKeyAndOrderFront:nil]; + } +} + +auto pWindow::setFullScreen(bool fullScreen) -> void { + @autoreleasepool { + if(fullScreen) { + windowedGeometry = state().geometry; + [NSApp setPresentationOptions:NSApplicationPresentationFullScreen]; + [cocoaWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + [cocoaWindow toggleFullScreen:nil]; + state().geometry = _geometry(); + } else { + [cocoaWindow toggleFullScreen:nil]; + [cocoaWindow setCollectionBehavior:NSWindowCollectionBehaviorDefault]; + [NSApp setPresentationOptions:NSApplicationPresentationDefault]; + state().geometry = windowedGeometry; + } + } +} + +auto pWindow::setGeometry(Geometry geometry) -> void { + lock(); + + @autoreleasepool { + [cocoaWindow + setFrame:[cocoaWindow + frameRectForContentRect:NSMakeRect( + geometry.x(), Desktop::size().height() - geometry.y() - geometry.height(), + geometry.width(), geometry.height() + statusBarHeight() + ) + ] + display:YES + ]; + + if(auto& layout = state().layout) { + layout->setGeometry(self().geometry().setPosition(0, 0)); + } + + statusBarReposition(); + } + + unlock(); +} + +auto pWindow::setModal(bool modal) -> void { + @autoreleasepool { + if(modal == true) { + [NSApp runModalForWindow:cocoaWindow]; + } else { + [NSApp stopModal]; + NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0]; + [NSApp postEvent:event atStart:true]; + } + } +} + +auto pWindow::setResizable(bool resizable) -> void { + @autoreleasepool { + NSUInteger style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; + if(resizable) style |= NSResizableWindowMask; + [cocoaWindow setStyleMask:style]; + } +} + +auto pWindow::setTitle(const string& text) -> void { + @autoreleasepool { + [cocoaWindow setTitle:[NSString stringWithUTF8String:text]]; + } +} + +auto pWindow::setVisible(bool visible) -> void { + @autoreleasepool { + if(visible) [cocoaWindow makeKeyAndOrderFront:nil]; + else [cocoaWindow orderOut:nil]; + } +} + +auto pWindow::moveEvent() -> void { + if(!locked() && !self().fullScreen() && self().visible()) { + @autoreleasepool { + NSRect area = [cocoaWindow contentRectForFrameRect:[cocoaWindow frame]]; + area.size.height -= statusBarHeight(); + state().geometry.setX(area.origin.x); + state().geometry.setY(Desktop::size().height() - area.origin.y - area.size.height); + } + } + + if(!locked()) self().doMove(); +} + +auto pWindow::sizeEvent() -> void { + if(!locked() && !self().fullScreen() && self().visible()) { + @autoreleasepool { + NSRect area = [cocoaWindow contentRectForFrameRect:[cocoaWindow frame]]; + area.size.height -= statusBarHeight(); + state().geometry.setWidth(area.size.width); + state().geometry.setHeight(area.size.height); + } + } + + if(auto& layout = state().layout) { + layout->setGeometry(self().geometry().setPosition(0, 0)); + } + + statusBarReposition(); + + if(!locked()) self().doSize(); +} + +auto pWindow::statusBarHeight() -> uint { + if(auto& statusBar = state().statusBar) { + if(statusBar->visible()) { + return pFont::size(statusBar->font(true), " ").height() + 6; + } + } + return 0; +} + +auto pWindow::statusBarReposition() -> void { + @autoreleasepool { + NSRect area = [cocoaWindow contentRectForFrameRect:[cocoaWindow frame]]; + [[cocoaWindow statusBar] setFrame:NSMakeRect(0, 0, area.size.width, statusBarHeight())]; + [[cocoaWindow contentView] setNeedsDisplay:YES]; + } +} + +auto pWindow::_append(mWidget& widget) -> void { + @autoreleasepool { + if(auto pWidget = widget.self()) { + [pWidget->cocoaView removeFromSuperview]; + [[cocoaWindow contentView] addSubview:pWidget->cocoaView positioned:NSWindowAbove relativeTo:nil]; + pWidget->setGeometry(widget.geometry()); + [[cocoaWindow contentView] setNeedsDisplay:YES]; + } + } +} + +auto pWindow::_geometry() -> Geometry { + @autoreleasepool { + NSRect area = [cocoaWindow contentRectForFrameRect:[cocoaWindow frame]]; + area.size.height -= statusBarHeight(); + return { + (int)area.origin.x, (int)(Monitor::geometry(Monitor::primary()).height() - area.origin.y - area.size.height), + (int)area.size.width, (int)area.size.height + }; + } +} + +/* +auto pWindow::remove(Widget& widget) -> void { + @autoreleasepool { + [widget.p.cocoaView removeFromSuperview]; + [[cocoaWindow contentView] setNeedsDisplay:YES]; + } +} +*/ + +} + +#endif diff --git a/cocoa/window.hpp b/cocoa/window.hpp new file mode 100644 index 0000000..ef178a6 --- /dev/null +++ b/cocoa/window.hpp @@ -0,0 +1,65 @@ +#if defined(Hiro_Window) + +@interface CocoaWindow : NSWindow { +@public + hiro::mWindow* window; + NSMenu* menuBar; + NSMenu* rootMenu; + NSMenuItem* disableGatekeeperAutoRearm; + NSTextField* statusBar; +} +-(id) initWith:(hiro::mWindow&)window; +-(BOOL) canBecomeKeyWindow; +-(BOOL) canBecomeMainWindow; +-(void) windowDidBecomeMain:(NSNotification*)notification; +-(void) windowDidMove:(NSNotification*)notification; +-(void) windowDidResize:(NSNotification*)notification; +-(BOOL) windowShouldClose:(id)sender; +-(NSDragOperation) draggingEntered:(id)sender; +-(BOOL) performDragOperation:(id)sender; +-(NSMenu*) menuBar; +-(void) menuAbout; +-(void) menuPreferences; +-(void) menuDisableGatekeeperAutoRearm; +-(void) menuQuit; +-(NSTextField*) statusBar; +@end + +namespace hiro { + +struct pWindow : pObject { + Declare(Window, Object) + + auto append(sLayout layout) -> void; + auto append(sMenuBar menuBar) -> void; + auto append(sStatusBar statusBar) -> void; + auto focused() const -> bool override; + auto frameMargin() const -> Geometry; + auto remove(sLayout layout) -> void; + auto remove(sMenuBar menuBar) -> void; + auto remove(sStatusBar statusBar) -> void; + auto setBackgroundColor(Color color) -> void; + auto setDroppable(bool droppable) -> void; + 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& text) -> void; + auto setVisible(bool visible) -> void; + + auto moveEvent() -> void; + auto sizeEvent() -> void; + auto statusBarHeight() -> uint; + auto statusBarReposition() -> void; + + auto _append(mWidget& widget) -> void; + auto _geometry() -> Geometry; + + CocoaWindow* cocoaWindow = nullptr; + Geometry windowedGeometry; +}; + +} + +#endif diff --git a/components.hpp b/components.hpp new file mode 100644 index 0000000..cd48b86 --- /dev/null +++ b/components.hpp @@ -0,0 +1,98 @@ +/* hiro components + * + * By commenting out lines below, individual components of hiro can be disabled.) + * This can be useful to avoid dependencies (eg GTK+ relies on GtkSourceView for SourceEdit.) + * It's also very useful for porting hiro to new targets; or performing major core changes. + * + * Note that the core classes (Application, Window, Sizable, etc) have circular dependencies. + * Disabling only certain core pieces will result in compilation errors. + * As such, this file is really only meant for disabling individual widgets or menu items. + */ + +#define Hiro_Color +#define Hiro_Gradient +#define Hiro_Alignment +#define Hiro_Cursor +#define Hiro_Position +#define Hiro_Size +#define Hiro_Geometry +#define Hiro_Font + +#define Hiro_Application +#define Hiro_Desktop +#define Hiro_Monitor +#define Hiro_Keyboard +#define Hiro_Mouse +#define Hiro_BrowserWindow +#define Hiro_MessageWindow + +#define Hiro_Property + +#define Hiro_Object +#define Hiro_Group + +#define Hiro_Hotkey +#define Hiro_Timer + +#define Hiro_Window +#define Hiro_StatusBar +#define Hiro_MenuBar +#define Hiro_PopupMenu + +#define Hiro_Action +#define Hiro_Menu +#define Hiro_MenuSeparator +#define Hiro_MenuItem +#define Hiro_MenuCheckItem +#define Hiro_MenuRadioItem + +#define Hiro_Sizable +#define Hiro_Layout +#define Hiro_Widget +#define Hiro_Button +#define Hiro_Canvas +#define Hiro_CheckButton +#define Hiro_CheckLabel +#define Hiro_ComboButton +#define Hiro_Console +#define Hiro_Frame +#define Hiro_HexEdit +#define Hiro_HorizontalScrollBar +#define Hiro_HorizontalSlider +#define Hiro_IconView +#define Hiro_Label +#define Hiro_LineEdit +#define Hiro_ListView +#define Hiro_ProgressBar +#define Hiro_RadioButton +#define Hiro_RadioLabel +#define Hiro_SourceEdit +#define Hiro_TabFrame +#define Hiro_TextEdit +#define Hiro_TreeView +#define Hiro_VerticalScrollBar +#define Hiro_VerticalSlider +#define Hiro_Viewport + +#define Hiro_FixedLayout +#define Hiro_HorizontalLayout +#define Hiro_VerticalLayout + +#if defined(HIRO_WINDOWS) || defined(HIRO_COCOA) || defined(HIRO_QT) + #undef Hiro_Console + #undef Hiro_IconView + #undef Hiro_SourceEdit + #undef Hiro_TreeView +#endif + +#if defined(HIRO_COCOA) + #undef Hiro_HexEdit +#endif + +#if defined(Hiro_Button) && defined(Hiro_Canvas) && defined(Hiro_Label) + #define Hiro_MessageDialog +#endif + +#if defined(Hiro_Button) && defined(Hiro_ComboButton) && defined(Hiro_LineEdit) && defined(Hiro_ListView) && defined(Hiro_MessageDialog) + #define Hiro_BrowserDialog +#endif diff --git a/core/action/action.cpp b/core/action/action.cpp new file mode 100644 index 0000000..1251a42 --- /dev/null +++ b/core/action/action.cpp @@ -0,0 +1,18 @@ +#if defined(Hiro_Action) + +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 defined(Hiro_PopupMenu) + if(auto popupMenu = parentPopupMenu()) popupMenu->remove(*this); + #endif + return *this; +} + +#endif diff --git a/core/action/menu-check-item.cpp b/core/action/menu-check-item.cpp new file mode 100644 index 0000000..2670319 --- /dev/null +++ b/core/action/menu-check-item.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_MenuCheckItem) + +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& callback) -> type& { + state.onToggle = callback; + return *this; +} + +auto mMenuCheckItem::setChecked(bool checked) -> type& { + state.checked = checked; + signal(setChecked, checked); + return *this; +} + +auto mMenuCheckItem::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mMenuCheckItem::text() const -> string { + return state.text; +} + +#endif diff --git a/core/action/menu-item.cpp b/core/action/menu-item.cpp new file mode 100644 index 0000000..8f5ce5f --- /dev/null +++ b/core/action/menu-item.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_MenuItem) + +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& callback) -> type& { + state.onActivate = callback; + 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; +} + +#endif diff --git a/core/action/menu-radio-item.cpp b/core/action/menu-radio-item.cpp new file mode 100644 index 0000000..a8c74e5 --- /dev/null +++ b/core/action/menu-radio-item.cpp @@ -0,0 +1,57 @@ +#if defined(Hiro_MenuRadioItem) + +auto mMenuRadioItem::allocate() -> pObject* { + return new pMenuRadioItem(*this); +} + +// + +auto mMenuRadioItem::checked() const -> bool { + return state.checked; +} + +auto mMenuRadioItem::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mMenuRadioItem::group() const -> Group { + return state.group; +} + +auto mMenuRadioItem::onActivate(const function& callback) -> type& { + state.onActivate = callback; + return *this; +} + +auto mMenuRadioItem::setChecked() -> type& { + if(auto group = this->group()) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto menuRadioItem = dynamic_cast(object.data())) { + menuRadioItem->state.checked = false; + } + } + } + } + state.checked = true; + signal(setChecked); + return *this; +} + +auto mMenuRadioItem::setGroup(sGroup group) -> type& { + state.group = group ? group : Group{&instance}; + signal(setGroup, group); + 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; +} + +#endif diff --git a/core/action/menu-separator.cpp b/core/action/menu-separator.cpp new file mode 100644 index 0000000..3993980 --- /dev/null +++ b/core/action/menu-separator.cpp @@ -0,0 +1,7 @@ +#if defined(Hiro_MenuSeparator) + +auto mMenuSeparator::allocate() -> pObject* { + return new pMenuSeparator(*this); +} + +#endif diff --git a/core/action/menu.cpp b/core/action/menu.cpp new file mode 100644 index 0000000..45bea2e --- /dev/null +++ b/core/action/menu.cpp @@ -0,0 +1,78 @@ +#if defined(Hiro_Menu) + +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 -> Action { + if(position < actionCount()) return state.actions[position]; + return {}; +} + +auto mMenu::actionCount() const -> unsigned { + return state.actions.size(); +} + +auto mMenu::actions() const -> vector { + vector actions; + for(auto& action : state.actions) actions.append(action); + return actions; +} + +auto mMenu::append(sAction action) -> type& { + state.actions.append(action); + action->setParent(this, actionCount() - 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(), actionCount())) { + state.actions[n]->adjustOffset(-1); + } + action->setParent(); + return *this; +} + +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::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.actions)) state.actions[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& action : state.actions) action->setParent(this, action->offset()); + 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; +} + +#endif diff --git a/core/alignment.cpp b/core/alignment.cpp new file mode 100644 index 0000000..210a0aa --- /dev/null +++ b/core/alignment.cpp @@ -0,0 +1,44 @@ +#if defined(Hiro_Alignment) + +Alignment::Alignment() { + setAlignment(-1.0, -1.0); +} + +Alignment::Alignment(double horizontal, double vertical) { + setAlignment(horizontal, vertical); +} + +Alignment::operator bool() const { + return state.horizontal >= 0.0 && state.horizontal <= 1.0 + && state.vertical >= 0.0 && state.vertical <= 1.0; +} + +auto Alignment::horizontal() const -> double { + return state.horizontal; +} + +auto Alignment::reset() -> type& { + return setAlignment(-1.0, -1.0); +} + +auto Alignment::setAlignment(double horizontal, double vertical) -> type& { + state.horizontal = horizontal; + state.vertical = vertical; + return *this; +} + +auto Alignment::setHorizontal(double horizontal) -> type& { + state.horizontal = horizontal; + return *this; +} + +auto Alignment::setVertical(double vertical) -> type& { + state.vertical = vertical; + return *this; +} + +auto Alignment::vertical() const -> double { + return state.vertical; +} + +#endif diff --git a/core/application.cpp b/core/application.cpp new file mode 100644 index 0000000..949f5d3 --- /dev/null +++ b/core/application.cpp @@ -0,0 +1,103 @@ +#if defined(Hiro_Application) + +Application::State Application::state; + +auto Application::doMain() -> void { + if(state.onMain) return state.onMain(); +} + +auto Application::font() -> Font { + return state.font; +} + +auto Application::name() -> string { + return state.name; +} + +auto Application::onMain(const function& callback) -> void { + state.onMain = callback; +} + +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 Font& 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& callback) -> void { + state.windows.onModalChange = callback; +} + +//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& callback) -> void { + state.cocoa.onAbout = callback; +} + +auto Application::Cocoa::onActivate(const function& callback) -> void { + state.cocoa.onActivate = callback; +} + +auto Application::Cocoa::onPreferences(const function& callback) -> void { + state.cocoa.onPreferences = callback; +} + +auto Application::Cocoa::onQuit(const function& callback) -> void { + state.cocoa.onQuit = callback; +} + +//Internal +//======== + +auto Application::initialize() -> void { + static bool initialized = false; + if(initialized == false) { + initialized = true; + return pApplication::initialize(); + } +} + +#endif diff --git a/core/browser-window.cpp b/core/browser-window.cpp new file mode 100644 index 0000000..584edff --- /dev/null +++ b/core/browser-window.cpp @@ -0,0 +1,35 @@ +#if defined(Hiro_BrowserWindow) + +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; +} + +#endif diff --git a/core/color.cpp b/core/color.cpp new file mode 100644 index 0000000..63d8f00 --- /dev/null +++ b/core/color.cpp @@ -0,0 +1,79 @@ +#if defined(Hiro_Color) + +Color::Color() { + setColor(0, 0, 0, 0); +} + +Color::Color(signed red, signed green, signed blue, signed alpha) { + setColor(red, green, blue, alpha); +} + +Color::operator bool() const { + return state.red || state.green || state.blue || state.alpha; +} + +auto Color::operator==(const Color& source) const -> bool { + return red() == source.red() && green() == source.green() && blue() == source.blue() && alpha() == source.alpha(); +} + +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::green() const -> uint8_t { + return state.green; +} + +auto Color::red() const -> uint8_t { + return state.red; +} + +auto Color::reset() -> type& { + return setColor(0, 0, 0, 0); +} + +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.red(), color.green(), color.blue(), color.alpha()); +} + +auto Color::setColor(signed red, signed green, signed blue, signed alpha) -> type& { + state.red = max(0, min(255, red )); + state.green = max(0, min(255, green)); + state.blue = max(0, min(255, blue )); + state.alpha = max(0, min(255, alpha)); + 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; +} + +#endif diff --git a/core/core.cpp b/core/core.cpp new file mode 100644 index 0000000..d6fd5e1 --- /dev/null +++ b/core/core.cpp @@ -0,0 +1,108 @@ +#include + +#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; + +#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 "color.cpp" + #include "gradient.cpp" + #include "alignment.cpp" + #include "cursor.cpp" + #include "position.cpp" + #include "size.cpp" + #include "geometry.cpp" + #include "font.cpp" + + #include "application.cpp" + #include "desktop.cpp" + #include "monitor.cpp" + #include "keyboard.cpp" + #include "mouse.cpp" + #include "browser-window.cpp" + #include "message-window.cpp" + + #include "property.cpp" + + #include "object.cpp" + #include "group.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-scroll-bar.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-header.cpp" + #include "widget/list-view-column.cpp" + #include "widget/list-view-item.cpp" + #include "widget/list-view-cell.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-scroll-bar.cpp" + #include "widget/vertical-slider.cpp" + #include "widget/viewport.cpp" +} + +#undef signal diff --git a/core/core.hpp b/core/core.hpp new file mode 100644 index 0000000..c33f9d5 --- /dev/null +++ b/core/core.hpp @@ -0,0 +1,1916 @@ +#include +#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::nothing; +using nall::set; +using nall::shared_pointer; +using nall::shared_pointer_weak; +using nall::string; +using nall::vector; + +namespace hiro { + +struct Font; +struct Keyboard; + +#define Declare(Name) \ + struct Name; \ + struct m##Name; \ + struct p##Name; \ + using s##Name = shared_pointer; \ + using w##Name = shared_pointer_weak; \ + +Declare(Object) +Declare(Group) +Declare(Timer) +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(HorizontalScrollBar) +Declare(HorizontalSlider) +Declare(IconView) +Declare(IconViewItem) +Declare(Label) +Declare(LineEdit) +Declare(ListView) +Declare(ListViewHeader) +Declare(ListViewColumn) +Declare(ListViewItem) +Declare(ListViewCell) +Declare(ProgressBar) +Declare(RadioButton) +Declare(RadioLabel) +Declare(SourceEdit) +Declare(TabFrame) +Declare(TabFrameItem) +Declare(TextEdit) +Declare(TreeView) +Declare(TreeViewItem) +Declare(VerticalScrollBar) +Declare(VerticalSlider) +Declare(Viewport) + +#undef Declare + +enum class Orientation : unsigned { Horizontal, Vertical }; +enum class Navigation : unsigned { Top, Bottom, Left, Right }; + +#if defined(Hiro_Color) +struct Color { + using type = Color; + + Color(); + Color(signed red, signed green, signed blue, signed alpha = 255); + + 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 green() const -> uint8_t; + auto red() const -> uint8_t; + auto reset() -> type&; + auto setAlpha(signed alpha) -> type&; + auto setBlue(signed blue) -> type&; + auto setColor(Color color = {}) -> type&; + auto setColor(signed red, signed green, signed blue, signed alpha = 255) -> type&; + auto setGreen(signed green) -> type&; + auto setRed(signed red) -> type&; + auto value() const -> uint32_t; + +//private: + struct State { + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t alpha; + } state; +}; +#endif + +#if defined(Hiro_Gradient) +struct Gradient { + using type = Gradient; + + Gradient(); + + explicit operator bool() const; + auto operator==(const Gradient& source) const -> bool; + auto operator!=(const Gradient& source) const -> bool; + + auto setBilinear(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> type&; + auto setHorizontal(Color left, Color right) -> type&; + auto setVertical(Color top, Color bottom) -> type&; + +//private: + struct State { + vector colors; + } state; +}; +#endif + +#if defined(Hiro_Alignment) +struct Alignment { + using type = Alignment; + + Alignment(); + Alignment(double horizontal, double vertical = 0.5); + + explicit operator bool() const; + auto operator==(const Alignment& source) const -> bool; + auto operator!=(const Alignment& source) const -> bool; + + auto horizontal() const -> double; + auto reset() -> type&; + auto setAlignment(double horizontal = -1.0, double vertical = 0.5) -> type&; + auto setHorizontal(double horizontal) -> type&; + auto setVertical(double vertical) -> type&; + auto vertical() const -> double; + +//private: + struct State { + float horizontal; + float vertical; + } state; +}; +#endif + +#if defined(Hiro_Cursor) +struct Cursor { + using type = Cursor; + + Cursor(signed offset = 0, signed length = 0); + + explicit operator bool() const; + auto operator==(const Cursor& source) const -> bool; + auto operator!=(const Cursor& source) const -> bool; + + auto length() const -> signed; + auto offset() const -> signed; + auto setCursor(signed offset = 0, signed length = 0) -> type&; + auto setLength(signed length = 0) -> type&; + auto setOffset(signed offset = 0) -> type&; + +//private: + struct State { + signed offset; + signed length; + } state; +}; +#endif + +#if defined(Hiro_Position) +struct Position { + using type = Position; + + Position(); + Position(signed x, signed y); + + explicit operator bool() const; + auto operator==(const Position& source) const -> bool; + auto operator!=(const Position& source) const -> bool; + + auto reset() -> type&; + 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; +}; +#endif + +#if defined(Hiro_Size) +struct Size { + using type = Size; + + Size(); + Size(signed width, signed height); + + explicit operator bool() const; + auto operator==(const Size& source) const -> bool; + auto operator!=(const Size& source) const -> bool; + + auto height() const -> signed; + auto reset() -> type&; + 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; +}; +#endif + +#if defined(Hiro_Geometry) +struct Geometry { + using type = Geometry; + + Geometry(); + Geometry(Position position, Size size); + Geometry(signed x, signed y, signed width, signed height); + + explicit operator bool() const; + auto operator==(const Geometry& source) const -> bool; + auto operator!=(const Geometry& source) const -> bool; + + auto height() const -> signed; + auto position() const -> Position; + auto reset() -> type&; + 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 width() const -> signed; + auto x() const -> signed; + auto y() const -> signed; + +//private: + struct State { + signed x; + signed y; + signed width; + signed height; + } state; +}; +#endif + +#if defined(Hiro_Font) +struct Font { + using type = Font; + + Font(const string& family = "", unsigned size = 0); + + explicit operator bool() const; + auto operator==(const Font& source) const -> bool; + auto operator!=(const Font& source) const -> bool; + + auto bold() const -> bool; + auto family() const -> string; + auto italic() const -> bool; + auto reset() -> type&; + auto setBold(bool bold = true) -> type&; + auto setFamily(const string& family = "") -> type&; + auto setItalic(bool italic = true) -> type&; + auto setSize(unsigned size = 0) -> type&; + auto size() const -> unsigned; + auto size(const string& text) const -> Size; + + static const string Sans; + static const string Serif; + static const string Mono; + +//private: + struct State { + string family; + unsigned size; + bool bold; + bool italic; + } state; +}; +#endif + +#if defined(Hiro_Hotkey) +struct Hotkey { + using type = Hotkey; + + Hotkey(); + Hotkey(const string& sequence); + + explicit operator bool() const; + auto operator==(const Hotkey& source) const -> bool; + auto operator!=(const Hotkey& source) const -> bool; + + auto doPress() const -> void; + auto doRelease() const -> void; + auto onPress(const function& callback = {}) -> type&; + auto onRelease(const function& callback = {}) -> type&; + auto reset() -> type&; + auto sequence() const -> string; + auto setSequence(const string& sequence = "") -> type&; + +//private: + struct State { + bool active = false; + vector keys; + function onPress; + function onRelease; + string sequence; + }; + shared_pointer state; +}; +#endif + +#if defined(Hiro_Application) +struct Application { + Application() = delete; + + static auto doMain() -> void; + static auto font() -> Font; + static auto name() -> string; + static auto onMain(const function& callback = {}) -> void; + static auto run() -> void; + static auto pendingEvents() -> bool; + static auto processEvents() -> void; + static auto quit() -> void; + static auto setFont(const Font& font = {}) -> void; + static auto setName(const string& name = "") -> void; + + struct Windows { + static auto doModalChange(bool modal) -> void; + static auto onModalChange(const function& callback = {}) -> void; + }; + + struct Cocoa { + static auto doAbout() -> void; + static auto doActivate() -> void; + static auto doPreferences() -> void; + static auto doQuit() -> void; + static auto onAbout(const function& callback = {}) -> void; + static auto onActivate(const function& callback = {}) -> void; + static auto onPreferences(const function& callback = {}) -> void; + static auto onQuit(const function& callback = {}) -> void; + }; + +//private: + struct State { + Font 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; +}; +#endif + +#if defined(Hiro_Desktop) +struct Desktop { + Desktop() = delete; + + static auto size() -> Size; + static auto workspace() -> Geometry; +}; +#endif + +#if defined(Hiro_Monitor) +struct Monitor { + Monitor() = delete; + + static auto count() -> unsigned; + static auto geometry(unsigned monitor) -> Geometry; + static auto primary() -> unsigned; +}; +#endif + +#if defined(Hiro_Keyboard) +struct Keyboard { + Keyboard() = delete; + + static auto append(Hotkey hotkey) -> void; + static auto hotkey(unsigned position) -> Hotkey; + static auto hotkeyCount() -> unsigned; + static auto hotkeys() -> vector; + static auto poll() -> vector; + static auto pressed(const string& key) -> bool; + static auto released(const string& key) -> bool; + static auto remove(Hotkey hotkey) -> void; + + static const vector keys; + +//private: + struct State { + vector hotkeys; + }; + static State state; +}; +#endif + +#if defined(Hiro_Mouse) +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; +}; +#endif + +#if defined(Hiro_BrowserWindow) +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; +}; +#endif + +#if defined(Hiro_MessageWindow) +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; +}; +#endif + +struct Property { + using type = Property; + + Property(const string& name, const string& value = ""); + + auto operator==(const Property& source) const -> bool; + auto operator< (const Property& source) const -> bool; + + auto name() const -> string; + auto setValue(const string& value = "") -> type&; + auto value() const -> string; + +private: + struct State { + string name; + string value; + } 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; \ + setGroup(); \ + if(!abstract()) construct(); \ + } \ + auto unbind() -> void { \ + reset(); \ + destruct(); \ + instance.reset(); \ + } \ + virtual auto allocate() -> pObject*; \ + +#if defined(Hiro_Object) +struct mObject { + Declare(Object) + + mObject(); + virtual ~mObject(); + mObject(const mObject&) = delete; + mObject& operator=(const mObject&) = delete; + + explicit operator bool() const; + + auto abstract() const -> bool; + auto adjustOffset(signed displacement) -> type&; + auto enabled(bool recursive = false) const -> bool; + virtual auto focused() const -> bool; + auto font(bool recursive = false) const -> Font; + virtual auto group() const -> Group; + auto offset() const -> signed; + 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 parentListViewHeader(bool recursive = false) const -> mListViewHeader*; + auto parentListViewItem(bool recursive = false) const -> mListViewItem*; + 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*; + auto property(const string& name) const -> string; + virtual auto remove() -> type&; + virtual auto reset() -> type&; + virtual auto setEnabled(bool enabled = true) -> type&; + virtual auto setFocused() -> type&; + virtual auto setFont(const Font& font = {}) -> type&; + virtual auto setGroup(sGroup group = {}) -> type&; + virtual auto setParent(mObject* parent = nullptr, signed offset = -1) -> type&; + virtual auto setProperty(const string& name, const string& value = "") -> type&; + virtual auto setVisible(bool visible = true) -> type&; + auto visible(bool recursive = false) const -> bool; + +//private: + struct State { + bool enabled = true; + Font font; + signed offset = -1; + mObject* parent = nullptr; + set properties; + bool visible = true; + } state; + + wObject instance; + pObject* delegate = nullptr; + + virtual auto construct() -> void; + virtual auto destruct() -> void; +}; +#endif + +#if defined(Hiro_Group) +struct mGroup : mObject { + Declare(Group) + using mObject::remove; + + auto append(sObject object) -> type&; + auto object(unsigned offset) const -> Object; + auto objectCount() const -> unsigned; + auto objects() const -> vector; + auto remove(sObject object) -> type&; + +//private: + struct State { + vector objects; + } state; +}; +#endif + +#if defined(Hiro_Timer) +struct mTimer : mObject { + Declare(Timer) + + auto doActivate() const -> void; + auto interval() const -> unsigned; + auto onActivate(const function& callback = {}) -> type&; + auto setInterval(unsigned interval = 0) -> type&; + +//private: + struct State { + unsigned interval = 0; + function onActivate; + } state; +}; +#endif + +#if defined(Hiro_Window) +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 -> Layout; + auto menuBar() const -> MenuBar; + auto modal() const -> bool; + auto onClose(const function& callback = {}) -> type&; + auto onDrop(const function& callback = {}) -> type&; + auto onKeyPress(const function& callback = {}) -> type&; + auto onKeyRelease(const function& callback = {}) -> type&; + auto onMove(const function& callback = {}) -> type&; + auto onSize(const function& callback = {}) -> 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 setAlignment(Alignment alignment) -> type&; + auto setBackgroundColor(Color color = {}) -> 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 -> StatusBar; + 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; +}; +#endif + +#if defined(Hiro_StatusBar) +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; +}; +#endif + +#if defined(Hiro_MenuBar) +struct mMenuBar : mObject { + Declare(MenuBar) + + auto append(sMenu menu) -> type&; + auto menu(unsigned position) const -> Menu; + auto menuCount() const -> unsigned; + auto menus() const -> vector; + auto remove() -> type& override; + auto remove(sMenu menu) -> type&; + auto reset() -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; + +//private: + struct State { + vector menus; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_PopupMenu) +struct mPopupMenu : mObject { + Declare(PopupMenu) + using mObject::remove; + + auto action(unsigned position) const -> Action; + auto actionCount() const -> unsigned; + auto actions() const -> vector; + auto append(sAction action) -> type&; + auto remove(sAction action) -> type&; + auto reset() -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; + auto setVisible(bool visible = true) -> type& override; + +//private: + struct State { + vector actions; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_Action) +struct mAction : mObject { + Declare(Action) + + auto remove() -> type& override; + +//private: + struct State { + } state; +}; +#endif + +#if defined(Hiro_Menu) +struct mMenu : mAction { + Declare(Menu) + using mObject::remove; + + auto action(unsigned position) const -> Action; + auto actionCount() const -> unsigned; + auto actions() const -> vector; + auto append(sAction action) -> type&; + auto icon() const -> image; + auto remove(sAction action) -> type&; + auto reset() -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + vector actions; + image icon; + string text; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_MenuSeparator) +struct mMenuSeparator : mAction { + Declare(MenuSeparator) + +//private: + struct State { + } state; +}; +#endif + +#if defined(Hiro_MenuItem) +struct mMenuItem : mAction { + Declare(MenuItem) + + auto doActivate() const -> void; + auto icon() const -> image; + auto onActivate(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_MenuCheckItem) +struct mMenuCheckItem : mAction { + Declare(MenuCheckItem) + + auto checked() const -> bool; + auto doToggle() const -> void; + auto onToggle(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_MenuRadioItem) +struct mMenuRadioItem : mAction { + Declare(MenuRadioItem) + + auto checked() const -> bool; + auto doActivate() const -> void; + auto group() const -> Group override; + auto onActivate(const function& callback = {}) -> type&; + auto setChecked() -> type&; + auto setGroup(sGroup group = {}) -> type& override; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + bool checked = false; + sGroup group; + function onActivate; + string text; + } state; +}; +#endif + +#if defined(Hiro_Sizable) +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; +}; +#endif + +#if defined(Hiro_Layout) +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 -> Sizable; + auto sizableCount() const -> unsigned; + auto sizables() const -> vector; + +//private: + struct State { + vector sizables; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_Widget) +struct mWidget : mSizable { + Declare(Widget) + + auto doSize() const -> void; + auto onSize(const function& callback = {}) -> type&; + auto remove() -> type& override; + +//private: + struct State { + function onSize; + } state; +}; +#endif + +#if defined(Hiro_Button) +struct mButton : mWidget { + Declare(Button) + + auto bordered() const -> bool; + auto doActivate() const -> void; + auto icon() const -> image; + auto onActivate(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_Canvas) +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 -> Gradient; + auto icon() const -> image; + auto onDrop(const function& callback = {}) -> type&; + auto onMouseLeave(const function& callback = {}) -> type&; + auto onMouseMove(const function& callback = {}) -> type&; + auto onMousePress(const function& callback = {}) -> type&; + auto onMouseRelease(const function& callback = {}) -> type&; + auto setColor(Color color = {}) -> type&; + auto setDroppable(bool droppable = true) -> type&; + auto setGradient(Gradient gradient = {}) -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setSize(Size size = {}) -> type&; + auto size() const -> Size; + auto update() -> type&; + +//private: + struct State { + Color color; + bool droppable = false; + Gradient gradient; + image icon; + function onDrop; + function onMouseLeave; + function onMouseMove; + function onMousePress; + function onMouseRelease; + } state; +}; +#endif + +#if defined(Hiro_CheckButton) +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& callback = {}) -> 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 = true; + bool checked = false; + image icon; + function onToggle; + Orientation orientation = Orientation::Horizontal; + string text; + } state; +}; +#endif + +#if defined(Hiro_CheckLabel) +struct mCheckLabel : mWidget { + Declare(CheckLabel) + + auto checked() const -> bool; + auto doToggle() const -> void; + auto onToggle(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_ComboButton) +struct mComboButton : mWidget { + Declare(ComboButton) + using mObject::remove; + + auto append(sComboButtonItem item) -> type&; + auto doChange() const -> void; + auto item(unsigned position) const -> ComboButtonItem; + auto itemCount() const -> unsigned; + auto items() const -> vector; + auto onChange(const function& callback = {}) -> type&; + auto remove(sComboButtonItem item) -> type&; + auto reset() -> type&; + auto selected() const -> ComboButtonItem; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; + +//private: + struct State { + vector items; + function onChange; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_ComboButton) +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; + bool selected = false; + string text; + } state; +}; +#endif + +#if defined(Hiro_Console) +struct mConsole : mWidget { + Declare(Console) + + auto backgroundColor() const -> Color; + auto doActivate(string) const -> void; + auto foregroundColor() const -> Color; + auto onActivate(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_Frame) +struct mFrame : mWidget { + Declare(Frame) + using mObject::remove; + + auto append(sLayout layout) -> type&; + auto layout() const -> Layout; + auto remove(sLayout layout) -> type&; + auto reset() -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + sLayout layout; + string text; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_HexEdit) +struct mHexEdit : mWidget { + Declare(HexEdit) + + auto address() const -> unsigned; + 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 onRead(const function& callback = {}) -> type&; + auto onWrite(const function& callback = {}) -> type&; + auto rows() const -> unsigned; + auto setAddress(unsigned address = 0) -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setColumns(unsigned columns = 16) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setLength(unsigned length) -> type&; + auto setRows(unsigned rows = 16) -> type&; + auto update() -> type&; + +//private: + struct State { + unsigned address = 0; + Color backgroundColor; + unsigned columns = 16; + Color foregroundColor; + unsigned length = 0; + function onRead; + function onWrite; + unsigned rows = 16; + } state; +}; +#endif + +#if defined(Hiro_HorizontalScrollBar) +struct mHorizontalScrollBar : mWidget { + Declare(HorizontalScrollBar) + + auto doChange() const -> void; + auto length() const -> unsigned; + auto onChange(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_HorizontalSlider) +struct mHorizontalSlider : mWidget { + Declare(HorizontalSlider) + + auto doChange() const -> void; + auto length() const -> unsigned; + auto onChange(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_IconView) +struct mIconView : mWidget { + Declare(IconView) + using mObject::remove; + + auto append(sIconViewItem item) -> type&; + auto backgroundColor() const -> Color; + auto batchable() const -> bool; + auto batched() const -> vector; + 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 -> IconViewItem; + auto itemCount() const -> unsigned; + auto items() const -> vector; + auto onActivate(const function& callback = {}) -> type&; + auto onChange(const function& callback = {}) -> type&; + auto onContext(const function& callback = {}) -> type&; + auto orientation() const -> Orientation; + auto remove(sIconViewItem item) -> type&; + auto reset() -> type&; + auto selected() const -> IconViewItem; + auto setBackgroundColor(Color color = {}) -> type&; + auto setBatchable(bool batchable = true) -> type&; + auto setFlow(Orientation flow = Orientation::Vertical) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; + auto setParent(mObject* object = nullptr, signed offset = -1) -> type& override; + auto setSelected(const vector& selections) -> type&; + +//private: + struct State { + Color backgroundColor; + bool batchable = false; + Color foregroundColor; + Orientation flow = Orientation::Vertical; + vector items; + function onActivate; + function onChange; + function onContext; + Orientation orientation = Orientation::Horizontal; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_IconView) +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; +}; +#endif + +#if defined(Hiro_Label) +struct mLabel : mWidget { + Declare(Label) + + auto alignment() const -> Alignment; + auto setAlignment(Alignment alignment = {}) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + Alignment alignment; + string text; + } state; +}; +#endif + +#if defined(Hiro_LineEdit) +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& callback = {}) -> type&; + auto onChange(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_ListView) +struct mListView : mWidget { + Declare(ListView) + using mObject::remove; + + auto alignment() const -> Alignment; + auto append(sListViewHeader column) -> type&; + auto append(sListViewItem item) -> type&; + auto backgroundColor() const -> Color; + auto batchable() const -> bool; + auto batched() const -> vector; + auto bordered() const -> bool; + auto doActivate() const -> void; + auto doChange() const -> void; + auto doContext() const -> void; + auto doEdit(sListViewCell cell) const -> void; + auto doSort(sListViewColumn column) const -> void; + auto doToggle(sListViewCell cell) const -> void; + auto foregroundColor() const -> Color; + auto header() const -> ListViewHeader; + auto item(unsigned position) const -> ListViewItem; + auto itemCount() const -> unsigned; + auto items() const -> vector; + auto onActivate(const function& callback = {}) -> type&; + auto onChange(const function& callback = {}) -> type&; + auto onContext(const function& callback = {}) -> type&; + auto onEdit(const function& callback = {}) -> type&; + auto onSort(const function& callback = {}) -> type&; + auto onToggle(const function& callback = {}) -> type&; + auto remove(sListViewHeader column) -> type&; + auto remove(sListViewItem item) -> type&; + auto reset() -> type&; + auto resizeColumns() -> type&; + auto selected() const -> ListViewItem; + auto setAlignment(Alignment alignment = {}) -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setBatchable(bool batchable = true) -> type&; + auto setBordered(bool bordered = true) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; + +//private: + struct State { + unsigned activeColumn = 0; + Alignment alignment; + Color backgroundColor; + bool batchable = false; + bool bordered = false; + Color foregroundColor; + sListViewHeader header; + vector items; + function onActivate; + function onChange; + function onContext; + function onEdit; + function onSort; + function onToggle; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_ListView) +struct mListViewHeader : mObject { + Declare(ListViewHeader) + + auto append(sListViewColumn column) -> type&; + auto column(unsigned position) const -> ListViewColumn; + auto columnCount() const -> unsigned; + auto columns() const -> vector; + auto remove() -> type& override; + auto remove(sListViewColumn column) -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; + +//private: + struct State { + vector columns; + } state; +}; +#endif + +#if defined(Hiro_ListView) +struct mListViewColumn : mObject { + Declare(ListViewColumn) + + auto active() const -> bool; + auto alignment() const -> Alignment; + auto backgroundColor() const -> Color; + auto editable() const -> bool; + auto expandable() 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 setAlignment(Alignment alignment = {}) -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setEditable(bool editable = true) -> type&; + auto setExpandable(bool expandable = true) -> 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 { + Alignment alignment; + Color backgroundColor; + bool editable = false; + bool expandable = false; + 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; +}; +#endif + +#if defined(Hiro_ListView) +struct mListViewItem : mObject { + Declare(ListViewItem) + + auto alignment() const -> Alignment; + auto append(sListViewCell cell) -> type&; + auto backgroundColor() const -> Color; + auto cell(unsigned position) const -> ListViewCell; + auto cellCount() const -> unsigned; + auto cells() const -> vector; + auto foregroundColor() const -> Color; + auto remove() -> type& override; + auto remove(sListViewCell cell) -> type&; + auto selected() const -> bool; + auto setAlignment(Alignment alignment = {}) -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setFocused() -> type& override; + auto setForegroundColor(Color color = {}) -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; + auto setSelected(bool selected = true) -> type&; + +//private: + struct State { + Alignment alignment; + Color backgroundColor; + vector cells; + Color foregroundColor; + bool selected = false; + } state; +}; +#endif + +#if defined(Hiro_ListView) +struct mListViewCell : mObject { + Declare(ListViewCell) + + auto alignment(bool recursive = false) const -> Alignment; + auto backgroundColor(bool recursive = false) const -> Color; + auto checkable() const -> bool; + auto checked() const -> bool; + auto font(bool recursive = false) const -> Font; + auto foregroundColor(bool recursive = false) const -> Color; + auto icon() const -> image; + auto setAlignment(Alignment alignment = {}) -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setCheckable(bool checkable = true) -> type&; + auto setChecked(bool checked = true) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + Alignment alignment; + Color backgroundColor; + bool checkable = false; + bool checked = false; + Color foregroundColor; + image icon; + string text; + } state; +}; +#endif + +#if defined(Hiro_ProgressBar) +struct mProgressBar : mWidget { + Declare(ProgressBar) + + auto position() const -> unsigned; + auto setPosition(unsigned position) -> type&; + +//private: + struct State { + unsigned position = 0; + } state; +}; +#endif + +#if defined(Hiro_RadioButton) +struct mRadioButton : mWidget { + Declare(RadioButton) + + auto bordered() const -> bool; + auto checked() const -> bool; + auto doActivate() const -> void; + auto group() const -> Group override; + auto icon() const -> image; + auto onActivate(const function& callback = {}) -> type&; + auto orientation() const -> Orientation; + auto setBordered(bool bordered = true) -> type&; + auto setChecked() -> type&; + auto setGroup(sGroup group = {}) -> type& override; + 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; + bool checked = false; + sGroup group; + image icon; + function onActivate; + Orientation orientation = Orientation::Horizontal; + string text; + } state; +}; +#endif + +#if defined(Hiro_RadioLabel) +struct mRadioLabel : mWidget { + Declare(RadioLabel) + + auto checked() const -> bool; + auto doActivate() const -> void; + auto group() const -> Group override; + auto onActivate(const function& callback = {}) -> type&; + auto setChecked() -> type&; + auto setGroup(sGroup group = {}) -> type& override; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + bool checked = false; + sGroup group; + function onActivate; + string text; + } state; +}; +#endif + +#if defined(Hiro_SourceEdit) +struct mSourceEdit : mWidget { + Declare(SourceEdit) + + auto cursor() const -> Cursor; + auto doChange() const -> void; + auto doMove() const -> void; + auto onChange(const function& callback = {}) -> type&; + auto onMove(const function& callback = {}) -> type&; + auto setCursor(Cursor cursor = {}) -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + Cursor cursor; + function onChange; + function onMove; + string text; + } state; +}; +#endif + +#if defined(Hiro_TabFrame) +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 item(unsigned position) const -> TabFrameItem; + auto itemCount() const -> unsigned; + auto items() const -> vector; + auto navigation() const -> Navigation; + auto onChange(const function& callback = {}) -> type&; + auto onClose(const function& callback = {}) -> type&; + auto onMove(const function& callback = {}) -> type&; + auto remove(sTabFrameItem item) -> type&; + auto reset() -> type&; + auto selected() const -> TabFrameItem; + auto setNavigation(Navigation navigation = Navigation::Top) -> type&; + auto setParent(mObject* object = nullptr, signed offset = -1) -> type& override; + +//private: + struct State { + vector items; + Navigation navigation = Navigation::Top; + function onChange; + function onClose; + function onMove; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_TabFrame) +struct mTabFrameItem : mObject { + Declare(TabFrameItem) + + auto append(sLayout layout) -> type&; + auto closable() const -> bool; + auto icon() const -> image; + auto layout() const -> Layout; + 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; + bool selected = false; + string text; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_TextEdit) +struct mTextEdit : mWidget { + Declare(TextEdit) + + auto backgroundColor() const -> Color; + auto cursor() const -> Cursor; + auto doChange() const -> void; + auto doMove() const -> void; + auto editable() const -> bool; + auto foregroundColor() const -> Color; + auto onChange(const function& callback = {}) -> type&; + auto onMove(const function& callback = {}) -> type&; + auto setBackgroundColor(Color color = {}) -> type&; + auto setCursor(Cursor cursor = {}) -> 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; + Cursor cursor; + bool editable = true; + Color foregroundColor; + function onChange; + function onMove; + string text; + bool wordWrap = true; + } state; +}; +#endif + +#if defined(Hiro_TreeView) +struct mTreeView : mWidget { + Declare(TreeView) + using mObject::remove; + + auto append(sTreeViewItem item) -> type&; + auto backgroundColor() const -> Color; + auto doActivate() const -> void; + auto doChange() const -> void; + auto doContext() const -> void; + auto doToggle(sTreeViewItem item) const -> void; + auto foregroundColor() const -> Color; + auto item(const string& path) const -> TreeViewItem; + auto itemCount() const -> unsigned; + auto items() const -> vector; + auto onActivate(const function& callback = {}) -> type&; + auto onChange(const function& callback = {}) -> type&; + auto onContext(const function& callback = {}) -> type&; + auto onToggle(const function& callback = {}) -> type&; + auto remove(sTreeViewItem item) -> type&; + auto reset() -> type&; + auto selected() const -> TreeViewItem; + auto setBackgroundColor(Color color = {}) -> type&; + auto setForegroundColor(Color color = {}) -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type&; + +//private: + struct State { + Color backgroundColor; + Color foregroundColor; + vector items; + function onActivate; + function onChange; + function onContext; + function onToggle; + string selectedPath; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_TreeView) +struct mTreeViewItem : mObject { + Declare(TreeViewItem) + + auto append(sTreeViewItem item) -> type&; + auto backgroundColor(bool recursive = false) const -> Color; + auto checkable() const -> bool; + auto checked() const -> bool; + auto foregroundColor(bool recursive = false) const -> Color; + auto icon() const -> image; + auto item(const string& path) const -> TreeViewItem; + auto itemCount() const -> unsigned; + auto items() const -> vector; + auto path() const -> string; + auto remove() -> type& override; + auto remove(sTreeViewItem item) -> type&; + auto selected() const -> bool; + auto setBackgroundColor(Color color = {}) -> type&; + auto setCheckable(bool checkable = true) -> type&; + auto setChecked(bool checked = true) -> type&; + auto setExpanded(bool expanded = true) -> type&; + auto setFocused() -> type& override; + auto setForegroundColor(Color color = {}) -> type&; + auto setIcon(const image& icon = {}) -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type&; + auto setSelected() -> type&; + auto setText(const string& text = "") -> type&; + auto text() const -> string; + +//private: + struct State { + Color backgroundColor; + bool checkable = false; + bool checked = false; + Color foregroundColor; + image icon; + vector items; + string text; + } state; + + auto destruct() -> void override; +}; +#endif + +#if defined(Hiro_VerticalScrollBar) +struct mVerticalScrollBar : mWidget { + Declare(VerticalScrollBar) + + auto doChange() const -> void; + auto length() const -> unsigned; + auto onChange(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_VerticalSlider) +struct mVerticalSlider : mWidget { + Declare(VerticalSlider) + + auto doChange() const -> void; + auto length() const -> unsigned; + auto onChange(const function& callback = {}) -> 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; +}; +#endif + +#if defined(Hiro_Viewport) +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& callback = {}) -> type&; + auto onMouseLeave(const function& callback = {}) -> type&; + auto onMouseMove(const function& callback = {}) -> type&; + auto onMousePress(const function& callback = {}) -> type&; + auto onMouseRelease(const function& callback = {}) -> type&; + auto setDroppable(bool droppable = true) -> type&; + +//private: + struct State { + bool droppable = false; + function onDrop; + function onMouseLeave; + function onMouseMove; + function onMousePress; + function onMouseRelease; + } state; +}; +#endif + +#undef Declare + +#include "shared.hpp" + +} diff --git a/core/cursor.cpp b/core/cursor.cpp new file mode 100644 index 0000000..4db6e46 --- /dev/null +++ b/core/cursor.cpp @@ -0,0 +1,43 @@ +#if defined(Hiro_Cursor) + +Cursor::Cursor(signed offset, signed length) { + setCursor(offset, length); +} + +Cursor::operator bool() const { + return offset() && length(); +} + +auto Cursor::operator==(const Cursor& source) const -> bool { + return offset() == source.offset() && length() == source.length(); +} + +auto Cursor::operator!=(const Cursor& source) const -> bool { + return !operator==(source); +} + +auto Cursor::length() const -> signed { + return state.length; +} + +auto Cursor::offset() const -> signed { + return state.offset; +} + +auto Cursor::setCursor(signed offset, signed length) -> type& { + state.offset = offset; + state.length = length; + return *this; +} + +auto Cursor::setOffset(signed offset) -> type& { + state.offset = offset; + return *this; +} + +auto Cursor::setLength(signed length) -> type& { + state.length = length; + return *this; +} + +#endif diff --git a/core/desktop.cpp b/core/desktop.cpp new file mode 100644 index 0000000..9e33060 --- /dev/null +++ b/core/desktop.cpp @@ -0,0 +1,11 @@ +#if defined(Hiro_Desktop) + +auto Desktop::size() -> Size { + return pDesktop::size(); +} + +auto Desktop::workspace() -> Geometry { + return pDesktop::workspace(); +} + +#endif diff --git a/core/font.cpp b/core/font.cpp new file mode 100644 index 0000000..d082c9c --- /dev/null +++ b/core/font.cpp @@ -0,0 +1,74 @@ +#if defined(Hiro_Font) + +const string Font::Sans = "{sans}"; +const string Font::Serif = "{serif}"; +const string Font::Mono = "{mono}"; + +Font::Font(const string& family, unsigned size) { + setFamily(family); + setSize(size); + state.bold = false; + state.italic = false; +} + +Font::operator bool() const { + return state.family || state.size || state.bold || state.italic; +} + +auto Font::operator==(const Font& source) const -> bool { + return family() == source.family() && size() == source.size() && bold() == source.bold() && italic() == source.italic(); +} + +auto Font::operator!=(const Font& source) const -> bool { + return !operator==(source); +} + +auto Font::bold() const -> bool { + return state.bold; +} + +auto Font::family() const -> string { + return state.family; +} + +auto Font::italic() const -> bool { + return state.italic; +} + +auto Font::reset() -> type& { + state.family = ""; + state.size = 0; + state.bold = false; + state.italic = false; + return *this; +} + +auto Font::setBold(bool bold) -> type& { + state.bold = bold; + return *this; +} + +auto Font::setFamily(const string& family) -> type& { + state.family = family; + return *this; +} + +auto Font::setItalic(bool italic) -> type& { + state.italic = italic; + return *this; +} + +auto Font::setSize(unsigned size) -> type& { + state.size = size; + return *this; +} + +auto Font::size() const -> unsigned { + return state.size; +} + +auto Font::size(const string& text) const -> Size { + return pFont::size(*this, text); +} + +#endif diff --git a/core/geometry.cpp b/core/geometry.cpp new file mode 100644 index 0000000..fe90141 --- /dev/null +++ b/core/geometry.cpp @@ -0,0 +1,112 @@ +#if defined(Hiro_Geometry) + +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::operator bool() const { + return state.x || state.y || state.width || state.height; +} + +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::reset() -> type& { + return setGeometry(0, 0, 0, 0); +} + +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::width() const -> signed { + return state.width; +} + +auto Geometry::x() const -> signed { + return state.x; +} + +auto Geometry::y() const -> signed { + return state.y; +} + +#endif diff --git a/core/gradient.cpp b/core/gradient.cpp new file mode 100644 index 0000000..946ad0f --- /dev/null +++ b/core/gradient.cpp @@ -0,0 +1,37 @@ +#if defined(Hiro_Gradient) + +Gradient::Gradient() { +} + +Gradient::operator bool() const { + return state.colors.size() == 4; +} + +auto Gradient::operator==(const Gradient& source) const -> bool { + if(state.colors.size() != source.state.colors.size()) return false; + for(auto n : range(state.colors)) { + if(state.colors[n] != source.state.colors[n]) return false; + } + return true; +} + +auto Gradient::operator!=(const Gradient& source) const -> bool { + return !operator==(source); +} + +auto Gradient::setBilinear(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> type& { + state.colors = {topLeft, topRight, bottomLeft, bottomRight}; + return *this; +} + +auto Gradient::setHorizontal(Color left, Color right) -> type& { + state.colors = {left, right, left, right}; + return *this; +} + +auto Gradient::setVertical(Color top, Color bottom) -> type& { + state.colors = {top, top, bottom, bottom}; + return *this; +} + +#endif diff --git a/core/group.cpp b/core/group.cpp new file mode 100644 index 0000000..e7691b6 --- /dev/null +++ b/core/group.cpp @@ -0,0 +1,51 @@ +#if defined(Hiro_Group) + +auto mGroup::allocate() -> pObject* { + return new pGroup(*this); +} + +// + +auto mGroup::append(sObject object) -> type& { + if(auto group = instance.acquire()) { + state.objects.append(object); + object->setGroup(group); + } + return *this; +} + +auto mGroup::object(unsigned position) const -> Object { + if(position < objectCount()) { + if(auto object = state.objects[position].acquire()) { + return object; + } + } + return {}; +} + +auto mGroup::objectCount() const -> unsigned { + return state.objects.size(); +} + +auto mGroup::objects() const -> vector { + vector objects; + for(auto& weak : state.objects) { + if(auto object = weak.acquire()) objects.append(object); + } + return objects; +} + +auto mGroup::remove(sObject object) -> type& { + object->setGroup(); + for(auto offset : range(state.objects)) { + if(auto shared = state.objects[offset].acquire()) { + if(object == shared) { + state.objects.remove(offset); + break; + } + } + } + return *this; +} + +#endif diff --git a/core/hotkey.cpp b/core/hotkey.cpp new file mode 100644 index 0000000..021c0eb --- /dev/null +++ b/core/hotkey.cpp @@ -0,0 +1,62 @@ +#if defined(Hiro_Hotkey) + +Hotkey::Hotkey() : state(new Hotkey::State) { + setSequence(); +} + +Hotkey::Hotkey(const string& sequence) : state(new Hotkey::State) { + setSequence(sequence); +} + +Hotkey::operator bool() const { + return (bool)state->sequence; +} + +auto Hotkey::operator==(const Hotkey& source) const -> bool { + return state == source.state; +} + +auto Hotkey::operator!=(const Hotkey& source) const -> bool { + return !operator==(source); +} + +auto Hotkey::doPress() const -> void { + if(state->onPress) state->onPress(); +} + +auto Hotkey::doRelease() const -> void { + if(state->onRelease) state->onRelease(); +} + +auto Hotkey::onPress(const function& callback) -> type& { + state->onPress = callback; + return *this; +} + +auto Hotkey::onRelease(const function& callback) -> type& { + state->onRelease = callback; + return *this; +} + +auto Hotkey::reset() -> type& { + setSequence(); + return *this; +} + +auto Hotkey::sequence() const -> string { + return state->sequence; +} + +auto Hotkey::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; +} + +#endif diff --git a/core/keyboard.cpp b/core/keyboard.cpp new file mode 100644 index 0000000..8abbbf3 --- /dev/null +++ b/core/keyboard.cpp @@ -0,0 +1,79 @@ +#if defined(Hiro_Keyboard) + +Keyboard::State Keyboard::state; + +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(Hotkey hotkey) -> void { + state.hotkeys.append(hotkey); +} + +auto Keyboard::hotkey(unsigned position) -> Hotkey { + if(position < hotkeyCount()) return state.hotkeys[position]; + return {}; +} + +auto Keyboard::hotkeyCount() -> unsigned { + return state.hotkeys.size(); +} + +auto Keyboard::hotkeys() -> vector { + return state.hotkeys; +} + +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(hotkey.state->active != active) { + hotkey.state->active = active; + active ? hotkey.doPress() : 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(Hotkey hotkey) -> void { + if(auto offset = state.hotkeys.find(hotkey)) { + state.hotkeys.remove(*offset); + } +} + +#endif diff --git a/core/layout.cpp b/core/layout.cpp new file mode 100644 index 0000000..cf4a94e --- /dev/null +++ b/core/layout.cpp @@ -0,0 +1,70 @@ +#if defined(Hiro_Layout) + +auto mLayout::allocate() -> pObject* { + return new pLayout(*this); +} + +auto mLayout::destruct() -> void { + for(auto& sizable : state.sizables) sizable->destruct(); + mSizable::destruct(); +} + +// + +auto mLayout::append(sSizable sizable) -> type& { + state.sizables.append(sizable); + sizable->setParent(this, sizableCount() - 1); + setGeometry(geometry()); + return *this; +} + +auto mLayout::remove() -> type& { + #if defined(Hiro_TabFrame) + if(auto tabFrameItem = parentTabFrameItem()) tabFrameItem->remove(tabFrameItem->layout()); + #endif + 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(sSizable sizable) -> type& { + auto offset = sizable->offset(); + sizable->setParent(); + state.sizables.remove(offset); + for(auto n : range(offset, sizableCount())) { + state.sizables[n]->adjustOffset(-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 -> Sizable { + if(position < sizableCount()) return state.sizables[position]; + return {}; +} + +auto mLayout::sizableCount() const -> unsigned { + return state.sizables.size(); +} + +auto mLayout::sizables() const -> vector { + vector sizables; + for(auto& sizable : sizables) sizables.append(sizable); + return sizables; +} + +#endif diff --git a/core/menu-bar.cpp b/core/menu-bar.cpp new file mode 100644 index 0000000..329f082 --- /dev/null +++ b/core/menu-bar.cpp @@ -0,0 +1,64 @@ +#if defined(Hiro_MenuBar) + +auto mMenuBar::allocate() -> pObject* { + return new pMenuBar(*this); +} + +auto mMenuBar::destruct() -> void { + for(auto& menu : state.menus) menu->destruct(); + mObject::destruct(); +} + +// + +auto mMenuBar::append(sMenu menu) -> type& { + state.menus.append(menu); + menu->setParent(this, menuCount() - 1); + signal(append, menu); + return *this; +} + +auto mMenuBar::menu(unsigned position) const -> Menu { + if(position < menuCount()) return state.menus[position]; + return {}; +} + +auto mMenuBar::menuCount() const -> unsigned { + return state.menus.size(); +} + +auto mMenuBar::menus() const -> vector { + vector menus; + for(auto& menu : state.menus) menus.append(menu); + return menus; +} + +auto mMenuBar::remove() -> type& { + if(auto window = parentWindow()) window->remove(window->menuBar()); + return *this; +} + +auto mMenuBar::remove(sMenu menu) -> type& { + signed offset = menu->offset(); + signal(remove, *menu); + state.menus.remove(offset); + for(auto n : range(offset, menuCount())) { + state.menus[n]->adjustOffset(-1); + } + menu->setParent(); + return *this; +} + +auto mMenuBar::reset() -> type& { + while(state.menus) remove(state.menus.last()); + return *this; +} + +auto mMenuBar::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.menus)) state.menus[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& menu : state.menus) menu->setParent(this, menu->offset()); + return *this; +} + +#endif diff --git a/core/message-window.cpp b/core/message-window.cpp new file mode 100644 index 0000000..1b238a3 --- /dev/null +++ b/core/message-window.cpp @@ -0,0 +1,42 @@ +#if defined(Hiro_MessageWindow) + +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); +} + +#endif diff --git a/core/monitor.cpp b/core/monitor.cpp new file mode 100644 index 0000000..e4f0769 --- /dev/null +++ b/core/monitor.cpp @@ -0,0 +1,15 @@ +#if defined(Hiro_Monitor) + +auto Monitor::count() -> unsigned { + return pMonitor::count(); +} + +auto Monitor::geometry(unsigned monitor) -> Geometry { + return pMonitor::geometry(monitor); +} + +auto Monitor::primary() -> unsigned { + return pMonitor::primary(); +} + +#endif diff --git a/core/mouse.cpp b/core/mouse.cpp new file mode 100644 index 0000000..7042d9d --- /dev/null +++ b/core/mouse.cpp @@ -0,0 +1,15 @@ +#if defined(Hiro_Mouse) + +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); +} + +#endif diff --git a/core/object.cpp b/core/object.cpp new file mode 100644 index 0000000..810e9e0 --- /dev/null +++ b/core/object.cpp @@ -0,0 +1,331 @@ +#if defined(Hiro_Object) + +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; +} + +// + +//used to test if returned items "exist" from eg Window::layout(), ListView::selected(), etc. +mObject::operator bool() const { + return parent() || !abstract(); +} + +//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 defined(Hiro_Group) + if(dynamic_cast(this)) return false; + #endif + + #if defined(Hiro_Timer) + if(dynamic_cast(this)) return false; + #endif + + #if defined(Hiro_Window) + if(dynamic_cast(this)) return false; + #endif + + #if defined(Hiro_PopupMenu) + if(dynamic_cast(this)) return false; + #endif + + if(auto object = parent()) return object->abstract(); + return true; +} + +auto mObject::adjustOffset(signed displacement) -> type& { + state.offset += displacement; + return *this; +} + +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 -> Font { + if(!recursive || state.font) return state.font; + if(auto object = parent()) return object->font(true); + return Application::font(); +} + +auto mObject::group() const -> Group { + return {}; +} + +auto mObject::offset() const -> signed { + return state.offset; +} + +auto mObject::parent() const -> mObject* { + return state.parent; +} + +#if defined(Hiro_ComboButton) +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; +} +#endif + +#if defined(Hiro_Frame) +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; +} +#endif + +#if defined(Hiro_IconView) +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; +} +#endif + +#if defined(Hiro_Layout) +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; +} +#endif + +#if defined(Hiro_ListView) +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; +} +#endif + +#if defined(Hiro_ListView) +auto mObject::parentListViewHeader(bool recursive) const -> mListViewHeader* { + if(auto listViewHeader = dynamic_cast(parent())) return listViewHeader; + if(recursive) { + if(auto object = parent()) return object->parentListViewHeader(true); + } + return nullptr; +} +#endif + +#if defined(Hiro_ListView) +auto mObject::parentListViewItem(bool recursive) const -> mListViewItem* { + if(auto listViewItem = dynamic_cast(parent())) return listViewItem; + if(recursive) { + if(auto object = parent()) return object->parentListViewItem(true); + } + return nullptr; +} +#endif + +#if defined(Hiro_Menu) +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; +} +#endif + +#if defined(Hiro_MenuBar) +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; +} +#endif + +#if defined(Hiro_PopupMenu) +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; +} +#endif + +#if defined(Hiro_Sizable) +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; +} +#endif + +#if defined(Hiro_TabFrame) +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; +} +#endif + +#if defined(Hiro_TabFrame) +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; +} +#endif + +#if defined(Hiro_TreeView) +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; +} +#endif + +#if defined(Hiro_TreeView) +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; +} +#endif + +#if defined(Hiro_Widget) +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; +} +#endif + +#if defined(Hiro_Window) +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; +} +#endif + +auto mObject::property(const string& name) const -> string { + if(auto property = state.properties.find({name})) { + return property->value(); + } + return {}; +} + +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 Font& font) -> type& { + state.font = font; + signal(setFont, this->font(true)); + return *this; +} + +auto mObject::setGroup(sGroup group) -> type& { + return *this; +} + +auto mObject::setParent(mObject* parent, signed offset) -> type& { + destruct(); + state.parent = parent; + state.offset = offset; + if(!abstract()) construct(); + return *this; +} + +auto mObject::setProperty(const string& name, const string& value) -> type& { + if(auto property = state.properties.find(name)) { + if(value) property->setValue(value); + else state.properties.remove(*property); + } else { + if(value) state.properties.insert({name, value}); + } + 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; +} + +#endif diff --git a/core/popup-menu.cpp b/core/popup-menu.cpp new file mode 100644 index 0000000..f064df7 --- /dev/null +++ b/core/popup-menu.cpp @@ -0,0 +1,64 @@ +#if defined(Hiro_PopupMenu) + +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 -> Action { + if(position < actionCount()) return state.actions[position]; + return {}; +} + +auto mPopupMenu::actionCount() const -> unsigned { + return state.actions.size(); +} + +auto mPopupMenu::actions() const -> vector { + vector actions; + for(auto& action : state.actions) actions.append(action); + return actions; +} + +auto mPopupMenu::append(sAction action) -> type& { + state.actions.append(action); + action->setParent(this, actionCount() - 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, actionCount())) { + state.actions[n]->adjustOffset(-1); + } + action->setParent(); + return *this; +} + +auto mPopupMenu::reset() -> type& { + while(state.actions) remove(state.actions.last()); + return *this; +} + +auto mPopupMenu::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.actions)) state.actions[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& action : state.actions) action->construct(); + return *this; +} + +auto mPopupMenu::setVisible(bool visible) -> type& { + signal(setVisible, visible); + return *this; +} + +#endif diff --git a/core/position.cpp b/core/position.cpp new file mode 100644 index 0000000..0bab72e --- /dev/null +++ b/core/position.cpp @@ -0,0 +1,55 @@ +#if defined(Hiro_Position) + +Position::Position() { + setPosition(0, 0); +} + +Position::Position(signed x, signed y) { + setPosition(x, y); +} + +Position::operator bool() const { + return state.x || state.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::reset() -> type& { + return setPosition(0, 0); +} + +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; +} + +#endif diff --git a/core/property.cpp b/core/property.cpp new file mode 100644 index 0000000..e1b7536 --- /dev/null +++ b/core/property.cpp @@ -0,0 +1,29 @@ +#if defined(Hiro_Property) + +Property::Property(const string& name, const string& value) { + state.name = name; + state.value = value; +} + +auto Property::operator==(const Property& source) const -> bool { + return state.name == source.state.name; +} + +auto Property::operator<(const Property& source) const -> bool { + return state.name < source.state.name; +} + +auto Property::name() const -> string { + return state.name; +} + +auto Property::setValue(const string& value) -> type& { + state.value = value; + return *this; +} + +auto Property::value() const -> string { + return state.value; +} + +#endif diff --git a/core/shared.hpp b/core/shared.hpp new file mode 100644 index 0000000..947e091 --- /dev/null +++ b/core/shared.hpp @@ -0,0 +1,942 @@ +#define DeclareShared(Name) \ + using type = Name; \ + Name() : s##Name(new m##Name, [](auto p) { \ + p->unbind(); \ + delete p; \ + }) { \ + (*this)->bind(*this); \ + } \ + Name(const s##Name& source) : s##Name(source) { assert(source); } \ + explicit operator bool() const { return self().operator bool(); } \ + auto self() const -> m##Name& { return (m##Name&)operator*(); } \ + +#define DeclareSharedObject(Name) \ + DeclareShared(Name) \ + template Name(T* parent, P&&... p) : Name() { \ + if(parent) (*parent)->append(*this, std::forward

(p)...); \ + } \ + auto enabled(bool recursive = false) const { return self().enabled(recursive); } \ + auto focused() const { return self().focused(); } \ + auto font(bool recursive = false) const { return self().font(recursive); } \ + auto offset() const { return self().offset(); } \ + auto parent() const { \ + if(auto object = self().parent()) { \ + if(auto instance = object->instance.acquire()) return Object(instance); \ + } \ + return Object(); \ + } \ + auto property(const string& name) const { return self().property(name); } \ + auto remove() { return self().remove(), *this; } \ + auto setEnabled(bool enabled = true) { return self().setEnabled(enabled), *this; } \ + auto setFocused() { return self().setFocused(), *this; } \ + auto setFont(const Font& font = {}) { return self().setFont(font), *this; } \ + auto setProperty(const string& name, const string& value = "") { return self().setProperty(name, value), *this; } \ + auto setVisible(bool visible = true) { return self().setVisible(visible), *this; } \ + auto visible(bool recursive = false) const { return self().visible(recursive); } \ + +#define DeclareSharedAction(Name) \ + DeclareSharedObject(Name) \ + +#define DeclareSharedSizable(Name) \ + DeclareSharedObject(Name) \ + auto geometry() const { return self().geometry(); } \ + auto minimumSize() const { return self().minimumSize(); } \ + auto setGeometry(Geometry geometry) { return self().setGeometry(geometry), *this; } \ + +#define DeclareSharedLayout(Name) \ + DeclareSharedSizable(Name) \ + auto append(sSizable sizable) { return self().append(sizable), *this; } \ + auto remove(sSizable sizable) { return self().remove(sizable), *this; } \ + auto reset() { return self().reset(), *this; } \ + auto sizable(unsigned position) { return self().sizable(position); } \ + auto sizableCount() const { return self().sizableCount(); } \ + auto sizables() const { return self().sizables(); } \ + +#define DeclareSharedWidget(Name) \ + DeclareSharedSizable(Name) \ + auto doSize() const { return self().doSize(); } \ + auto onSize(const function& callback = {}) { return self().onSize(callback), *this; } \ + +#if defined(Hiro_Object) +struct Object : sObject { + DeclareSharedObject(Object) + using internalType = mObject; + + template auto cast() -> T { + if(auto pointer = dynamic_cast(data())) { + if(auto shared = pointer->instance.acquire()) return T(shared); + } + return T(); + } +}; +#endif + +#if defined(Hiro_Group) +struct Group : sGroup { + DeclareShared(Group) + using internalType = mGroup; + template Group(P&&... p) : Group() { _append(std::forward

(p)...); } + + auto append(sObject object) -> type& { return self().append(object), *this; } + auto object(unsigned position) const { return self().object(position); } + auto objectCount() const { return self().objectCount(); } +//auto objects() const { return self().objects(); } + auto remove(sObject object) -> type& { return self().remove(object), *this; } + + template auto objects() const -> vector { + vector objects; + for(auto object : self().objects()) { + if(auto cast = object.cast()) objects.append(cast); + } + return objects; + } + +private: + auto _append() {} + template auto _append(T* object, P&&... p) { + append(*object); + _append(std::forward

(p)...); + } +}; +#endif + +#if defined(Hiro_Timer) +struct Timer : sTimer { + DeclareSharedObject(Timer) + using internalType = mTimer; + + auto doActivate() const { return self().doActivate(); } + auto interval() const { return self().interval(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto setInterval(unsigned interval = 0) { return self().setInterval(interval), *this; } +}; +#endif + +#if defined(Hiro_Action) +struct Action : sAction { + DeclareSharedAction(Action) + using internalType = mAction; +}; +#endif + +#if defined(Hiro_Menu) +struct Menu : sMenu { + DeclareSharedAction(Menu) + using internalType = mMenu; + + auto action(unsigned position) const { return self().action(position); } + auto actionCount() const { return self().actionCount(); } + auto actions() const { return self().actions(); } + auto append(sAction action) { return self().append(action), *this; } + auto icon() const { return self().icon(); } + auto remove(sAction action) { return self().remove(action), *this; } + auto reset() { return self().reset(), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_MenuSeparator) +struct MenuSeparator : sMenuSeparator { + DeclareSharedAction(MenuSeparator) + using internalType = mMenuSeparator; +}; +#endif + +#if defined(Hiro_MenuItem) +struct MenuItem : sMenuItem { + DeclareSharedAction(MenuItem) + using internalType = mMenuItem; + + auto doActivate() const { return self().doActivate(); } + auto icon() const { return self().icon(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_MenuCheckItem) +struct MenuCheckItem : sMenuCheckItem { + DeclareSharedAction(MenuCheckItem) + using internalType = mMenuCheckItem; + + auto checked() const { return self().checked(); } + auto doToggle() const { return self().doToggle(); } + auto onToggle(const function& callback = {}) { return self().onToggle(callback), *this; } + auto setChecked(bool checked = true) { return self().setChecked(checked), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_MenuRadioItem) +struct MenuRadioItem : sMenuRadioItem { + DeclareSharedAction(MenuRadioItem) + using internalType = mMenuRadioItem; + + auto checked() const { return self().checked(); } + auto doActivate() const { return self().doActivate(); } + auto group() const { return self().group(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto setChecked() { return self().setChecked(), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_Sizable) +struct Sizable : sSizable { + DeclareSharedSizable(Sizable) + using internalType = mSizable; +}; +#endif + +#if defined(Hiro_Layout) +struct Layout : sLayout { + DeclareSharedLayout(Layout) + using internalType = mLayout; +}; +#endif + +#if defined(Hiro_Widget) +struct Widget : sWidget { + DeclareSharedWidget(Widget) + using internalType = mWidget; +}; +#endif + +#if defined(Hiro_Button) +struct Button : sButton { + DeclareSharedWidget(Button) + using internalType = mButton; + + auto bordered() const { return self().bordered(); } + auto doActivate() const { return self().doActivate(); } + auto icon() const { return self().icon(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto orientation() const { return self().orientation(); } + auto setBordered(bool bordered = true) { return self().setBordered(bordered), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setOrientation(Orientation orientation = Orientation::Horizontal) { return self().setOrientation(orientation), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_Canvas) +struct Canvas : sCanvas { + DeclareSharedWidget(Canvas) + using internalType = mCanvas; + + auto color() const { return self().color(); } + auto data() { return self().data(); } + auto droppable() const { return self().droppable(); } + auto doDrop(lstring names) { return self().doDrop(names); } + auto doMouseLeave() const { return self().doMouseLeave(); } + auto doMouseMove(Position position) const { return self().doMouseMove(position); } + auto doMousePress(Mouse::Button button) const { return self().doMousePress(button); } + auto doMouseRelease(Mouse::Button button) const { return self().doMouseRelease(button); } + auto gradient() const { return self().gradient(); } + auto icon() const { return self().icon(); } + auto onDrop(const function& callback = {}) { return self().onDrop(callback), *this; } + auto onMouseLeave(const function& callback = {}) { return self().onMouseLeave(callback), *this; } + auto onMouseMove(const function& callback = {}) { return self().onMouseMove(callback), *this; } + auto onMousePress(const function& callback = {}) { return self().onMousePress(callback), *this; } + auto onMouseRelease(const function& callback = {}) { return self().onMouseRelease(callback), *this; } + auto setColor(Color color) { return self().setColor(color), *this; } + auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; } + auto setGradient(Gradient gradient = {}) { return self().setGradient(gradient), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setSize(Size size = {}) { return self().setSize(size), *this; } + auto update() { return self().update(), *this; } +}; +#endif + +#if defined(Hiro_CheckButton) +struct CheckButton : sCheckButton { + DeclareSharedWidget(CheckButton) + using internalType = mCheckButton; + + auto bordered() const { return self().bordered(); } + auto checked() const { return self().checked(); } + auto doToggle() const { return self().doToggle(); } + auto icon() const { return self().icon(); } + auto onToggle(const function& callback = {}) { return self().onToggle(callback), *this; } + auto orientation() const { return self().orientation(); } + auto setBordered(bool bordered = true) { return self().setBordered(bordered), *this; } + auto setChecked(bool checked = true) { return self().setChecked(checked), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setOrientation(Orientation orientation = Orientation::Horizontal) { return self().setOrientation(orientation), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_CheckLabel) +struct CheckLabel : sCheckLabel { + DeclareSharedWidget(CheckLabel) + using internalType = mCheckLabel; + + auto checked() const { return self().checked(); } + auto doToggle() const { return self().doToggle(); } + auto onToggle(const function& callback = {}) { return self().onToggle(callback), *this; } + auto setChecked(bool checked = true) { return self().setChecked(checked), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_ComboButton) +struct ComboButtonItem : sComboButtonItem { + DeclareSharedObject(ComboButtonItem) + using internalType = mComboButtonItem; + + auto icon() const { return self().icon(); } + auto selected() const { return self().selected(); } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setSelected() { return self().setSelected(), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_ComboButton) +struct ComboButton : sComboButton { + DeclareSharedWidget(ComboButton) + using internalType = mComboButton; + + auto append(sComboButtonItem item) { return self().append(item), *this; } + auto doChange() const { return self().doChange(); } + auto item(unsigned position) const { return self().item(position); } + auto itemCount() const { return self().itemCount(); } + auto items() const { return self().items(); } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto remove(sComboButtonItem item) { return self().remove(item), *this; } + auto reset() { return self().reset(), *this; } + auto selected() const { return self().selected(); } + auto setParent(mObject* parent = nullptr, signed offset = -1) { return self().setParent(parent, offset), *this; } +}; +#endif + +#if defined(Hiro_Console) +struct Console : sConsole { + DeclareSharedWidget(Console) + using internalType = mConsole; + + auto backgroundColor() const { return self().backgroundColor(); } + auto doActivate(string command) const { return self().doActivate(command); } + auto foregroundColor() const { return self().foregroundColor(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto print(const string& text) { return self().print(text), *this; } + auto prompt() const { return self().prompt(); } + auto reset() { return self().reset(), *this; } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setPrompt(const string& prompt = "") { return self().setPrompt(prompt), *this; } +}; +#endif + +#if defined(Hiro_Frame) +struct Frame : sFrame { + DeclareSharedWidget(Frame) + using internalType = mFrame; + + auto append(sLayout layout) { return self().append(layout), *this; } + auto layout() const { return self().layout(); } + auto remove(sLayout layout) { return self().remove(layout), *this; } + auto reset() { return self().reset(), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_HexEdit) +struct HexEdit : sHexEdit { + DeclareSharedWidget(HexEdit) + using internalType = mHexEdit; + + auto address() const { return self().address(); } + auto backgroundColor() const { return self().backgroundColor(); } + auto columns() const { return self().columns(); } + auto doRead(unsigned offset) const { return self().doRead(offset); } + auto doWrite(unsigned offset, uint8_t data) const { return self().doWrite(offset, data); } + auto foregroundColor() const { return self().foregroundColor(); } + auto length() const { return self().length(); } + auto onRead(const function& callback = {}) { return self().onRead(callback), *this; } + auto onWrite(const function& callback = {}) { return self().onWrite(callback), *this; } + auto rows() const { return self().rows(); } + auto setAddress(unsigned address) { return self().setAddress(address), *this; } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setColumns(unsigned columns = 16) { return self().setColumns(columns), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setLength(unsigned length) { return self().setLength(length), *this; } + auto setRows(unsigned rows = 16) { return self().setRows(rows), *this; } + auto update() { return self().update(), *this; } +}; +#endif + +#if defined(Hiro_HorizontalScrollBar) +struct HorizontalScrollBar : sHorizontalScrollBar { + DeclareSharedWidget(HorizontalScrollBar) + using internalType = mHorizontalScrollBar; + + auto doChange() const { return self().doChange(); } + auto length() const { return self().length(); } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto position() const { return self().position(); } + auto setLength(unsigned length = 101) { return self().setLength(length), *this; } + auto setPosition(unsigned position = 0) { return self().setPosition(position), *this; } +}; +#endif + +#if defined(Hiro_HorizontalSlider) +struct HorizontalSlider : sHorizontalSlider { + DeclareSharedWidget(HorizontalSlider) + using internalType = mHorizontalSlider; + + auto doChange() const { return self().doChange(); } + auto length() const { return self().length(); } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto position() const { return self().position(); } + auto setLength(unsigned length = 101) { return self().setLength(length), *this; } + auto setPosition(unsigned position = 0) { return self().setPosition(position), *this; } +}; +#endif + +#if defined(Hiro_IconView) +struct IconViewItem : sIconViewItem { + DeclareSharedObject(IconViewItem) + using internalType = mIconViewItem; + + auto icon() const { return self().icon(); } + auto selected() const { return self().selected(); } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setSelected(bool selected = true) { return self().setSelected(selected), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_IconView) +struct IconView : sIconView { + DeclareSharedWidget(IconView) + using internalType = mIconView; + + auto append(sIconViewItem item) { return self().append(item), *this; } + auto backgroundColor() const { return self().backgroundColor(); } + auto batchable() const { return self().batchable(); } + auto batched() const { return self().batched(); } + auto doActivate() const { return self().doActivate(); } + auto doChange() const { return self().doChange(); } + auto doContext() const { return self().doContext(); } + auto flow() const { return self().flow(); } + auto foregroundColor() const { return self().foregroundColor(); } + auto item(unsigned position) const { return self().item(position); } + auto itemCount() const { return self().itemCount(); } + auto items() const { return self().items(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto onContext(const function& callback = {}) { return self().onContext(callback), *this; } + auto orientation() const { return self().orientation(); } + auto remove(sIconViewItem item) { return self().remove(item), *this; } + auto reset() { return self().reset(), *this; } + auto selected() const { return self().selected(); } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setBatchable(bool batchable = true) { return self().setBatchable(batchable), *this; } + auto setFlow(Orientation orientation = Orientation::Vertical) { return self().setFlow(orientation), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setOrientation(Orientation orientation = Orientation::Horizontal) { return self().setOrientation(orientation), *this; } + auto setSelected(const vector& selections) { return self().setSelected(selections), *this; } +}; +#endif + +#if defined(Hiro_Label) +struct Label : sLabel { + DeclareSharedWidget(Label) + using internalType = mLabel; + + auto alignment() const { return self().alignment(); } + auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_LineEdit) +struct LineEdit : sLineEdit { + DeclareSharedWidget(LineEdit) + using internalType = mLineEdit; + + auto backgroundColor() const { return self().backgroundColor(); } + auto doActivate() const { return self().doActivate(); } + auto doChange() const { return self().doChange(); } + auto editable() const { return self().editable(); } + auto foregroundColor() const { return self().foregroundColor(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setEditable(bool editable = true) { return self().setEditable(editable), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_ListView) +struct ListViewColumn : sListViewColumn { + DeclareSharedObject(ListViewColumn) + using internalType = mListViewColumn; + + auto active() const { return self().active(); } + auto alignment() const { return self().alignment(); } + auto backgroundColor() const { return self().backgroundColor(); } + auto editable() const { return self().editable(); } + auto expandable() const { return self().expandable(); } + auto foregroundColor() const { return self().foregroundColor(); } + auto horizontalAlignment() const { return self().horizontalAlignment(); } + auto icon() const { return self().icon(); } + auto resizable() const { return self().resizable(); } + auto setActive() { return self().setActive(), *this; } + auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setEditable(bool editable = true) { return self().setEditable(editable), *this; } + auto setExpandable(bool expandable = true) { return self().setExpandable(expandable), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setResizable(bool resizable = true) { return self().setResizable(resizable), *this; } + auto setSortable(bool sortable = true) { return self().setSortable(sortable), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto setWidth(signed width = 0) { return self().setWidth(width), *this; } + auto sortable() const { return self().sortable(); } + auto text() const { return self().text(); } + auto verticalAlignment() const { return self().verticalAlignment(); } + auto width() const { return self().width(); } +}; +#endif + +#if defined(Hiro_ListView) +struct ListViewHeader : sListViewHeader { + DeclareSharedObject(ListViewHeader) + using internalType = mListViewHeader; + + auto append(sListViewColumn column) { return self().append(column), *this; } + auto column(unsigned position) const { return self().column(position); } + auto columnCount() const { return self().columnCount(); } + auto columns() const { return self().columns(); } + auto remove(sListViewColumn column) { return self().remove(column), *this; } +}; +#endif + +#if defined(Hiro_ListView) +struct ListViewCell : sListViewCell { + DeclareSharedObject(ListViewCell) + using internalType = mListViewCell; + + auto alignment() const { return self().alignment(); } + auto backgroundColor() const { return self().backgroundColor(); } + auto checkable() const { return self().checkable(); } + auto checked() const { return self().checked(); } + auto foregroundColor() const { return self().foregroundColor(); } + auto icon() const { return self().icon(); } + auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setCheckable(bool checkable = true) const { return self().setCheckable(checkable), *this; } + auto setChecked(bool checked = true) const { return self().setChecked(checked), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_ListView) +struct ListViewItem : sListViewItem { + DeclareSharedObject(ListViewItem) + using internalType = mListViewItem; + + auto alignment() const { return self().alignment(); } + auto append(sListViewCell cell) { return self().append(cell), *this; } + auto backgroundColor() const { return self().backgroundColor(); } + auto cell(unsigned position) const { return self().cell(position); } + auto cellCount() const { return self().cellCount(); } + auto cells() const { return self().cells(); } + auto foregroundColor() const { return self().foregroundColor(); } + auto remove(sListViewCell cell) { return self().remove(cell), *this; } + auto selected() const { return self().selected(); } + auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setSelected(bool selected = true) { return self().setSelected(selected), *this; } +}; +#endif + +#if defined(Hiro_ListView) +struct ListView : sListView { + DeclareSharedWidget(ListView) + using internalType = mListView; + + auto alignment() const { return self().alignment(); } + auto append(sListViewHeader header) { return self().append(header), *this; } + auto append(sListViewItem item) { return self().append(item), *this; } + auto backgroundColor() const { return self().backgroundColor(); } + auto batchable() const { return self().batchable(); } + auto batched() const { return self().batched(); } + auto bordered() const { return self().bordered(); } + auto doActivate() const { return self().doActivate(); } + auto doChange() const { return self().doChange(); } + auto doContext() const { return self().doContext(); } + auto doEdit(sListViewCell cell) const { return self().doEdit(cell); } + auto doSort(sListViewColumn column) const { return self().doSort(column); } + auto doToggle(sListViewCell cell) const { return self().doToggle(cell); } + auto foregroundColor() const { return self().foregroundColor(); } + auto header() const { return self().header(); } + auto item(unsigned position) const { return self().item(position); } + auto itemCount() const { return self().itemCount(); } + auto items() const { return self().items(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto onContext(const function& callback = {}) { return self().onContext(callback), *this; } + auto onEdit(const function& callback = {}) { return self().onEdit(callback), *this; } + auto onSort(const function& callback = {}) { return self().onSort(callback), *this; } + auto onToggle(const function& callback = {}) { return self().onToggle(callback), *this; } + auto remove(sListViewHeader header) { return self().remove(header), *this; } + auto remove(sListViewItem item) { return self().remove(item), *this; } + auto reset() { return self().reset(), *this; } + auto resizeColumns() { return self().resizeColumns(), *this; } + auto selected() const { return self().selected(); } + auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setBatchable(bool batchable = true) { return self().setBatchable(batchable), *this; } + auto setBordered(bool bordered = true) { return self().setBordered(bordered), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } +}; +#endif + +#if defined(Hiro_ProgressBar) +struct ProgressBar : sProgressBar { + DeclareSharedWidget(ProgressBar) + using internalType = mProgressBar; + + auto position() const { return self().position(); } + auto setPosition(unsigned position = 0) { return self().setPosition(position), *this; } +}; +#endif + +#if defined(Hiro_RadioButton) +struct RadioButton : sRadioButton { + DeclareSharedWidget(RadioButton) + using internalType = mRadioButton; + + auto bordered() const { return self().bordered(); } + auto checked() const { return self().checked(); } + auto doActivate() const { return self().doActivate(); } + auto group() const { return self().group(); } + auto icon() const { return self().icon(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto orientation() const { return self().orientation(); } + auto setBordered(bool bordered = true) { return self().setBordered(bordered), *this; } + auto setChecked() { return self().setChecked(), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setOrientation(Orientation orientation = Orientation::Horizontal) { return self().setOrientation(orientation), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_RadioLabel) +struct RadioLabel : sRadioLabel { + DeclareSharedWidget(RadioLabel) + using internalType = mRadioLabel; + + auto checked() const { return self().checked(); } + auto doActivate() const { return self().doActivate(); } + auto group() const { return self().group(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto setChecked() { return self().setChecked(), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_SourceEdit) +struct SourceEdit : sSourceEdit { + DeclareSharedWidget(SourceEdit) + using internalType = mSourceEdit; + + auto cursor() const { return self().cursor(); } + auto doChange() const { return self().doChange(); } + auto doMove() const { return self().doMove(); } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto onMove(const function& callback = {}) { return self().onMove(callback), *this; } + auto setCursor(Cursor cursor = {}) { return self().setCursor(cursor), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_TabFrame) +struct TabFrameItem : sTabFrameItem { + DeclareSharedObject(TabFrameItem) + using internalType = mTabFrameItem; + + auto append(sLayout layout) { return self().append(layout), *this; } + auto closable() const { return self().closable(); } + auto icon() const { return self().icon(); } + auto layout() const { return self().layout(); } + auto movable() const { return self().movable(); } + auto remove(sLayout layout) { return self().remove(layout), *this; } + auto reset() { return self().reset(), *this; } + auto selected() const { return self().selected(); } + auto setClosable(bool closable = true) { return self().setClosable(closable), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setMovable(bool movable = true) { return self().setMovable(movable), *this; } + auto setSelected() { return self().setSelected(), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_TabFrame) +struct TabFrame : sTabFrame { + DeclareSharedWidget(TabFrame) + using internalType = mTabFrame; + + auto append(sTabFrameItem item) { return self().append(item), *this; } + auto doChange() const { return self().doChange(); } + auto doClose(sTabFrameItem item) const { return self().doClose(item); } + auto doMove(sTabFrameItem from, sTabFrameItem to) const { return self().doMove(from, to); } + auto item(unsigned position) const { return self().item(position); } + auto itemCount() const { return self().itemCount(); } + auto items() const { return self().items(); } + auto navigation() const { return self().navigation(); } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto onClose(const function& callback = {}) { return self().onClose(callback), *this; } + auto onMove(const function& callback = {}) { return self().onMove(callback), *this; } + auto remove(sTabFrameItem item) { return self().remove(item), *this; } + auto reset() { return self().reset(), *this; } + auto selected() const { return self().selected(); } + auto setNavigation(Navigation navigation = Navigation::Top) { return self().setNavigation(navigation), *this; } +}; +#endif + +#if defined(Hiro_TextEdit) +struct TextEdit : sTextEdit { + DeclareSharedWidget(TextEdit) + using internalType = mTextEdit; + + auto backgroundColor() const { return self().backgroundColor(); } + auto cursor() const { return self().cursor(); } + auto doChange() const { return self().doChange(); } + auto doMove() const { return self().doMove(); } + auto editable() const { return self().editable(); } + auto foregroundColor() const { return self().foregroundColor(); } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto onMove(const function& callback = {}) { return self().onMove(callback), *this; } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setCursor(Cursor cursor = {}) { return self().setCursor(cursor), *this; } + auto setEditable(bool editable = true) { return self().setEditable(editable), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto setWordWrap(bool wordWrap = true) { return self().setWordWrap(wordWrap), *this; } + auto text() const { return self().text(); } + auto wordWrap() const { return self().wordWrap(); } +}; +#endif + +#if defined(Hiro_TreeView) +struct TreeViewItem : sTreeViewItem { + DeclareSharedObject(TreeViewItem) + using internalType = mTreeViewItem; + + auto append(sTreeViewItem item) { return self().append(item), *this; } + auto backgroundColor() const { return self().backgroundColor(); } + auto checkable() const { return self().checkable(); } + auto checked() const { return self().checked(); } + auto foregroundColor() const { return self().foregroundColor(); } + auto icon() const { return self().icon(); } + auto item(const string& path) const { return self().item(path); } + auto itemCount() const { return self().itemCount(); } + auto items() const { return self().items(); } + auto path() const { return self().path(); } + auto remove(sTreeViewItem item) { return self().remove(item), *this; } + auto selected() const { return self().selected(); } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setCheckable(bool checkable = true) { return self().setCheckable(checkable), *this; } + auto setChecked(bool checked = true) { return self().setChecked(checked), *this; } + auto setExpanded(bool expanded = true) { return self().setExpanded(expanded), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setSelected() { return self().setSelected(), *this; } + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_TreeView) +struct TreeView : sTreeView { + DeclareSharedWidget(TreeView) + using internalType = mTreeView; + + auto append(sTreeViewItem item) { return self().append(item), *this; } + auto backgroundColor() const { return self().backgroundColor(); } + auto doActivate() const { return self().doActivate(); } + auto doChange() const { return self().doChange(); } + auto doContext() const { return self().doContext(); } + auto doToggle(sTreeViewItem item) const { return self().doToggle(item); } + auto foregroundColor() const { return self().foregroundColor(); } + auto item(const string& path) const { return self().item(path); } + auto itemCount() const { return self().itemCount(); } + auto items() const { return self().items(); } + auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto onContext(const function& callback = {}) { return self().onContext(callback), *this; } + auto onToggle(const function& callback = {}) { return self().onToggle(callback), *this; } + auto remove(sTreeViewItem item) { return self().remove(item), *this; } + auto reset() { return self().reset(), *this; } + auto selected() const { return self().selected(); } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } +}; +#endif + +#if defined(Hiro_VerticalScrollBar) +struct VerticalScrollBar : sVerticalScrollBar { + DeclareSharedWidget(VerticalScrollBar) + using internalType = mVerticalScrollBar; + + auto doChange() const { return self().doChange(); } + auto length() const { return self().length(); } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto position() const { return self().position(); } + auto setLength(unsigned length = 101) { return self().setLength(length), *this; } + auto setPosition(unsigned position = 0) { return self().setPosition(position), *this; } +}; +#endif + +#if defined(Hiro_VerticalSlider) +struct VerticalSlider : sVerticalSlider { + DeclareSharedWidget(VerticalSlider) + using internalType = mVerticalSlider; + + auto doChange() const { return self().doChange(); } + auto length() const { return self().length(); } + auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } + auto position() const { return self().position(); } + auto setLength(unsigned length = 101) { return self().setLength(length), *this; } + auto setPosition(unsigned position = 0) { return self().setPosition(position), *this; } +}; +#endif + +#if defined(Hiro_Viewport) +struct Viewport : sViewport { + DeclareSharedWidget(Viewport) + using internalType = mViewport; + + auto doDrop(lstring names) const { return self().doDrop(names); } + auto doMouseLeave() const { return self().doMouseLeave(); } + auto doMouseMove(Position position) const { return self().doMouseMove(position); } + auto doMousePress(Mouse::Button button) const { return self().doMousePress(button); } + auto doMouseRelease(Mouse::Button button) const { return self().doMouseRelease(button); } + auto droppable() const { return self().droppable(); } + auto handle() const { return self().handle(); } + auto onDrop(const function& callback = {}) { return self().onDrop(callback), *this; } + auto onMouseLeave(const function& callback = {}) { return self().onMouseLeave(callback), *this; } + auto onMouseMove(const function& callback = {}) { return self().onMouseMove(callback), *this; } + auto onMousePress(const function& callback = {}) { return self().onMousePress(callback), *this; } + auto onMouseRelease(const function& callback = {}) { return self().onMouseRelease(callback), *this; } + auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; } +}; +#endif + +#if defined(Hiro_StatusBar) +struct StatusBar : sStatusBar { + DeclareSharedObject(StatusBar) + using internalType = mStatusBar; + + auto setText(const string& text = "") { return self().setText(text), *this; } + auto text() const { return self().text(); } +}; +#endif + +#if defined(Hiro_PopupMenu) +struct PopupMenu : sPopupMenu { + DeclareSharedObject(PopupMenu) + using internalType = mPopupMenu; + + auto action(unsigned position) const { return self().action(position); } + auto actionCount() const { return self().actionCount(); } + auto actions() const { return self().actions(); } + auto append(sAction action) { return self().append(action), *this; } + auto remove(sAction action) { return self().remove(action), *this; } + auto reset() { return self().reset(), *this; } +}; +#endif + +#if defined(Hiro_MenuBar) +struct MenuBar : sMenuBar { + DeclareSharedObject(MenuBar) + using internalType = mMenuBar; + + auto append(sMenu menu) { return self().append(menu), *this; } + auto menu(unsigned position) const { return self().menu(position); } + auto menuCount() const { return self().menuCount(); } + auto menus() const { return self().menus(); } + auto remove(sMenu menu) { return self().remove(menu), *this; } + auto reset() { return self().reset(), *this; } +}; +#endif + +#if defined(Hiro_Window) +struct Window : sWindow { + DeclareSharedObject(Window) + using internalType = mWindow; + + auto append(sLayout layout) { return self().append(layout), *this; } + auto append(sMenuBar menuBar) { return self().append(menuBar), *this; } + auto append(sStatusBar statusBar) { return self().append(statusBar), *this; } + auto backgroundColor() const { return self().backgroundColor(); } + auto doClose() const { return self().doClose(); } + auto doDrop(lstring names) const { return self().doDrop(names); } + auto doKeyPress(signed key) const { return self().doKeyPress(key); } + auto doKeyRelease(signed key) const { return self().doKeyRelease(key); } + auto doMove() const { return self().doMove(); } + auto doSize() const { return self().doSize(); } + auto droppable() const { return self().droppable(); } + auto frameGeometry() const { return self().frameGeometry(); } + auto fullScreen() const { return self().fullScreen(); } + auto geometry() const { return self().geometry(); } + auto layout() const { return self().layout(); } + auto menuBar() const { return self().menuBar(); } + auto modal() const { return self().modal(); } + auto onClose(const function& callback = {}) { return self().onClose(callback), *this; } + auto onDrop(const function& callback = {}) { return self().onDrop(callback), *this; } + auto onKeyPress(const function& callback = {}) { return self().onKeyPress(callback), *this; } + auto onKeyRelease(const function& callback = {}) { return self().onKeyRelease(callback), *this; } + auto onMove(const function& callback = {}) { return self().onMove(callback), *this; } + auto onSize(const function& callback = {}) { return self().onSize(callback), *this; } + auto remove(sLayout layout) { return self().remove(layout), *this; } + auto remove(sMenuBar menuBar) { return self().remove(menuBar), *this; } + auto remove(sStatusBar statusBar) { return self().remove(statusBar), *this; } + auto reset() { return self().reset(), *this; } + auto resizable() const { return self().resizable(); } + auto setAlignment(Alignment alignment) { return self().setAlignment(alignment), *this; } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setCentered(sWindow parent = {}) { return self().setCentered(parent), *this; } + auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; } + auto setFrameGeometry(Geometry geometry) { return self().setFrameGeometry(geometry), *this; } + auto setFramePosition(Position position) { return self().setFramePosition(position), *this; } + auto setFrameSize(Size size) { return self().setFrameSize(size), *this; } + auto setFullScreen(bool fullScreen = true) { return self().setFullScreen(fullScreen), *this; } + auto setGeometry(Geometry geometry) { return self().setGeometry(geometry), *this; } + auto setModal(bool modal = true) { return self().setModal(modal), *this; } + auto setPosition(Position position) { return self().setPosition(position), *this; } + auto setResizable(bool resizable = true) { return self().setResizable(resizable), *this; } + auto setSize(Size size) { return self().setSize(size), *this; } + auto setTitle(const string& title = "") { return self().setTitle(title), *this; } + auto statusBar() const { return self().statusBar(); } + auto title() const { return self().title(); } +}; +#endif diff --git a/core/sizable.cpp b/core/sizable.cpp new file mode 100644 index 0000000..b0a66c4 --- /dev/null +++ b/core/sizable.cpp @@ -0,0 +1,21 @@ +#if defined(Hiro_Sizable) + +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; +} + +#endif diff --git a/core/size.cpp b/core/size.cpp new file mode 100644 index 0000000..26cd316 --- /dev/null +++ b/core/size.cpp @@ -0,0 +1,55 @@ +#if defined(Hiro_Size) + +Size::Size() { + setSize(0, 0); +} + +Size::Size(signed width, signed height) { + setSize(width, height); +} + +Size::operator bool() const { + return state.width || state.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::reset() -> type& { + return setSize(0, 0); +} + +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; +} + +#endif diff --git a/core/status-bar.cpp b/core/status-bar.cpp new file mode 100644 index 0000000..5f8e797 --- /dev/null +++ b/core/status-bar.cpp @@ -0,0 +1,24 @@ +#if defined(Hiro_StatusBar) + +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; +} + +#endif diff --git a/core/timer.cpp b/core/timer.cpp new file mode 100644 index 0000000..ac1ae64 --- /dev/null +++ b/core/timer.cpp @@ -0,0 +1,28 @@ +#if defined(Hiro_Timer) + +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& callback) -> type& { + state.onActivate = callback; + return *this; +} + +auto mTimer::setInterval(unsigned interval) -> type& { + state.interval = interval; + signal(setInterval, interval); + return *this; +} + +#endif diff --git a/core/widget/button.cpp b/core/widget/button.cpp new file mode 100644 index 0000000..d754ba0 --- /dev/null +++ b/core/widget/button.cpp @@ -0,0 +1,58 @@ +#if defined(Hiro_Button) + +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& callback) -> type& { + state.onActivate = callback; + 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; +} + +#endif diff --git a/core/widget/canvas.cpp b/core/widget/canvas.cpp new file mode 100644 index 0000000..64d8e57 --- /dev/null +++ b/core/widget/canvas.cpp @@ -0,0 +1,113 @@ +#if defined(Hiro_Canvas) + +auto mCanvas::allocate() -> pObject* { + return new pCanvas(*this); +} + +// + +auto mCanvas::color() const -> Color { + return state.color; +} + +auto mCanvas::data() -> uint32_t* { + return (uint32_t*)state.icon.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 -> Gradient { + return state.gradient; +} + +auto mCanvas::icon() const -> image { + return state.icon; +} + +auto mCanvas::onDrop(const function& callback) -> type& { + state.onDrop = callback; + return *this; +} + +auto mCanvas::onMouseLeave(const function& callback) -> type& { + state.onMouseLeave = callback; + return *this; +} + +auto mCanvas::onMouseMove(const function& callback) -> type& { + state.onMouseMove = callback; + return *this; +} + +auto mCanvas::onMousePress(const function& callback) -> type& { + state.onMousePress = callback; + return *this; +} + +auto mCanvas::onMouseRelease(const function& callback) -> type& { + state.onMouseRelease = callback; + return *this; +} + +auto mCanvas::setColor(Color color) -> type& { + state.color = color; + signal(setColor, color); + return *this; +} + +auto mCanvas::setDroppable(bool droppable) -> type& { + state.droppable = droppable; + signal(setDroppable, droppable); + return *this; +} + +auto mCanvas::setGradient(Gradient gradient) -> type& { + state.gradient = gradient; + signal(setGradient, gradient); + return *this; +} + +auto mCanvas::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mCanvas::setSize(Size size) -> type& { + image icon; + icon.allocate(size.width(), size.height()); + return setIcon(icon); +} + +auto mCanvas::size() const -> Size { + return {(int)state.icon.width(), (int)state.icon.height()}; +} + +auto mCanvas::update() -> type& { + signal(update); + return *this; +} + +#endif diff --git a/core/widget/check-button.cpp b/core/widget/check-button.cpp new file mode 100644 index 0000000..e67bf17 --- /dev/null +++ b/core/widget/check-button.cpp @@ -0,0 +1,68 @@ +#if defined(Hiro_CheckButton) + +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& callback) -> type& { + state.onToggle = callback; + 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; +} + +#endif diff --git a/core/widget/check-label.cpp b/core/widget/check-label.cpp new file mode 100644 index 0000000..968d5b3 --- /dev/null +++ b/core/widget/check-label.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_CheckLabel) + +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& callback) -> type& { + state.onToggle = callback; + 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; +} + +#endif diff --git a/core/widget/combo-button-item.cpp b/core/widget/combo-button-item.cpp new file mode 100644 index 0000000..ff836d3 --- /dev/null +++ b/core/widget/combo-button-item.cpp @@ -0,0 +1,47 @@ +#if defined(Hiro_ComboButton) + +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 { + return state.selected; +} + +auto mComboButtonItem::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mComboButtonItem::setSelected() -> type& { + if(auto parent = parentComboButton()) { + for(auto& item : parent->state.items) item->state.selected = false; + } + state.selected = true; + 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; +} + +#endif diff --git a/core/widget/combo-button.cpp b/core/widget/combo-button.cpp new file mode 100644 index 0000000..8291a74 --- /dev/null +++ b/core/widget/combo-button.cpp @@ -0,0 +1,77 @@ +#if defined(Hiro_ComboButton) + +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& { + if(!state.items) item->state.selected = true; + state.items.append(item); + item->setParent(this, itemCount() - 1); + signal(append, item); + return *this; +} + +auto mComboButton::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mComboButton::item(unsigned position) const -> ComboButtonItem { + if(position < itemCount()) return state.items[position]; + return {}; +} + +auto mComboButton::itemCount() const -> unsigned { + return state.items.size(); +} + +auto mComboButton::items() const -> vector { + vector items; + for(auto& item : state.items) items.append(item); + return items; +} + +auto mComboButton::onChange(const function& callback) -> type& { + state.onChange = callback; + return *this; +} + +auto mComboButton::remove(sComboButtonItem item) -> type& { + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(item->offset(), itemCount())) { + state.items[n]->adjustOffset(-1); + } + item->setParent(); + return *this; +} + +auto mComboButton::reset() -> type& { + signal(reset); + for(auto& item : state.items) item->setParent(); + state.items.reset(); + return *this; +} + +auto mComboButton::selected() const -> ComboButtonItem { + for(auto& item : state.items) { + if(item->selected()) return item; + } + return {}; +} + +auto mComboButton::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; +} + +#endif diff --git a/core/widget/console.cpp b/core/widget/console.cpp new file mode 100644 index 0000000..3b6fcfd --- /dev/null +++ b/core/widget/console.cpp @@ -0,0 +1,58 @@ +#if defined(Hiro_Console) + +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& callback) -> type& { + state.onActivate = callback; + 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; +} + +#endif diff --git a/core/widget/frame.cpp b/core/widget/frame.cpp new file mode 100644 index 0000000..e269c96 --- /dev/null +++ b/core/widget/frame.cpp @@ -0,0 +1,55 @@ +#if defined(Hiro_Frame) + +auto mFrame::allocate() -> pObject* { + return new pFrame(*this); +} + +auto mFrame::destruct() -> void { + if(auto& layout = state.layout) layout->destruct(); + mWidget::destruct(); +} + +// + +auto mFrame::append(sLayout layout) -> type& { + if(auto& layout = state.layout) remove(layout); + state.layout = layout; + layout->setParent(this, 0); + signal(append, layout); + return *this; +} + +auto mFrame::layout() const -> Layout { + return state.layout; +} + +auto mFrame::remove(sLayout layout) -> type& { + signal(remove, layout); + layout->setParent(); + state.layout.reset(); + return *this; +} + +auto mFrame::reset() -> type& { + if(auto& layout = state.layout) remove(layout); + return *this; +} + +auto mFrame::setParent(mObject* object, signed offset) -> type& { + if(auto& layout = state.layout) layout->destruct(); + mObject::setParent(object, offset); + if(auto& layout = state.layout) layout->setParent(this, 0); + 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; +} + +#endif diff --git a/core/widget/hex-edit.cpp b/core/widget/hex-edit.cpp new file mode 100644 index 0000000..986072c --- /dev/null +++ b/core/widget/hex-edit.cpp @@ -0,0 +1,93 @@ +#if defined(Hiro_HexEdit) + +auto mHexEdit::allocate() -> pObject* { + return new pHexEdit(*this); +} + +// + +auto mHexEdit::address() const -> unsigned { + return state.address; +} + +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::onRead(const function& callback) -> type& { + state.onRead = callback; + return *this; +} + +auto mHexEdit::onWrite(const function& callback) -> type& { + state.onWrite = callback; + return *this; +} + +auto mHexEdit::rows() const -> unsigned { + return state.rows; +} + +auto mHexEdit::setAddress(unsigned address) -> type& { + state.address = address; + signal(setAddress, address); + return *this; +} + +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::setRows(unsigned rows) -> type& { + state.rows = rows; + signal(setRows, rows); + return *this; +} + +auto mHexEdit::update() -> type& { + signal(update); + return *this; +} + +#endif diff --git a/core/widget/horizontal-scroll-bar.cpp b/core/widget/horizontal-scroll-bar.cpp new file mode 100644 index 0000000..226b1bc --- /dev/null +++ b/core/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_HorizontalScrollBar) + +auto mHorizontalScrollBar::allocate() -> pObject* { + return new pHorizontalScrollBar(*this); +} + +// + +auto mHorizontalScrollBar::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mHorizontalScrollBar::length() const -> unsigned { + return state.length; +} + +auto mHorizontalScrollBar::onChange(const function& callback) -> type& { + state.onChange = callback; + return *this; +} + +auto mHorizontalScrollBar::position() const -> unsigned { + return state.position; +} + +auto mHorizontalScrollBar::setLength(unsigned length) -> type& { + state.length = length; + signal(setLength, length); + return *this; +} + +auto mHorizontalScrollBar::setPosition(unsigned position) -> type& { + state.position = position; + signal(setPosition, position); + return *this; +} + +#endif diff --git a/core/widget/horizontal-slider.cpp b/core/widget/horizontal-slider.cpp new file mode 100644 index 0000000..9330b43 --- /dev/null +++ b/core/widget/horizontal-slider.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_HorizontalSlider) + +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& callback) -> type& { + state.onChange = callback; + 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; +} + +#endif diff --git a/core/widget/icon-view-item.cpp b/core/widget/icon-view-item.cpp new file mode 100644 index 0000000..bff5694 --- /dev/null +++ b/core/widget/icon-view-item.cpp @@ -0,0 +1,44 @@ +#if defined(Hiro_IconView) + +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; +} + +#endif diff --git a/core/widget/icon-view.cpp b/core/widget/icon-view.cpp new file mode 100644 index 0000000..9026c95 --- /dev/null +++ b/core/widget/icon-view.cpp @@ -0,0 +1,165 @@ +#if defined(Hiro_IconView) + +auto mIconView::allocate() -> pObject* { + return new pIconView(*this); +} + +auto mIconView::destruct() -> void { + for(auto& item : state.items) item->destruct(); + mWidget::destruct(); +} + +// + +auto mIconView::append(sIconViewItem item) -> type& { + state.items.append(item); + item->setParent(this, itemCount() - 1); + signal(append, item); + return *this; +} + +auto mIconView::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mIconView::batchable() const -> bool { + return state.batchable; +} + +auto mIconView::batched() const -> vector { + vector items; + for(auto& item : state.items) { + if(item->selected()) items.append(item); + } + return items; +} + +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 -> IconViewItem { + if(position < itemCount()) return state.items[position]; + return {}; +} + +auto mIconView::itemCount() const -> unsigned { + return state.items.size(); +} + +auto mIconView::items() const -> vector { + vector items; + for(auto& item : state.items) items.append(item); + return items; +} + +auto mIconView::onActivate(const function& callback) -> type& { + state.onActivate = callback; + return *this; +} + +auto mIconView::onChange(const function& callback) -> type& { + state.onChange = callback; + return *this; +} + +auto mIconView::onContext(const function& callback) -> type& { + state.onContext = callback; + return *this; +} + +auto mIconView::orientation() const -> Orientation { + return state.orientation; +} + +auto mIconView::remove(sIconViewItem item) -> type& { + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(item->offset(), itemCount())) { + state.items[n]->adjustOffset(-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 -> IconViewItem { + for(auto& item : state.items) { + if(item->selected()) return item; + } + return {}; +} + +auto mIconView::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mIconView::setBatchable(bool batchable) -> type& { + state.batchable = batchable; + signal(setBatchable, batchable); + 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::setOrientation(Orientation orientation) -> type& { + state.orientation = orientation; + signal(setOrientation, orientation); + return *this; +} + +auto mIconView::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.items)) state.items[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& item : state.items) item->setParent(this, item->offset()); + 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 >= itemCount()) continue; + state.items[position]->state.selected = true; + } + signal(setItemSelected, selections); + return *this; +} + +#endif diff --git a/core/widget/label.cpp b/core/widget/label.cpp new file mode 100644 index 0000000..fe15699 --- /dev/null +++ b/core/widget/label.cpp @@ -0,0 +1,29 @@ +#if defined(Hiro_Label) + +auto mLabel::allocate() -> pObject* { + return new pLabel(*this); +} + +// + +auto mLabel::alignment() const -> Alignment { + return state.alignment; +} + +auto mLabel::setAlignment(Alignment alignment) -> type& { + state.alignment = alignment; + signal(setAlignment, alignment); + return *this; +} + +auto mLabel::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mLabel::text() const -> string { + return state.text; +} + +#endif diff --git a/core/widget/line-edit.cpp b/core/widget/line-edit.cpp new file mode 100644 index 0000000..51654cd --- /dev/null +++ b/core/widget/line-edit.cpp @@ -0,0 +1,67 @@ +#if defined(Hiro_LineEdit) + +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& callback) -> type& { + state.onActivate = callback; + return *this; +} + +auto mLineEdit::onChange(const function& callback) -> type& { + state.onChange = callback; + 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; +} + +#endif diff --git a/core/widget/list-view-cell.cpp b/core/widget/list-view-cell.cpp new file mode 100644 index 0000000..f9c4d01 --- /dev/null +++ b/core/widget/list-view-cell.cpp @@ -0,0 +1,148 @@ +#if defined(Hiro_ListView) + +auto mListViewCell::allocate() -> pObject* { + return new pListViewCell(*this); +} + +// + +auto mListViewCell::alignment(bool recursive) const -> Alignment { + if(auto alignment = state.alignment) return alignment; + if(recursive) { + if(auto parent = parentListViewItem()) { + if(auto alignment = parent->state.alignment) return alignment; + if(auto grandparent = parent->parentListView()) { + if(auto header = grandparent->state.header) { + if(offset() < header->columnCount()) { + if(auto column = header->state.columns[offset()]) { + if(auto alignment = column->state.alignment) return alignment; + } + } + } + if(auto alignment = grandparent->state.alignment) return alignment; + } + } + } + return {}; +} + +auto mListViewCell::backgroundColor(bool recursive) const -> Color { + if(auto color = state.backgroundColor) return color; + if(recursive) { + if(auto parent = parentListViewItem()) { + if(auto color = parent->state.backgroundColor) return color; + if(auto grandparent = parent->parentListView()) { + if(auto header = grandparent->state.header) { + if(offset() < header->columnCount()) { + if(auto column = header->state.columns[offset()]) { + if(auto color = column->state.backgroundColor) return color; + } + } + } + if(auto color = grandparent->state.backgroundColor) return color; + } + } + } + return {}; +} + +auto mListViewCell::checkable() const -> bool { + return state.checkable; +} + +auto mListViewCell::checked() const -> bool { + return state.checkable && state.checked; +} + +auto mListViewCell::font(bool recursive) const -> Font { + if(auto font = mObject::font()) return font; + if(recursive) { + if(auto parent = parentListViewItem()) { + if(auto font = parent->font()) return font; + if(auto grandparent = parent->parentListView()) { + if(auto header = grandparent->state.header) { + if(offset() < header->columnCount()) { + if(auto column = header->state.columns[offset()]) { + if(auto font = column->font()) return font; + } + } + } + if(auto font = grandparent->font(true)) return font; + } + } + } + return {}; +} + +auto mListViewCell::foregroundColor(bool recursive) const -> Color { + if(auto color = state.foregroundColor) return color; + if(recursive) { + if(auto parent = parentListViewItem()) { + if(auto color = parent->state.foregroundColor) return color; + if(auto grandparent = parent->parentListView()) { + if(auto header = grandparent->state.header) { + if(offset() < header->columnCount()) { + if(auto column = header->state.columns[offset()]) { + if(auto color = column->state.foregroundColor) return color; + } + } + } + if(auto color = grandparent->state.foregroundColor) return color; + } + } + } + return state.foregroundColor; +} + +auto mListViewCell::icon() const -> image { + return state.icon; +} + +auto mListViewCell::setAlignment(Alignment alignment) -> type& { + state.alignment = alignment; + signal(setAlignment, alignment); + return *this; +} + +auto mListViewCell::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mListViewCell::setCheckable(bool checkable) -> type& { + state.checkable = checkable; + signal(setCheckable, checkable); + return *this; +} + +auto mListViewCell::setChecked(bool checked) -> type& { + setCheckable(true); + state.checked = checked; + signal(setChecked, checked); + return *this; +} + +auto mListViewCell::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mListViewCell::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mListViewCell::setText(const string& text) -> type& { + state.text = text; + signal(setText, text); + return *this; +} + +auto mListViewCell::text() const -> string { + return state.text; +} + +#endif diff --git a/core/widget/list-view-column.cpp b/core/widget/list-view-column.cpp new file mode 100644 index 0000000..e23e67d --- /dev/null +++ b/core/widget/list-view-column.cpp @@ -0,0 +1,153 @@ +#if defined(Hiro_ListView) + +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::alignment() const -> Alignment { + return state.alignment; +} + +auto mListViewColumn::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mListViewColumn::editable() const -> bool { + return state.editable; +} + +auto mListViewColumn::expandable() const -> bool { + return state.expandable; +} + +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 = parentListViewHeader()) 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::setAlignment(Alignment alignment) -> type& { + state.alignment = alignment; + signal(setAlignment, alignment); + 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::setExpandable(bool expandable) -> type& { + state.expandable = expandable; + signal(setExpandable, expandable); + 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 = max(0, 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; +} + +#endif diff --git a/core/widget/list-view-header.cpp b/core/widget/list-view-header.cpp new file mode 100644 index 0000000..9469ef3 --- /dev/null +++ b/core/widget/list-view-header.cpp @@ -0,0 +1,53 @@ +#if defined(Hiro_ListView) + +auto mListViewHeader::allocate() -> pObject* { + return new pListViewHeader(*this); +} + +// + +auto mListViewHeader::append(sListViewColumn column) -> type& { + state.columns.append(column); + column->setParent(this, columnCount() - 1); + signal(append, column); + return *this; +} + +auto mListViewHeader::column(unsigned position) const -> ListViewColumn { + if(position < columnCount()) return state.columns[position]; + return {}; +} + +auto mListViewHeader::columnCount() const -> unsigned { + return state.columns.size(); +} + +auto mListViewHeader::columns() const -> vector { + vector columns; + for(auto& column : state.columns) columns.append(column); + return columns; +} + +auto mListViewHeader::remove() -> type& { + if(auto listView = parentListView()) listView->remove(*this); + return *this; +} + +auto mListViewHeader::remove(sListViewColumn column) -> type& { + signal(remove, column); + state.columns.remove(column->offset()); + for(auto n : range(column->offset(), columnCount())) { + state.columns[n]->adjustOffset(-1); + } + column->setParent(); + return *this; +} + +auto mListViewHeader::setParent(mObject* parent, signed offset) -> type& { + for(auto& column : state.columns) column->destruct(); + mObject::setParent(parent, offset); + for(auto& column : state.columns) column->setParent(this, column->offset()); + return *this; +} + +#endif diff --git a/core/widget/list-view-item.cpp b/core/widget/list-view-item.cpp new file mode 100644 index 0000000..4b9a0d3 --- /dev/null +++ b/core/widget/list-view-item.cpp @@ -0,0 +1,98 @@ +#if defined(Hiro_ListView) + +auto mListViewItem::allocate() -> pObject* { + return new pListViewItem(*this); +} + +// + +auto mListViewItem::alignment() const -> Alignment { + return state.alignment; +} + +auto mListViewItem::append(sListViewCell cell) -> type& { + state.cells.append(cell); + cell->setParent(this, cellCount() - 1); + signal(append, cell); + return *this; +} + +auto mListViewItem::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mListViewItem::cell(unsigned position) const -> ListViewCell { + if(position < cellCount()) return state.cells[position]; + return {}; +} + +auto mListViewItem::cellCount() const -> unsigned { + return state.cells.size(); +} + +auto mListViewItem::cells() const -> vector { + vector cells; + for(auto& cell : state.cells) cells.append(cell); + return cells; +} + +auto mListViewItem::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mListViewItem::remove() -> type& { + if(auto listView = parentListView()) listView->remove(*this); + return *this; +} + +auto mListViewItem::remove(sListViewCell cell) -> type& { + signal(remove, cell); + state.cells.remove(cell->offset()); + for(auto n : range(cell->offset(), cellCount())) { + state.cells[n]->adjustOffset(-1); + } + cell->setParent(); + return *this; +} + +auto mListViewItem::selected() const -> bool { + return state.selected; +} + +auto mListViewItem::setAlignment(Alignment alignment) -> type& { + state.alignment = alignment; + signal(setAlignment, alignment); + return *this; +} + +auto mListViewItem::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mListViewItem::setFocused() -> type& { + signal(setFocused); + return *this; +} + +auto mListViewItem::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mListViewItem::setParent(mObject* parent, signed offset) -> type& { + for(auto& cell : state.cells) cell->destruct(); + mObject::setParent(parent, offset); + for(auto& cell : state.cells) cell->setParent(this, cell->offset()); + return *this; +} + +auto mListViewItem::setSelected(bool selected) -> type& { + state.selected = selected; + signal(setSelected, selected); + return *this; +} + +#endif diff --git a/core/widget/list-view.cpp b/core/widget/list-view.cpp new file mode 100644 index 0000000..14a8ccb --- /dev/null +++ b/core/widget/list-view.cpp @@ -0,0 +1,205 @@ +#if defined(Hiro_ListView) + +auto mListView::allocate() -> pObject* { + return new pListView(*this); +} + +auto mListView::destruct() -> void { + for(auto& item : state.items) item->destruct(); + if(auto& header = state.header) header->destruct(); + mWidget::destruct(); +} + +// + +auto mListView::alignment() const -> Alignment { + return state.alignment; +} + +auto mListView::append(sListViewHeader header) -> type& { + if(auto& header = state.header) remove(header); + state.header = header; + header->setParent(this, 0); + signal(append, header); + return *this; +} + +auto mListView::append(sListViewItem item) -> type& { + state.items.append(item); + item->setParent(this, itemCount() - 1); + signal(append, item); + return *this; +} + +auto mListView::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mListView::batchable() const -> bool { + return state.batchable; +} + +auto mListView::batched() const -> vector { + vector items; + for(auto& item : state.items) { + if(item->selected()) items.append(item); + } + return items; +} + +auto mListView::bordered() const -> bool { + return state.bordered; +} + +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(sListViewCell cell) const -> void { + if(state.onEdit) return state.onEdit(cell); +} + +auto mListView::doSort(sListViewColumn column) const -> void { + if(state.onSort) return state.onSort(column); +} + +auto mListView::doToggle(sListViewCell cell) const -> void { + if(state.onToggle) return state.onToggle(cell); +} + +auto mListView::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mListView::header() const -> ListViewHeader { + return state.header; +} + +auto mListView::item(unsigned position) const -> ListViewItem { + if(position < itemCount()) return state.items[position]; + return {}; +} + +auto mListView::itemCount() const -> unsigned { + return state.items.size(); +} + +auto mListView::items() const -> vector { + vector items; + for(auto& item : state.items) items.append(item); + return items; +} + +auto mListView::onActivate(const function& callback) -> type& { + state.onActivate = callback; + return *this; +} + +auto mListView::onChange(const function& callback) -> type& { + state.onChange = callback; + return *this; +} + +auto mListView::onContext(const function& callback) -> type& { + state.onContext = callback; + return *this; +} + +auto mListView::onEdit(const function& callback) -> type& { + state.onEdit = callback; + return *this; +} + +auto mListView::onSort(const function& callback) -> type& { + state.onSort = callback; + return *this; +} + +auto mListView::onToggle(const function& callback) -> type& { + state.onToggle = callback; + return *this; +} + +auto mListView::remove(sListViewHeader header) -> type& { + signal(remove, header); + header->setParent(); + state.header.reset(); + return *this; +} + +auto mListView::remove(sListViewItem item) -> type& { + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(item->offset(), itemCount())) { + state.items[n]->adjustOffset(-1); + } + item->setParent(); + return *this; +} + +auto mListView::reset() -> type& { + for(auto n : rrange(state.items)) remove(state.items[n]); + if(auto& header = state.header) remove(header); + return *this; +} + +auto mListView::resizeColumns() -> type& { + signal(resizeColumns); + return *this; +} + +auto mListView::selected() const -> ListViewItem { + for(auto& item : state.items) { + if(item->selected()) return item; + } + return {}; +} + +auto mListView::setAlignment(Alignment alignment) -> type& { + state.alignment = alignment; + signal(setAlignment, alignment); + return *this; +} + +auto mListView::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mListView::setBatchable(bool batchable) -> type& { + state.batchable = batchable; + signal(setBatchable, batchable); + return *this; +} + +auto mListView::setBordered(bool bordered) -> type& { + state.bordered = bordered; + signal(setBordered, bordered); + return *this; +} + +auto mListView::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mListView::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.items)) state.items[n]->destruct(); + if(auto& header = state.header) header->destruct(); + mObject::setParent(parent, offset); + if(auto& header = state.header) header->setParent(this, 0); + for(auto& item : state.items) item->setParent(this, item->offset()); + return *this; +} + +#endif diff --git a/core/widget/progress-bar.cpp b/core/widget/progress-bar.cpp new file mode 100644 index 0000000..d55b203 --- /dev/null +++ b/core/widget/progress-bar.cpp @@ -0,0 +1,19 @@ +#if defined(Hiro_ProgressBar) + +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; +} + +#endif diff --git a/core/widget/radio-button.cpp b/core/widget/radio-button.cpp new file mode 100644 index 0000000..7cd47f4 --- /dev/null +++ b/core/widget/radio-button.cpp @@ -0,0 +1,87 @@ +#if defined(Hiro_RadioButton) + +auto mRadioButton::allocate() -> pObject* { + return new pRadioButton(*this); +} + +// + +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::group() const -> Group { + return state.group; +} + +auto mRadioButton::icon() const -> image { + return state.icon; +} + +auto mRadioButton::onActivate(const function& callback) -> type& { + state.onActivate = callback; + 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& { + if(auto group = this->group()) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioButton = dynamic_cast(object.data())) { + radioButton->state.checked = false; + } + } + } + } + state.checked = true; + signal(setChecked); + return *this; +} + +auto mRadioButton::setGroup(sGroup group) -> type& { + state.group = group ? group : Group{&instance}; + signal(setGroup, group); + 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; +} + +#endif diff --git a/core/widget/radio-label.cpp b/core/widget/radio-label.cpp new file mode 100644 index 0000000..6961ba7 --- /dev/null +++ b/core/widget/radio-label.cpp @@ -0,0 +1,57 @@ +#if defined(Hiro_RadioLabel) + +auto mRadioLabel::allocate() -> pObject* { + return new pRadioLabel(*this); +} + +// + +auto mRadioLabel::checked() const -> bool { + return state.checked; +} + +auto mRadioLabel::doActivate() const -> void { + if(state.onActivate) return state.onActivate(); +} + +auto mRadioLabel::group() const -> Group { + return state.group; +} + +auto mRadioLabel::onActivate(const function& callback) -> type& { + state.onActivate = callback; + return *this; +} + +auto mRadioLabel::setChecked() -> type& { + if(auto group = this->group()) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioLabel = dynamic_cast(object.data())) { + radioLabel->state.checked = false; + } + } + } + } + state.checked = true; + signal(setChecked); + return *this; +} + +auto mRadioLabel::setGroup(sGroup group) -> type& { + state.group = group ? group : Group{&instance}; + signal(setGroup, group); + 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; +} + +#endif diff --git a/core/widget/source-edit.cpp b/core/widget/source-edit.cpp new file mode 100644 index 0000000..5ef494a --- /dev/null +++ b/core/widget/source-edit.cpp @@ -0,0 +1,47 @@ +#if defined(Hiro_SourceEdit) + +auto mSourceEdit::allocate() -> pObject* { + return new pSourceEdit(*this); +} + +// + +auto mSourceEdit::cursor() const -> Cursor { + return state.cursor; +} + +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& callback) -> type& { + state.onChange = callback; + return *this; +} + +auto mSourceEdit::onMove(const function& callback) -> type& { + state.onMove = callback; + return *this; +} + +auto mSourceEdit::setCursor(Cursor cursor) -> type& { + state.cursor = cursor; + signal(setCursor, cursor); + 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); +} + +#endif diff --git a/core/widget/tab-frame-item.cpp b/core/widget/tab-frame-item.cpp new file mode 100644 index 0000000..2c6998f --- /dev/null +++ b/core/widget/tab-frame-item.cpp @@ -0,0 +1,103 @@ +#if defined(Hiro_TabFrame) + +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); + signal(append, layout); + return *this; +} + +auto mTabFrameItem::closable() const -> bool { + return state.closable; +} + +auto mTabFrameItem::icon() const -> image { + return state.icon; +} + +auto mTabFrameItem::layout() const -> Layout { + 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& { + signal(remove, layout); + state.layout.reset(); + layout->setParent(); + return *this; +} + +auto mTabFrameItem::reset() -> type& { + if(auto layout = state.layout) remove(layout); + return *this; +} + +auto mTabFrameItem::selected() const -> bool { + return state.selected; +} + +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 parent = parentTabFrame()) { + for(auto& item : parent->state.items) item->state.selected = false; + } + state.selected = true; + 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; +} + +#endif diff --git a/core/widget/tab-frame.cpp b/core/widget/tab-frame.cpp new file mode 100644 index 0000000..1ac78bf --- /dev/null +++ b/core/widget/tab-frame.cpp @@ -0,0 +1,104 @@ +#if defined(Hiro_TabFrame) + +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& { + if(!state.items) item->state.selected = true; + state.items.append(item); + item->setParent(this, itemCount() - 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::item(unsigned position) const -> TabFrameItem { + if(position < itemCount()) return state.items[position]; + return {}; +} + +auto mTabFrame::itemCount() const -> unsigned { + return state.items.size(); +} + +auto mTabFrame::items() const -> vector { + vector items; + for(auto& item : state.items) items.append(item); + return items; +} + +auto mTabFrame::navigation() const -> Navigation { + return state.navigation; +} + +auto mTabFrame::onChange(const function& callback) -> type& { + state.onChange = callback; + return *this; +} + +auto mTabFrame::onClose(const function& callback) -> type& { + state.onClose = callback; + return *this; +} + +auto mTabFrame::onMove(const function& callback) -> type& { + state.onMove = callback; + 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, itemCount())) { + state.items[n]->adjustOffset(-1); + } + return *this; +} + +auto mTabFrame::reset() -> type& { + while(state.items) remove(state.items.last()); + return *this; +} + +auto mTabFrame::selected() const -> TabFrameItem { + for(auto& item : state.items) { + if(item->selected()) return item; + } + return {}; +} + +auto mTabFrame::setNavigation(Navigation navigation) -> type& { + state.navigation = navigation; + signal(setNavigation, navigation); + return *this; +} + +auto mTabFrame::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.items)) state.items[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& item : state.items) item->setParent(this, item->offset()); + return *this; +} + +#endif diff --git a/core/widget/text-edit.cpp b/core/widget/text-edit.cpp new file mode 100644 index 0000000..1421190 --- /dev/null +++ b/core/widget/text-edit.cpp @@ -0,0 +1,87 @@ +#if defined(Hiro_TextEdit) + +auto mTextEdit::allocate() -> pObject* { + return new pTextEdit(*this); +} + +// + +auto mTextEdit::backgroundColor() const -> Color { + return state.backgroundColor; +} + +auto mTextEdit::cursor() const -> Cursor { + return state.cursor; +} + +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& callback) -> type& { + state.onChange = callback; + return *this; +} + +auto mTextEdit::onMove(const function& callback) -> type& { + state.onMove = callback; + return *this; +} + +auto mTextEdit::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mTextEdit::setCursor(Cursor cursor) -> type& { + state.cursor = cursor; + signal(setCursor, cursor); + 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; +} + +#endif diff --git a/core/widget/tree-view-item.cpp b/core/widget/tree-view-item.cpp new file mode 100644 index 0000000..75724a0 --- /dev/null +++ b/core/widget/tree-view-item.cpp @@ -0,0 +1,167 @@ +#if defined(Hiro_TreeView) + +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, itemCount() - 1); + signal(append, item); + return *this; +} + +auto mTreeViewItem::backgroundColor(bool recursive) const -> Color { + if(auto color = state.backgroundColor) return color; + if(recursive) { + if(auto parent = parentTreeViewItem()) { + if(auto color = parent->backgroundColor(true)) return color; + } + if(auto parent = parentTreeView()) { + if(auto color = parent->backgroundColor()) return color; + } + } + return {}; +} + +auto mTreeViewItem::checkable() const -> bool { + return state.checkable; +} + +auto mTreeViewItem::checked() const -> bool { + return state.checked; +} + +auto mTreeViewItem::foregroundColor(bool recursive) const -> Color { + if(auto color = state.foregroundColor) return color; + if(recursive) { + if(auto parent = parentTreeViewItem()) { + if(auto color = parent->foregroundColor(true)) return color; + } + if(auto parent = parentTreeView()) { + if(auto color = parent->foregroundColor()) return color; + } + } + return {}; +} + +auto mTreeViewItem::icon() const -> image { + return state.icon; +} + +auto mTreeViewItem::item(const string& path) const -> TreeViewItem { + if(path.empty()) return {}; + auto paths = path.split("/"); + unsigned position = paths.takeFirst().natural(); + if(position >= itemCount()) return {}; + if(paths.empty()) return state.items[position]; + return state.items[position]->item(paths.merge("/")); +} + +auto mTreeViewItem::itemCount() const -> unsigned { + return state.items.size(); +} + +auto mTreeViewItem::items() const -> vector { + vector items; + for(auto& item : state.items) items.append(item); + return items; +} + +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(), itemCount())) { + state.items[n]->adjustOffset(-1); + } + item->setParent(); + return *this; +} + +auto mTreeViewItem::selected() const -> bool { + if(auto treeView = parentTreeView(true)) { + return path() == treeView->state.selectedPath; + } + return false; +} + +auto mTreeViewItem::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mTreeViewItem::setCheckable(bool checkable) -> type& { + state.checkable = checkable; + signal(setCheckable, checkable); + return *this; +} + +auto mTreeViewItem::setChecked(bool checked) -> type& { + state.checked = checked; + signal(setChecked, checked); + return *this; +} + +auto mTreeViewItem::setExpanded(bool expanded) -> type& { + signal(setExpanded, expanded); + return *this; +} + +auto mTreeViewItem::setFocused() -> type& { + signal(setFocused); + return *this; +} + +auto mTreeViewItem::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mTreeViewItem::setIcon(const image& icon) -> type& { + state.icon = icon; + signal(setIcon, icon); + return *this; +} + +auto mTreeViewItem::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.items)) state.items[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& item : state.items) item->setParent(this, item->offset()); +} + +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; +} + +#endif diff --git a/core/widget/tree-view.cpp b/core/widget/tree-view.cpp new file mode 100644 index 0000000..a62d211 --- /dev/null +++ b/core/widget/tree-view.cpp @@ -0,0 +1,123 @@ +#if defined(Hiro_TreeView) + +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, itemCount() - 1); + signal(append, item); + return *this; +} + +auto mTreeView::backgroundColor() const -> Color { + return state.backgroundColor; +} + +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::foregroundColor() const -> Color { + return state.foregroundColor; +} + +auto mTreeView::item(const string& path) const -> TreeViewItem { + if(path.empty()) return {}; + auto paths = path.split("/"); + unsigned position = paths.takeFirst().natural(); + if(position >= itemCount()) return {}; + if(paths.empty()) return state.items[position]; + return state.items[position]->item(paths.merge("/")); +} + +auto mTreeView::itemCount() const -> unsigned { + return state.items.size(); +} + +auto mTreeView::items() const -> vector { + vector items; + for(auto& item : state.items) items.append(item); + return items; +} + +auto mTreeView::onActivate(const function& callback) -> type& { + state.onActivate = callback; + return *this; +} + +auto mTreeView::onChange(const function& callback) -> type& { + state.onChange = callback; + return *this; +} + +auto mTreeView::onContext(const function& callback) -> type& { + state.onContext = callback; + return *this; +} + +auto mTreeView::onToggle(const function& callback) -> type& { + state.onToggle = callback; + return *this; +} + +auto mTreeView::remove(sTreeViewItem item) -> type& { + signal(remove, item); + state.items.remove(item->offset()); + for(auto n : range(item->offset(), itemCount())) { + state.items[n]->adjustOffset(-1); + } + item->setParent(); + return *this; +} + +auto mTreeView::reset() -> type& { + state.selectedPath.reset(); + for(auto n : rrange(state.items)) remove(state.items[n]); + return *this; +} + +auto mTreeView::selected() const -> TreeViewItem { + return item(state.selectedPath); +} + +auto mTreeView::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mTreeView::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); + return *this; +} + +auto mTreeView::setParent(mObject* object, signed offset) -> type& { + for(auto n : rrange(state.items)) state.items[n]->destruct(); + mObject::setParent(object, offset); + for(auto& item : state.items) item->setParent(this, item->offset()); + return *this; +} + +#endif diff --git a/core/widget/vertical-scroll-bar.cpp b/core/widget/vertical-scroll-bar.cpp new file mode 100644 index 0000000..d32409b --- /dev/null +++ b/core/widget/vertical-scroll-bar.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_VerticalScrollBar) + +auto mVerticalScrollBar::allocate() -> pObject* { + return new pVerticalScrollBar(*this); +} + +// + +auto mVerticalScrollBar::doChange() const -> void { + if(state.onChange) return state.onChange(); +} + +auto mVerticalScrollBar::length() const -> unsigned { + return state.length; +} + +auto mVerticalScrollBar::onChange(const function& callback) -> type& { + state.onChange = callback; + return *this; +} + +auto mVerticalScrollBar::position() const -> unsigned { + return state.position; +} + +auto mVerticalScrollBar::setLength(unsigned length) -> type& { + state.length = length; + signal(setLength, length); + return *this; +} + +auto mVerticalScrollBar::setPosition(unsigned position) -> type& { + state.position = position; + signal(setPosition, position); + return *this; +} + +#endif diff --git a/core/widget/vertical-slider.cpp b/core/widget/vertical-slider.cpp new file mode 100644 index 0000000..7517f23 --- /dev/null +++ b/core/widget/vertical-slider.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_VerticalSlider) + +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& callback) -> type& { + state.onChange = callback; + 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; +} + +#endif diff --git a/core/widget/viewport.cpp b/core/widget/viewport.cpp new file mode 100644 index 0000000..763703b --- /dev/null +++ b/core/widget/viewport.cpp @@ -0,0 +1,68 @@ +#if defined(Hiro_Viewport) + +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& callback) -> type& { + state.onDrop = callback; + return *this; +} + +auto mViewport::onMouseLeave(const function& callback) -> type& { + state.onMouseLeave = callback; + return *this; +} + +auto mViewport::onMouseMove(const function& callback) -> type& { + state.onMouseMove = callback; + return *this; +} + +auto mViewport::onMousePress(const function& callback) -> type& { + state.onMousePress = callback; + return *this; +} + +auto mViewport::onMouseRelease(const function& callback) -> type& { + state.onMouseRelease = callback; + return *this; +} + +auto mViewport::setDroppable(bool droppable) -> type& { + state.droppable = droppable; + signal(setDroppable, droppable); + return *this; +} + +#endif diff --git a/core/widget/widget.cpp b/core/widget/widget.cpp new file mode 100644 index 0000000..3cf4a29 --- /dev/null +++ b/core/widget/widget.cpp @@ -0,0 +1,24 @@ +#if defined(Hiro_Widget) + +auto mWidget::allocate() -> pObject* { + return new pWidget(*this); +} + +// + +auto mWidget::doSize() const -> void { + if(state.onSize) return state.onSize(); +} + +auto mWidget::onSize(const function& callback) -> type& { + state.onSize = callback; + return *this; +} + +auto mWidget::remove() -> type& { + if(auto layout = parentLayout()) layout->remove(layout->sizable(offset())); + setParent(); + return *this; +} + +#endif diff --git a/core/window.cpp b/core/window.cpp new file mode 100644 index 0000000..16d1b14 --- /dev/null +++ b/core/window.cpp @@ -0,0 +1,278 @@ +#if defined(Hiro_Window) + +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(sLayout 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)); + signal(append, layout); + return *this; +} + +auto mWindow::append(sMenuBar menuBar) -> type& { + if(auto& menuBar = state.menuBar) remove(menuBar); + menuBar->setParent(this, 0); + state.menuBar = menuBar; + signal(append, menuBar); + return *this; +} + +auto mWindow::append(sStatusBar 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 -> Layout { + return state.layout; +} + +auto mWindow::menuBar() const -> MenuBar { + return state.menuBar; +} + +auto mWindow::modal() const -> bool { + return state.modal; +} + +auto mWindow::onClose(const function& callback) -> type& { + state.onClose = callback; + return *this; +} + +auto mWindow::onDrop(const function& callback) -> type& { + state.onDrop = callback; + return *this; +} + +auto mWindow::onKeyPress(const function& callback) -> type& { + state.onKeyPress = callback; + return *this; +} + +auto mWindow::onKeyRelease(const function& callback) -> type& { + state.onKeyRelease = callback; + return *this; +} + +auto mWindow::onMove(const function& callback) -> type& { + state.onMove = callback; + return *this; +} + +auto mWindow::onSize(const function& callback) -> type& { + state.onSize = callback; + return *this; +} + +auto mWindow::remove(sLayout layout) -> type& { + signal(remove, layout); + layout->setParent(); + state.layout.reset(); + return *this; +} + +auto mWindow::remove(sMenuBar menuBar) -> type& { + signal(remove, menuBar); + menuBar->reset(); + menuBar->setParent(); + state.menuBar.reset(); + return *this; +} + +auto mWindow::remove(sStatusBar 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::setAlignment(Alignment alignment) -> type& { + if(!alignment) alignment = {0.0, 0.0}; + auto workspace = Desktop::workspace(); + auto geometry = frameGeometry(); + signed left = alignment.horizontal() * (workspace.width() - geometry.width()); + signed top = alignment.vertical() * (workspace.height() - geometry.height()); + setFramePosition({left, top}); + return *this; +} + +auto mWindow::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mWindow::setCentered(sWindow parent) -> type& { + Geometry workspace = parent ? parent->frameGeometry() : 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::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& { + if(fullScreen != state.fullScreen) { + 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 -> StatusBar { + return state.statusBar; +} + +auto mWindow::title() const -> string { + return state.title; +} + +#endif diff --git a/extension/browser-dialog.cpp b/extension/browser-dialog.cpp new file mode 100644 index 0000000..56a784a --- /dev/null +++ b/extension/browser-dialog.cpp @@ -0,0 +1,261 @@ +#if defined(Hiro_BrowserDialog) + +struct BrowserDialogWindow { + BrowserDialogWindow(BrowserDialog::State& state) : state(state) {} + auto accept() -> void; + auto activate() -> void; + auto change() -> void; + auto isFolder(const string& name) -> bool; + auto isMatch(const string& name) -> bool; + auto run() -> lstring; + auto setPath(string path) -> void; + +private: + Window window; + VerticalLayout layout{&window}; + HorizontalLayout pathLayout{&layout, Size{~0, 0}, 5}; + LineEdit pathName{&pathLayout, Size{~0, 0}, 0}; + Button pathRefresh{&pathLayout, Size{0, 0}, 0}; + Button pathHome{&pathLayout, Size{0, 0}, 0}; + Button pathUp{&pathLayout, Size{0, 0}, 0}; + ListView view{&layout, Size{~0, ~0}, 5}; + HorizontalLayout controlLayout{&layout, Size{~0, 0}}; + ComboButton filterList{&controlLayout, Size{120, 0}, 5}; + LineEdit fileName{&controlLayout, Size{~0, 0}, 5}; + Button acceptButton{&controlLayout, Size{80, 0}, 5}; + Button cancelButton{&controlLayout, Size{80, 0}, 5}; + + BrowserDialog::State& state; + vector filters; +}; + +//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 batched = view.batched(); + + if(state.action == "openFile" && batched) { + string name = batched.first()->cell(0)->text(); + if(isFolder(name)) return setPath({state.path, name}); + state.response.append(string{state.path, name}); + } + + if(state.action == "openFiles") { + for(auto item : batched) { + string name = item->cell(0)->text(); + state.response.append(string{state.path, name, isFolder(name) ? "/" : ""}); + } + } + + if(state.action == "openFolder" && batched) { + string name = batched.first()->cell(0)->text(); + if(!isMatch(name)) return setPath({state.path, name}); + state.response.append(string{state.path, name, "/"}); + } + + if(state.action == "saveFile") { + string name = fileName.text(); + if(!name && batched) name = batched.first()->cell(0)->text(); + if(!name || isFolder(name)) return; + if(file::exists({state.path, name})) { + if(MessageDialog("File already exists; overwrite it?").question() != "Yes") return; + } + state.response.append(string{state.path, name}); + } + + if(state.action == "selectFolder" && batched) { + string name = batched.first()->cell(0)->text(); + 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->cell(0)->text(); + if(isFolder(name)) return setPath({state.path, name}); + fileName.setText(name); + } + + if(state.action == "selectFolder" && selectedItem) { + string name = selectedItem->cell(0)->text(); + 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->cell(0)->text(); + if(!isFolder(name)) fileName.setText(name); + } + } +} + +auto BrowserDialogWindow::isFolder(const string& name) -> bool { + return directory::exists({state.path, name}); +} + +auto BrowserDialogWindow::isMatch(const string& name) -> bool { + if(auto selectedItem = filterList.selected()) { + for(auto& filter : filters[selectedItem->offset()]) { + if(name.match(filter)) return true; + } + } + return false; +} + +auto BrowserDialogWindow::run() -> lstring { + state.response.reset(); + + layout.setMargin(5); + pathName.onActivate([&] { setPath(pathName.text()); }); + pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh).onActivate([&] { setPath(state.path); }); + pathHome.setBordered(false).setIcon(Icon::Go::Home).onActivate([&] { setPath(userpath()); }); + pathUp.setBordered(false).setIcon(Icon::Go::Up).onActivate([&] { setPath(dirname(state.path)); }); + view.setBatchable(state.action == "openFiles").onActivate([&] { activate(); }).onChange([&] { change(); }); + filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); }); + for(auto& filter : state.filters) { + auto part = filter.split("|", 1L); + filterList.append(ComboButtonItem().setText(part.first())); + } + fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); }); + acceptButton.onActivate([&] { accept(); }); + if(state.action == "openFile" || state.action == "openFiles" || state.action == "openFolder") acceptButton.setText("Open"); + if(state.action == "saveFile") acceptButton.setText("Save"); + if(state.action == "selectFolder") acceptButton.setText("Select"); + cancelButton.setText("Cancel").onActivate([&] { window.setModal(false); }); + + if(!state.filters) state.filters.append("All|*"); + for(auto& filter : state.filters) { + auto part = filter.split("|", 1L); + filters.append(part.last().split(":")); + } + + 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(); + view.setFocused(); + 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(ListViewHeader().setVisible(false) + .append(ListViewColumn().setExpandable()) + ); + + auto contents = directory::icontents(path); + bool folderMode = state.action == "openFolder"; + + for(auto content : contents) { + if(!content.endsWith("/")) continue; + content.rtrim("/"); + if(folderMode && isMatch(content)) continue; + + view.append(ListViewItem() + .append(ListViewCell().setText(content).setIcon(Icon::Emblem::Folder)) + ); + } + + for(auto content : contents) { + if(content.endsWith("/") != folderMode) continue; //file mode shows files; folder mode shows folders + content.rtrim("/"); + if(!isMatch(content)) continue; + + view.append(ListViewItem() + .append(ListViewCell().setText(content).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File)) + ); + } + + 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::openFolder() -> string { + state.action = "openFolder"; + if(!state.title) state.title = "Open Folder"; + if(auto result = _run()) return result.first(); + 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 sWindow& 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(); +} + +#endif diff --git a/extension/browser-dialog.hpp b/extension/browser-dialog.hpp new file mode 100644 index 0000000..dee0287 --- /dev/null +++ b/extension/browser-dialog.hpp @@ -0,0 +1,34 @@ +#if defined(Hiro_BrowserDialog) + +struct BrowserDialogWindow; + +struct BrowserDialog { + using type = BrowserDialog; + + BrowserDialog(); + auto openFile() -> string; //one existing file + auto openFiles() -> lstring; //any existing files or folders + auto openFolder() -> string; //one existing folder + auto saveFile() -> string; //one file + auto selectFolder() -> string; //one existing folder + auto setFilters(const lstring& filters = {}) -> type&; + auto setParent(const sWindow& parent) -> type&; + auto setPath(const string& path = "") -> type&; + auto setTitle(const string& title = "") -> type&; + +private: + struct State { + string action; + lstring filters = {"*"}; + sWindow parent; + string path; + lstring response; + string title; + } state; + + auto _run() -> lstring; + + friend class BrowserDialogWindow; +}; + +#endif diff --git a/extension/extension.cpp b/extension/extension.cpp new file mode 100644 index 0000000..aa46d45 --- /dev/null +++ b/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/extension/extension.hpp b/extension/extension.hpp new file mode 100644 index 0000000..f3655ab --- /dev/null +++ b/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/extension/fixed-layout.cpp b/extension/fixed-layout.cpp new file mode 100644 index 0000000..8fe302f --- /dev/null +++ b/extension/fixed-layout.cpp @@ -0,0 +1,63 @@ +#if defined(Hiro_FixedLayout) + +auto mFixedLayout::append(sSizable sizable, Geometry geometry) -> type& { + properties.append({geometry}); + mLayout::append(sizable); + sizable->setGeometry(geometry); + return *this; +} + +auto mFixedLayout::modify(sSizable sizable, Geometry geometry) -> type& { + if(sizable && this->sizable(sizable->offset()) == sizable) { + auto& properties = this->properties[sizable->offset()]; + properties.geometry = geometry; + } + return *this; +} + +auto mFixedLayout::minimumSize() const -> Size { + signed width = Size::Minimum, height = Size::Minimum; + for(auto n : range(sizableCount())) { + width = max(width, sizable(n)->minimumSize().width()); + height = max(height, sizable(n)->minimumSize().height()); + } + return {width, height}; +} + +auto mFixedLayout::remove(sSizable 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(sizableCount())) { + sizable(n)->setEnabled(sizable(n)->enabled()); + } + return *this; +} + +auto mFixedLayout::setFont(const Font& font) -> type& { + mLayout::setFont(font); + for(auto n : range(sizableCount())) { + sizable(n)->setFont(sizable(n)->font()); + } + return *this; +} + +auto mFixedLayout::setVisible(bool visible) -> type& { + mLayout::setVisible(visible); + for(auto n : range(sizableCount())) { + sizable(n)->setVisible(sizable(n)->visible()); + } + return *this; +} + +#endif diff --git a/extension/fixed-layout.hpp b/extension/fixed-layout.hpp new file mode 100644 index 0000000..bcfb2e6 --- /dev/null +++ b/extension/fixed-layout.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_FixedLayout) + +struct mFixedLayout : mLayout { + using type = mFixedLayout; + using mLayout::append; + using mLayout::remove; + + auto append(sSizable sizable, Geometry geometry) -> type&; + auto modify(sSizable sizable, Geometry geometry) -> type&; + auto minimumSize() const -> Size override; + auto remove(sSizable sizable) -> type& override; + auto reset() -> type& override; + auto setEnabled(bool enabled = true) -> type& override; + auto setFont(const Font& font = {}) -> type& override; + auto setVisible(bool visible = true) ->type& override; + + struct Properties { + Geometry geometry; + }; + vector properties; +}; + +#endif diff --git a/extension/horizontal-layout.cpp b/extension/horizontal-layout.cpp new file mode 100644 index 0000000..c120c17 --- /dev/null +++ b/extension/horizontal-layout.cpp @@ -0,0 +1,141 @@ +#if defined(Hiro_HorizontalLayout) + +auto mHorizontalLayout::append(sSizable sizable, Size size, signed spacing) -> type& { + properties.append({size.width(), size.height(), spacing < 0 ? settings.spacing : spacing}); + mLayout::append(sizable); + return *this; +} + +auto mHorizontalLayout::modify(sSizable sizable, Size size, signed spacing) -> type& { + if(sizable && this->sizable(sizable->offset()) == sizable) { + auto& properties = this->properties[sizable->offset()]; + properties.width = size.width(); + properties.height = size.height(); + properties.spacing = spacing; + } + return *this; +} + +auto mHorizontalLayout::minimumSize() const -> Size { + signed width = 0, height = 0; + + for(auto n : range(sizableCount())) { + 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(sizableCount())) { + 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(sSizable 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(sizableCount())) { + sizable(n)->setEnabled(sizable(n)->enabled()); + } + return *this; +} + +auto mHorizontalLayout::setFont(const Font& font) -> type& { + mLayout::setFont(font); + for(auto n : range(sizableCount())) { + sizable(n)->setFont(sizable(n)->font()); + } + return *this; +} + +auto mHorizontalLayout::setGeometry(Geometry containerGeometry) -> type& { + mLayout::setGeometry(containerGeometry); + + auto properties = this->properties; + for(auto n : range(sizableCount())) { + 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(sizableCount())) { + 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); + } + + return *this; +} + +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(sizableCount())) { + sizable(n)->setVisible(sizable(n)->visible()); + } + return *this; +} + +#endif diff --git a/extension/horizontal-layout.hpp b/extension/horizontal-layout.hpp new file mode 100644 index 0000000..13a4d95 --- /dev/null +++ b/extension/horizontal-layout.hpp @@ -0,0 +1,35 @@ +#if defined(Hiro_HorizontalLayout) + +struct mHorizontalLayout : mLayout { + using type = mHorizontalLayout; + using mLayout::append; + using mLayout::remove; + + auto append(sSizable sizable, Size size, signed spacing = 5) -> type&; + auto minimumSize() const -> Size override; + auto modify(sSizable sizable, Size size, signed spacing = 5) -> type&; + auto remove(sSizable sizable) -> type& override; + auto reset() -> type& override; + auto setAlignment(double alignment = 0.5) -> type&; + auto setEnabled(bool enabled = true) -> type& override; + auto setFont(const Font& 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; + }; + vector properties; +}; + +#endif diff --git a/extension/message-dialog.cpp b/extension/message-dialog.cpp new file mode 100644 index 0000000..d9e379d --- /dev/null +++ b/extension/message-dialog.cpp @@ -0,0 +1,81 @@ +#if defined(Hiro_MessageDialog) + +MessageDialog::MessageDialog(const string& text) { + state.text = text; +} + +auto MessageDialog::error(const lstring& buttons) -> string { + state.buttons = buttons; + state.icon = Icon::Prompt::Error; + return _run(); +} + +auto MessageDialog::information(const lstring& buttons) -> string { + state.buttons = buttons; + state.icon = Icon::Prompt::Information; + return _run(); +} + +auto MessageDialog::question(const lstring& buttons) -> string { + 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) -> string { + state.buttons = buttons; + state.icon = Icon::Prompt::Warning; + return _run(); +} + +auto MessageDialog::_run() -> string { + Window window; + VerticalLayout layout{&window}; + HorizontalLayout messageLayout{&layout, Size{~0, 0}, 5}; + Canvas messageIcon{&messageLayout, Size{16, 16}, 5}; + Label messageText{&messageLayout, Size{~0, 0}}; + HorizontalLayout controlLayout{&layout, Size{~0, 0}}; + Widget controlSpacer{&controlLayout, Size{~0, 0}}; + + layout.setMargin(5); + messageIcon.setIcon(state.icon); + messageText.setText(state.text); + for(auto n : range(state.buttons)) { + Button button{&controlLayout, Size{80, 0}, 5}; + button.onActivate([&, n] { state.response = state.buttons[n]; window.setModal(false); }); + button.setText(state.buttons[n]); + button.setFocused(); //the last button will have effective focus + } + + signed widthMessage = 5 + 16 + 5 + Font().size(state.text).width() + 5; + signed widthButtons = 5 + state.buttons.size() * 85; + signed width = max(320, widthMessage, widthButtons); + + window.onClose([&] { 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; +} + +#endif diff --git a/extension/message-dialog.hpp b/extension/message-dialog.hpp new file mode 100644 index 0000000..64f845a --- /dev/null +++ b/extension/message-dialog.hpp @@ -0,0 +1,28 @@ +#if defined(Hiro_MessageDialog) + +struct MessageDialog { + using type = MessageDialog; + + MessageDialog(const string& text = ""); + auto error(const lstring& buttons = {"Ok"}) -> string; + auto information(const lstring& buttons = {"Ok"}) -> string; + auto question(const lstring& buttons = {"Yes", "No"}) -> string; + auto setParent(sWindow parent = {}) -> type&; + auto setText(const string& text = "") -> type&; + auto setTitle(const string& title = "") -> type&; + auto warning(const lstring& buttons = {"Ok"}) -> string; + +private: + struct State { + lstring buttons; + vector icon; + sWindow parent; + string response; + string text; + string title; + } state; + + auto _run() -> string; +}; + +#endif diff --git a/extension/shared.hpp b/extension/shared.hpp new file mode 100644 index 0000000..de05c1c --- /dev/null +++ b/extension/shared.hpp @@ -0,0 +1,35 @@ +#if defined(Hiro_FixedLayout) +using sFixedLayout = shared_pointer; +struct FixedLayout : sFixedLayout { + DeclareSharedLayout(FixedLayout) + + auto append(sSizable sizable, Geometry geometry) { return self().append(sizable, geometry), *this; } + auto modify(sSizable sizable, Geometry geometry) { return self().modify(sizable, geometry), *this; } +}; +#endif + +#if defined(Hiro_HorizontalLayout) +using sHorizontalLayout = shared_pointer; +struct HorizontalLayout : sHorizontalLayout { + DeclareSharedLayout(HorizontalLayout) + + auto append(sSizable sizable, Size size, signed spacing = 5) { return self().append(sizable, size, spacing), *this; } + auto modify(sSizable sizable, Size size, signed spacing = 5) { return self().modify(sizable, size, spacing), *this; } + auto setAlignment(double alignment = 0.5) { return self().setAlignment(alignment), *this; } + auto setMargin(signed margin = 0) { return self().setMargin(margin), *this; } + auto setSpacing(signed spacing = 5) { return self().setSpacing(spacing), *this; } +}; +#endif + +#if defined(Hiro_VerticalLayout) +using sVerticalLayout = shared_pointer; +struct VerticalLayout : sVerticalLayout { + DeclareSharedLayout(VerticalLayout) + + auto append(sSizable sizable, Size size, signed spacing = 5) { return self().append(sizable, size, spacing), *this; } + auto modify(sSizable sizable, Size size, signed spacing = 5) { return self().modify(sizable, size, spacing), *this; } + auto setAlignment(double alignment = 0.0) { return self().setAlignment(alignment), *this; } + auto setMargin(signed margin = 0) { return self().setMargin(margin), *this; } + auto setSpacing(signed spacing = 5) { return self().setSpacing(spacing), *this; } +}; +#endif diff --git a/extension/vertical-layout.cpp b/extension/vertical-layout.cpp new file mode 100644 index 0000000..d5a2867 --- /dev/null +++ b/extension/vertical-layout.cpp @@ -0,0 +1,141 @@ +#if defined(Hiro_VerticalLayout) + +auto mVerticalLayout::append(sSizable sizable, Size size, signed spacing) -> type& { + properties.append({size.width(), size.height(), spacing < 0 ? settings.spacing : spacing}); + mLayout::append(sizable); + return *this; +} + +auto mVerticalLayout::modify(sSizable sizable, Size size, signed spacing) -> type& { + if(sizable && this->sizable(sizable->offset()) == sizable) { + auto& properties = this->properties[sizable->offset()]; + properties.width = size.width(); + properties.height = size.height(); + properties.spacing = spacing; + } + return *this; +} + +auto mVerticalLayout::minimumSize() const -> Size { + signed width = 0, height = 0; + + for(auto n : range(sizableCount())) { + 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(sizableCount())) { + 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(sSizable 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(sizableCount())) { + sizable(n)->setEnabled(sizable(n)->enabled()); + } + return *this; +} + +auto mVerticalLayout::setFont(const Font& font) -> type& { + mLayout::setFont(font); + for(auto n : range(sizableCount())) { + sizable(n)->setFont(sizable(n)->font()); + } + return *this; +} + +auto mVerticalLayout::setGeometry(Geometry containerGeometry) -> type& { + mLayout::setGeometry(containerGeometry); + + auto properties = this->properties; + for(auto n : range(sizableCount())) { + 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(sizableCount())) { + 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(sizableCount())) { + sizable(n)->setVisible(sizable(n)->visible()); + } + return *this; +} + +#endif diff --git a/extension/vertical-layout.hpp b/extension/vertical-layout.hpp new file mode 100644 index 0000000..c208fc2 --- /dev/null +++ b/extension/vertical-layout.hpp @@ -0,0 +1,35 @@ +#if defined(Hiro_VerticalLayout) + +struct mVerticalLayout : mLayout { + using type = mVerticalLayout; + using mLayout::append; + using mLayout::remove; + + auto append(sSizable sizable, Size size, signed spacing = 5) -> type&; + auto modify(sSizable sizable, Size size, signed spacing = 5) -> type&; + auto minimumSize() const -> Size override; + auto remove(sSizable sizable) -> type& override; + auto reset() -> type& override; + auto setAlignment(double alignment = 0.0) -> type&; + auto setEnabled(bool enabled = true) -> type& override; + auto setFont(const Font& 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; + }; + vector properties; +}; + +#endif diff --git a/gtk/action/action.cpp b/gtk/action/action.cpp new file mode 100644 index 0000000..010125b --- /dev/null +++ b/gtk/action/action.cpp @@ -0,0 +1,35 @@ +#if defined(Hiro_Action) + +namespace hiro { + +auto pAction::construct() -> void { +} + +auto pAction::destruct() -> void { +} + +auto pAction::setEnabled(bool enabled) -> void { + gtk_widget_set_sensitive(widget, enabled); +} + +auto pAction::setFont(const Font& font) -> void { + pFont::setFont(widget, font); +} + +auto pAction::setVisible(bool visible) -> void { + gtk_widget_set_visible(widget, visible); +} + +//GTK+ uses _ for mnemonics, __ for _ +//transform so that & is used for mnemonics, && for & +auto pAction::_mnemonic(string text) -> string { + text.transform("&_", "\x01\x02"); + text.replace("\x01\x01", "&"); + text.transform("\x01", "_"); + text.replace("\x02", "__"); + return text; +} + +} + +#endif diff --git a/gtk/action/action.hpp b/gtk/action/action.hpp new file mode 100644 index 0000000..62fe99f --- /dev/null +++ b/gtk/action/action.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_Action) + +namespace hiro { + +struct pAction : pObject { + Declare(Action, Object) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; + + auto _mnemonic(string text) -> string; + + GtkWidget* widget = nullptr; +}; + +} + +#endif diff --git a/gtk/action/menu-check-item.cpp b/gtk/action/menu-check-item.cpp new file mode 100644 index 0000000..3061dc3 --- /dev/null +++ b/gtk/action/menu-check-item.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_MenuCheckItem) + +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)); +} + +} + +#endif diff --git a/gtk/action/menu-check-item.hpp b/gtk/action/menu-check-item.hpp new file mode 100644 index 0000000..3a288f8 --- /dev/null +++ b/gtk/action/menu-check-item.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_MenuCheckItem) + +namespace hiro { + +struct pMenuCheckItem : pAction { + Declare(MenuCheckItem, Action) + auto orphan() -> void; + + auto setChecked(bool checked) -> void; + auto setText(const string& text) -> void; +}; + +} + +#endif diff --git a/gtk/action/menu-item.cpp b/gtk/action/menu-item.cpp new file mode 100644 index 0000000..7451b74 --- /dev/null +++ b/gtk/action/menu-item.cpp @@ -0,0 +1,35 @@ +#if defined(Hiro_MenuItem) + +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); + setIcon(state().icon); + 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)); +} + +} + +#endif diff --git a/gtk/action/menu-item.hpp b/gtk/action/menu-item.hpp new file mode 100644 index 0000000..8d980c3 --- /dev/null +++ b/gtk/action/menu-item.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_MenuItem) + +namespace hiro { + +struct pMenuItem : pAction { + Declare(MenuItem, Action) + + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; +}; + +} + +#endif diff --git a/gtk/action/menu-radio-item.cpp b/gtk/action/menu-radio-item.cpp new file mode 100644 index 0000000..f1e28e7 --- /dev/null +++ b/gtk/action/menu-radio-item.cpp @@ -0,0 +1,78 @@ +#if defined(Hiro_MenuRadioItem) + +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, ""); + gtkCheckMenuItem = GTK_CHECK_MENU_ITEM(widget); + gtkRadioMenuItem = GTK_RADIO_MENU_ITEM(widget); + + setText(state().text); + + 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 { + lock(); + gtk_check_menu_item_set_active(gtkCheckMenuItem, true); + unlock(); +} + +auto pMenuRadioItem::setGroup(sGroup group) -> void { + maybe gtkRadioMenuItem; + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto menuRadioItem = dynamic_cast(object.data())) { + if(auto self = menuRadioItem->self()) { + self->lock(); + gtk_radio_menu_item_set_group(self->gtkRadioMenuItem, nullptr); + if(!gtkRadioMenuItem) { + gtkRadioMenuItem = self->gtkRadioMenuItem; + gtk_check_menu_item_set_active(self->gtkCheckMenuItem, menuRadioItem->state.checked = true); + } else { + gtk_radio_menu_item_set_group(self->gtkRadioMenuItem, gtk_radio_menu_item_get_group(*gtkRadioMenuItem)); + gtk_check_menu_item_set_active(self->gtkCheckMenuItem, menuRadioItem->state.checked = false); + } + self->unlock(); + } + } + } + } +} + +auto pMenuRadioItem::setText(const string& text) -> void { + gtk_menu_item_set_label(GTK_MENU_ITEM(widget), _mnemonic(text)); +} + +auto pMenuRadioItem::groupLocked() const -> bool { + if(auto group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto self = object->self()) { + if(self->locked()) return true; + } + } + } + return false; + } + return locked(); +} + +auto pMenuRadioItem::_doActivate() -> void { + if(groupLocked()) return; + bool wasChecked = state().checked; + self().setChecked(); + if(!wasChecked) self().doActivate(); +} + +} + +#endif diff --git a/gtk/action/menu-radio-item.hpp b/gtk/action/menu-radio-item.hpp new file mode 100644 index 0000000..f943f26 --- /dev/null +++ b/gtk/action/menu-radio-item.hpp @@ -0,0 +1,22 @@ +#if defined(Hiro_MenuRadioItem) + +namespace hiro { + +struct pMenuRadioItem : pAction { + Declare(MenuRadioItem, Action) + + auto setChecked() -> void; + auto setGroup(sGroup group) -> void; + auto setText(const string& text) -> void; + + auto groupLocked() const -> bool; + + auto _doActivate() -> void; + + GtkCheckMenuItem* gtkCheckMenuItem = nullptr; + GtkRadioMenuItem* gtkRadioMenuItem = nullptr; +}; + +} + +#endif diff --git a/gtk/action/menu-separator.cpp b/gtk/action/menu-separator.cpp new file mode 100644 index 0000000..d638641 --- /dev/null +++ b/gtk/action/menu-separator.cpp @@ -0,0 +1,15 @@ +#if defined(Hiro_MenuSeparator) + +namespace hiro { + +auto pMenuSeparator::construct() -> void { + widget = gtk_separator_menu_item_new(); +} + +auto pMenuSeparator::destruct() -> void { + if(widget) gtk_widget_destroy(widget), widget = nullptr; +} + +} + +#endif diff --git a/gtk/action/menu-separator.hpp b/gtk/action/menu-separator.hpp new file mode 100644 index 0000000..a94dbf6 --- /dev/null +++ b/gtk/action/menu-separator.hpp @@ -0,0 +1,11 @@ +#if defined(Hiro_MenuSeparator) + +namespace hiro { + +struct pMenuSeparator : pAction { + Declare(MenuSeparator, Action) +}; + +} + +#endif diff --git a/gtk/action/menu.cpp b/gtk/action/menu.cpp new file mode 100644 index 0000000..652853a --- /dev/null +++ b/gtk/action/menu.cpp @@ -0,0 +1,53 @@ +#if defined(Hiro_Menu) + +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); + setIcon(state().icon); + 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()); //hidden parent will hide child; no need to inherit visibility + } +} + +auto pMenu::remove(sAction action) -> void { +} + +auto pMenu::setFont(const Font& 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)); +} + +} + +#endif diff --git a/gtk/action/menu.hpp b/gtk/action/menu.hpp new file mode 100644 index 0000000..d99cd75 --- /dev/null +++ b/gtk/action/menu.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_Menu) + +namespace hiro { + +struct pMenu : pAction { + Declare(Menu, Action) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setFont(const Font& font) -> void override; + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + GtkWidget* gtkMenu = nullptr; +}; + +} + +#endif diff --git a/gtk/application.cpp b/gtk/application.cpp new file mode 100644 index 0000000..9ca4c22 --- /dev/null +++ b/gtk/application.cpp @@ -0,0 +1,112 @@ +#if defined(Hiro_Application) + +namespace hiro { + +#if defined(DISPLAY_XORG) +XlibDisplay* pApplication::display = nullptr; +#endif + +auto pApplication::run() -> void { + if(Application::state.onMain) { + while(!Application::state.quit) { + Application::doMain(); + processEvents(); + } + } else { + gtk_main(); + } +} + +auto pApplication::pendingEvents() -> bool { + return gtk_events_pending(); +} + +auto pApplication::processEvents() -> void { + while(pendingEvents()) gtk_main_iteration_do(false); +} + +auto pApplication::quit() -> void { + //if gtk_main() was invoked, call gtk_main_quit() + if(gtk_main_level()) gtk_main_quit(); + + #if defined(DISPLAY_XORG) + //todo: Keyboard::poll() is being called after Application::quit(); + //so if display is closed; this causes a segfault + //XCloseDisplay(display); + //display = nullptr; + #endif +} + +auto pApplication::initialize() -> void { + #if defined(DISPLAY_XORG) + display = XOpenDisplay(nullptr); + #endif + + 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[5], nullptr}; + strcpy(argv[0], "hiro"); + #else + //--g-fatal-warnings will force a trap on Gtk-CRITICAL errors + //this allows gdb to perform a backtrace to find an error's origin point + int argc = 2; + char* argv[] = {new char[5], new char[19], nullptr}; + strcpy(argv[0], "hiro"); + strcpy(argv[1], "--g-fatal-warnings"); + #endif + char** argvp = argv; + + gtk_init(&argc, &argvp); + GtkSettings* gtkSettings = gtk_settings_get_default(); + + //allow buttons to show icons + g_type_class_unref(g_type_class_ref(GTK_TYPE_BUTTON)); + g_object_set(gtkSettings, "gtk-button-images", true, nullptr); + + #if defined(DISPLAY_WINDOWS) + //there is a serious bug in GTK 2.24 for Windows with the "ime" (Windows IME) input method: + //by default, it will be impossible to type in text fields at all. + //there are various tricks to get around this; but they are unintuitive and unreliable. + //the "ime" method is chosen when various international system locales (eg Japanese) are selected. + //here, we override the default input method to use the "Simple" type instead to avoid the bug. + //obviously, this has a drawback: in-place editing for IMEs will not work in this mode. + g_object_set(gtkSettings, "gtk-im-module", "gtk-im-context-simple", nullptr); + #endif + + gtk_rc_parse_string(R"( + style "HiroWindow" + { + GtkWindow::resize-grip-width = 0 + GtkWindow::resize-grip-height = 0 + } + class "GtkWindow" style "HiroWindow" + + style "HiroTreeView" + { + GtkTreeView::vertical-separator = 0 + } + class "GtkTreeView" style "HiroTreeView" + + style "HiroTabFrameCloseButton" + { + 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 "HiroTabFrameCloseButton" + )"); + + pKeyboard::initialize(); +} + +} + +#endif diff --git a/gtk/application.hpp b/gtk/application.hpp new file mode 100644 index 0000000..9f8feb7 --- /dev/null +++ b/gtk/application.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_Application) + +namespace hiro { + +struct pApplication { + #if defined(DISPLAY_XORG) + static XlibDisplay* display; + #endif + + static auto run() -> void; + static auto pendingEvents() -> bool; + static auto processEvents() -> void; + static auto quit() -> void; + + static auto initialize() -> void; +}; + +} + +#endif diff --git a/gtk/browser-window.cpp b/gtk/browser-window.cpp new file mode 100644 index 0000000..947feb1 --- /dev/null +++ b/gtk/browser-window.cpp @@ -0,0 +1,92 @@ +#if defined(Hiro_BrowserWindow) + +namespace hiro { + +static auto BrowserWindow_addFilters(GtkWidget* dialog, lstring filters) -> void { + for(auto& filter : filters) { + GtkFileFilter* gtkFilter = gtk_file_filter_new(); + gtk_file_filter_set_name(gtkFilter, filter); + lstring patterns = filter.split("(", 1L)(1).rtrim(")", 1L).split(",").strip(); + for(auto& pattern : patterns) gtk_file_filter_add_pattern(gtkFilter, pattern); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter); + } +} + +auto pBrowserWindow::directory(BrowserWindow::State& state) -> string { + string name; + + GtkWidget* dialog = gtk_file_chooser_dialog_new( + state.title ? state.title : "Select Directory", + 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, + (const gchar*)nullptr + ); + + if(state.path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), state.path); + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char* temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + name = temp; + g_free(temp); + } + + gtk_widget_destroy(dialog); + if(name && !name.endsWith("/")) name.append("/"); + return name; +} + +auto pBrowserWindow::open(BrowserWindow::State& state) -> string { + string name; + + GtkWidget* dialog = gtk_file_chooser_dialog_new( + state.title ? state.title : "Open File", + 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, + (const gchar*)nullptr + ); + + if(state.path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), state.path); + BrowserWindow_addFilters(dialog, state.filters); + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char* temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + name = temp; + g_free(temp); + } + + gtk_widget_destroy(dialog); + return name; +} + +auto pBrowserWindow::save(BrowserWindow::State& state) -> string { + string name; + + GtkWidget* dialog = gtk_file_chooser_dialog_new( + state.title ? state.title : "Save File", + 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, + (const gchar*)nullptr + ); + + if(state.path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), state.path); + BrowserWindow_addFilters(dialog, state.filters); + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char* temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + name = temp; + g_free(temp); + } + + gtk_widget_destroy(dialog); + return name; +} + +} + +#endif diff --git a/gtk/browser-window.hpp b/gtk/browser-window.hpp new file mode 100644 index 0000000..80e561b --- /dev/null +++ b/gtk/browser-window.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_BrowserWindow) + +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; +}; + +} + +#endif diff --git a/gtk/desktop.cpp b/gtk/desktop.cpp new file mode 100644 index 0000000..3a58829 --- /dev/null +++ b/gtk/desktop.cpp @@ -0,0 +1,52 @@ +#if defined(Hiro_Desktop) + +namespace hiro { + +auto pDesktop::size() -> Size { + return { + gdk_screen_get_width(gdk_screen_get_default()), + gdk_screen_get_height(gdk_screen_get_default()) + }; +} + +auto pDesktop::workspace() -> Geometry { + #if defined(DISPLAY_WINDOWS) + RECT rc; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); + return {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top}; + #endif + + #if defined(DISPLAY_XORG) + XlibDisplay* display = XOpenDisplay(nullptr); + int screen = DefaultScreen(display); + + static Atom atom = XlibNone; + if(atom == XlibNone) atom = XInternAtom(display, "_NET_WORKAREA", True); + + int format; + unsigned char* data = nullptr; + unsigned long items, after; + Atom returnAtom; + + int result = XGetWindowProperty( + display, RootWindow(display, screen), atom, 0, 4, False, XA_CARDINAL, &returnAtom, &format, &items, &after, &data + ); + + XCloseDisplay(display); + + if(result == Success && returnAtom == XA_CARDINAL && format == 32 && items == 4) { + unsigned long *workarea = (unsigned long*)data; + return {(signed)workarea[0], (signed)workarea[1], (signed)workarea[2], (signed)workarea[3]}; + } + + return { + 0, 0, + gdk_screen_get_width(gdk_screen_get_default()), + gdk_screen_get_height(gdk_screen_get_default()) + }; + #endif +} + +} + +#endif diff --git a/gtk/desktop.hpp b/gtk/desktop.hpp new file mode 100644 index 0000000..2c179b6 --- /dev/null +++ b/gtk/desktop.hpp @@ -0,0 +1,12 @@ +#if defined(Hiro_Desktop) + +namespace hiro { + +struct pDesktop { + static auto size() -> Size; + static auto workspace() -> Geometry; +}; + +} + +#endif diff --git a/gtk/font.cpp b/gtk/font.cpp new file mode 100644 index 0000000..1a85e97 --- /dev/null +++ b/gtk/font.cpp @@ -0,0 +1,68 @@ +#if defined(Hiro_Font) + +namespace hiro { + +auto pFont::size(const Font& font, const string& text) -> Size { + PangoFontDescription* description = create(font); + Size size = pFont::size(description, text); + free(description); + return size; +} + +auto pFont::size(PangoFontDescription* font, const string& text) -> Size { + PangoContext* context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); + PangoLayout* layout = pango_layout_new(context); + pango_layout_set_font_description(layout, font); + pango_layout_set_text(layout, text, -1); + signed width = 0, height = 0; + pango_layout_get_pixel_size(layout, &width, &height); + g_object_unref((gpointer)layout); + return {width, height}; +} + +auto pFont::family(const string& family) -> string { + #if defined(DISPLAY_WINDOWS) + if(family == Font::Sans ) return "Tahoma"; + if(family == Font::Serif) return "Georgia"; + if(family == Font::Mono ) return "Lucida Console"; + return family ? family : "Tahoma"; + #elif defined(DISPLAY_XORG) + if(family == Font::Sans ) return "Sans"; + if(family == Font::Serif) return "Serif"; + if(family == Font::Mono ) return "Liberation Mono"; + return family ? family : "Sans"; + #else + return family; + #endif +} + +auto pFont::create(const Font& font) -> PangoFontDescription* { + auto p = pango_font_description_new(); + pango_font_description_set_family(p, family(font.family())); + pango_font_description_set_size(p, (font.size() ? font.size() : 8) * PANGO_SCALE); + pango_font_description_set_weight(p, font.bold() ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); + pango_font_description_set_style(p, font.italic() ? PANGO_STYLE_OBLIQUE : PANGO_STYLE_NORMAL); + return p; +} + +auto pFont::free(PangoFontDescription* font) -> void { + pango_font_description_free(font); +} + +auto pFont::setFont(GtkWidget* widget, const Font& font) -> void { + auto gtkFont = pFont::create(font); + pFont::setFont(widget, (gpointer)gtkFont); + pFont::free(gtkFont); +} + +auto pFont::setFont(GtkWidget* widget, gpointer font) -> void { + if(font == nullptr) return; + gtk_widget_modify_font(widget, (PangoFontDescription*)font); + if(GTK_IS_CONTAINER(widget)) { + gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)pFont::setFont, font); + } +} + +} + +#endif diff --git a/gtk/font.hpp b/gtk/font.hpp new file mode 100644 index 0000000..3ad59dd --- /dev/null +++ b/gtk/font.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_Font) + +namespace hiro { + +struct pFont { + static auto size(const Font& font, const string& text) -> Size; + static auto size(PangoFontDescription* font, const string& text) -> Size; + static auto family(const string& family) -> string; + static auto create(const Font& font) -> PangoFontDescription*; + static auto free(PangoFontDescription* font) -> void; + static auto setFont(GtkWidget* widget, const Font& font) -> void; + static auto setFont(GtkWidget* widget, gpointer font) -> void; +}; + +} + +#endif diff --git a/gtk/group.cpp b/gtk/group.cpp new file mode 100644 index 0000000..cbf387f --- /dev/null +++ b/gtk/group.cpp @@ -0,0 +1,13 @@ +#if defined(Hiro_Group) + +namespace hiro { + +auto pGroup::construct() -> void { +} + +auto pGroup::destruct() -> void { +} + +} + +#endif diff --git a/gtk/group.hpp b/gtk/group.hpp new file mode 100644 index 0000000..a2ac6d7 --- /dev/null +++ b/gtk/group.hpp @@ -0,0 +1,11 @@ +#if defined(Hiro_Group) + +namespace hiro { + +struct pGroup : pObject { + Declare(Group, Object) +}; + +} + +#endif diff --git a/gtk/header.hpp b/gtk/header.hpp new file mode 100644 index 0000000..7b1002b --- /dev/null +++ b/gtk/header.hpp @@ -0,0 +1,47 @@ +#if defined(DISPLAY_WINDOWS) + #define UNICODE + #define WINVER 0x0601 + #define _WIN32_WINNT WINVER + #define _WIN32_IE WINVER + #define __MSVCRT_VERSION__ WINVER + #define NOMINMAX + #define TBS_TRANSPARENTBKGND 0x1000 + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #if defined(Hiro_SourceEdit) + #include + #include + #include + #endif + #include + #include + #include +#endif + +#if defined(DISPLAY_XORG) + #include + #include + #include + #include + #include + #include + #include + #if defined(Hiro_SourceEdit) + #include + #include + #include + #endif + #include +#endif diff --git a/gtk/keyboard.cpp b/gtk/keyboard.cpp new file mode 100644 index 0000000..90315ab --- /dev/null +++ b/gtk/keyboard.cpp @@ -0,0 +1,251 @@ +#if defined(Hiro_Keyboard) + +namespace hiro { + +auto pKeyboard::poll() -> vector { + vector result; + char state[256]; + #if defined(DISPLAY_XORG) + XQueryKeymap(pApplication::display, state); + #endif + for(auto& code : settings->keycodes) { + result.append(_pressed(state, code)); + } + return result; +} + +auto pKeyboard::pressed(unsigned code) -> bool { + char state[256]; + #if defined(DISPLAY_XORG) + XQueryKeymap(pApplication::display, state); + #endif + return _pressed(state, code); +} + +auto pKeyboard::_pressed(const char* state, uint16_t code) -> bool { + uint8_t lo = code >> 0; + uint8_t hi = code >> 8; + + #if defined(DISPLAY_WINDOWS) + if(lo && GetAsyncKeyState(lo) & 0x8000) return true; + if(hi && GetAsyncKeyState(hi) & 0x8000) return true; + #endif + + #if defined(DISPLAY_XORG) + if(lo && state[lo >> 3] & (1 << (lo & 7))) return true; + if(hi && state[hi >> 3] & (1 << (hi & 7))) return true; + #endif + + 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) { + #if defined(DISPLAY_XORG) + lo = lo ? (uint8_t)XKeysymToKeycode(pApplication::display, lo) : 0; + hi = hi ? (uint8_t)XKeysymToKeycode(pApplication::display, hi) : 0; + #endif + settings->keycodes.append(lo | (hi << 8)); + }; + + #define map(name, ...) if(key == name) { append(__VA_ARGS__); continue; } + for(auto& key : Keyboard::keys) { + #if defined(DISPLAY_WINDOWS) + #include + #endif + + #if defined(DISPLAY_XORG) + #include + #endif + + //print("[hiro/gtk] warning: unhandled key: ", key, "\n"); + append(0); + } + #undef map +} + +} + +#endif diff --git a/gtk/keyboard.hpp b/gtk/keyboard.hpp new file mode 100644 index 0000000..5733268 --- /dev/null +++ b/gtk/keyboard.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_Keyboard) + +namespace hiro { + +struct pKeyboard { + static auto poll() -> vector; + static auto pressed(unsigned code) -> bool; + + static auto _pressed(const char* state, uint16_t code) -> bool; + static auto _translate(unsigned code) -> signed; + + static auto initialize() -> void; +}; + +} + +#endif diff --git a/gtk/layout.cpp b/gtk/layout.cpp new file mode 100644 index 0000000..dd58131 --- /dev/null +++ b/gtk/layout.cpp @@ -0,0 +1,33 @@ +#if defined(Hiro_Layout) + +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(auto self = sizable->self()) self->setEnabled(sizable->enabled(true)); + } +} + +auto pLayout::setFont(const Font& font) -> void { + for(auto& sizable : state().sizables) { + if(auto self = sizable->self()) self->setFont(sizable->font(true)); + } +} + +auto pLayout::setVisible(bool visible) -> void { + for(auto& sizable : state().sizables) { + if(auto self = sizable->self()) self->setVisible(sizable->visible(true)); + } +} + +} + +#endif diff --git a/gtk/layout.hpp b/gtk/layout.hpp new file mode 100644 index 0000000..dba1183 --- /dev/null +++ b/gtk/layout.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_Layout) + +namespace hiro { + +struct pLayout : pSizable { + Declare(Layout, Sizable) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; +}; + +} + +#endif diff --git a/gtk/menu-bar.cpp b/gtk/menu-bar.cpp new file mode 100644 index 0000000..d1522dd --- /dev/null +++ b/gtk/menu-bar.cpp @@ -0,0 +1,49 @@ +#if defined(Hiro_MenuBar) + +namespace hiro { + +auto pMenuBar::construct() -> void { +} + +auto pMenuBar::destruct() -> void { +} + +auto pMenuBar::append(sMenu 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(sMenu menu) -> void { +} + +auto pMenuBar::setEnabled(bool enabled) -> void { + if(auto parent = _parent()) { + parent->_setMenuEnabled(enabled); + } +} + +auto pMenuBar::setFont(const Font& 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; +} + +} + +#endif diff --git a/gtk/menu-bar.hpp b/gtk/menu-bar.hpp new file mode 100644 index 0000000..25ffbda --- /dev/null +++ b/gtk/menu-bar.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_MenuBar) + +namespace hiro { + +struct pMenuBar : pObject { + Declare(MenuBar, Object) + + auto append(sMenu menu) -> void; + auto remove(sMenu menu) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; + + auto _parent() -> pWindow*; +}; + +} + +#endif diff --git a/gtk/message-window.cpp b/gtk/message-window.cpp new file mode 100644 index 0000000..4391297 --- /dev/null +++ b/gtk/message-window.cpp @@ -0,0 +1,64 @@ +#if defined(Hiro_MessageWindow) + +namespace hiro { + +static auto Message(MessageWindow::State& state, GtkMessageType messageStyle) -> MessageWindow::Response { + GtkWidget* dialog = gtk_message_dialog_new( + 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(Application::state.name) gtk_window_set_title(GTK_WINDOW(dialog), Application::state.name); + + switch(state.buttons) { + case MessageWindow::Buttons::Ok: + gtk_dialog_add_buttons(GTK_DIALOG(dialog), "Ok", GTK_RESPONSE_OK, nullptr); + break; + case MessageWindow::Buttons::OkCancel: + gtk_dialog_add_buttons(GTK_DIALOG(dialog), "Ok", GTK_RESPONSE_OK, "Cancel", GTK_RESPONSE_CANCEL, nullptr); + break; + case MessageWindow::Buttons::YesNo: + gtk_dialog_add_buttons(GTK_DIALOG(dialog), "Yes", GTK_RESPONSE_YES, "No", GTK_RESPONSE_NO, nullptr); + break; + case MessageWindow::Buttons::YesNoCancel: + gtk_dialog_add_buttons(GTK_DIALOG(dialog), "Yes", GTK_RESPONSE_YES, "No", GTK_RESPONSE_NO, "Cancel", GTK_RESPONSE_CANCEL, nullptr); + break; + } + + auto response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + if(response == GTK_RESPONSE_OK) return MessageWindow::Response::Ok; + if(response == GTK_RESPONSE_CANCEL) return MessageWindow::Response::Cancel; + if(response == GTK_RESPONSE_YES) return MessageWindow::Response::Yes; + if(response == GTK_RESPONSE_NO) return MessageWindow::Response::No; + + //if dialog was closed without choosing a button, choose the most appropriate response + if(state.buttons == MessageWindow::Buttons::Ok) return MessageWindow::Response::Ok; + if(state.buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; + if(state.buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; + if(state.buttons == MessageWindow::Buttons::YesNoCancel) return MessageWindow::Response::Cancel; + + throw; +} + +auto pMessageWindow::error(MessageWindow::State& state) -> MessageWindow::Response { + return Message(state, GTK_MESSAGE_ERROR); +} + +auto pMessageWindow::information(MessageWindow::State& state) -> MessageWindow::Response { + return Message(state, GTK_MESSAGE_INFO); +} + +auto pMessageWindow::question(MessageWindow::State& state) -> MessageWindow::Response { + return Message(state, GTK_MESSAGE_QUESTION); +} + +auto pMessageWindow::warning(MessageWindow::State& state) -> MessageWindow::Response { + return Message(state, GTK_MESSAGE_WARNING); +} + +} + +#endif diff --git a/gtk/message-window.hpp b/gtk/message-window.hpp new file mode 100644 index 0000000..b8b26af --- /dev/null +++ b/gtk/message-window.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_MessageWindow) + +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; +}; + +} + +#endif diff --git a/gtk/monitor.cpp b/gtk/monitor.cpp new file mode 100644 index 0000000..498ea8b --- /dev/null +++ b/gtk/monitor.cpp @@ -0,0 +1,21 @@ +#if defined(Hiro_Monitor) + +namespace hiro { + +auto pMonitor::count() -> uint { + return gdk_screen_get_n_monitors(gdk_screen_get_default()); +} + +auto pMonitor::geometry(uint monitor) -> Geometry { + GdkRectangle rectangle = {0}; + gdk_screen_get_monitor_geometry(gdk_screen_get_default(), monitor, &rectangle); + return {rectangle.x, rectangle.y, rectangle.width, rectangle.height}; +} + +auto pMonitor::primary() -> uint { + return gdk_screen_get_primary_monitor(gdk_screen_get_default()); +} + +} + +#endif diff --git a/gtk/monitor.hpp b/gtk/monitor.hpp new file mode 100644 index 0000000..53df3c9 --- /dev/null +++ b/gtk/monitor.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_Monitor) + +namespace hiro { + +struct pMonitor { + static auto count() -> uint; + static auto geometry(unsigned monitor) -> Geometry; + static auto primary() -> uint; +}; + +} + +#endif diff --git a/gtk/mouse.cpp b/gtk/mouse.cpp new file mode 100644 index 0000000..645d9b7 --- /dev/null +++ b/gtk/mouse.cpp @@ -0,0 +1,47 @@ +#if defined(Hiro_Mouse) + +namespace hiro { + +auto pMouse::position() -> Position { + #if defined(DISPLAY_WINDOWS) + POINT point{0}; + GetCursorPos(&point); + return {point.x, point.y}; + #endif + + #if defined(DISPLAY_XORG) + XlibWindow root, child; + int rootx, rooty, winx, winy; + unsigned int mask; + XQueryPointer(pApplication::display, DefaultRootWindow(pApplication::display), &root, &child, &rootx, &rooty, &winx, &winy, &mask); + return {rootx, rooty}; + #endif +} + +auto pMouse::pressed(Mouse::Button button) -> bool { + #if defined(DISPLAY_WINDOWS) + switch(button) { + case Mouse::Button::Left: return GetAsyncKeyState(VK_LBUTTON) & 0x8000; + case Mouse::Button::Middle: return GetAsyncKeyState(VK_MBUTTON) & 0x8000; + case Mouse::Button::Right: return GetAsyncKeyState(VK_RBUTTON) & 0x8000; + } + #endif + + #if defined(DISPLAY_XORG) + XlibWindow root, child; + int rootx, rooty, winx, winy; + unsigned int mask; + XQueryPointer(pApplication::display, DefaultRootWindow(pApplication::display), &root, &child, &rootx, &rooty, &winx, &winy, &mask); + switch(button) { + case Mouse::Button::Left: return mask & Button1Mask; + case Mouse::Button::Middle: return mask & Button2Mask; + case Mouse::Button::Right: return mask & Button3Mask; + } + #endif + + return false; +} + +} + +#endif diff --git a/gtk/mouse.hpp b/gtk/mouse.hpp new file mode 100644 index 0000000..72a5605 --- /dev/null +++ b/gtk/mouse.hpp @@ -0,0 +1,12 @@ +#if defined(Hiro_Mouse) + +namespace hiro { + +struct pMouse { + static auto position() -> Position; + static auto pressed(Mouse::Button button) -> bool; +}; + +} + +#endif diff --git a/gtk/object.cpp b/gtk/object.cpp new file mode 100644 index 0000000..3c6ac44 --- /dev/null +++ b/gtk/object.cpp @@ -0,0 +1,35 @@ +#if defined(Hiro_Object) + +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 Font& font) -> void { +} + +auto pObject::setVisible(bool visible) -> void { +} + +} + +#endif diff --git a/gtk/object.hpp b/gtk/object.hpp new file mode 100644 index 0000000..056ed0b --- /dev/null +++ b/gtk/object.hpp @@ -0,0 +1,31 @@ +#if defined(Hiro_Object) + +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 Font& 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; +}; + +} + +#endif diff --git a/gtk/platform.cpp b/gtk/platform.cpp new file mode 100644 index 0000000..72a42b4 --- /dev/null +++ b/gtk/platform.cpp @@ -0,0 +1,66 @@ +#include "platform.hpp" +#include "utility.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 "group.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-scroll-bar.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-header.cpp" +#include "widget/list-view-column.cpp" +#include "widget/list-view-item.cpp" +#include "widget/list-view-cell.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-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +#include "application.cpp" +#include "settings.cpp" diff --git a/gtk/platform.hpp b/gtk/platform.hpp new file mode 100644 index 0000000..828959e --- /dev/null +++ b/gtk/platform.hpp @@ -0,0 +1,79 @@ +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 "group.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-scroll-bar.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-header.hpp" +#include "widget/list-view-column.hpp" +#include "widget/list-view-item.hpp" +#include "widget/list-view-cell.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-scroll-bar.hpp" +#include "widget/vertical-slider.hpp" +#include "widget/viewport.hpp" + +#undef Declare + +#include "application.hpp" +#include "settings.hpp" diff --git a/gtk/popup-menu.cpp b/gtk/popup-menu.cpp new file mode 100644 index 0000000..65fa6a3 --- /dev/null +++ b/gtk/popup-menu.cpp @@ -0,0 +1,36 @@ +#if defined(Hiro_PopupMenu) + +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 Font& 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()); +} + +} + +#endif diff --git a/gtk/popup-menu.hpp b/gtk/popup-menu.hpp new file mode 100644 index 0000000..2c44cf7 --- /dev/null +++ b/gtk/popup-menu.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_PopupMenu) + +namespace hiro { + +struct pPopupMenu : pObject { + Declare(PopupMenu, Object) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void; + + GtkWidget* gtkMenu = nullptr; +}; + +} + +#endif diff --git a/gtk/settings.cpp b/gtk/settings.cpp new file mode 100644 index 0000000..53a03d5 --- /dev/null +++ b/gtk/settings.cpp @@ -0,0 +1,26 @@ +namespace hiro { + +Settings::Settings() { + geometry.append(geometry.frameX = 4, "FrameX"); + geometry.append(geometry.frameY = 24, "FrameY"); + geometry.append(geometry.frameWidth = 8, "FrameWidth"); + geometry.append(geometry.frameHeight = 28, "FrameHeight"); + geometry.append(geometry.menuHeight = 20, "MenuHeight"); + geometry.append(geometry.statusHeight = 20, "StatusHeight"); + append(geometry, "Geometry"); + window.append(window.backgroundColor = 0xedeceb, "BackgroundColor"); + append(window, "Window"); +} + +auto Settings::load() -> void { + string path = {configpath(), "hiro/"}; + Configuration::Document::load({path, "gtk.bml"}); +} + +auto Settings::save() -> void { + string path = {configpath(), "hiro/"}; + directory::create(path, 0755); + Configuration::Document::save({path, "gtk.bml"}); +} + +} diff --git a/gtk/settings.hpp b/gtk/settings.hpp new file mode 100644 index 0000000..8bcd1ed --- /dev/null +++ b/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; + + Settings(); + auto load() -> void; + auto save() -> void; +}; + +static Settings* settings = nullptr; + +} diff --git a/gtk/sizable.cpp b/gtk/sizable.cpp new file mode 100644 index 0000000..4e793ab --- /dev/null +++ b/gtk/sizable.cpp @@ -0,0 +1,20 @@ +#if defined(Hiro_Sizable) + +namespace hiro { + +auto pSizable::construct() -> void { +} + +auto pSizable::destruct() -> void { +} + +auto pSizable::minimumSize() const -> Size { + return {0, 0}; +} + +auto pSizable::setGeometry(Geometry geometry) -> void { +} + +} + +#endif diff --git a/gtk/sizable.hpp b/gtk/sizable.hpp new file mode 100644 index 0000000..5270283 --- /dev/null +++ b/gtk/sizable.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_Sizable) + +namespace hiro { + +struct pSizable : pObject { + Declare(Sizable, Object) + + virtual auto minimumSize() const -> Size; + virtual auto setGeometry(Geometry geometry) -> void; +}; + +} + +#endif diff --git a/gtk/status-bar.cpp b/gtk/status-bar.cpp new file mode 100644 index 0000000..3d4d88d --- /dev/null +++ b/gtk/status-bar.cpp @@ -0,0 +1,42 @@ +#if defined(Hiro_StatusBar) + +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 Font& 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; +} + +} + +#endif diff --git a/gtk/status-bar.hpp b/gtk/status-bar.hpp new file mode 100644 index 0000000..7e2a9be --- /dev/null +++ b/gtk/status-bar.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_StatusBar) + +namespace hiro { + +struct pStatusBar : pObject { + Declare(StatusBar, Object) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> pWindow*; +}; + +} + +#endif diff --git a/gtk/timer.cpp b/gtk/timer.cpp new file mode 100644 index 0000000..38b182b --- /dev/null +++ b/gtk/timer.cpp @@ -0,0 +1,35 @@ +#if defined(Hiro_Timer) + +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(uint interval) -> void { +} + +} + +#endif diff --git a/gtk/timer.hpp b/gtk/timer.hpp new file mode 100644 index 0000000..ce0d950 --- /dev/null +++ b/gtk/timer.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_Timer) + +namespace hiro { + +struct pTimer : pObject { + Declare(Timer, Object) + + auto setEnabled(bool enabled) -> void override; + auto setInterval(uint interval) -> void; +}; + +} + +#endif diff --git a/gtk/utility.cpp b/gtk/utility.cpp new file mode 100644 index 0000000..c30286f --- /dev/null +++ b/gtk/utility.cpp @@ -0,0 +1,58 @@ +namespace hiro { + +#if defined(Hiro_Color) +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; +} +#endif + +static auto CreatePixbuf(image icon, bool scale = false) -> GdkPixbuf* { + if(!icon) return nullptr; + + if(scale) icon.scale(15, 15); + icon.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); //GTK stores images in ABGR format + + auto pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, icon.width(), icon.height()); + memory::copy(gdk_pixbuf_get_pixels(pixbuf), icon.data(), icon.size()); + + if(scale) { + auto scaled = gdk_pixbuf_scale_simple(pixbuf, 15, 15, GDK_INTERP_BILINEAR); + g_object_unref(pixbuf); + pixbuf = scaled; + } + + return pixbuf; +} + +static auto CreateImage(const image& icon, bool scale = false) -> GtkImage* { + auto pixbuf = CreatePixbuf(icon, scale); + auto gtkIcon = (GtkImage*)gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + return gtkIcon; +} + +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/gtk/widget/button.cpp b/gtk/widget/button.cpp new file mode 100644 index 0000000..764af85 --- /dev/null +++ b/gtk/widget/button.cpp @@ -0,0 +1,72 @@ +#if defined(Hiro_Button) + +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(); +} + +} + +#endif diff --git a/gtk/widget/button.hpp b/gtk/widget/button.hpp new file mode 100644 index 0000000..76108e6 --- /dev/null +++ b/gtk/widget/button.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_Button) + +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; +}; + +} + +#endif diff --git a/gtk/widget/canvas.cpp b/gtk/widget/canvas.cpp new file mode 100644 index 0000000..ca9fc7a --- /dev/null +++ b/gtk/widget/canvas.cpp @@ -0,0 +1,196 @@ +#if defined(Hiro_Canvas) + +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 { + if(auto& icon = state().icon) return {(int)icon.width(), (int)icon.height()}; + return {0, 0}; +} + +auto pCanvas::setColor(Color color) -> void { + 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(Gradient gradient) -> void { + update(); +} + +auto pCanvas::setIcon(const image& icon) -> void { + update(); +} + +auto pCanvas::update() -> void { + _rasterize(); + _redraw(); +} + +auto pCanvas::_onExpose(GdkEventExpose* expose) -> void { + if(surface == nullptr) return; + + int sx = 0, sy = 0, dx = 0, dy = 0; + int width = surfaceWidth; + int 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 { + int width = 0; + int height = 0; + + if(auto& icon = state().icon) { + width = icon.width(); + height = icon.height(); + } else { + width = pSizable::state().geometry.width(); + height = pSizable::state().geometry.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); + auto buffer = (uint32_t*)gdk_pixbuf_get_pixels(surface); + + if(auto& icon = state().icon) { + memory::copy(buffer, state().icon.data(), width * height * sizeof(uint32_t)); + } else if(auto& gradient = state().gradient) { + auto& colors = gradient.state.colors; + image fill; + fill.allocate(width, height); + fill.gradient(colors[0].value(), colors[1].value(), colors[2].value(), colors[3].value()); + memory::copy(buffer, fill.data(), fill.size()); + } else { + uint32_t color = state().color.value(); + for(auto n : range(width * height)) buffer[n] = color; + } + + //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; +} + +} + +#endif diff --git a/gtk/widget/canvas.hpp b/gtk/widget/canvas.hpp new file mode 100644 index 0000000..3a9c61a --- /dev/null +++ b/gtk/widget/canvas.hpp @@ -0,0 +1,28 @@ +#if defined(Hiro_Canvas) + +namespace hiro { + +struct pCanvas : pWidget { + Declare(Canvas, Widget) + + auto minimumSize() const -> Size; + auto setColor(Color color) -> void; + auto setDroppable(bool droppable) -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setGradient(Gradient gradient) -> void; + auto setIcon(const image& icon) -> void; + auto update() -> void; + + auto _onExpose(GdkEventExpose* event) -> void; + auto _rasterize() -> void; + auto _redraw() -> void; + auto _release() -> void; + + GdkPixbuf* surface = nullptr; + uint surfaceWidth = 0; + uint surfaceHeight = 0; +}; + +} + +#endif diff --git a/gtk/widget/check-button.cpp b/gtk/widget/check-button.cpp new file mode 100644 index 0000000..3ff37aa --- /dev/null +++ b/gtk/widget/check-button.cpp @@ -0,0 +1,77 @@ +#if defined(Hiro_CheckButton) + +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 +} + +} + +#endif diff --git a/gtk/widget/check-button.hpp b/gtk/widget/check-button.hpp new file mode 100644 index 0000000..886f4e5 --- /dev/null +++ b/gtk/widget/check-button.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_CheckButton) + +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; +}; + +} + +#endif diff --git a/gtk/widget/check-label.cpp b/gtk/widget/check-label.cpp new file mode 100644 index 0000000..5139cfa --- /dev/null +++ b/gtk/widget/check-label.cpp @@ -0,0 +1,43 @@ +#if defined(Hiro_CheckLabel) + +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 +} + +} + +#endif diff --git a/gtk/widget/check-label.hpp b/gtk/widget/check-label.hpp new file mode 100644 index 0000000..3037573 --- /dev/null +++ b/gtk/widget/check-label.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_CheckLabel) + +namespace hiro { + +struct pCheckLabel : pWidget { + Declare(CheckLabel, Widget) + + auto minimumSize() const -> Size; + auto setChecked(bool checked) -> void; + auto setText(const string& text) -> void; +}; + +} + +#endif diff --git a/gtk/widget/combo-button-item.cpp b/gtk/widget/combo-button-item.cpp new file mode 100644 index 0000000..01ca947 --- /dev/null +++ b/gtk/widget/combo-button-item.cpp @@ -0,0 +1,40 @@ +#if defined(Hiro_ComboButton) + +namespace hiro { + +auto pComboButtonItem::construct() -> void { +} + +auto pComboButtonItem::destruct() -> void { +} + +auto pComboButtonItem::setIcon(const image& icon) -> void { + if(auto parent = _parent()) { + auto size = pFont::size(self().font(true), " ").height(); + auto pixbuf = CreatePixbuf(icon, true); + gtk_list_store_set(parent->gtkListStore, >kIter, 0, pixbuf, -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; +} + +} + +#endif diff --git a/gtk/widget/combo-button-item.hpp b/gtk/widget/combo-button-item.hpp new file mode 100644 index 0000000..3afd541 --- /dev/null +++ b/gtk/widget/combo-button-item.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_ComboButton) + +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; +}; + +} + +#endif diff --git a/gtk/widget/combo-button.cpp b/gtk/widget/combo-button.cpp new file mode 100644 index 0000000..1959e27 --- /dev/null +++ b/gtk/widget/combo-button.cpp @@ -0,0 +1,91 @@ +#if defined(Hiro_ComboButton) + +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); + + 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 self = item->self()) { + gtk_list_store_append(gtkListStore, &self->gtkIter); + self->setIcon(item->state.icon); + if(item->state.selected) self->setSelected(); + self->setText(item->state.text); + } + if(gtk_combo_box_get_active(gtkComboBox) < 0) item->setSelected(); + unlock(); +} + +auto pComboButton::minimumSize() const -> Size { + auto font = self().font(true); + signed maximumWidth = 0; + for(auto& item : state().items) { + maximumWidth = max(maximumWidth, + (item->state.icon ? pFont::size(font, " ").height() + 2 : 0) + + pFont::size(font, item->state.text).width() + ); + } + return {maximumWidth + 40, pFont::size(font, " ").height() + 12}; +} + +auto pComboButton::remove(sComboButtonItem item) -> void { + lock(); + if(auto delegate = item->self()) { + gtk_list_store_remove(gtkListStore, &delegate->gtkIter); + if(gtk_combo_box_get_active(gtkComboBox) < 0) { + if(auto item = self().item(0)) item->setSelected(); + } + } + unlock(); +} + +auto pComboButton::reset() -> void { + lock(); + gtk_list_store_clear(gtkListStore); + unlock(); +} + +auto pComboButton::setFont(const Font& font) -> void { + pWidget::setFont(font); + auto fontDescription = pFont::create(font); + g_object_set(G_OBJECT(gtkCellText), "font-desc", fontDescription, nullptr); +} + +auto pComboButton::_updateSelected() -> void { + for(auto& item : state().items) item->state.selected = false; + signed selected = gtk_combo_box_get_active(gtkComboBox); + if(selected >= 0) { + if(auto item = self().item(selected)) { + item->state.selected = true; + if(!locked()) self().doChange(); + } + } +} + +} + +#endif diff --git a/gtk/widget/combo-button.hpp b/gtk/widget/combo-button.hpp new file mode 100644 index 0000000..a81470e --- /dev/null +++ b/gtk/widget/combo-button.hpp @@ -0,0 +1,25 @@ +#if defined(Hiro_ComboButton) + +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 Font& font) -> void override; + + auto _updateSelected() -> void; + + GtkListStore* gtkListStore = nullptr; + GtkTreeModel* gtkTreeModel = nullptr; + GtkComboBox* gtkComboBox = nullptr; + GtkCellRenderer* gtkCellIcon = nullptr; + GtkCellRenderer* gtkCellText = nullptr; +}; + +} + +#endif diff --git a/gtk/widget/console.cpp b/gtk/widget/console.cpp new file mode 100644 index 0000000..2a687bf --- /dev/null +++ b/gtk/widget/console.cpp @@ -0,0 +1,189 @@ +#if defined(Hiro_Console) + +namespace hiro { + +static auto Console_keyPress(GtkWidget*, GdkEventKey* event, pConsole* p) -> signed { + return p->_keyPress(event->keyval, event->state); +} + +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(); +} + +auto pConsole::reset() -> void { + //flush history and redraw prompt + gtk_text_buffer_set_text(textBuffer, state().prompt, -1); + _seekToEnd(); +} + +auto pConsole::setBackgroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pConsole::setForegroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +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); + gtk_text_buffer_get_iter_at_line_offset(textBuffer, &rhs, gtk_text_buffer_get_line_count(textBuffer), previousPrompt.size()); + 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(); +} + +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), state().prompt.size()); + gtk_text_buffer_get_iter_at_mark(textBuffer, &cursor, mark); + gtk_text_buffer_get_end_iter(textBuffer, &end); + + if(scancode == GDK_KEY_Return || scancode == GDK_KEY_KP_Enter) { + 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", state().prompt}, -1); + self().doActivate(s); + if(s) history.prepend(s); + if(history.size() > 128) history.removeLast(); + historyOffset = 0; + _seekToEnd(); + return true; + } + + if(scancode == GDK_KEY_Up) { + gtk_text_buffer_delete(textBuffer, &start, &end); + gtk_text_buffer_get_end_iter(textBuffer, &end); + if(historyOffset < history.size()) { + gtk_text_buffer_insert(textBuffer, &end, history[historyOffset++], -1); + } + _seekToEnd(); + return true; + } + + if(scancode == GDK_KEY_Down) { + gtk_text_buffer_delete(textBuffer, &start, &end); + gtk_text_buffer_get_end_iter(textBuffer, &end); + if(historyOffset > 0) { + gtk_text_buffer_insert(textBuffer, &end, history[--historyOffset], -1); + } + _seekToEnd(); + return true; + } + + if(scancode == GDK_KEY_Left) { + if(gtk_text_iter_get_offset(&cursor) <= gtk_text_iter_get_offset(&start)) { + gtk_text_buffer_place_cursor(textBuffer, &start); + } else { + gtk_text_iter_set_offset(&cursor, gtk_text_iter_get_offset(&cursor) - 1); + gtk_text_buffer_place_cursor(textBuffer, &cursor); + } + _seekToMark(); + return true; + } + + if(scancode == GDK_KEY_Right) { + if(gtk_text_iter_get_offset(&cursor) < gtk_text_iter_get_offset(&start)) { + gtk_text_buffer_place_cursor(textBuffer, &end); + } else if(gtk_text_iter_get_offset(&cursor) < gtk_text_iter_get_offset(&end)) { + gtk_text_iter_set_offset(&cursor, gtk_text_iter_get_offset(&cursor) + 1); + gtk_text_buffer_place_cursor(textBuffer, &cursor); + } + _seekToMark(); + return true; + } + + if(scancode == GDK_KEY_Home) { + gtk_text_buffer_place_cursor(textBuffer, &start); + _seekToMark(); + return true; + } + + if(scancode == GDK_KEY_End) { + gtk_text_buffer_place_cursor(textBuffer, &end); + _seekToMark(); + return true; + } + + if(scancode == GDK_KEY_BackSpace) { + if(gtk_text_iter_get_offset(&cursor) <= gtk_text_iter_get_offset(&start)) return true; + GtkTextIter lhs = cursor; + gtk_text_iter_set_offset(&lhs, gtk_text_iter_get_offset(&cursor) - 1); + gtk_text_buffer_delete(textBuffer, &lhs, &cursor); + _seekToMark(); + return true; + } + + if(scancode == GDK_KEY_Delete) { + if(gtk_text_iter_get_offset(&cursor) < gtk_text_iter_get_offset(&start)) return true; + if(gtk_text_iter_get_offset(&cursor) == gtk_text_iter_get_offset(&end)) return true; + GtkTextIter rhs = cursor; + gtk_text_iter_set_offset(&rhs, gtk_text_iter_get_offset(&cursor) + 1); + gtk_text_buffer_delete(textBuffer, &cursor, &rhs); + _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(); + return true; + } + + return false; +} + +auto pConsole::_seekToEnd() -> void { + GtkTextIter iter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + gtk_text_buffer_place_cursor(textBuffer, &iter); + _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); +} + +} + +#endif diff --git a/gtk/widget/console.hpp b/gtk/widget/console.hpp new file mode 100644 index 0000000..5d27957 --- /dev/null +++ b/gtk/widget/console.hpp @@ -0,0 +1,27 @@ +#if defined(Hiro_Console) + +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; +}; + +} + +#endif diff --git a/gtk/widget/frame.cpp b/gtk/widget/frame.cpp new file mode 100644 index 0000000..e07f2a6 --- /dev/null +++ b/gtk/widget/frame.cpp @@ -0,0 +1,70 @@ +#if defined(Hiro_Frame) + +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 Font& 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; +} + +} + +#endif diff --git a/gtk/widget/frame.hpp b/gtk/widget/frame.hpp new file mode 100644 index 0000000..71f4900 --- /dev/null +++ b/gtk/widget/frame.hpp @@ -0,0 +1,24 @@ +#if defined(Hiro_Frame) + +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 Font& 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; +}; + +} + +#endif diff --git a/gtk/widget/hex-edit.cpp b/gtk/widget/hex-edit.cpp new file mode 100644 index 0000000..49ae797 --- /dev/null +++ b/gtk/widget/hex-edit.cpp @@ -0,0 +1,313 @@ +#if defined(Hiro_HexEdit) + +namespace hiro { + +static auto HexEdit_keyPress(GtkWidget* widget, GdkEventKey* event, pHexEdit* p) -> signed { + return p->keyPress(event->keyval, event->state); +} + +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) { + p->scroll(position - 1); + } + + if(event->direction == GDK_SCROLL_DOWN) { + p->scroll(position + 1); + } + + return true; //do not propagate event further +} + +static auto HexEdit_scroll(GtkRange* range, GtkScrollType scroll, double value, pHexEdit* p) -> signed { + p->scroll((signed)value); + return true; //do not propagate event further +} + +auto pHexEdit::construct() -> void { + gtkWidget = gtk_hbox_new(false, 0); + + container = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(container), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(container), 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(container), subWidget); + + 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); + + gtk_box_pack_start(GTK_BOX(gtkWidget), container, true, true, 0); + gtk_box_pack_start(GTK_BOX(gtkWidget), scrollBar, false, false, 1); + + textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); + textCursor = gtk_text_buffer_get_mark(textBuffer, "insert"); + + gtk_widget_show(scrollBar); + gtk_widget_show(subWidget); + gtk_widget_show(container); + + setAddress(state().address); + setBackgroundColor(state().backgroundColor); + setColumns(state().columns); + setForegroundColor(state().foregroundColor); + setRows(state().rows); + setLength(state().length); + 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(); +} + +auto pHexEdit::destruct() -> void { + gtk_widget_destroy(scrollBar); + gtk_widget_destroy(subWidget); + gtk_widget_destroy(container); + gtk_widget_destroy(gtkWidget); +} + +auto pHexEdit::focused() const -> bool { + return GTK_WIDGET_HAS_FOCUS(subWidget) || GTK_WIDGET_HAS_FOCUS(scrollBar); +} + +auto pHexEdit::setAddress(unsigned address) -> void { + setScroll(); + updateScroll(); + update(); +} + +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::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 address = state().address; + for(auto row : range(state().rows)) { + output.append(hex(address, 8L)); + output.append(" "); + + string hexdata; + string ansidata = " "; + for(auto column : range(state().columns)) { + if(address < state().length) { + uint8_t data = self().doRead(address++); + hexdata.append(hex(data, 2L)); + hexdata.append(" "); + ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.'); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(address >= 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); +} + +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 + (state().columns * 3) + 1 + state().columns + 1; + signed cursorY = position / lineWidth; + signed cursorX = position % lineWidth; + + if(scancode == GDK_Home) { + setCursorPosition(cursorY * lineWidth + 10); + return true; + } + + if(scancode == GDK_End) { + setCursorPosition(cursorY * lineWidth + 10 + (state().columns * 3 - 1)); + return true; + } + + if(scancode == GDK_Up) { + if(cursorY != 0) return false; + + signed newAddress = state().address - state().columns; + if(newAddress >= 0) { + self().setAddress(newAddress); + update(); + } + return true; + } + + if(scancode == GDK_Down) { + if(cursorY >= rows() - 1) return true; + if(cursorY != state().rows - 1) return false; + + signed newAddress = state().address + state().columns; + if(newAddress + state().columns * state().rows - (state().columns - 1) <= state().length) { + self().setAddress(newAddress); + update(); + } + return true; + } + + if(scancode == GDK_Page_Up) { + signed newAddress = state().address - state().columns * state().rows; + if(newAddress >= 0) { + self().setAddress(newAddress); + } else { + self().setAddress(0); + } + update(); + return true; + } + + if(scancode == GDK_Page_Down) { + signed newAddress = state().address + state().columns * state().rows; + for(auto n : range(state().rows)) { + if(newAddress + state().columns * state().rows - (state().columns - 1) <= state().length) { + self().setAddress(newAddress); + update(); + break; + } + newAddress -= state().columns; + } + return true; + } + + //convert scancode to hex nibble + if(scancode >= '0' && scancode <= '9') scancode = scancode - '0'; + else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10; + else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10; + else return false; //not a valid hex value + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < state().columns) { + //not in ANSI region + unsigned address = state().address + (cursorY * state().columns + cursorX); + + if(address >= state().length) return false; //do not edit past end of data + uint8_t data = self().doRead(address); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (scancode << 0); + } else { + data = (data & 0x0f) | (scancode << 4); + } + self().doWrite(address, data); + + //auto-advance cursor to next nibble/byte + position++; + if(cursorNibble && cursorX != state().columns - 1) position++; + setCursorPosition(position); + + //refresh output to reflect modified data + update(); + } + } + } + + return true; +} + +//number of actual rows +auto pHexEdit::rows() -> signed { + return (max(1u, state().length) + state().columns - 1) / state().columns; +} + +//number of scrollable row positions +auto pHexEdit::rowsScrollable() -> signed { + return max(0u, rows() - state().rows); +} + +auto pHexEdit::scroll(signed position) -> void { + if(position > rowsScrollable()) position = rowsScrollable(); + if(position < 0) position = 0; + self().setAddress(position * state().columns); +} + +auto pHexEdit::setCursorPosition(unsigned position) -> void { + GtkTextIter iter; + gtk_text_buffer_get_iter_at_mark(textBuffer, &iter, textCursor); + + //GTK+ will throw many errors to the terminal if you set iterator past end of buffer + GtkTextIter endIter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + unsigned endPosition = gtk_text_iter_get_offset(&iter); + + gtk_text_iter_set_offset(&iter, min(position, endPosition)); + gtk_text_buffer_place_cursor(textBuffer, &iter); +} + +auto pHexEdit::setScroll() -> void { + if(rowsScrollable() > 0) { + gtk_range_set_range(GTK_RANGE(scrollBar), 0, rowsScrollable()); + gtk_widget_set_sensitive(scrollBar, true); + } else { + gtk_widget_set_sensitive(scrollBar, false); + } +} + +auto pHexEdit::updateScroll() -> void { + unsigned row = state().address / state().columns; + gtk_range_set_value(GTK_RANGE(scrollBar), row); +} + +} + +#endif diff --git a/gtk/widget/hex-edit.hpp b/gtk/widget/hex-edit.hpp new file mode 100644 index 0000000..54d835d --- /dev/null +++ b/gtk/widget/hex-edit.hpp @@ -0,0 +1,35 @@ +#if defined(Hiro_HexEdit) + +namespace hiro { + +struct pHexEdit : pWidget { + Declare(HexEdit, Widget) + + auto focused() const -> bool override; + auto setAddress(unsigned address) -> void; + auto setBackgroundColor(Color color) -> void; + auto setColumns(unsigned columns) -> void; + auto setForegroundColor(Color color) -> void; + auto setLength(unsigned length) -> 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; +}; + +} + +#endif diff --git a/gtk/widget/horizontal-scroll-bar.cpp b/gtk/widget/horizontal-scroll-bar.cpp new file mode 100644 index 0000000..30521b5 --- /dev/null +++ b/gtk/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,45 @@ +#if defined(Hiro_HorizontalScrollBar) + +namespace hiro { + +static auto HorizontalScrollBar_change(GtkRange* gtkRange, pHorizontalScrollBar* 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 pHorizontalScrollBar::construct() -> void { + gtkWidget = gtk_hscrollbar_new(0); + + setLength(state().length); + setPosition(state().position); + + g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalScrollBar_change), (gpointer)this); + + pWidget::construct(); +} + +auto pHorizontalScrollBar::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pHorizontalScrollBar::minimumSize() const -> Size { + return {0, 20}; +} + +auto pHorizontalScrollBar::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 pHorizontalScrollBar::setPosition(unsigned position) -> void { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +} + +#endif diff --git a/gtk/widget/horizontal-scroll-bar.hpp b/gtk/widget/horizontal-scroll-bar.hpp new file mode 100644 index 0000000..2cb6392 --- /dev/null +++ b/gtk/widget/horizontal-scroll-bar.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_HorizontalScrollBar) + +namespace hiro { + +struct pHorizontalScrollBar : pWidget { + Declare(HorizontalScrollBar, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; +}; + +} + +#endif diff --git a/gtk/widget/horizontal-slider.cpp b/gtk/widget/horizontal-slider.cpp new file mode 100644 index 0000000..7af5821 --- /dev/null +++ b/gtk/widget/horizontal-slider.cpp @@ -0,0 +1,44 @@ +#if defined(Hiro_HorizontalSlider) + +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); +} + +} + +#endif diff --git a/gtk/widget/horizontal-slider.hpp b/gtk/widget/horizontal-slider.hpp new file mode 100644 index 0000000..a05ba41 --- /dev/null +++ b/gtk/widget/horizontal-slider.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_HorizontalSlider) + +namespace hiro { + +struct pHorizontalSlider : pWidget { + Declare(HorizontalSlider, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; +}; + +} + +#endif diff --git a/gtk/widget/icon-view-item.cpp b/gtk/widget/icon-view-item.cpp new file mode 100644 index 0000000..48081e8 --- /dev/null +++ b/gtk/widget/icon-view-item.cpp @@ -0,0 +1,36 @@ +#if defined(Hiro_IconView) + +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; +} + +} + +#endif diff --git a/gtk/widget/icon-view-item.hpp b/gtk/widget/icon-view-item.hpp new file mode 100644 index 0000000..e406011 --- /dev/null +++ b/gtk/widget/icon-view-item.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_IconView) + +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*; +}; + +} + +#endif diff --git a/gtk/widget/icon-view.cpp b/gtk/widget/icon-view.cpp new file mode 100644 index 0000000..eb8c3ea --- /dev/null +++ b/gtk/widget/icon-view.cpp @@ -0,0 +1,228 @@ +#if defined(Hiro_IconView) + +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); + setBatchable(state().batchable); + setFlow(state().flow); + setForegroundColor(state().foregroundColor); + 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::setBatchable(bool batchable) -> void { + gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(subWidget), + batchable ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE + ); +} + +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().itemCount()) 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().itemCount()) 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().itemCount()) 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::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 = natural(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().itemCount()) continue; + state().items[position]->state.selected = true; + } + + if(!locked()) self().doChange(); +} + +} + +#endif diff --git a/gtk/widget/icon-view.hpp b/gtk/widget/icon-view.hpp new file mode 100644 index 0000000..6b48359 --- /dev/null +++ b/gtk/widget/icon-view.hpp @@ -0,0 +1,33 @@ +#if defined(Hiro_IconView) + +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 setBatchable(bool batchable) -> 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 setOrientation(Orientation orientation) -> void; + + auto _updateSelected() -> void; + + GtkWidget* subWidget = nullptr; + GtkListStore* store = nullptr; + vector currentSelection; +}; + +} + +#endif diff --git a/gtk/widget/label.cpp b/gtk/widget/label.cpp new file mode 100644 index 0000000..446a17b --- /dev/null +++ b/gtk/widget/label.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_Label) + +namespace hiro { + +auto pLabel::construct() -> void { + gtkWidget = gtk_label_new(""); + + setAlignment(state().alignment); + setText(state().text); + + pWidget::construct(); +} + +auto pLabel::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pLabel::minimumSize() const -> Size { + auto size = pFont::size(self().font(true), state().text); + return {size.width(), size.height()}; +} + +auto pLabel::setAlignment(Alignment alignment) -> void { + if(!alignment) alignment = {0.0, 0.5}; + gtk_misc_set_alignment(GTK_MISC(gtkWidget), alignment.horizontal(), alignment.vertical()); + auto justify = GTK_JUSTIFY_CENTER; + if(alignment.horizontal() < 0.333) justify = GTK_JUSTIFY_LEFT; + if(alignment.horizontal() > 0.666) justify = GTK_JUSTIFY_RIGHT; + gtk_label_set_justify(GTK_LABEL(gtkWidget), justify); +} + +auto pLabel::setText(const string& text) -> void { + gtk_label_set_text(GTK_LABEL(gtkWidget), text); +} + +} + +#endif diff --git a/gtk/widget/label.hpp b/gtk/widget/label.hpp new file mode 100644 index 0000000..91e99f6 --- /dev/null +++ b/gtk/widget/label.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_Label) + +namespace hiro { + +struct pLabel : pWidget { + Declare(Label, Widget) + + auto minimumSize() const -> Size override; + auto setAlignment(Alignment alignment) -> void; + auto setText(const string& text) -> void; +}; + +} + +#endif diff --git a/gtk/widget/line-edit.cpp b/gtk/widget/line-edit.cpp new file mode 100644 index 0000000..169c966 --- /dev/null +++ b/gtk/widget/line-edit.cpp @@ -0,0 +1,59 @@ +#if defined(Hiro_LineEdit) + +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(); +} + +} + +#endif diff --git a/gtk/widget/line-edit.hpp b/gtk/widget/line-edit.hpp new file mode 100644 index 0000000..591fe14 --- /dev/null +++ b/gtk/widget/line-edit.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_LineEdit) + +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; +}; + +} + +#endif diff --git a/gtk/widget/list-view-cell.cpp b/gtk/widget/list-view-cell.cpp new file mode 100644 index 0000000..94e22bc --- /dev/null +++ b/gtk/widget/list-view-cell.cpp @@ -0,0 +1,62 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewCell::construct() -> void { + _setState(); +} + +auto pListViewCell::destruct() -> void { +} + +auto pListViewCell::setAlignment(Alignment alignment) -> void { +} + +auto pListViewCell::setBackgroundColor(Color color) -> void { +} + +auto pListViewCell::setCheckable(bool checkable) -> void { +} + +auto pListViewCell::setChecked(bool checked) -> void { + _setState(); +} + +auto pListViewCell::setForegroundColor(Color color) -> void { +} + +auto pListViewCell::setIcon(const image& icon) -> void { + _setState(); +} + +auto pListViewCell::setText(const string& text) -> void { + _setState(); +} + +auto pListViewCell::_grandparent() -> maybe { + if(auto parent = _parent()) return parent->_parent(); + return nothing; +} + +auto pListViewCell::_parent() -> maybe { + if(auto parent = self().parentListViewItem()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pListViewCell::_setState() -> void { + if(auto parent = _parent()) { + if(auto grandparent = _grandparent()) { + grandparent->lock(); + gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 0, state().checked, -1); + gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 1, CreatePixbuf(state().icon), -1); + gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 2, state().text.data(), -1); + grandparent->unlock(); + } + } +} + +} + +#endif diff --git a/gtk/widget/list-view-cell.hpp b/gtk/widget/list-view-cell.hpp new file mode 100644 index 0000000..2fd0082 --- /dev/null +++ b/gtk/widget/list-view-cell.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewCell : pObject { + Declare(ListViewCell, Object) + + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; + auto setChecked(bool checked) -> void; + auto setForegroundColor(Color color) -> void; + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + auto _grandparent() -> maybe; + auto _parent() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/gtk/widget/list-view-column.cpp b/gtk/widget/list-view-column.cpp new file mode 100644 index 0000000..0584207 --- /dev/null +++ b/gtk/widget/list-view-column.cpp @@ -0,0 +1,138 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewColumn::construct() -> void { + if(auto grandparent = _grandparent()) { + auto handle = grandparent.data(); + 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); + + gtkCellToggle = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(gtkColumn, gtkCellToggle, false); + gtk_tree_view_column_set_attributes(gtkColumn, gtkCellToggle, "active", 3 * offset + 0, nullptr); + gtk_tree_view_column_set_cell_data_func(gtkColumn, GTK_CELL_RENDERER(gtkCellToggle), (GtkTreeCellDataFunc)ListView_dataFunc, (gpointer)handle, 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", 3 * offset + 1, nullptr); + gtk_tree_view_column_set_cell_data_func(gtkColumn, GTK_CELL_RENDERER(gtkCellIcon), (GtkTreeCellDataFunc)ListView_dataFunc, (gpointer)handle, nullptr); + + gtkCellText = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(gtkColumn, gtkCellText, true); //text must expand to cell width for horizontal alignment to work + gtk_tree_view_column_set_attributes(gtkColumn, gtkCellText, "text", 3 * offset + 2, nullptr); + gtk_tree_view_column_set_cell_data_func(gtkColumn, GTK_CELL_RENDERER(gtkCellText), (GtkTreeCellDataFunc)ListView_dataFunc, (gpointer)handle, nullptr); + + g_signal_connect(G_OBJECT(gtkColumn), "clicked", G_CALLBACK(ListView_headerActivate), (gpointer)handle); + g_signal_connect(G_OBJECT(gtkCellText), "edited", G_CALLBACK(ListView_edit), (gpointer)handle); + g_signal_connect(G_OBJECT(gtkCellToggle), "toggled", G_CALLBACK(ListView_toggle), (gpointer)handle); + + gtk_tree_view_append_column(grandparent->gtkTreeView, gtkColumn); + gtk_widget_show_all(gtkHeader); + grandparent->_createModel(); + + _setState(); + } +} + +auto pListViewColumn::destruct() -> void { + if(auto grandparent = _grandparent()) { + gtk_tree_view_remove_column(grandparent->gtkTreeView, gtkColumn); + gtkColumn = nullptr; + grandparent->_createModel(); + } +} + +auto pListViewColumn::setActive() -> void { + _setState(); +} + +auto pListViewColumn::setAlignment(Alignment alignment) -> void { +} + +auto pListViewColumn::setBackgroundColor(Color color) -> void { +} + +auto pListViewColumn::setEditable(bool editable) -> void { + g_object_set(G_OBJECT(gtkCellText), "editable", editable ? true : false, nullptr); +} + +auto pListViewColumn::setExpandable(bool expandable) -> void { + if(auto grandparent = _grandparent()) { + grandparent->resizeColumns(); + } +} + +auto pListViewColumn::setFont(const Font& font) -> void { +} + +auto pListViewColumn::setForegroundColor(Color color) -> void { +} + +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 { + _setState(); +} + +auto pListViewColumn::setSortable(bool sortable) -> void { + _setState(); +} + +auto pListViewColumn::setText(const string& text) -> void { + _setState(); +} + +auto pListViewColumn::setVisible(bool visible) -> void { + _setState(); +} + +auto pListViewColumn::setWidth(signed width) -> void { + if(auto grandparent = _grandparent()) { + grandparent->resizeColumns(); + } +} + +auto pListViewColumn::_grandparent() -> maybe { + if(auto parent = _parent()) return parent->_parent(); + return nothing; +} + +auto pListViewColumn::_parent() -> maybe { + if(auto parent = self().parentListViewHeader()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pListViewColumn::_setState() -> void { + if(auto grandparent = _grandparent()) { + gtk_tree_view_set_search_column(grandparent->gtkTreeView, 3 * self().offset() + 2); + gtk_tree_view_column_set_resizable(gtkColumn, state().resizable); + gtk_tree_view_column_set_clickable(gtkColumn, state().sortable); + gtk_label_set_text(GTK_LABEL(gtkHeaderText), state().text); + gtk_tree_view_column_set_visible(gtkColumn, self().visible()); + } +} + +} + +#endif diff --git a/gtk/widget/list-view-column.hpp b/gtk/widget/list-view-column.hpp new file mode 100644 index 0000000..1cc4b18 --- /dev/null +++ b/gtk/widget/list-view-column.hpp @@ -0,0 +1,39 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewColumn : pObject { + Declare(ListViewColumn, Object) + + auto setActive() -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setEditable(bool editable) -> void; + auto setExpandable(bool expandable) -> void; + auto setFont(const Font& font) -> void override; + auto setForegroundColor(Color color) -> void; + auto setHorizontalAlignment(double) -> 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) -> void {} + auto setVisible(bool visible) -> void override; + auto setWidth(signed width) -> void; + + auto _grandparent() -> maybe; + auto _parent() -> maybe; + auto _setState() -> void; + + GtkTreeViewColumn* gtkColumn = nullptr; + GtkWidget* gtkHeader = nullptr; + GtkWidget* gtkHeaderIcon = nullptr; + GtkWidget* gtkHeaderText = nullptr; + GtkCellRenderer* gtkCellToggle = nullptr; + GtkCellRenderer* gtkCellIcon = nullptr; + GtkCellRenderer* gtkCellText = nullptr; +}; + +} + +#endif diff --git a/gtk/widget/list-view-header.cpp b/gtk/widget/list-view-header.cpp new file mode 100644 index 0000000..569a753 --- /dev/null +++ b/gtk/widget/list-view-header.cpp @@ -0,0 +1,41 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewHeader::construct() -> void { + _setState(); +} + +auto pListViewHeader::destruct() -> void { +} + +auto pListViewHeader::append(sListViewColumn column) -> void { + _setState(); +} + +auto pListViewHeader::remove(sListViewColumn column) -> void { +} + +auto pListViewHeader::setVisible(bool visible) -> void { + _setState(); +} + +auto pListViewHeader::_parent() -> maybe { + if(auto parent = self().parentListView()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pListViewHeader::_setState() -> void { + if(auto parent = _parent()) { + gtk_tree_view_set_headers_visible(parent->gtkTreeView, self().visible()); + for(auto& column : state().columns) { + if(auto self = column->self()) self->_setState(); + } + } +} + +} + +#endif diff --git a/gtk/widget/list-view-header.hpp b/gtk/widget/list-view-header.hpp new file mode 100644 index 0000000..a46855b --- /dev/null +++ b/gtk/widget/list-view-header.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewHeader : pObject { + Declare(ListViewHeader, Object) + + auto append(sListViewColumn column) -> void; + auto remove(sListViewColumn column) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/gtk/widget/list-view-item.cpp b/gtk/widget/list-view-item.cpp new file mode 100644 index 0000000..c70aad5 --- /dev/null +++ b/gtk/widget/list-view-item.cpp @@ -0,0 +1,76 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewItem::construct() -> void { + if(auto parent = _parent()) { + parent->lock(); + gtk_list_store_append(parent->gtkListStore, >kIter); + _setState(); + parent->unlock(); + } +} + +auto pListViewItem::destruct() -> void { + if(auto parent = _parent()) { + parent->lock(); + gtk_list_store_remove(parent->gtkListStore, >kIter); + parent->_updateSelected(); + parent->unlock(); + } +} + +auto pListViewItem::append(sListViewCell cell) -> void { +} + +auto pListViewItem::remove(sListViewCell cell) -> void { +} + +auto pListViewItem::setAlignment(Alignment alignment) -> void { +} + +auto pListViewItem::setBackgroundColor(Color color) -> void { +} + +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::setForegroundColor(Color color) -> void { +} + +auto pListViewItem::setSelected(bool selected) -> void { + _setState(); +} + +auto pListViewItem::_parent() -> maybe { + if(auto parent = self().parentListView()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pListViewItem::_setState() -> void { + if(auto parent = _parent()) { + parent->lock(); + if(state().selected) { + gtk_tree_selection_select_iter(parent->gtkTreeSelection, >kIter); + } else { + gtk_tree_selection_unselect_iter(parent->gtkTreeSelection, >kIter); + } + parent->_updateSelected(); + for(auto& cell : state().cells) { + if(auto self = cell->self()) self->_setState(); + } + parent->unlock(); + } +} + +} + +#endif diff --git a/gtk/widget/list-view-item.hpp b/gtk/widget/list-view-item.hpp new file mode 100644 index 0000000..2194879 --- /dev/null +++ b/gtk/widget/list-view-item.hpp @@ -0,0 +1,24 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewItem : pObject { + Declare(ListViewItem, Object) + + auto append(sListViewCell cell) -> void; + auto remove(sListViewCell cell) -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setFocused() -> void; + auto setForegroundColor(Color color) -> void; + auto setSelected(bool selected) -> void; + + auto _parent() -> maybe; + auto _setState() -> void; + + GtkTreeIter gtkIter; +}; + +} + +#endif diff --git a/gtk/widget/list-view.cpp b/gtk/widget/list-view.cpp new file mode 100644 index 0000000..5947a37 --- /dev/null +++ b/gtk/widget/list-view.cpp @@ -0,0 +1,421 @@ +#if defined(Hiro_ListView) + +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_dataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, pListView* p) -> void { return p->_doDataFunc(column, renderer, iter); } +static auto ListView_toggle(GtkCellRendererToggle* toggle, const char* path, pListView* p) -> void { return p->_doToggle(toggle, path); } + +//gtk_tree_view_set_rules_hint(gtkTreeView, true); + +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); + setBatchable(state().batchable); + setBordered(state().bordered); + setFont(self().font(true)); + setForegroundColor(state().foregroundColor); + + 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(sListViewHeader header) -> void { +} + +auto pListView::append(sListViewItem item) -> void { +} + +auto pListView::focused() const -> bool { + return GTK_WIDGET_HAS_FOCUS(gtkTreeView); +} + +auto pListView::remove(sListViewHeader header) -> void { +} + +auto pListView::remove(sListViewItem item) -> void { +} + +auto pListView::resizeColumns() -> void { + lock(); + + if(auto& header = state().header) { + vector widths; + signed minimumWidth = 0; + signed expandable = 0; + for(auto column : range(header->columnCount())) { + signed width = _width(column); + widths.append(width); + minimumWidth += width; + if(header->column(column).expandable()) expandable++; + } + + signed maximumWidth = self().geometry().width() - 6; + if(auto scrollBar = gtk_scrolled_window_get_vscrollbar(gtkScrolledWindow)) { + if(gtk_widget_get_visible(scrollBar)) maximumWidth -= scrollBar->allocation.width; + } + + signed expandWidth = 0; + if(expandable && maximumWidth > minimumWidth) { + expandWidth = (maximumWidth - minimumWidth) / expandable; + } + + for(auto column : range(header->columnCount())) { + if(auto self = header->state.columns[column]->self()) { + signed width = widths[column]; + if(self->state().expandable) width += expandWidth; + gtk_tree_view_column_set_fixed_width(self->gtkColumn, width); + } + } + } + + unlock(); +} + +auto pListView::setAlignment(Alignment alignment) -> void { +} + +auto pListView::setBackgroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pListView::setBatchable(bool batchable) -> void { + gtk_tree_selection_set_mode(gtkTreeSelection, batchable ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE); +} + +auto pListView::setBordered(bool bordered) -> void { + gtk_tree_view_set_grid_lines(gtkTreeView, bordered ? GTK_TREE_VIEW_GRID_LINES_BOTH : GTK_TREE_VIEW_GRID_LINES_NONE); +} + +auto pListView::setFocused() -> void { + //gtk_widget_grab_focus() will select the first item if nothing is currently selected + //this behavior is undesirable. detect selection state first, and restore if required + lock(); + bool selected = gtk_tree_selection_get_selected(gtkTreeSelection, nullptr, nullptr); + gtk_widget_grab_focus(gtkWidgetChild); + if(!selected) gtk_tree_selection_unselect_all(gtkTreeSelection); + unlock(); +} + +auto pListView::setFont(const Font& font) -> void { + if(auto& header = state().header) { + if(auto self = header->self()) self->_setState(); + } +} + +auto pListView::setForegroundColor(Color color) -> void { + GdkColor gdkColor = CreateColor(color); + gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pListView::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + if(auto& header = state().header) { + for(auto& column : header->state.columns) { + if(column->state.expandable) return resizeColumns(); + } + } +} + +auto pListView::_cellWidth(unsigned _row, unsigned _column) -> unsigned { + unsigned width = 8; + if(auto item = self().item(_row)) { + if(auto cell = item->cell(_column)) { + if(cell->state.checkable) { + width += 24; + } + if(auto& icon = cell->state.icon) { + width += icon.width() + 2; + } + if(auto& text = cell->state.text) { + width += pFont::size(cell->font(true), text).width(); + } + } + } + return width; +} + +auto pListView::_columnWidth(unsigned _column) -> unsigned { + unsigned width = 8; + if(auto& header = state().header) { + if(auto column = header->column(_column)) { + if(auto& icon = column->state.icon) { + width += icon.width() + 2; + } + if(auto& text = column->state.text) { + width += pFont::size(column->font(true), text).width(); + } + } + } + return width; +} + +auto pListView::_createModel() -> void { + gtk_tree_view_set_model(gtkTreeView, nullptr); + gtkListStore = nullptr; + gtkTreeModel = nullptr; + + vector types; + if(auto& header = state().header) { + for(auto column : header->state.columns) { + if(auto self = column->self()) { + if(!self->gtkColumn) continue; //may not have been created yet; or recently destroyed + 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::_doDataFunc(GtkTreeViewColumn* gtkColumn, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void { + auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter); + auto row = natural(path); + g_free(path); + + if(auto& header = state().header) { + for(auto& column : header->state.columns) { + if(auto p = column->self()) { + if(renderer != GTK_CELL_RENDERER(p->gtkCellToggle) + && renderer != GTK_CELL_RENDERER(p->gtkCellIcon) + && renderer != GTK_CELL_RENDERER(p->gtkCellText) + ) continue; + if(auto item = self().item(row)) { + if(auto cell = item->cell(column->offset())) { + if(renderer == GTK_CELL_RENDERER(p->gtkCellToggle)) { + gtk_cell_renderer_set_visible(renderer, cell->state.checkable); + } else if(renderer == GTK_CELL_RENDERER(p->gtkCellText)) { + auto alignment = cell->alignment(true); + if(!alignment) alignment = {0.0, 0.5}; + //note: below line will center column header text; but causes strange glitches + //(specifically, windows fail to respond to the close button ... some kind of heap corruption inside GTK+) + //gtk_tree_view_column_set_alignment(gtkColumn, alignment.horizontal()); + gtk_cell_renderer_set_alignment(renderer, alignment.horizontal(), alignment.vertical()); + auto pangoAlignment = PANGO_ALIGN_CENTER; + if(alignment.horizontal() < 0.333) pangoAlignment = PANGO_ALIGN_LEFT; + if(alignment.horizontal() > 0.666) pangoAlignment = PANGO_ALIGN_RIGHT; + g_object_set(G_OBJECT(renderer), "alignment", pangoAlignment, nullptr); + auto font = pFont::create(cell->font(true)); + g_object_set(G_OBJECT(renderer), "font-desc", font, nullptr); + pango_font_description_free(font); + if(auto color = cell->foregroundColor(true)) { + auto gdkColor = CreateColor(color); + g_object_set(G_OBJECT(renderer), "foreground-gdk", &gdkColor, nullptr); + } else { + g_object_set(G_OBJECT(renderer), "foreground-set", false, nullptr); + } + } + if(auto color = cell->backgroundColor(true)) { + auto gdkColor = CreateColor(color); + g_object_set(G_OBJECT(renderer), "cell-background-gdk", &gdkColor, nullptr); + } else { + g_object_set(G_OBJECT(renderer), "cell-background-set", false, nullptr); + } + } + } + } + } + } +} + +auto pListView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void { + if(auto& header = state().header) { + for(auto& column : header->state.columns) { + if(auto delegate = column->self()) { + if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) { + auto row = natural(path); + if(auto item = self().item(row)) { + if(auto cell = item->cell(column->offset())) { + if(string{text} != cell->state.text) { + cell->setText(text); + if(!locked()) self().doEdit(cell); + } + 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) { + for(auto& item : state().items) item->setSelected(false); + 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 { + if(auto& header = state().header) { + for(auto& column : header->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(GtkCellRendererToggle* gtkCellRendererToggle, const char* path) -> void { + if(auto& header = state().header) { + for(auto& column : header->state.columns) { + if(auto delegate = column->self()) { + if(gtkCellRendererToggle == GTK_CELL_RENDERER_TOGGLE(delegate->gtkCellToggle)) { + auto row = natural(path); + if(auto item = self().item(row)) { + if(auto cell = item->cell(column->offset())) { + cell->setChecked(!cell->checked()); + if(!locked()) self().doToggle(cell); + return; + } + } + } + } + } + } +} + +//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 = natural(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().itemCount()) continue; + self().item(position)->state.selected = true; + } + + if(!locked()) self().doChange(); +} + +auto pListView::_width(unsigned column) -> unsigned { + if(auto& header = state().header) { + if(auto width = header->column(column).width()) return width; + unsigned width = 1; + if(!header->column(column).visible()) return width; + if(header->visible()) width = max(width, _columnWidth(column)); + for(auto row : range(state().items)) { + width = max(width, _cellWidth(row, column)); + } + return width; + } + return 1; +} + +} + +#endif diff --git a/gtk/widget/list-view.hpp b/gtk/widget/list-view.hpp new file mode 100644 index 0000000..1df15df --- /dev/null +++ b/gtk/widget/list-view.hpp @@ -0,0 +1,49 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListView : pWidget { + Declare(ListView, Widget) + + auto append(sListViewHeader column) -> void; + auto append(sListViewItem item) -> void; + auto focused() const -> bool override; + auto remove(sListViewHeader column) -> void; + auto remove(sListViewItem item) -> void; + auto resizeColumns() -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setBatchable(bool batchable) -> void; + auto setBordered(bool bordered) -> void; + auto setFocused() -> void override; + auto setFont(const Font& font) -> void override; + auto setForegroundColor(Color color) -> void; + auto setGeometry(Geometry geometry) -> void override; + + auto _cellWidth(unsigned row, unsigned column) -> unsigned; + auto _columnWidth(unsigned column) -> unsigned; + auto _createModel() -> void; + auto _doActivate() -> void; + auto _doChange() -> void; + auto _doContext() -> void; + auto _doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void; + auto _doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void; + auto _doEvent(GdkEventButton* event) -> signed; + auto _doHeaderActivate(GtkTreeViewColumn* column) -> void; + auto _doMouseMove() -> signed; + auto _doToggle(GtkCellRendererToggle* gtkCellRendererToggle, const char* path) -> void; + auto _updateSelected() -> void; + auto _width(unsigned column) -> unsigned; + + GtkScrolledWindow* gtkScrolledWindow = nullptr; + GtkWidget* gtkWidgetChild = nullptr; + GtkTreeView* gtkTreeView = nullptr; + GtkTreeSelection* gtkTreeSelection = nullptr; + GtkListStore* gtkListStore = nullptr; + GtkTreeModel* gtkTreeModel = nullptr; + vector currentSelection; +}; + +} + +#endif diff --git a/gtk/widget/progress-bar.cpp b/gtk/widget/progress-bar.cpp new file mode 100644 index 0000000..b291423 --- /dev/null +++ b/gtk/widget/progress-bar.cpp @@ -0,0 +1,28 @@ +#if defined(Hiro_ProgressBar) + +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); +} + +} + +#endif diff --git a/gtk/widget/progress-bar.hpp b/gtk/widget/progress-bar.hpp new file mode 100644 index 0000000..a6c23d2 --- /dev/null +++ b/gtk/widget/progress-bar.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_ProgressBar) + +namespace hiro { + +struct pProgressBar : pWidget { + Declare(ProgressBar, Widget) + + auto minimumSize() const -> Size; + auto setPosition(unsigned position) -> void; +}; + +} + +#endif diff --git a/gtk/widget/radio-button.cpp b/gtk/widget/radio-button.cpp new file mode 100644 index 0000000..53605d0 --- /dev/null +++ b/gtk/widget/radio-button.cpp @@ -0,0 +1,116 @@ +#if defined(Hiro_RadioButton) + +namespace hiro { + +static auto RadioButton_activate(GtkToggleButton*, pRadioButton* p) -> void { + if(p->groupLocked()) return; + bool wasChecked = p->state().checked; + p->self().setChecked(); + if(!wasChecked) p->self().doActivate(); +} + +auto pRadioButton::construct() -> void { + gtkWidget = gtk_toggle_button_new(); + + 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 { + for(auto& weak : self().group()->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioButton = dynamic_cast(object.data())) { + if(auto self = radioButton->self()) { + self->lock(); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->gtkWidget), radioButton->state.checked); + self->unlock(); + } + } + } + } +} + +auto pRadioButton::setGroup(sGroup group) -> void { + bool first = true; + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioButton = dynamic_cast(object.data())) { + if(auto self = radioButton->self()) { + self->lock(); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->gtkWidget), radioButton->state.checked = first); + first = false; + self->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::groupLocked() const -> bool { + if(auto group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto self = object->self()) { + if(self->locked()) return true; + } + } + } + return false; + } + return locked(); +} + +} + +#endif diff --git a/gtk/widget/radio-button.hpp b/gtk/widget/radio-button.hpp new file mode 100644 index 0000000..2be014d --- /dev/null +++ b/gtk/widget/radio-button.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_RadioButton) + +namespace hiro { + +struct pRadioButton : pWidget { + Declare(RadioButton, Widget) + + auto minimumSize() const -> Size; + auto setBordered(bool bordered) -> void; + auto setChecked() -> void; + auto setGroup(sGroup group) -> void; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + + auto groupLocked() const -> bool; +}; + +} + +#endif diff --git a/gtk/widget/radio-label.cpp b/gtk/widget/radio-label.cpp new file mode 100644 index 0000000..89d6b6c --- /dev/null +++ b/gtk/widget/radio-label.cpp @@ -0,0 +1,82 @@ +#if defined(Hiro_RadioLabel) + +namespace hiro { + +static auto RadioLabel_activate(GtkToggleButton*, pRadioLabel* p) -> void { + if(p->groupLocked()) return; + bool wasChecked = p->state().checked; + p->self().setChecked(); + if(!wasChecked) p->self().doActivate(); +} + +auto pRadioLabel::construct() -> void { + gtkWidget = gtk_radio_button_new_with_label(nullptr, ""); + gtkToggleButton = GTK_TOGGLE_BUTTON(gtkWidget); + gtkRadioButton = GTK_RADIO_BUTTON(gtkWidget); + + 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 { + lock(); + gtk_toggle_button_set_active(gtkToggleButton, true); + unlock(); +} + +auto pRadioLabel::setGroup(sGroup group) -> void { + maybe gtkRadioButton; + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioLabel = dynamic_cast(object.data())) { + if(auto self = radioLabel->self()) { + self->lock(); + gtk_radio_button_set_group(self->gtkRadioButton, nullptr); + if(!gtkRadioButton) { + gtkRadioButton = self->gtkRadioButton; + gtk_toggle_button_set_active(self->gtkToggleButton, radioLabel->state.checked = true); + } else { + gtk_radio_button_set_group(self->gtkRadioButton, gtk_radio_button_get_group(*gtkRadioButton)); + gtk_toggle_button_set_active(self->gtkToggleButton, radioLabel->state.checked = false); + } + self->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::groupLocked() const -> bool { + if(auto group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto self = object->self()) { + if(self->locked()) return true; + } + } + } + return false; + } + return locked(); +} + +} + +#endif diff --git a/gtk/widget/radio-label.hpp b/gtk/widget/radio-label.hpp new file mode 100644 index 0000000..25bb71b --- /dev/null +++ b/gtk/widget/radio-label.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_RadioLabel) + +namespace hiro { + +struct pRadioLabel : pWidget { + Declare(RadioLabel, Widget) + + auto minimumSize() const -> Size; + auto setChecked() -> void; + auto setGroup(sGroup group) -> void; + auto setText(const string& text) -> void; + + auto groupLocked() const -> bool; + + GtkToggleButton* gtkToggleButton = nullptr; + GtkRadioButton* gtkRadioButton = nullptr; +}; + +} + +#endif diff --git a/gtk/widget/source-edit.cpp b/gtk/widget/source-edit.cpp new file mode 100644 index 0000000..b1a6fd0 --- /dev/null +++ b/gtk/widget/source-edit.cpp @@ -0,0 +1,146 @@ +#if defined(Hiro_SourceEdit) + +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 offset = 0; + g_object_get(G_OBJECT(p->gtkSourceBuffer), "cursor-position", &offset, nullptr); + + if(p->state().cursor.offset() != offset) { + p->state().cursor.setOffset(offset); + 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::setCursor(Cursor cursor) -> void { + lock(); + GtkTextIter offset, length; + gtk_text_buffer_get_end_iter(gtkTextBuffer, &offset); + gtk_text_buffer_get_end_iter(gtkTextBuffer, &length); + signed end = gtk_text_iter_get_offset(&offset); + gtk_text_iter_set_offset(&offset, max(0, min(end, cursor.offset()))); + gtk_text_iter_set_offset(&length, max(0, min(end, cursor.offset() + cursor.length()))); + gtk_text_buffer_select_range(gtkTextBuffer, &offset, &length); + auto mark = gtk_text_buffer_get_mark(gtkTextBuffer, "insert"); + gtk_text_view_scroll_mark_onscreen(gtkTextView, mark); + unlock(); +} + +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; +} + +} + +#endif diff --git a/gtk/widget/source-edit.hpp b/gtk/widget/source-edit.hpp new file mode 100644 index 0000000..f892318 --- /dev/null +++ b/gtk/widget/source-edit.hpp @@ -0,0 +1,28 @@ +#if defined(Hiro_SourceEdit) + +namespace hiro { + +struct pSourceEdit : pWidget { + Declare(SourceEdit, Widget) + + auto setCursor(Cursor cursor) -> void; + auto setFocused() -> void override; + 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; +}; + +} + +#endif diff --git a/gtk/widget/tab-frame-item.cpp b/gtk/widget/tab-frame-item.cpp new file mode 100644 index 0000000..3b8f548 --- /dev/null +++ b/gtk/widget/tab-frame-item.cpp @@ -0,0 +1,56 @@ +#if defined(Hiro_TabFrame) + +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::append(sLayout layout) -> void { +} + +auto pTabFrameItem::remove(sLayout layout) -> void { +} + +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; +} + +} + +#endif diff --git a/gtk/widget/tab-frame-item.hpp b/gtk/widget/tab-frame-item.hpp new file mode 100644 index 0000000..495555b --- /dev/null +++ b/gtk/widget/tab-frame-item.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +struct pTabFrameItem : pObject { + Declare(TabFrameItem, Object) + + auto append(sLayout layout) -> void; + auto remove(sLayout layout) -> void; + 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*; +}; + +} + +#endif diff --git a/gtk/widget/tab-frame.cpp b/gtk/widget/tab-frame.cpp new file mode 100644 index 0000000..5b5e539 --- /dev/null +++ b/gtk/widget/tab-frame.cpp @@ -0,0 +1,285 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +static auto TabFrame_change(GtkNotebook* notebook, GtkWidget* page, unsigned position, pTabFrame* p) -> void { + for(auto& item : p->state().items) item->state.selected = false; + if(auto item = p->self().item(position)) item->state.selected = true; + + 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 { + unsigned position = gtk_notebook_get_current_page(notebook); + for(auto& item : p->state().items) item->state.selected = false; + if(auto item = p->self().item(position)) item->state.selected = true; + + 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); + setNavigation(state().navigation); + + 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).setBold()); + 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()); + if(item->selected()) setItemSelected(item->offset()); + _synchronizeTab(tabs.size() - 1); + setGeometry(self().geometry()); + unlock(); +} + +auto pTabFrame::container(mWidget& widget) -> GtkWidget* { + //TabFrame holds multiple TabFrameItem controls + //each TabFrameItem has its own GtkWindow; plus its own layout + //we need to recurse up from the widget to its topmost layout before the TabFrameItem + //once we know the topmost layout, we search through all TabFrameItems for a match + mObject* object = &widget; + while(object) { + if(object->parentTabFrameItem()) break; + if(auto layout = object->parentLayout()) { object = layout; continue; } + break; + } + + unsigned position = 0; + for(auto& item : state().items) { + if(item->state.layout.data() == object) 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().itemCount() - 1) displacement = -1; + //... unless there are no tabs left, in which case nothing is selected + if(self().itemCount() > 1) { + setItemSelected(item->offset() + displacement); + } + } + tabs.remove(item->offset()); + gtk_notebook_remove_page(GTK_NOTEBOOK(gtkWidget), item->offset()); + + unsigned position = gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkWidget)); + for(auto& item : state().items) item->state.selected = false; + if(auto item = self().item(position)) item->state.selected = true; + unlock(); +} + +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 Font& 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().navigation == Navigation::Top || state().navigation == Navigation::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::setNavigation(Navigation navigation) -> void { + GtkPositionType type; + switch(navigation) { default: + case Navigation::Top: type = GTK_POS_TOP; break; + case Navigation::Bottom: type = GTK_POS_BOTTOM; break; + case Navigation::Left: type = GTK_POS_LEFT; break; + case Navigation::Right: type = GTK_POS_RIGHT; break; + } + gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkWidget), type); + setGeometry(self().geometry()); +} + +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 { + for(auto& item : state().items) { + if(auto layout = item->state.layout) { + if(auto self = layout->self()) { + self->setVisible(layout->visible(true) && item->selected()); + } + } + } +} + +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& icon = item->state.icon) { + uint size = pFont::size(self().font(true), " ").height(); + auto pixbuf = CreatePixbuf(icon, true); + 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; +} + +} + +#endif diff --git a/gtk/widget/tab-frame.hpp b/gtk/widget/tab-frame.hpp new file mode 100644 index 0000000..a0cf067 --- /dev/null +++ b/gtk/widget/tab-frame.hpp @@ -0,0 +1,43 @@ +#if defined(Hiro_TabFrame) + +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 setEnabled(bool enabled) -> void override; + auto setFont(const Font& 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 setNavigation(Navigation navigation) -> 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; +}; + +} + +#endif diff --git a/gtk/widget/text-edit.cpp b/gtk/widget/text-edit.cpp new file mode 100644 index 0000000..7e6c4e3 --- /dev/null +++ b/gtk/widget/text-edit.cpp @@ -0,0 +1,112 @@ +#if defined(Hiro_TextEdit) + +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 { + signed offset = 0; + g_object_get(p->textBuffer, "cursor-position", &offset, nullptr); + + if(p->state().cursor.offset() != offset) { + p->state().cursor.setOffset(offset); + 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); + setCursor(state().cursor); + + 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::setCursor(Cursor cursor) -> void { + lock(); + GtkTextIter offset, length; + gtk_text_buffer_get_end_iter(textBuffer, &offset); + gtk_text_buffer_get_end_iter(textBuffer, &length); + signed end = gtk_text_iter_get_offset(&offset); + gtk_text_iter_set_offset(&offset, max(0, min(end, cursor.offset()))); + gtk_text_iter_set_offset(&length, max(0, min(end, cursor.offset() + cursor.length()))); + gtk_text_buffer_select_range(textBuffer, &offset, &length); + auto mark = gtk_text_buffer_get_mark(textBuffer, "insert"); + 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::setFocused() -> void { + gtk_widget_grab_focus(subWidget); +} + +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; +} + +} + +#endif diff --git a/gtk/widget/text-edit.hpp b/gtk/widget/text-edit.hpp new file mode 100644 index 0000000..4bb7e1f --- /dev/null +++ b/gtk/widget/text-edit.hpp @@ -0,0 +1,24 @@ +#if defined(Hiro_TextEdit) + +namespace hiro { + +struct pTextEdit : pWidget { + Declare(TextEdit, Widget) + + auto focused() const -> bool override; + auto setBackgroundColor(Color color) -> void; + auto setCursor(Cursor cursor) -> void; + auto setEditable(bool editable) -> void; + auto setFocused() -> void override; + 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; +}; + +} + +#endif diff --git a/gtk/widget/tree-view-item.cpp b/gtk/widget/tree-view-item.cpp new file mode 100644 index 0000000..db19987 --- /dev/null +++ b/gtk/widget/tree-view-item.cpp @@ -0,0 +1,111 @@ +#if defined(Hiro_TreeView) + +namespace hiro { + +auto pTreeViewItem::construct() -> void { + if(auto parentWidget = _parentWidget()) { + if(auto parentItem = _parentItem()) { + gtk_tree_store_append(parentWidget->gtkTreeStore, >kIter, &parentItem->gtkIter); + } else { + gtk_tree_store_append(parentWidget->gtkTreeStore, >kIter, nullptr); + } + setChecked(state().checked); + setIcon(state().icon); + setText(state().text); + } +} + +auto pTreeViewItem::destruct() -> void { + if(auto parent = _parentWidget()) { + gtk_tree_store_remove(parent->gtkTreeStore, >kIter); + } +} + +// + +auto pTreeViewItem::append(sTreeViewItem item) -> void { +} + +auto pTreeViewItem::remove(sTreeViewItem item) -> void { +} + +auto pTreeViewItem::setBackgroundColor(Color color) -> void { +} + +auto pTreeViewItem::setCheckable(bool checkable) -> void { +} + +auto pTreeViewItem::setChecked(bool checked) -> void { + if(auto parentWidget = _parentWidget()) { + gtk_tree_store_set(parentWidget->gtkTreeStore, >kIter, 0, checked, -1); + } +} + +auto pTreeViewItem::setExpanded(bool expanded) -> void { + if(auto parentWidget = _parentWidget()) { + auto path = gtk_tree_model_get_path(parentWidget->gtkTreeModel, >kIter); + if(expanded) { + gtk_tree_view_expand_row(parentWidget->gtkTreeView, path, false); + } else { + gtk_tree_view_collapse_row(parentWidget->gtkTreeView, path); + } + gtk_tree_path_free(path); + } +} + +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::setForegroundColor(Color color) -> void { +} + +auto pTreeViewItem::setIcon(const image& icon) -> void { + if(auto parentWidget = _parentWidget()) { + if(icon) { + auto pixbuf = CreatePixbuf(icon); + 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; +} + +} + +#endif diff --git a/gtk/widget/tree-view-item.hpp b/gtk/widget/tree-view-item.hpp new file mode 100644 index 0000000..7633a48 --- /dev/null +++ b/gtk/widget/tree-view-item.hpp @@ -0,0 +1,28 @@ +#if defined(Hiro_TreeView) + +namespace hiro { + +struct pTreeViewItem : pObject { + Declare(TreeViewItem, Object) + + auto append(sTreeViewItem item) -> void; + auto remove(sTreeViewItem item) -> void; + auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; + auto setChecked(bool checked) -> void; + auto setExpanded(bool expanded) -> void; + auto setFocused() -> void; + auto setForegroundColor(Color color) -> void; + auto setIcon(const image& icon) -> void; + auto setSelected() -> void; + auto setText(const string& text) -> void; + + auto _parentItem() -> pTreeViewItem*; + auto _parentWidget() -> pTreeView*; + + GtkTreeIter gtkIter; +}; + +} + +#endif diff --git a/gtk/widget/tree-view.cpp b/gtk/widget/tree-view.cpp new file mode 100644 index 0000000..44e2fa5 --- /dev/null +++ b/gtk/widget/tree-view.cpp @@ -0,0 +1,193 @@ +#if defined(Hiro_TreeView) + +namespace hiro { + +//gtk_tree_view_collapse_all(gtkTreeView); +//gtk_tree_view_expand_all(gtkTreeView); + +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_dataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, pTreeView* p) -> void { return p->_doDataFunc(column, renderer, iter); } +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_tree_view_column_set_cell_data_func(gtkTreeViewColumn, GTK_CELL_RENDERER(gtkCellToggle), (GtkTreeCellDataFunc)TreeView_dataFunc, (gpointer)this, nullptr); + + 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); + gtk_tree_view_column_set_cell_data_func(gtkTreeViewColumn, GTK_CELL_RENDERER(gtkCellPixbuf), (GtkTreeCellDataFunc)TreeView_dataFunc, (gpointer)this, 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_column_set_cell_data_func(gtkTreeViewColumn, GTK_CELL_RENDERER(gtkCellText), (GtkTreeCellDataFunc)TreeView_dataFunc, (gpointer)this, 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 { +} + +auto pTreeView::remove(sTreeViewItem item) -> void { +} + +auto pTreeView::setBackgroundColor(Color color) -> void { + auto gdkColor = CreateColor(color); + gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); +} + +auto pTreeView::setFocused() -> void { + //gtk_widget_grab_focus() will select the first item if nothing is currently selected + //this behavior is undesirable. detect selection state first, and restore if required + lock(); + bool selected = gtk_tree_selection_get_selected(gtkTreeSelection, nullptr, nullptr); + gtk_widget_grab_focus(gtkWidgetChild); + if(!selected) gtk_tree_selection_unselect_all(gtkTreeSelection); + unlock(); +} + +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::_doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void { + auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter); + auto parts = string{path}.split(":"); + g_free(path); + + auto item = self().item(parts.takeFirst().natural()); + if(!item) return; + while(parts) { + item = item.item(parts.takeFirst().natural()); + if(!item) return; + } + + if(renderer == GTK_CELL_RENDERER(gtkCellToggle)) { + gtk_cell_renderer_set_visible(renderer, item->state.checkable); + } else if(renderer == GTK_CELL_RENDERER(gtkCellPixbuf)) { + gtk_cell_renderer_set_visible(renderer, (bool)item->state.icon); + } else if(renderer == GTK_CELL_RENDERER(gtkCellText)) { + auto font = pFont::create(item->font(true)); + g_object_set(G_OBJECT(renderer), "font-desc", font, nullptr); + pango_font_description_free(font); + if(auto color = item->foregroundColor(true)) { + auto gdkColor = CreateColor(color); + g_object_set(G_OBJECT(renderer), "foreground-gdk", &gdkColor, nullptr); + } else { + g_object_set(G_OBJECT(renderer), "foreground-set", false, nullptr); + } + } + if(auto color = item->backgroundColor(true)) { + auto gdkColor = CreateColor(color); + g_object_set(G_OBJECT(renderer), "cell-background-gdk", &gdkColor, nullptr); + } else { + g_object_set(G_OBJECT(renderer), "cell-background-set", false, nullptr); + } +} + +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(); + } +} + +} + +#endif diff --git a/gtk/widget/tree-view.hpp b/gtk/widget/tree-view.hpp new file mode 100644 index 0000000..c9412f9 --- /dev/null +++ b/gtk/widget/tree-view.hpp @@ -0,0 +1,34 @@ +#if defined(Hiro_TreeView) + +namespace hiro { + +struct pTreeView : pWidget { + Declare(TreeView, Widget) + + auto append(sTreeViewItem item) -> void; + auto remove(sTreeViewItem item) -> void; + auto setBackgroundColor(Color color) -> void; + auto setFocused() -> void override; + auto setForegroundColor(Color color) -> void; + + auto _activatePath(GtkTreePath* gtkPath) -> void; + auto _buttonEvent(GdkEventButton* gdkEvent) -> signed; + auto _doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void; + 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; +}; + +} + +#endif diff --git a/gtk/widget/vertical-scroll-bar.cpp b/gtk/widget/vertical-scroll-bar.cpp new file mode 100644 index 0000000..45848df --- /dev/null +++ b/gtk/widget/vertical-scroll-bar.cpp @@ -0,0 +1,45 @@ +#if defined(Hiro_VerticalScrollBar) + +namespace hiro { + +static auto VerticalScrollBar_change(GtkRange* gtkRange, pVerticalScrollBar* 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 pVerticalScrollBar::construct() -> void { + gtkWidget = gtk_vscrollbar_new(0); + + setLength(state().length); + setPosition(state().position); + + g_signal_connect(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalScrollBar_change), (gpointer)this); + + pWidget::construct(); +} + +auto pVerticalScrollBar::destruct() -> void { + gtk_widget_destroy(gtkWidget); +} + +auto pVerticalScrollBar::minimumSize() const -> Size { + return {20, 0}; +} + +auto pVerticalScrollBar::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 pVerticalScrollBar::setPosition(unsigned position) -> void { + gtk_range_set_value(GTK_RANGE(gtkWidget), position); +} + +} + +#endif diff --git a/gtk/widget/vertical-scroll-bar.hpp b/gtk/widget/vertical-scroll-bar.hpp new file mode 100644 index 0000000..37db953 --- /dev/null +++ b/gtk/widget/vertical-scroll-bar.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_VerticalScrollBar) + +namespace hiro { + +struct pVerticalScrollBar : pWidget { + Declare(VerticalScrollBar, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; +}; + +} + +#endif diff --git a/gtk/widget/vertical-slider.cpp b/gtk/widget/vertical-slider.cpp new file mode 100644 index 0000000..8413096 --- /dev/null +++ b/gtk/widget/vertical-slider.cpp @@ -0,0 +1,44 @@ +#if defined(Hiro_VerticalSlider) + +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); +} + +} + +#endif diff --git a/gtk/widget/vertical-slider.hpp b/gtk/widget/vertical-slider.hpp new file mode 100644 index 0000000..d970aaa --- /dev/null +++ b/gtk/widget/vertical-slider.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_VerticalSlider) + +namespace hiro { + +struct pVerticalSlider : pWidget { + Declare(VerticalSlider, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; +}; + +} + +#endif diff --git a/gtk/widget/viewport.cpp b/gtk/widget/viewport.cpp new file mode 100644 index 0000000..8d52e90 --- /dev/null +++ b/gtk/widget/viewport.cpp @@ -0,0 +1,88 @@ +#if defined(Hiro_Viewport) + +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 { + #if defined(DISPLAY_WINDOWS) + return (uintptr_t)GDK_WINDOW_HWND(gtk_widget_get_window(gtkWidget)); + #endif + + #if defined(DISPLAY_XORG) + return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget)); + #endif +} + +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); + } +} + +} + +#endif diff --git a/gtk/widget/viewport.hpp b/gtk/widget/viewport.hpp new file mode 100644 index 0000000..ed0b17f --- /dev/null +++ b/gtk/widget/viewport.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_Viewport) + +namespace hiro { + +struct pViewport : pWidget { + Declare(Viewport, Widget) + + auto handle() const -> uintptr_t; + auto setDroppable(bool droppable) -> void; +}; + +} + +#endif diff --git a/gtk/widget/widget.cpp b/gtk/widget/widget.cpp new file mode 100644 index 0000000..8d7a783 --- /dev/null +++ b/gtk/widget/widget.cpp @@ -0,0 +1,55 @@ +#if defined(Hiro_Widget) + +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 Font& 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); +} + +} + +#endif diff --git a/gtk/widget/widget.hpp b/gtk/widget/widget.hpp new file mode 100644 index 0000000..831f000 --- /dev/null +++ b/gtk/widget/widget.hpp @@ -0,0 +1,22 @@ +#if defined(Hiro_Widget) + +namespace hiro { + +struct pWidget : pSizable { + Declare(Widget, Sizable) + + virtual auto container(mWidget& widget) -> GtkWidget*; + auto focused() const -> bool override; + auto setEnabled(bool enabled) -> void override; + auto setFocused() -> void override; + auto setFont(const Font& font) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setVisible(bool visible) -> void override; + + GtkWidget* gtkWidget = nullptr; + GtkWidget* gtkParent = nullptr; +}; + +} + +#endif diff --git a/gtk/window.cpp b/gtk/window.cpp new file mode 100644 index 0000000..ef816ba --- /dev/null +++ b/gtk/window.cpp @@ -0,0 +1,422 @@ +#if defined(Hiro_Window) + +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.setPosition({geometry.x(), 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; + + if(!p->state().fullScreen) { + p->state().geometry.setSize({allocation->width, 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 { + gtk_widget_destroy(widget); +} + +auto pWindow::append(sLayout layout) -> void { +} + +auto pWindow::append(sMenuBar menuBar) -> void { + _setMenuEnabled(menuBar->enabled(true)); + _setMenuFont(menuBar->font(true)); + _setMenuVisible(menuBar->visible(true)); +} + +auto pWindow::append(sStatusBar 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(sLayout layout) -> void { +} + +auto pWindow::remove(sMenuBar menuBar) -> void { + _setMenuVisible(false); +} + +auto pWindow::remove(sStatusBar 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(auto self = menuBar->self()) self->setEnabled(menuBar->enabled(true)); + } + + if(auto& statusBar = state().statusBar) { + if(auto self = statusBar->self()) self->setEnabled(statusBar->enabled(true)); + } + + if(auto& layout = state().layout) { + if(auto self = layout->self()) self->setEnabled(layout->enabled(true)); + } +} + +auto pWindow::setFocused() -> void { + gtk_window_present(GTK_WINDOW(widget)); +} + +auto pWindow::setFullScreen(bool fullScreen) -> void { + if(fullScreen) { + windowedGeometry = state().geometry; + gtk_window_fullscreen(GTK_WINDOW(widget)); + state().geometry = Monitor::geometry(Monitor::primary()); + } else { + gtk_window_unfullscreen(GTK_WINDOW(widget)); + state().geometry = windowedGeometry; + } +} + +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(!Application::state.quit && state().modal) { + if(Application::state.onMain) { + Application::doMain(); + } else { + usleep(20 * 1000); + } + Application::processEvents(); + } + 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& layout = state().layout) { + if(layout->self()) layout->self()->setVisible(layout->visible(true)); + } + + if(auto& statusBar = state().statusBar) { + if(statusBar->self()) statusBar->self()->setVisible(statusBar->visible(true)); + } + + //GTK+ returns invalid widget sizes below without this call + Application::processEvents(); + + 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) { + layout->setGeometry(self().geometry().setPosition(0, 0)); + } +} + +auto pWindow::_append(mWidget& widget) -> void { + if(!widget.self()) return; + if(auto parent = widget.parentWidget(true)) { + if(auto instance = parent->self()) widget.self()->gtkParent = instance->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 + image icon(filename); + icon.scale(min(256u, icon.width()), min(256u, icon.height()), true); + auto 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 Font& 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 Font& 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; +} + +} + +#endif diff --git a/gtk/window.hpp b/gtk/window.hpp new file mode 100644 index 0000000..ac6fc84 --- /dev/null +++ b/gtk/window.hpp @@ -0,0 +1,53 @@ +#if defined(Hiro_Window) + +namespace hiro { + +struct pWindow : pObject { + Declare(Window, Object) + + auto append(sLayout layout) -> void; + auto append(sMenuBar menuBar) -> void; + auto append(sStatusBar statusBar) -> void; + auto focused() const -> bool override; + auto frameMargin() const -> Geometry; + auto remove(sLayout layout) -> void; + auto remove(sMenuBar menuBar) -> void; + auto remove(sStatusBar 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 Font& font) -> void; + auto _setMenuVisible(bool visible) -> void; + auto _setStatusEnabled(bool enabled) -> void; + auto _setStatusFont(const Font& font) -> void; + auto _setStatusText(const string& text) -> void; + auto _setStatusVisible(bool visible) -> void; + auto _statusHeight() const -> signed; + + GtkWidget* widget = nullptr; + GtkWidget* menuContainer = nullptr; + GtkWidget* formContainer = nullptr; + GtkWidget* statusContainer = nullptr; + GtkWidget* gtkMenu = nullptr; + GtkWidget* gtkStatus = nullptr; + GtkAllocation lastAllocation = {0}; + bool onSizePending = false; + Geometry windowedGeometry{128, 128, 256, 256}; +}; + +} + +#endif diff --git a/hiro.cpp b/hiro.cpp new file mode 100644 index 0000000..9c4a141 --- /dev/null +++ b/hiro.cpp @@ -0,0 +1,8 @@ +#ifndef HIRO_CPP +#define HIRO_CPP + +#include "components.hpp" +#include "core/core.cpp" +#include "extension/extension.cpp" + +#endif diff --git a/hiro.hpp b/hiro.hpp new file mode 100644 index 0000000..e9be057 --- /dev/null +++ b/hiro.hpp @@ -0,0 +1,21 @@ +#pragma once + +/* 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 + */ + +#include "components.hpp" +#include "core/core.hpp" +#include "extension/extension.hpp" + +#undef DeclareShared +#undef DeclareSharedObject +#undef DeclareSharedAction +#undef DeclareSharedSizable +#undef DeclareSharedLayout +#undef DeclareSharedWidget diff --git a/platform/windows/keyboard.hpp b/platform/windows/keyboard.hpp new file mode 100644 index 0000000..88b914a --- /dev/null +++ b/platform/windows/keyboard.hpp @@ -0,0 +1,119 @@ +map("Escape", VK_ESCAPE); +map("F1", VK_F1); +map("F2", VK_F2); +map("F3", VK_F3); +map("F4", VK_F4); +map("F5", VK_F5); +map("F6", VK_F6); +map("F7", VK_F7); +map("F8", VK_F8); +map("F9", VK_F9); +map("F10", VK_F10); +map("F11", VK_F11); +map("F12", VK_F12); + +map("PrintScreen", VK_SNAPSHOT); +map("ScrollLock", VK_SCROLL); +map("Pause", VK_PAUSE); + +map("Insert", VK_INSERT); +map("Delete", VK_DELETE); +map("Home", VK_HOME); +map("End", VK_END); +map("PageUp", VK_PRIOR); +map("PageDown", VK_NEXT); + +map("Up", VK_UP); +map("Down", VK_DOWN); +map("Left", VK_LEFT); +map("Right", VK_RIGHT); + +map("Grave", VK_OEM_3); +map("1", '1'); +map("2", '2'); +map("3", '3'); +map("4", '4'); +map("5", '5'); +map("6", '6'); +map("7", '7'); +map("8", '8'); +map("9", '9'); +map("0", '0'); +map("Dash", VK_OEM_MINUS); +map("Equal", VK_OEM_PLUS); +map("Backspace", VK_BACK); + +map("Tab", VK_TAB); +map("CapsLock", VK_CAPITAL); +map("LeftEnter", VK_RETURN); +map("LeftShift", VK_LSHIFT); +map("RightShift", VK_RSHIFT); +map("LeftControl", VK_LCONTROL); +map("RightControl", VK_RCONTROL); +map("LeftAlt", VK_LMENU); +map("RightAlt", VK_RMENU); +map("LeftSuper", VK_LWIN); +map("RightSuper", VK_RWIN); +map("Menu", VK_APPS); +map("Space", VK_SPACE); + +map("OpenBracket", VK_OEM_4); +map("CloseBracket", VK_OEM_6); +map("Backslash", VK_OEM_5); +map("Semicolon", VK_OEM_1); +map("Apostrophe", VK_OEM_7); +map("Comma", VK_OEM_COMMA); +map("Period", VK_OEM_PERIOD); +map("Slash", VK_OEM_2); + +map("A", 'A'); +map("B", 'B'); +map("C", 'C'); +map("D", 'D'); +map("E", 'E'); +map("F", 'F'); +map("G", 'G'); +map("H", 'H'); +map("I", 'I'); +map("J", 'J'); +map("K", 'K'); +map("L", 'L'); +map("M", 'M'); +map("N", 'N'); +map("O", 'O'); +map("P", 'P'); +map("Q", 'Q'); +map("R", 'R'); +map("S", 'S'); +map("T", 'T'); +map("U", 'U'); +map("V", 'V'); +map("W", 'W'); +map("X", 'X'); +map("Y", 'Y'); +map("Z", 'Z'); + +map("NumLock", VK_NUMLOCK); +map("Divide", VK_DIVIDE); +map("Multiply", VK_MULTIPLY); +map("Subtract", VK_SUBTRACT); +map("Add", VK_ADD); +//map("RightEnter", ...); +map("Point", VK_DECIMAL); + +map("One", VK_NUMPAD1); +map("Two", VK_NUMPAD2); +map("Three", VK_NUMPAD3); +map("Four", VK_NUMPAD4); +map("Five", VK_NUMPAD5); +map("Six", VK_NUMPAD6); +map("Seven", VK_NUMPAD7); +map("Eight", VK_NUMPAD8); +map("Nine", VK_NUMPAD9); +map("Zero", VK_NUMPAD0); + +map("Shift", VK_LSHIFT, VK_RSHIFT); +map("Control", VK_LCONTROL, VK_RCONTROL); +map("Alt", VK_LMENU, VK_RMENU); +map("Super", VK_LWIN, VK_RWIN); +map("Enter", VK_RETURN); diff --git a/platform/xorg/keyboard.hpp b/platform/xorg/keyboard.hpp new file mode 100644 index 0000000..3a0fb67 --- /dev/null +++ b/platform/xorg/keyboard.hpp @@ -0,0 +1,119 @@ +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); diff --git a/qt/action/action.cpp b/qt/action/action.cpp new file mode 100644 index 0000000..37b2762 --- /dev/null +++ b/qt/action/action.cpp @@ -0,0 +1,49 @@ +#if defined(Hiro_Action) + +namespace hiro { + +auto pAction::construct() -> void { +} + +auto pAction::destruct() -> void { +} + +auto pAction::setEnabled(bool enabled) -> void { + _setState(); +} + +auto pAction::setFont(const Font& font) -> void { + _setState(); +} + +auto pAction::setVisible(bool visible) -> void { + _setState(); +} + +auto pAction::_parentMenu() -> maybe { + if(auto parent = self().parentMenu()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pAction::_parentMenuBar() -> maybe { + if(auto parent = self().parentMenuBar()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pAction::_parentPopupMenu() -> maybe { + if(auto parent = self().parentPopupMenu()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pAction::_setState() -> void { +} + +} + +#endif diff --git a/qt/action/action.hpp b/qt/action/action.hpp new file mode 100644 index 0000000..584d4a8 --- /dev/null +++ b/qt/action/action.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_Action) + +namespace hiro { + +struct pAction : pObject { + Declare(Action, Object) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; + + auto _parentMenu() -> maybe; + auto _parentMenuBar() -> maybe; + auto _parentPopupMenu() -> maybe; + virtual auto _setState() -> void; +}; + +} + +#endif diff --git a/qt/action/menu-check-item.cpp b/qt/action/menu-check-item.cpp new file mode 100644 index 0000000..98a39d7 --- /dev/null +++ b/qt/action/menu-check-item.cpp @@ -0,0 +1,46 @@ +#if defined(Hiro_MenuCheckItem) + +namespace hiro { + +auto pMenuCheckItem::construct() -> void { + qtMenuCheckItem = new QtMenuCheckItem(*this); + qtMenuCheckItem->setCheckable(true); + qtMenuCheckItem->connect(qtMenuCheckItem, SIGNAL(triggered()), SLOT(onToggle())); + + if(auto parent = _parentMenu()) { + parent->qtMenu->addAction(qtMenuCheckItem); + } + + if(auto parent = _parentPopupMenu()) { + parent->qtPopupMenu->addAction(qtMenuCheckItem); + } + + _setState(); +} + +auto pMenuCheckItem::destruct() -> void { + delete qtMenuCheckItem; + qtMenuCheckItem = nullptr; +} + +auto pMenuCheckItem::setChecked(bool checked) -> void { + _setState(); +} + +auto pMenuCheckItem::setText(const string& text) -> void { + _setState(); +} + +auto pMenuCheckItem::_setState() -> void { + qtMenuCheckItem->setChecked(state().checked); + qtMenuCheckItem->setText(QString::fromUtf8(state().text)); +} + +auto QtMenuCheckItem::onToggle() -> void { + p.state().checked = isChecked(); + p.self().doToggle(); +} + +} + +#endif diff --git a/qt/action/menu-check-item.hpp b/qt/action/menu-check-item.hpp new file mode 100644 index 0000000..649dadb --- /dev/null +++ b/qt/action/menu-check-item.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_MenuCheckItem) + +namespace hiro { + +struct pMenuCheckItem : pAction { + Declare(MenuCheckItem, Action) + + auto setChecked(bool checked) -> void; + auto setText(const string& text) -> void; + + auto _setState() -> void override; + + QtMenuCheckItem* qtMenuCheckItem = nullptr; +}; + +} + +#endif diff --git a/qt/action/menu-item.cpp b/qt/action/menu-item.cpp new file mode 100644 index 0000000..000cdce --- /dev/null +++ b/qt/action/menu-item.cpp @@ -0,0 +1,44 @@ +#if defined(Hiro_MenuItem) + +namespace hiro { + +auto pMenuItem::construct() -> void { + qtMenuItem = new QtMenuItem(*this); + qtMenuItem->connect(qtMenuItem, SIGNAL(triggered()), SLOT(onActivate())); + + if(auto parent = _parentMenu()) { + parent->qtMenu->addAction(qtMenuItem); + } + + if(auto parent = _parentPopupMenu()) { + parent->qtPopupMenu->addAction(qtMenuItem); + } + + _setState(); +} + +auto pMenuItem::destruct() -> void { + delete qtMenuItem; + qtMenuItem = nullptr; +} + +auto pMenuItem::setIcon(const image& icon) -> void { + _setState(); +} + +auto pMenuItem::setText(const string& text) -> void { + _setState(); +} + +auto pMenuItem::_setState() -> void { + qtMenuItem->setIcon(CreateIcon(state().icon)); + qtMenuItem->setText(QString::fromUtf8(state().text)); +} + +auto QtMenuItem::onActivate() -> void { + p.self().doActivate(); +} + +} + +#endif diff --git a/qt/action/menu-item.hpp b/qt/action/menu-item.hpp new file mode 100644 index 0000000..35d815f --- /dev/null +++ b/qt/action/menu-item.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_MenuItem) + +namespace hiro { + +struct pMenuItem : pAction { + Declare(MenuItem, Action) + + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + auto _setState() -> void override; + + QtMenuItem* qtMenuItem = nullptr; +}; + +} + +#endif diff --git a/qt/action/menu-radio-item.cpp b/qt/action/menu-radio-item.cpp new file mode 100644 index 0000000..a8d1dcb --- /dev/null +++ b/qt/action/menu-radio-item.cpp @@ -0,0 +1,78 @@ +#if defined(Hiro_MenuRadioItem) + +namespace hiro { + +auto pMenuRadioItem::construct() -> void { + qtMenuRadioItem = new QtMenuRadioItem(*this); + qtActionGroup = new QActionGroup(nullptr); + qtMenuRadioItem->setCheckable(true); + qtMenuRadioItem->setActionGroup(qtActionGroup); + qtMenuRadioItem->setChecked(true); + qtMenuRadioItem->connect(qtMenuRadioItem, SIGNAL(triggered()), SLOT(onActivate())); + + if(auto parent = _parentMenu()) { + parent->qtMenu->addAction(qtMenuRadioItem); + } + + if(auto parent = _parentPopupMenu()) { + parent->qtPopupMenu->addAction(qtMenuRadioItem); + } + + setGroup(state().group); + _setState(); +} + +auto pMenuRadioItem::destruct() -> void { + delete qtMenuRadioItem; + delete qtActionGroup; + qtMenuRadioItem = nullptr; + qtActionGroup = nullptr; +} + +auto pMenuRadioItem::setChecked() -> void { + _setState(); +} + +auto pMenuRadioItem::setGroup(sGroup group) -> void { + bool first = true; + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto menuRadioItem = dynamic_cast(object.data())) { + if(auto self = menuRadioItem->self()) { + self->qtMenuRadioItem->setChecked(menuRadioItem->state.checked = first); + first = false; + } + } + } + } + } +} + +auto pMenuRadioItem::setText(const string& text) -> void { + _setState(); +} + +auto pMenuRadioItem::_setState() -> void { + if(auto& group = state().group) { + if(auto object = group->object(0)) { + if(auto menuRadioItem = dynamic_cast(object.data())) { + if(auto self = menuRadioItem->self()) { + qtMenuRadioItem->setActionGroup(self->qtActionGroup); + } + } + } + } + qtMenuRadioItem->setChecked(state().checked); + qtMenuRadioItem->setText(QString::fromUtf8(state().text)); +} + +auto QtMenuRadioItem::onActivate() -> void { + if(p.state().checked) return; + p.self().setChecked(); + p.self().doActivate(); +} + +} + +#endif diff --git a/qt/action/menu-radio-item.hpp b/qt/action/menu-radio-item.hpp new file mode 100644 index 0000000..58af841 --- /dev/null +++ b/qt/action/menu-radio-item.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_MenuRadioItem) + +namespace hiro { + +struct pMenuRadioItem : pAction { + Declare(MenuRadioItem, Action) + + auto setChecked() -> void; + auto setGroup(sGroup group) -> void; + auto setText(const string& text) -> void; + + auto _setState() -> void override; + + QtMenuRadioItem* qtMenuRadioItem = nullptr; + QActionGroup* qtActionGroup = nullptr; +}; + +} + +#endif diff --git a/qt/action/menu-separator.cpp b/qt/action/menu-separator.cpp new file mode 100644 index 0000000..099e942 --- /dev/null +++ b/qt/action/menu-separator.cpp @@ -0,0 +1,25 @@ +#if defined(Hiro_MenuSeparator) + +namespace hiro { + +auto pMenuSeparator::construct() -> void { + qtMenuSeparator = new QAction(nullptr); + qtMenuSeparator->setSeparator(true); + + if(auto parent = _parentMenu()) { + parent->qtMenu->addAction(qtMenuSeparator); + } + + if(auto parent = _parentPopupMenu()) { + parent->qtPopupMenu->addAction(qtMenuSeparator); + } +} + +auto pMenuSeparator::destruct() -> void { + delete qtMenuSeparator; + qtMenuSeparator = nullptr; +} + +} + +#endif diff --git a/qt/action/menu-separator.hpp b/qt/action/menu-separator.hpp new file mode 100644 index 0000000..afcb1ef --- /dev/null +++ b/qt/action/menu-separator.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_MenuSeparator) + +namespace hiro { + +struct pMenuSeparator : pAction { + Declare(MenuSeparator, Action) + + QAction* qtMenuSeparator = nullptr; +}; + +} + +#endif diff --git a/qt/action/menu.cpp b/qt/action/menu.cpp new file mode 100644 index 0000000..001444b --- /dev/null +++ b/qt/action/menu.cpp @@ -0,0 +1,58 @@ +#if defined(Hiro_Menu) + +namespace hiro { + +auto pMenu::construct() -> void { + qtMenu = new QMenu; + + if(auto parent = _parentMenu()) { + parent->qtMenu->addMenu(qtMenu); + } + + if(auto parent = _parentMenuBar()) { + if(auto window = parent->_parent()) { + window->qtMenuBar->addMenu(qtMenu); + } + } + + if(auto parent = _parentPopupMenu()) { + parent->qtPopupMenu->addMenu(qtMenu); + } + + _setState(); +} + +auto pMenu::destruct() -> void { + delete qtMenu; + qtMenu = nullptr; +} + +auto pMenu::append(sAction action) -> void { +} + +auto pMenu::remove(sAction action) -> void { +} + +auto pMenu::setIcon(const image& icon) -> void { + _setState(); +} + +auto pMenu::setText(const string& text) -> void { + _setState(); +} + +auto pMenu::_setState() -> void { + qtMenu->setEnabled(self().enabled()); + qtMenu->setFont(pFont::create(self().font(true))); + qtMenu->setIcon(CreateIcon(state().icon)); + qtMenu->setTitle(QString::fromUtf8(state().text)); + qtMenu->menuAction()->setVisible(self().visible()); + + for(auto& action : state().actions) { + if(auto self = action->self()) self->setFont(action->font(true)); + } +} + +} + +#endif diff --git a/qt/action/menu.hpp b/qt/action/menu.hpp new file mode 100644 index 0000000..f09ca43 --- /dev/null +++ b/qt/action/menu.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_Menu) + +namespace hiro { + +struct pMenu : public pAction { + Declare(Menu, Action) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + auto _setState() -> void override; + + QMenu* qtMenu = nullptr; +}; + +} + +#endif diff --git a/qt/application.cpp b/qt/application.cpp new file mode 100644 index 0000000..fc09378 --- /dev/null +++ b/qt/application.cpp @@ -0,0 +1,59 @@ +#if defined(Hiro_Application) + +namespace hiro { + +XlibDisplay* pApplication::display = nullptr; + +auto pApplication::run() -> void { + if(Application::state.onMain) { + while(!Application::state.quit) { + Application::doMain(); + processEvents(); + } + } else { + QApplication::exec(); + } +} + +auto pApplication::pendingEvents() -> bool { + return QApplication::hasPendingEvents(); +} + +auto pApplication::processEvents() -> void { + while(pendingEvents()) QApplication::processEvents(); +} + +auto pApplication::quit() -> void { + QApplication::quit(); + qtApplication = nullptr; //note: deleting QApplication will crash libQtGui +} + +//this is sadly necessary for things like determining window frame geometry +//obviously, it is used as sparingly as possible +auto pApplication::syncX() -> void { + for(auto n : range(8)) { + QApplication::syncX(); + Application::processEvents(); + usleep(2000); + } +} + +auto pApplication::initialize() -> void { + display = XOpenDisplay(0); + + settings = new Settings; + settings->load(); + + static int argc = 1; + static char* argv[] = {new char[8], nullptr}; + strcpy(argv[0], "hiro"); + char** argvp = argv; + + qtApplication = new QApplication(argc, argvp); + + pKeyboard::initialize(); +} + +} + +#endif diff --git a/qt/application.hpp b/qt/application.hpp new file mode 100644 index 0000000..3789df7 --- /dev/null +++ b/qt/application.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_Application) + +namespace hiro { + +struct pApplication { + static auto run() -> void; + static auto pendingEvents() -> bool; + static auto processEvents() -> void; + static auto quit() -> void; + + static auto initialize() -> void; + static auto syncX() -> void; + + static XlibDisplay* display; +}; + +static QApplication* qtApplication = nullptr; + +} + +#endif diff --git a/qt/browser-window.cpp b/qt/browser-window.cpp new file mode 100644 index 0000000..6232982 --- /dev/null +++ b/qt/browser-window.cpp @@ -0,0 +1,64 @@ +#if defined(Hiro_BrowserWindow) + +namespace hiro { + +auto pBrowserWindow::directory(BrowserWindow::State& state) -> string { +/* + QString directory = QFileDialog::getExistingDirectory( + state.parent ? state.parent->p.qtWindow : nullptr, + state.title ? state.title : "Select Directory", + QString::fromUtf8(state.path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks + ); + string name = directory.toUtf8().constData(); + if(name && name.endsWith("/") == false) name.append("/"); + return name; +*/ +} + +auto pBrowserWindow::open(BrowserWindow::State& state) -> string { +/* + string filters = state.filters.merge(";;"); + + //convert filter list from phoenix to Qt format, example: + //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" + signed parentheses = 0; + for(auto& n : filters) { + if(n == '(') parentheses++; + if(n == ')') parentheses--; + if(n == ',' && parentheses) n = ' '; + } + + QString filename = QFileDialog::getOpenFileName( + state.parent ? state.parent->p.qtWindow : nullptr, + state.title ? state.title : "Open File", + QString::fromUtf8(state.path), QString::fromUtf8(filters) + ); + return filename.toUtf8().constData(); +*/ +} + +auto pBrowserWindow::save(BrowserWindow::State& state) -> string { +/* + string filters = state.filters.merge(";;"); + + //convert filter list from phoenix to Qt format, example: + //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" + signed parentheses = 0; + for(auto& n : filters) { + if(n == '(') parentheses++; + if(n == ')') parentheses--; + if(n == ',' && parentheses) n = ' '; + } + + QString filename = QFileDialog::getSaveFileName( + state.parent ? state.parent->p.qtWindow : nullptr, + state.title ? state.title : "Save File", + QString::fromUtf8(state.path), QString::fromUtf8(filters) + ); + return filename.toUtf8().constData(); +*/ +} + +} + +#endif diff --git a/qt/browser-window.hpp b/qt/browser-window.hpp new file mode 100644 index 0000000..80e561b --- /dev/null +++ b/qt/browser-window.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_BrowserWindow) + +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; +}; + +} + +#endif diff --git a/qt/desktop.cpp b/qt/desktop.cpp new file mode 100644 index 0000000..8cc8362 --- /dev/null +++ b/qt/desktop.cpp @@ -0,0 +1,17 @@ +#if defined(Hiro_Desktop) + +namespace hiro { + +auto pDesktop::size() -> Size { + QRect rect = QApplication::desktop()->screenGeometry(); + return {rect.width(), rect.height()}; +} + +auto pDesktop::workspace() -> Geometry { + QRect rect = QApplication::desktop()->availableGeometry(); + return {rect.x(), rect.y(), rect.width(), rect.height()}; +} + +} + +#endif diff --git a/qt/desktop.hpp b/qt/desktop.hpp new file mode 100644 index 0000000..2c179b6 --- /dev/null +++ b/qt/desktop.hpp @@ -0,0 +1,12 @@ +#if defined(Hiro_Desktop) + +namespace hiro { + +struct pDesktop { + static auto size() -> Size; + static auto workspace() -> Geometry; +}; + +} + +#endif diff --git a/qt/font.cpp b/qt/font.cpp new file mode 100644 index 0000000..62667f0 --- /dev/null +++ b/qt/font.cpp @@ -0,0 +1,37 @@ +#if defined(Hiro_Font) + +namespace hiro { + +auto pFont::size(const Font& font, const string& text) -> Size { + return pFont::size(pFont::create(font), text); +} + +auto pFont::size(const QFont& qtFont, const string& text) -> Size { + QFontMetrics metrics(qtFont); + signed maxWidth = 0; + auto lines = text.split("\n"); + for(auto& line : lines) { + maxWidth = max(maxWidth, metrics.width(QString::fromUtf8(line))); + } + return {maxWidth, metrics.height() * (signed)lines.size()}; +} + +auto pFont::family(const string& family) -> QString { + if(family == Font::Sans ) return "Sans"; + if(family == Font::Serif) return "Serif"; + if(family == Font::Mono ) return "Liberation Mono"; + return family ? QString::fromUtf8(family) : "Sans"; +} + +auto pFont::create(const Font& font) -> QFont { + QFont qtFont; + qtFont.setFamily(family(font.family())); + qtFont.setPointSize(font.size() ? font.size() : 8); + qtFont.setBold(font.bold()); + qtFont.setItalic(font.italic()); + return qtFont; +} + +} + +#endif diff --git a/qt/font.hpp b/qt/font.hpp new file mode 100644 index 0000000..abafd54 --- /dev/null +++ b/qt/font.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_Font) + +namespace hiro { + +struct pFont { + static auto size(const Font& font, const string& text) -> Size; + static auto size(const QFont& qtFont, const string& text) -> Size; + static auto family(const string& family) -> QString; + static auto create(const Font& font) -> QFont; +}; + +} + +#endif diff --git a/qt/group.cpp b/qt/group.cpp new file mode 100644 index 0000000..cbf387f --- /dev/null +++ b/qt/group.cpp @@ -0,0 +1,13 @@ +#if defined(Hiro_Group) + +namespace hiro { + +auto pGroup::construct() -> void { +} + +auto pGroup::destruct() -> void { +} + +} + +#endif diff --git a/qt/group.hpp b/qt/group.hpp new file mode 100644 index 0000000..a2ac6d7 --- /dev/null +++ b/qt/group.hpp @@ -0,0 +1,11 @@ +#if defined(Hiro_Group) + +namespace hiro { + +struct pGroup : pObject { + Declare(Group, Object) +}; + +} + +#endif diff --git a/qt/header.hpp b/qt/header.hpp new file mode 100644 index 0000000..03c4a0c --- /dev/null +++ b/qt/header.hpp @@ -0,0 +1,16 @@ +#include +#include +#include +#define XK_MISCELLANY +#define XK_LATIN1 +#include +#include +#undef XK_MISCELLANY +#undef XK_LATIN1 +#include + +//Qt 4.8.0 and earlier improperly define the QLOCATION macro +//in C++11, it is detected as a malformed user-defined literal +//below is a workaround to fix compilation errors caused by this +#undef QLOCATION +#define QLOCATION "\0" __FILE__ ":" QTOSTRING(__LINE__) diff --git a/qt/keyboard.cpp b/qt/keyboard.cpp new file mode 100644 index 0000000..2dad0af --- /dev/null +++ b/qt/keyboard.cpp @@ -0,0 +1,47 @@ +#if defined(Hiro_Keyboard) + +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(const 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::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 << 0 | hi << 8); + }; + + #define map(name, ...) if(key == name) { append(__VA_ARGS__); continue; } + for(auto& key : Keyboard::keys) { + #include + } + #undef map +} + +} + +#endif diff --git a/qt/keyboard.hpp b/qt/keyboard.hpp new file mode 100644 index 0000000..74fc69e --- /dev/null +++ b/qt/keyboard.hpp @@ -0,0 +1,16 @@ +#if defined(Hiro_Keyboard) + +namespace hiro { + +struct pKeyboard { + static auto poll() -> vector; + static auto pressed(unsigned code) -> bool; + + static auto _pressed(const char* state, uint16_t code) -> bool; + + static auto initialize() -> void; +}; + +} + +#endif diff --git a/qt/layout.cpp b/qt/layout.cpp new file mode 100644 index 0000000..d8b998a --- /dev/null +++ b/qt/layout.cpp @@ -0,0 +1,19 @@ +#if defined(Hiro_Layout) + +namespace hiro { + +auto pLayout::construct() -> void { +} + +auto pLayout::destruct() -> void { +} + +auto pLayout::setVisible(bool visible) -> void { + for(auto& sizable : state().sizables) { + if(auto self = sizable->self()) self->setVisible(sizable->visible(true)); + } +} + +} + +#endif diff --git a/qt/layout.hpp b/qt/layout.hpp new file mode 100644 index 0000000..ec8345b --- /dev/null +++ b/qt/layout.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_Layout) + +namespace hiro { + +struct pLayout : pSizable { + Declare(Layout, Sizable) + + auto setVisible(bool visible) -> void override; +}; + +} + +#endif diff --git a/qt/menu-bar.cpp b/qt/menu-bar.cpp new file mode 100644 index 0000000..a2432c0 --- /dev/null +++ b/qt/menu-bar.cpp @@ -0,0 +1,46 @@ +#if defined(Hiro_MenuBar) + +namespace hiro { + +auto pMenuBar::construct() -> void { + _setState(); +} + +auto pMenuBar::destruct() -> void { +} + +auto pMenuBar::append(sMenu menu) -> void { +} + +auto pMenuBar::remove(sMenu menu) -> void { +} + +auto pMenuBar::setEnabled(bool enabled) -> void { + _setState(); +} + +auto pMenuBar::setFont(const Font& font) -> void { + _setState(); +} + +auto pMenuBar::setVisible(bool visible) -> void { + _setState(); +} + +auto pMenuBar::_parent() -> maybe { + if(auto parent = self().parentWindow()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pMenuBar::_setState() -> void { + if(auto parent = _parent()) { + parent->qtMenuBar->setFont(pFont::create(self().font(true))); + parent->qtMenuBar->setVisible(self().visible()); + } +} + +} + +#endif diff --git a/qt/menu-bar.hpp b/qt/menu-bar.hpp new file mode 100644 index 0000000..e1fed33 --- /dev/null +++ b/qt/menu-bar.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_MenuBar) + +namespace hiro { + +struct pMenuBar : pObject { + Declare(MenuBar, Object) + + auto append(sMenu menu) -> void; + auto remove(sMenu menu) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/qt/message-window.cpp b/qt/message-window.cpp new file mode 100644 index 0000000..f214b8a --- /dev/null +++ b/qt/message-window.cpp @@ -0,0 +1,59 @@ +#if defined(Hiro_MessageWindow) + +namespace hiro { + +static auto MessageWindow_buttons(MessageWindow::Buttons buttons) -> QMessageBox::StandardButtons { + QMessageBox::StandardButtons standardButtons = QMessageBox::NoButton; + if(buttons == MessageWindow::Buttons::Ok) standardButtons = QMessageBox::Ok; + if(buttons == MessageWindow::Buttons::OkCancel) standardButtons = QMessageBox::Ok | QMessageBox::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) standardButtons = QMessageBox::Yes | QMessageBox::No; + if(buttons == MessageWindow::Buttons::YesNoCancel) standardButtons = QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel; + return standardButtons; +} + +static auto MessageWindow_response(MessageWindow::Buttons buttons, QMessageBox::StandardButton response) -> MessageWindow::Response { + if(response == QMessageBox::Ok) return MessageWindow::Response::Ok; + if(response == QMessageBox::Cancel) return MessageWindow::Response::Cancel; + if(response == QMessageBox::Yes) return MessageWindow::Response::Yes; + if(response == QMessageBox::No) return MessageWindow::Response::No; + + //MessageWindow was closed via window manager, rather than by a button; assume a cancel/no response + if(buttons == MessageWindow::Buttons::Ok) return MessageWindow::Response::Ok; + if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; + if(buttons == MessageWindow::Buttons::YesNoCancel) return MessageWindow::Response::Cancel; + + throw; +} + +auto pMessageWindow::error(MessageWindow::State& state) -> MessageWindow::Response { +// return MessageWindow_response( +// state.buttons, QMessageBox::critical(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ", +// QString::fromUtf8(state.text), MessageWindow_buttons(state.buttons)) +// ); +} + +auto pMessageWindow::information(MessageWindow::State& state) -> MessageWindow::Response { +// return MessageWindow_response( +// state.buttons, QMessageBox::information(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ", +// QString::fromUtf8(state.text), MessageWindow_buttons(state.buttons)) +// ); +} + +auto pMessageWindow::question(MessageWindow::State& state) -> MessageWindow::Response { +// return MessageWindow_response( +// state.buttons, QMessageBox::question(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ", +// QString::fromUtf8(state.text), MessageWindow_buttons(state.buttons)) +// ); +} + +auto pMessageWindow::warning(MessageWindow::State& state) -> MessageWindow::Response { +// return MessageWindow_response( +// state.buttons, QMessageBox::warning(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ", +// QString::fromUtf8(state.text), MessageWindow_buttons(state.buttons)) +// ); +} + +} + +#endif diff --git a/qt/message-window.hpp b/qt/message-window.hpp new file mode 100644 index 0000000..b8b26af --- /dev/null +++ b/qt/message-window.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_MessageWindow) + +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; +}; + +} + +#endif diff --git a/qt/monitor.cpp b/qt/monitor.cpp new file mode 100644 index 0000000..a277418 --- /dev/null +++ b/qt/monitor.cpp @@ -0,0 +1,20 @@ +#if defined(Hiro_Monitor) + +namespace hiro { + +auto pMonitor::count() -> unsigned { + return QApplication::desktop()->screenCount(); +} + +auto pMonitor::geometry(unsigned monitor) -> Geometry { + QRect rectangle = QApplication::desktop()->screenGeometry(monitor); + return {rectangle.x(), rectangle.y(), rectangle.width(), rectangle.height()}; +} + +auto pMonitor::primary() -> unsigned { + return QApplication::desktop()->primaryScreen(); +} + +} + +#endif diff --git a/qt/monitor.hpp b/qt/monitor.hpp new file mode 100644 index 0000000..2ec7626 --- /dev/null +++ b/qt/monitor.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_Monitor) + +namespace hiro { + +struct pMonitor { + static auto count() -> unsigned; + static auto geometry(unsigned monitor) -> Geometry; + static auto primary() -> unsigned; +}; + +} + +#endif diff --git a/qt/mouse.cpp b/qt/mouse.cpp new file mode 100644 index 0000000..53cd825 --- /dev/null +++ b/qt/mouse.cpp @@ -0,0 +1,22 @@ +#if defined(Hiro_Mouse) + +namespace hiro { + +auto pMouse::position() -> Position { + QPoint point = QCursor::pos(); + return {point.x(), point.y()}; +} + +auto pMouse::pressed(Mouse::Button button) -> bool { + Qt::MouseButtons buttons = QApplication::mouseButtons(); + switch(button) { + case Mouse::Button::Left: return buttons & Qt::LeftButton; + case Mouse::Button::Middle: return buttons & Qt::MidButton; + case Mouse::Button::Right: return buttons & Qt::RightButton; + } + return false; +} + +} + +#endif diff --git a/qt/mouse.hpp b/qt/mouse.hpp new file mode 100644 index 0000000..72a5605 --- /dev/null +++ b/qt/mouse.hpp @@ -0,0 +1,12 @@ +#if defined(Hiro_Mouse) + +namespace hiro { + +struct pMouse { + static auto position() -> Position; + static auto pressed(Mouse::Button button) -> bool; +}; + +} + +#endif diff --git a/qt/object.cpp b/qt/object.cpp new file mode 100644 index 0000000..3c6ac44 --- /dev/null +++ b/qt/object.cpp @@ -0,0 +1,35 @@ +#if defined(Hiro_Object) + +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 Font& font) -> void { +} + +auto pObject::setVisible(bool visible) -> void { +} + +} + +#endif diff --git a/qt/object.hpp b/qt/object.hpp new file mode 100644 index 0000000..ec5b878 --- /dev/null +++ b/qt/object.hpp @@ -0,0 +1,31 @@ +#if defined(Hiro_Object) + +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 Font& 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; +}; + +} + +#endif diff --git a/qt/platform.cpp b/qt/platform.cpp new file mode 100644 index 0000000..e529b91 --- /dev/null +++ b/qt/platform.cpp @@ -0,0 +1,65 @@ +#include "qt.hpp" +#include "qt.moc" +#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 "object.cpp" +#include "group.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-scroll-bar.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" +#include "widget/list-view-header.cpp" +#include "widget/list-view-column.cpp" +#include "widget/list-view-item.cpp" +#include "widget/list-view-cell.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-button.cpp" +#include "widget/radio-label.cpp" +#include "widget/tab-frame.cpp" +#include "widget/tab-frame-item.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +#include "application.cpp" diff --git a/qt/platform.hpp b/qt/platform.hpp new file mode 100644 index 0000000..2f223cd --- /dev/null +++ b/qt/platform.hpp @@ -0,0 +1,136 @@ +#include "settings.hpp" + +#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 "application.hpp" +#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 "group.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/frame.hpp" +#include "widget/hex-edit.hpp" +#include "widget/horizontal-scroll-bar.hpp" +#include "widget/horizontal-slider.hpp" +#include "widget/label.hpp" +#include "widget/line-edit.hpp" +#include "widget/list-view.hpp" +#include "widget/list-view-header.hpp" +#include "widget/list-view-column.hpp" +#include "widget/list-view-item.hpp" +#include "widget/list-view-cell.hpp" +#include "widget/progress-bar.hpp" +#include "widget/radio-button.hpp" +#include "widget/radio-label.hpp" +#include "widget/tab-frame.hpp" +#include "widget/tab-frame-item.hpp" +#include "widget/text-edit.hpp" +#include "widget/vertical-scroll-bar.hpp" +#include "widget/vertical-slider.hpp" +#include "widget/viewport.hpp" + +namespace hiro { + +#if defined(Hiro_Console) +struct pConsole : public QObject, public pWidget { + Q_OBJECT + +public: + Console& console; + struct QtConsole : public QTextEdit { + pConsole& self; + void keyPressEvent(QKeyEvent*); + void keyPressEventAcknowledge(QKeyEvent*); + QtConsole(pConsole& self) : self(self) {} + }; + QtConsole* qtConsole; + + 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(); + void keyPressEvent(QKeyEvent*); +}; +#endif + +#if defined(Hiro_IconView) +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(); +}; +#endif + +#undef Declare + +} diff --git a/qt/popup-menu.cpp b/qt/popup-menu.cpp new file mode 100644 index 0000000..dcaef0e --- /dev/null +++ b/qt/popup-menu.cpp @@ -0,0 +1,40 @@ +#if defined(Hiro_PopupMenu) + +namespace hiro { + +auto pPopupMenu::construct() -> void { + qtPopupMenu = new QMenu; + _setState(); +} + +auto pPopupMenu::destruct() -> void { + delete qtPopupMenu; + qtPopupMenu = nullptr; +} + +auto pPopupMenu::append(sAction action) -> void { + _setState(); +} + +auto pPopupMenu::remove(sAction action) -> void { + _setState(); +} + +auto pPopupMenu::setFont(const Font& font) -> void { + _setState(); +} + +auto pPopupMenu::setVisible(bool visible) -> void { + if(visible) qtPopupMenu->popup(QCursor::pos()); +} + +auto pPopupMenu::_setState() -> void { + qtPopupMenu->setFont(pFont::create(self().font(true))); + for(auto& action : state().actions) { + if(auto self = action->self()) self->_setState(); + } +} + +} + +#endif diff --git a/qt/popup-menu.hpp b/qt/popup-menu.hpp new file mode 100644 index 0000000..707d81d --- /dev/null +++ b/qt/popup-menu.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_PopupMenu) + +namespace hiro { + +struct pPopupMenu : pObject { + Declare(PopupMenu, Object) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; + + auto _setState() -> void; + + QMenu* qtPopupMenu = nullptr; +}; + +} + +#endif diff --git a/qt/qt.hpp b/qt/qt.hpp new file mode 100644 index 0000000..df41bda --- /dev/null +++ b/qt/qt.hpp @@ -0,0 +1,303 @@ +/* + Qt requires moc in order to bind callbacks, which causes many complications. + + First, moc is not C++11-aware. Thus, all of the "public slots:" functions must + be declared using C++98 syntax. + + Second, multiple inheritance with QObject (eg pWindow : QObject, pObject) + seems to cause heap corruption. As such, we need to have separate classes for + inheriting from QObject, which are defined in this file. + + Third, moc preprocessor output is required for every Q_OBJECT class. So to + avoid needing to generate several .moc files, all QObject classes are placed + inside this one file instead. +*/ + +#if !defined(HIRO_QT) + #include "../components.hpp" +#endif + +namespace hiro { + +#if defined(Hiro_Timer) +struct QtTimer : public QTimer { + Q_OBJECT +public: + QtTimer(pTimer& p) : p(p) {} + pTimer& p; +public slots: + void onActivate(); +}; +#endif + +#if defined(Hiro_Window) +struct QtWindow : public QWidget { + QtWindow(pWindow& p) : p(p) {} + auto closeEvent(QCloseEvent*) -> void; + auto dragEnterEvent(QDragEnterEvent*) -> void; + auto dropEvent(QDropEvent*) -> void; + auto keyPressEvent(QKeyEvent*) -> void; + auto keyReleaseEvent(QKeyEvent*) -> void; + auto moveEvent(QMoveEvent*) -> void; + auto resizeEvent(QResizeEvent*) -> void; + auto sizeHint() const -> QSize; + pWindow& p; +}; +#endif + +#if defined(Hiro_MenuItem) +struct QtMenuItem : public QAction { + Q_OBJECT +public: + QtMenuItem(pMenuItem& p) : QAction(nullptr), p(p) {} + pMenuItem& p; +public slots: + void onActivate(); +}; +#endif + +#if defined(Hiro_MenuCheckItem) +struct QtMenuCheckItem : public QAction { + Q_OBJECT +public: + QtMenuCheckItem(pMenuCheckItem& p) : QAction(nullptr), p(p) {} + pMenuCheckItem& p; +public slots: + void onToggle(); +}; +#endif + +#if defined(Hiro_MenuRadioItem) +struct QtMenuRadioItem : public QAction { + Q_OBJECT +public: + QtMenuRadioItem(pMenuRadioItem& p) : QAction(nullptr), p(p) {} + pMenuRadioItem& p; +public slots: + void onActivate(); +}; +#endif + +#if defined(Hiro_Button) +struct QtButton : public QToolButton { + Q_OBJECT +public: + QtButton(pButton& p) : p(p) {} + pButton& p; +public slots: + void onActivate(); +}; +#endif + +#if defined(Hiro_Canvas) +struct QtCanvas : public QWidget { + Q_OBJECT +public: + QtCanvas(pCanvas& p) : p(p) {} + auto dragEnterEvent(QDragEnterEvent*) -> void; + auto dropEvent(QDropEvent*) -> void; + auto leaveEvent(QEvent*) -> void; + auto mouseMoveEvent(QMouseEvent*) -> void; + auto mousePressEvent(QMouseEvent*) -> void; + auto mouseReleaseEvent(QMouseEvent*) -> void; + auto paintEvent(QPaintEvent*) -> void; + pCanvas& p; +}; +#endif + +#if defined(Hiro_CheckButton) +struct QtCheckButton : public QToolButton { + Q_OBJECT +public: + QtCheckButton(pCheckButton& p) : p(p) {} + pCheckButton& p; +public slots: + void onToggle(bool checked); +}; +#endif + +#if defined(Hiro_CheckLabel) +struct QtCheckLabel : public QCheckBox { + Q_OBJECT +public: + QtCheckLabel(pCheckLabel& p) : p(p) {} + pCheckLabel& p; +public slots: + void onToggle(); +}; +#endif + +#if defined(Hiro_ComboButton) +struct QtComboButton : public QComboBox { + Q_OBJECT +public: + QtComboButton(pComboButton& p) : p(p) {} + pComboButton& p; +public slots: + void onChange(int offset); +}; +#endif + +#if defined(Hiro_HexEdit) +struct QtHexEdit : public QTextEdit { + Q_OBJECT +public: + QtHexEdit(pHexEdit& p) : p(p) {} + auto keyPressEvent(QKeyEvent*) -> void; + auto keyPressEventAcknowledge(QKeyEvent*) -> void; + auto wheelEvent(QWheelEvent*) -> void; + pHexEdit& p; +}; + +struct QtHexEditScrollBar : public QScrollBar { + Q_OBJECT +public: + QtHexEditScrollBar(pHexEdit& p) : p(p) {} + auto event(QEvent*) -> bool; + pHexEdit& p; +public slots: + void onScroll(); +}; +#endif + +#if defined(Hiro_HorizontalScrollBar) +struct QtHorizontalScrollBar : public QScrollBar { + Q_OBJECT +public: + QtHorizontalScrollBar(pHorizontalScrollBar& p) : QScrollBar(Qt::Horizontal), p(p) {} + pHorizontalScrollBar& p; +public slots: + void onChange(); +}; +#endif + +#if defined(Hiro_HorizontalSlider) +struct QtHorizontalSlider : public QSlider { + Q_OBJECT +public: + QtHorizontalSlider(pHorizontalSlider& p) : QSlider(Qt::Horizontal), p(p) {} + pHorizontalSlider& p; +public slots: + void onChange(); +}; +#endif + +#if defined(Hiro_LineEdit) +struct QtLineEdit : public QLineEdit { + Q_OBJECT +public: + QtLineEdit(pLineEdit& p) : p(p) {} + pLineEdit& p; +public slots: + void onActivate(); + void onChange(); +}; +#endif + +#if defined(Hiro_ListView) +struct QtListView : public QTreeWidget { + Q_OBJECT +public: + QtListView(pListView& p) : p(p) {} + auto mousePressEvent(QMouseEvent*) -> void override; + auto resizeEvent(QResizeEvent*) -> void override; + auto showEvent(QShowEvent*) -> void override; + pListView& p; +public slots: + void onActivate(); + void onChange(); + void onContext(); + void onSort(int column); + void onToggle(QTreeWidgetItem* item, int column); +}; + +struct QtListViewDelegate : public QStyledItemDelegate { + QtListViewDelegate(pListView& p); + auto paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const -> void; + pListView& p; +}; +#endif + +#if defined(Hiro_RadioLabel) +struct QtRadioLabel : public QRadioButton { + Q_OBJECT +public: + QtRadioLabel(pRadioLabel& p) : p(p) {} + pRadioLabel& p; +public slots: + void onActivate(); +}; +#endif + +#if defined(Hiro_RadioButton) +struct QtRadioButton : public QToolButton { + Q_OBJECT +public: + QtRadioButton(pRadioButton& p) : p(p) {} + pRadioButton& p; +public slots: + void onActivate(); +}; +#endif + +#if defined(Hiro_TabFrame) +struct QtTabFrame : public QTabWidget { + Q_OBJECT +public: + QtTabFrame(pTabFrame& p) : p(p) {} + pTabFrame& p; + auto showEvent(QShowEvent*) -> void override; +public slots: + void onChange(int selection); +}; +#endif + +#if defined(Hiro_TextEdit) +struct QtTextEdit : public QTextEdit { + Q_OBJECT +public: + QtTextEdit(pTextEdit& p) : p(p) {} + pTextEdit& p; +public slots: + void onChange(); +}; +#endif + +#if defined(Hiro_VerticalScrollBar) +struct QtVerticalScrollBar : public QScrollBar { + Q_OBJECT +public: + QtVerticalScrollBar(pVerticalScrollBar& p) : QScrollBar(Qt::Vertical), p(p) {} + pVerticalScrollBar& p; +public slots: + void onChange(); +}; +#endif + +#if defined(Hiro_VerticalSlider) +struct QtVerticalSlider : public QSlider { + Q_OBJECT +public: + QtVerticalSlider(pVerticalSlider& p) : QSlider(Qt::Vertical), p(p) {} + pVerticalSlider& p; +public slots: + void onChange(); +}; +#endif + +#if defined(Hiro_Viewport) +struct QtViewport : public QWidget { + Q_OBJECT +public: + QtViewport(pViewport& p) : p(p) {} + auto dragEnterEvent(QDragEnterEvent*) -> void; + auto dropEvent(QDropEvent*) -> void; + auto leaveEvent(QEvent*) -> void; + auto mouseMoveEvent(QMouseEvent*) -> void; + auto mousePressEvent(QMouseEvent*) -> void; + auto mouseReleaseEvent(QMouseEvent*) -> void; + pViewport& p; +}; +#endif + +} diff --git a/qt/qt.moc b/qt/qt.moc new file mode 100644 index 0000000..c3014c8 --- /dev/null +++ b/qt/qt.moc @@ -0,0 +1,1624 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'qt.hpp' +** +** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.6) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'qt.hpp' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 63 +#error "This file was generated using the moc from 4.8.6. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +static const uint qt_meta_data_hiro__QtTimer[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 14, 27, 27, 27, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtTimer[] = { + "hiro::QtTimer\0onActivate()\0\0" +}; + +void hiro::QtTimer::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtTimer *_t = static_cast(_o); + switch (_id) { + case 0: _t->onActivate(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtTimer::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtTimer::staticMetaObject = { + { &QTimer::staticMetaObject, qt_meta_stringdata_hiro__QtTimer, + qt_meta_data_hiro__QtTimer, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtTimer::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtTimer::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtTimer::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTimer)) + return static_cast(const_cast< QtTimer*>(this)); + return QTimer::qt_metacast(_clname); +} + +int hiro::QtTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QTimer::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtMenuItem[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 17, 30, 30, 30, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtMenuItem[] = { + "hiro::QtMenuItem\0onActivate()\0\0" +}; + +void hiro::QtMenuItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtMenuItem *_t = static_cast(_o); + switch (_id) { + case 0: _t->onActivate(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtMenuItem::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtMenuItem::staticMetaObject = { + { &QAction::staticMetaObject, qt_meta_stringdata_hiro__QtMenuItem, + qt_meta_data_hiro__QtMenuItem, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtMenuItem::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtMenuItem::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtMenuItem::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtMenuItem)) + return static_cast(const_cast< QtMenuItem*>(this)); + return QAction::qt_metacast(_clname); +} + +int hiro::QtMenuItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QAction::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtMenuCheckItem[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 22, 33, 33, 33, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtMenuCheckItem[] = { + "hiro::QtMenuCheckItem\0onToggle()\0\0" +}; + +void hiro::QtMenuCheckItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtMenuCheckItem *_t = static_cast(_o); + switch (_id) { + case 0: _t->onToggle(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtMenuCheckItem::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtMenuCheckItem::staticMetaObject = { + { &QAction::staticMetaObject, qt_meta_stringdata_hiro__QtMenuCheckItem, + qt_meta_data_hiro__QtMenuCheckItem, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtMenuCheckItem::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtMenuCheckItem::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtMenuCheckItem::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtMenuCheckItem)) + return static_cast(const_cast< QtMenuCheckItem*>(this)); + return QAction::qt_metacast(_clname); +} + +int hiro::QtMenuCheckItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QAction::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtMenuRadioItem[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 22, 35, 35, 35, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtMenuRadioItem[] = { + "hiro::QtMenuRadioItem\0onActivate()\0\0" +}; + +void hiro::QtMenuRadioItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtMenuRadioItem *_t = static_cast(_o); + switch (_id) { + case 0: _t->onActivate(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtMenuRadioItem::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtMenuRadioItem::staticMetaObject = { + { &QAction::staticMetaObject, qt_meta_stringdata_hiro__QtMenuRadioItem, + qt_meta_data_hiro__QtMenuRadioItem, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtMenuRadioItem::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtMenuRadioItem::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtMenuRadioItem::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtMenuRadioItem)) + return static_cast(const_cast< QtMenuRadioItem*>(this)); + return QAction::qt_metacast(_clname); +} + +int hiro::QtMenuRadioItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QAction::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtButton[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 15, 28, 28, 28, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtButton[] = { + "hiro::QtButton\0onActivate()\0\0" +}; + +void hiro::QtButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtButton *_t = static_cast(_o); + switch (_id) { + case 0: _t->onActivate(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtButton::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtButton::staticMetaObject = { + { &QToolButton::staticMetaObject, qt_meta_stringdata_hiro__QtButton, + qt_meta_data_hiro__QtButton, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtButton::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtButton::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtButton::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtButton)) + return static_cast(const_cast< QtButton*>(this)); + return QToolButton::qt_metacast(_clname); +} + +int hiro::QtButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QToolButton::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtCanvas[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 0, 0, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtCanvas[] = { + "hiro::QtCanvas\0" +}; + +void hiro::QtCanvas::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + Q_UNUSED(_o); + Q_UNUSED(_id); + Q_UNUSED(_c); + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtCanvas::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtCanvas::staticMetaObject = { + { &QWidget::staticMetaObject, qt_meta_stringdata_hiro__QtCanvas, + qt_meta_data_hiro__QtCanvas, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtCanvas::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtCanvas::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtCanvas::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtCanvas)) + return static_cast(const_cast< QtCanvas*>(this)); + return QWidget::qt_metacast(_clname); +} + +int hiro::QtCanvas::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QWidget::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return _id; +} +static const uint qt_meta_data_hiro__QtCheckButton[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 20, 35, 43, 43, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtCheckButton[] = { + "hiro::QtCheckButton\0onToggle(bool)\0" + "checked\0\0" +}; + +void hiro::QtCheckButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtCheckButton *_t = static_cast(_o); + switch (_id) { + case 0: _t->onToggle((*reinterpret_cast< bool(*)>(_a[1]))); break; + default: ; + } + } +} + +const QMetaObjectExtraData hiro::QtCheckButton::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtCheckButton::staticMetaObject = { + { &QToolButton::staticMetaObject, qt_meta_stringdata_hiro__QtCheckButton, + qt_meta_data_hiro__QtCheckButton, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtCheckButton::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtCheckButton::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtCheckButton::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtCheckButton)) + return static_cast(const_cast< QtCheckButton*>(this)); + return QToolButton::qt_metacast(_clname); +} + +int hiro::QtCheckButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QToolButton::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtCheckLabel[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 19, 30, 30, 30, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtCheckLabel[] = { + "hiro::QtCheckLabel\0onToggle()\0\0" +}; + +void hiro::QtCheckLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtCheckLabel *_t = static_cast(_o); + switch (_id) { + case 0: _t->onToggle(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtCheckLabel::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtCheckLabel::staticMetaObject = { + { &QCheckBox::staticMetaObject, qt_meta_stringdata_hiro__QtCheckLabel, + qt_meta_data_hiro__QtCheckLabel, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtCheckLabel::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtCheckLabel::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtCheckLabel::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtCheckLabel)) + return static_cast(const_cast< QtCheckLabel*>(this)); + return QCheckBox::qt_metacast(_clname); +} + +int hiro::QtCheckLabel::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QCheckBox::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtComboButton[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 20, 34, 41, 41, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtComboButton[] = { + "hiro::QtComboButton\0onChange(int)\0" + "offset\0\0" +}; + +void hiro::QtComboButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtComboButton *_t = static_cast(_o); + switch (_id) { + case 0: _t->onChange((*reinterpret_cast< int(*)>(_a[1]))); break; + default: ; + } + } +} + +const QMetaObjectExtraData hiro::QtComboButton::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtComboButton::staticMetaObject = { + { &QComboBox::staticMetaObject, qt_meta_stringdata_hiro__QtComboButton, + qt_meta_data_hiro__QtComboButton, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtComboButton::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtComboButton::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtComboButton::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtComboButton)) + return static_cast(const_cast< QtComboButton*>(this)); + return QComboBox::qt_metacast(_clname); +} + +int hiro::QtComboButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QComboBox::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtHexEdit[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 0, 0, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtHexEdit[] = { + "hiro::QtHexEdit\0" +}; + +void hiro::QtHexEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + Q_UNUSED(_o); + Q_UNUSED(_id); + Q_UNUSED(_c); + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtHexEdit::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtHexEdit::staticMetaObject = { + { &QTextEdit::staticMetaObject, qt_meta_stringdata_hiro__QtHexEdit, + qt_meta_data_hiro__QtHexEdit, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtHexEdit::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtHexEdit::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtHexEdit::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHexEdit)) + return static_cast(const_cast< QtHexEdit*>(this)); + return QTextEdit::qt_metacast(_clname); +} + +int hiro::QtHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QTextEdit::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return _id; +} +static const uint qt_meta_data_hiro__QtHexEditScrollBar[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 25, 36, 36, 36, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtHexEditScrollBar[] = { + "hiro::QtHexEditScrollBar\0onScroll()\0" + "\0" +}; + +void hiro::QtHexEditScrollBar::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtHexEditScrollBar *_t = static_cast(_o); + switch (_id) { + case 0: _t->onScroll(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtHexEditScrollBar::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtHexEditScrollBar::staticMetaObject = { + { &QScrollBar::staticMetaObject, qt_meta_stringdata_hiro__QtHexEditScrollBar, + qt_meta_data_hiro__QtHexEditScrollBar, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtHexEditScrollBar::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtHexEditScrollBar::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtHexEditScrollBar::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHexEditScrollBar)) + return static_cast(const_cast< QtHexEditScrollBar*>(this)); + return QScrollBar::qt_metacast(_clname); +} + +int hiro::QtHexEditScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QScrollBar::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtHorizontalScrollBar[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 28, 39, 39, 39, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtHorizontalScrollBar[] = { + "hiro::QtHorizontalScrollBar\0onChange()\0" + "\0" +}; + +void hiro::QtHorizontalScrollBar::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtHorizontalScrollBar *_t = static_cast(_o); + switch (_id) { + case 0: _t->onChange(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtHorizontalScrollBar::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtHorizontalScrollBar::staticMetaObject = { + { &QScrollBar::staticMetaObject, qt_meta_stringdata_hiro__QtHorizontalScrollBar, + qt_meta_data_hiro__QtHorizontalScrollBar, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtHorizontalScrollBar::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtHorizontalScrollBar::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtHorizontalScrollBar::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHorizontalScrollBar)) + return static_cast(const_cast< QtHorizontalScrollBar*>(this)); + return QScrollBar::qt_metacast(_clname); +} + +int hiro::QtHorizontalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QScrollBar::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtHorizontalSlider[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 25, 36, 36, 36, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtHorizontalSlider[] = { + "hiro::QtHorizontalSlider\0onChange()\0" + "\0" +}; + +void hiro::QtHorizontalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtHorizontalSlider *_t = static_cast(_o); + switch (_id) { + case 0: _t->onChange(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtHorizontalSlider::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtHorizontalSlider::staticMetaObject = { + { &QSlider::staticMetaObject, qt_meta_stringdata_hiro__QtHorizontalSlider, + qt_meta_data_hiro__QtHorizontalSlider, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtHorizontalSlider::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtHorizontalSlider::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtHorizontalSlider::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtHorizontalSlider)) + return static_cast(const_cast< QtHorizontalSlider*>(this)); + return QSlider::qt_metacast(_clname); +} + +int hiro::QtHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QSlider::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtLineEdit[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 2, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 17, 30, 30, 30, 0x0a, + 31, 30, 30, 30, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtLineEdit[] = { + "hiro::QtLineEdit\0onActivate()\0\0" + "onChange()\0" +}; + +void hiro::QtLineEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtLineEdit *_t = static_cast(_o); + switch (_id) { + case 0: _t->onActivate(); break; + case 1: _t->onChange(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtLineEdit::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtLineEdit::staticMetaObject = { + { &QLineEdit::staticMetaObject, qt_meta_stringdata_hiro__QtLineEdit, + qt_meta_data_hiro__QtLineEdit, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtLineEdit::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtLineEdit::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtLineEdit::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtLineEdit)) + return static_cast(const_cast< QtLineEdit*>(this)); + return QLineEdit::qt_metacast(_clname); +} + +int hiro::QtLineEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QLineEdit::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 2) + qt_static_metacall(this, _c, _id, _a); + _id -= 2; + } + return _id; +} +static const uint qt_meta_data_hiro__QtListView[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 5, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 17, 30, 30, 30, 0x0a, + 31, 30, 30, 30, 0x0a, + 42, 30, 30, 30, 0x0a, + 54, 66, 30, 30, 0x0a, + 73, 104, 30, 30, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtListView[] = { + "hiro::QtListView\0onActivate()\0\0" + "onChange()\0onContext()\0onSort(int)\0" + "column\0onToggle(QTreeWidgetItem*,int)\0" + "item,column\0" +}; + +void hiro::QtListView::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtListView *_t = static_cast(_o); + switch (_id) { + case 0: _t->onActivate(); 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])),(*reinterpret_cast< int(*)>(_a[2]))); break; + default: ; + } + } +} + +const QMetaObjectExtraData hiro::QtListView::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtListView::staticMetaObject = { + { &QTreeWidget::staticMetaObject, qt_meta_stringdata_hiro__QtListView, + qt_meta_data_hiro__QtListView, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtListView::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtListView::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtListView::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtListView)) + return static_cast(const_cast< QtListView*>(this)); + return QTreeWidget::qt_metacast(_clname); +} + +int hiro::QtListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QTreeWidget::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 5) + qt_static_metacall(this, _c, _id, _a); + _id -= 5; + } + return _id; +} +static const uint qt_meta_data_hiro__QtRadioLabel[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 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, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtRadioLabel[] = { + "hiro::QtRadioLabel\0onActivate()\0\0" +}; + +void hiro::QtRadioLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtRadioLabel *_t = static_cast(_o); + switch (_id) { + case 0: _t->onActivate(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtRadioLabel::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtRadioLabel::staticMetaObject = { + { &QRadioButton::staticMetaObject, qt_meta_stringdata_hiro__QtRadioLabel, + qt_meta_data_hiro__QtRadioLabel, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtRadioLabel::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtRadioLabel::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtRadioLabel::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtRadioLabel)) + return static_cast(const_cast< QtRadioLabel*>(this)); + return QRadioButton::qt_metacast(_clname); +} + +int hiro::QtRadioLabel::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QRadioButton::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtRadioButton[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 20, 33, 33, 33, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtRadioButton[] = { + "hiro::QtRadioButton\0onActivate()\0\0" +}; + +void hiro::QtRadioButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtRadioButton *_t = static_cast(_o); + switch (_id) { + case 0: _t->onActivate(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtRadioButton::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtRadioButton::staticMetaObject = { + { &QToolButton::staticMetaObject, qt_meta_stringdata_hiro__QtRadioButton, + qt_meta_data_hiro__QtRadioButton, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtRadioButton::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtRadioButton::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtRadioButton::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtRadioButton)) + return static_cast(const_cast< QtRadioButton*>(this)); + return QToolButton::qt_metacast(_clname); +} + +int hiro::QtRadioButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QToolButton::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtTabFrame[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 17, 31, 41, 41, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtTabFrame[] = { + "hiro::QtTabFrame\0onChange(int)\0selection\0" + "\0" +}; + +void hiro::QtTabFrame::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtTabFrame *_t = static_cast(_o); + switch (_id) { + case 0: _t->onChange((*reinterpret_cast< int(*)>(_a[1]))); break; + default: ; + } + } +} + +const QMetaObjectExtraData hiro::QtTabFrame::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtTabFrame::staticMetaObject = { + { &QTabWidget::staticMetaObject, qt_meta_stringdata_hiro__QtTabFrame, + qt_meta_data_hiro__QtTabFrame, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtTabFrame::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtTabFrame::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtTabFrame::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTabFrame)) + return static_cast(const_cast< QtTabFrame*>(this)); + return QTabWidget::qt_metacast(_clname); +} + +int hiro::QtTabFrame::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QTabWidget::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtTextEdit[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 17, 28, 28, 28, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtTextEdit[] = { + "hiro::QtTextEdit\0onChange()\0\0" +}; + +void hiro::QtTextEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtTextEdit *_t = static_cast(_o); + switch (_id) { + case 0: _t->onChange(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtTextEdit::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtTextEdit::staticMetaObject = { + { &QTextEdit::staticMetaObject, qt_meta_stringdata_hiro__QtTextEdit, + qt_meta_data_hiro__QtTextEdit, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtTextEdit::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtTextEdit::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtTextEdit::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtTextEdit)) + return static_cast(const_cast< QtTextEdit*>(this)); + return QTextEdit::qt_metacast(_clname); +} + +int hiro::QtTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QTextEdit::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtVerticalScrollBar[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 26, 37, 37, 37, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtVerticalScrollBar[] = { + "hiro::QtVerticalScrollBar\0onChange()\0" + "\0" +}; + +void hiro::QtVerticalScrollBar::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtVerticalScrollBar *_t = static_cast(_o); + switch (_id) { + case 0: _t->onChange(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtVerticalScrollBar::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtVerticalScrollBar::staticMetaObject = { + { &QScrollBar::staticMetaObject, qt_meta_stringdata_hiro__QtVerticalScrollBar, + qt_meta_data_hiro__QtVerticalScrollBar, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtVerticalScrollBar::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtVerticalScrollBar::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtVerticalScrollBar::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtVerticalScrollBar)) + return static_cast(const_cast< QtVerticalScrollBar*>(this)); + return QScrollBar::qt_metacast(_clname); +} + +int hiro::QtVerticalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QScrollBar::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtVerticalSlider[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: signature, parameters, type, tag, flags + 23, 34, 34, 34, 0x0a, + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtVerticalSlider[] = { + "hiro::QtVerticalSlider\0onChange()\0\0" +}; + +void hiro::QtVerticalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + Q_ASSERT(staticMetaObject.cast(_o)); + QtVerticalSlider *_t = static_cast(_o); + switch (_id) { + case 0: _t->onChange(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtVerticalSlider::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtVerticalSlider::staticMetaObject = { + { &QSlider::staticMetaObject, qt_meta_stringdata_hiro__QtVerticalSlider, + qt_meta_data_hiro__QtVerticalSlider, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtVerticalSlider::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtVerticalSlider::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtVerticalSlider::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtVerticalSlider)) + return static_cast(const_cast< QtVerticalSlider*>(this)); + return QSlider::qt_metacast(_clname); +} + +int hiro::QtVerticalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QSlider::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } + return _id; +} +static const uint qt_meta_data_hiro__QtViewport[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 0, 0, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtViewport[] = { + "hiro::QtViewport\0" +}; + +void hiro::QtViewport::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + Q_UNUSED(_o); + Q_UNUSED(_id); + Q_UNUSED(_c); + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtViewport::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtViewport::staticMetaObject = { + { &QWidget::staticMetaObject, qt_meta_stringdata_hiro__QtViewport, + qt_meta_data_hiro__QtViewport, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtViewport::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtViewport::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtViewport::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtViewport)) + return static_cast(const_cast< QtViewport*>(this)); + return QWidget::qt_metacast(_clname); +} + +int hiro::QtViewport::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QWidget::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return _id; +} +QT_END_MOC_NAMESPACE diff --git a/qt/settings.cpp b/qt/settings.cpp new file mode 100644 index 0000000..cbf2d56 --- /dev/null +++ b/qt/settings.cpp @@ -0,0 +1,26 @@ +namespace hiro { + +static Settings* settings = nullptr; + +Settings::Settings() { + geometry.append(geometry.frameX = 4, "FrameX"); + geometry.append(geometry.frameY = 24, "FrameY"); + geometry.append(geometry.frameWidth = 8, "FrameWidth"); + geometry.append(geometry.frameHeight = 28, "FrameHeight"); + geometry.append(geometry.menuHeight = 20, "MenuHeight"); + geometry.append(geometry.statusHeight = 20, "StatusHeight"); + append(geometry, "Geometry"); +} + +auto Settings::load() -> void { + string path{configpath(), "hiro/"}; + Configuration::Document::load({path, "qt.bml"}); +} + +auto Settings::save() -> void { + string path{configpath(), "hiro/"}; + directory::create(path, 0755); + Configuration::Document::save({path, "qt.bml"}); +} + +} diff --git a/qt/settings.hpp b/qt/settings.hpp new file mode 100644 index 0000000..c74657f --- /dev/null +++ b/qt/settings.hpp @@ -0,0 +1,20 @@ +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; + + Settings(); + auto load() -> void; + auto save() -> void; +}; + +} diff --git a/qt/sizable.cpp b/qt/sizable.cpp new file mode 100644 index 0000000..4e793ab --- /dev/null +++ b/qt/sizable.cpp @@ -0,0 +1,20 @@ +#if defined(Hiro_Sizable) + +namespace hiro { + +auto pSizable::construct() -> void { +} + +auto pSizable::destruct() -> void { +} + +auto pSizable::minimumSize() const -> Size { + return {0, 0}; +} + +auto pSizable::setGeometry(Geometry geometry) -> void { +} + +} + +#endif diff --git a/qt/sizable.hpp b/qt/sizable.hpp new file mode 100644 index 0000000..5270283 --- /dev/null +++ b/qt/sizable.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_Sizable) + +namespace hiro { + +struct pSizable : pObject { + Declare(Sizable, Object) + + virtual auto minimumSize() const -> Size; + virtual auto setGeometry(Geometry geometry) -> void; +}; + +} + +#endif diff --git a/qt/status-bar.cpp b/qt/status-bar.cpp new file mode 100644 index 0000000..17b0d81 --- /dev/null +++ b/qt/status-bar.cpp @@ -0,0 +1,45 @@ +#if defined(Hiro_StatusBar) + +namespace hiro { + +auto pStatusBar::construct() -> void { + _setState(); +} + +auto pStatusBar::destruct() -> void { +} + +auto pStatusBar::setEnabled(bool enabled) -> void { + _setState(); +} + +auto pStatusBar::setFont(const Font& font) -> void { + _setState(); +} + +auto pStatusBar::setText(const string& text) -> void { + _setState(); +} + +auto pStatusBar::setVisible(bool visible) -> void { + _setState(); +} + +auto pStatusBar::_parent() -> maybe { + if(auto parent = self().parentWindow()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pStatusBar::_setState() -> void { + if(auto parent = _parent()) { + parent->qtStatusBar->setFont(pFont::create(self().font(true))); + parent->qtStatusBar->showMessage(QString::fromUtf8(state().text), 0); + parent->qtStatusBar->setVisible(self().visible()); + } +} + +} + +#endif diff --git a/qt/status-bar.hpp b/qt/status-bar.hpp new file mode 100644 index 0000000..309e6c7 --- /dev/null +++ b/qt/status-bar.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_StatusBar) + +namespace hiro { + +struct pStatusBar : pObject { + Declare(StatusBar, Object) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/qt/timer.cpp b/qt/timer.cpp new file mode 100644 index 0000000..13a6761 --- /dev/null +++ b/qt/timer.cpp @@ -0,0 +1,33 @@ +#if defined(Hiro_Timer) + +namespace hiro { + +auto pTimer::construct() -> void { + qtTimer = new QtTimer(*this); + qtTimer->setInterval(0); + qtTimer->connect(qtTimer, SIGNAL(timeout()), SLOT(onActivate())); +} + +auto pTimer::destruct() -> void { + delete qtTimer; +} + +auto pTimer::setEnabled(bool enabled) -> void { + if(enabled) { + qtTimer->start(); + } else { + qtTimer->stop(); + } +} + +auto pTimer::setInterval(unsigned interval) -> void { + qtTimer->setInterval(interval); +} + +auto QtTimer::onActivate() -> void { + p.self().doActivate(); +} + +} + +#endif diff --git a/qt/timer.hpp b/qt/timer.hpp new file mode 100644 index 0000000..a3fb8f5 --- /dev/null +++ b/qt/timer.hpp @@ -0,0 +1,16 @@ +#if defined(Hiro_Timer) + +namespace hiro { + +struct pTimer : pObject { + Declare(Timer, Object) + + auto setEnabled(bool enabled) -> void override; + auto setInterval(unsigned interval) -> void; + + QtTimer* qtTimer = nullptr; +}; + +} + +#endif diff --git a/qt/utility.cpp b/qt/utility.cpp new file mode 100644 index 0000000..885fd64 --- /dev/null +++ b/qt/utility.cpp @@ -0,0 +1,260 @@ +namespace hiro { + +static auto CalculateAlignment(Alignment alignment) -> signed { + signed result = 0; + if(alignment.horizontal() < 0.333) result |= Qt::AlignLeft; + else if(alignment.horizontal() > 0.666) result |= Qt::AlignRight; + else result |= Qt::AlignCenter; + if(alignment.vertical() < 0.333) result |= Qt::AlignTop; + else if(alignment.vertical() > 0.666) result |= Qt::AlignBottom; + else result |= Qt::AlignVCenter; + return result; +} + +static auto CreateBrush(Color color) -> QBrush { + return color ? QColor(color.red(), color.green(), color.blue()) : QBrush(); +} + +static auto CreateIcon(const image& icon, bool scale = false) -> QIcon { + if(!icon) return QIcon(); + auto qtBuffer = icon; + qtBuffer.transform(); + if(scale) qtBuffer.scale(16, 16, Interpolation::Linear); + QImage qtImage(qtBuffer.data(), qtBuffer.width(), qtBuffer.height(), QImage::Format_ARGB32); + return QIcon(QPixmap::fromImage(qtImage)); +} + +static auto DropPaths(QDropEvent* event) -> lstring { + QList urls = event->mimeData()->urls(); + if(urls.size() == 0) return {}; + + lstring paths; + for(auto n : range(urls.size())) { + string path{urls[n].path().toUtf8().constData()}; + if(!path) continue; + if(directory::exists(path) && !path.endsWith("/")) path.append("/"); + paths.append(path); + } + + return paths; +} + +/* +static auto GetDisplacement(Sizable* sizable) -> Position { + 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 auto GetParentWidgetLayout(Sizable* sizable) -> Layout* { + while(sizable) { + if(sizable->state.parent && dynamic_cast(sizable->state.parent)) return (Layout*)sizable; + sizable = sizable->state.parent; + } + return nullptr; +} +*/ + +/* +static auto GetParentWidget(Sizable* sizable) -> Widget* { + while(sizable) { + if(sizable->state.parent && dynamic_cast(sizable->state.parent)) return (Widget*)sizable->state.parent; + sizable = sizable->state.parent; + } + return nullptr; +} +*/ + +/* +static auto Keysym(int keysym) -> Keyboard::Keycode { + switch(keysym) { + case XK_Escape: return Keyboard::Keycode::Escape; + case XK_F1: return Keyboard::Keycode::F1; + case XK_F2: return Keyboard::Keycode::F2; + case XK_F3: return Keyboard::Keycode::F3; + case XK_F4: return Keyboard::Keycode::F4; + case XK_F5: return Keyboard::Keycode::F5; + case XK_F6: return Keyboard::Keycode::F6; + case XK_F7: return Keyboard::Keycode::F7; + case XK_F8: return Keyboard::Keycode::F8; + case XK_F9: return Keyboard::Keycode::F9; + case XK_F10: return Keyboard::Keycode::F10; + case XK_F11: return Keyboard::Keycode::F11; + case XK_F12: return Keyboard::Keycode::F12; + + case XK_Print: return Keyboard::Keycode::PrintScreen; + //Keyboard::Keycode::SysRq + case XK_Scroll_Lock: return Keyboard::Keycode::ScrollLock; + case XK_Pause: return Keyboard::Keycode::Pause; + //Keyboard::Keycode::Break + + case XK_Insert: return Keyboard::Keycode::Insert; + case XK_Delete: return Keyboard::Keycode::Delete; + case XK_Home: return Keyboard::Keycode::Home; + case XK_End: return Keyboard::Keycode::End; + case XK_Prior: return Keyboard::Keycode::PageUp; + case XK_Next: return Keyboard::Keycode::PageDown; + + case XK_Up: return Keyboard::Keycode::Up; + case XK_Down: return Keyboard::Keycode::Down; + case XK_Left: return Keyboard::Keycode::Left; + case XK_Right: return Keyboard::Keycode::Right; + + case XK_grave: return Keyboard::Keycode::Grave; + case XK_1: return Keyboard::Keycode::Number1; + case XK_2: return Keyboard::Keycode::Number2; + case XK_3: return Keyboard::Keycode::Number3; + case XK_4: return Keyboard::Keycode::Number4; + case XK_5: return Keyboard::Keycode::Number5; + case XK_6: return Keyboard::Keycode::Number6; + case XK_7: return Keyboard::Keycode::Number7; + case XK_8: return Keyboard::Keycode::Number8; + case XK_9: return Keyboard::Keycode::Number9; + case XK_0: return Keyboard::Keycode::Number0; + case XK_minus: return Keyboard::Keycode::Minus; + case XK_equal: return Keyboard::Keycode::Equal; + case XK_BackSpace: return Keyboard::Keycode::Backspace; + + case XK_asciitilde: return Keyboard::Keycode::Tilde; + case XK_exclam: return Keyboard::Keycode::Exclamation; + case XK_at: return Keyboard::Keycode::At; + case XK_numbersign: return Keyboard::Keycode::Pound; + case XK_dollar: return Keyboard::Keycode::Dollar; + case XK_percent: return Keyboard::Keycode::Percent; + case XK_asciicircum: return Keyboard::Keycode::Power; + case XK_ampersand: return Keyboard::Keycode::Ampersand; + case XK_asterisk: return Keyboard::Keycode::Asterisk; + case XK_parenleft: return Keyboard::Keycode::ParenthesisLeft; + case XK_parenright: return Keyboard::Keycode::ParenthesisRight; + case XK_underscore: return Keyboard::Keycode::Underscore; + case XK_plus: return Keyboard::Keycode::Plus; + + case XK_bracketleft: return Keyboard::Keycode::BracketLeft; + case XK_bracketright: return Keyboard::Keycode::BracketRight; + case XK_backslash: return Keyboard::Keycode::Backslash; + case XK_semicolon: return Keyboard::Keycode::Semicolon; + case XK_apostrophe: return Keyboard::Keycode::Apostrophe; + case XK_comma: return Keyboard::Keycode::Comma; + case XK_period: return Keyboard::Keycode::Period; + case XK_slash: return Keyboard::Keycode::Slash; + + case XK_braceleft: return Keyboard::Keycode::BraceLeft; + case XK_braceright: return Keyboard::Keycode::BraceRight; + case XK_bar: return Keyboard::Keycode::Pipe; + case XK_colon: return Keyboard::Keycode::Colon; + case XK_quotedbl: return Keyboard::Keycode::Quote; + case XK_less: return Keyboard::Keycode::CaretLeft; + case XK_greater: return Keyboard::Keycode::CaretRight; + case XK_question: return Keyboard::Keycode::Question; + + case XK_Tab: return Keyboard::Keycode::Tab; + case XK_Caps_Lock: return Keyboard::Keycode::CapsLock; + case XK_Return: return Keyboard::Keycode::Return; + case XK_Shift_L: return Keyboard::Keycode::ShiftLeft; + case XK_Shift_R: return Keyboard::Keycode::ShiftRight; + case XK_Control_L: return Keyboard::Keycode::ControlLeft; + case XK_Control_R: return Keyboard::Keycode::ControlRight; + case XK_Super_L: return Keyboard::Keycode::SuperLeft; + case XK_Super_R: return Keyboard::Keycode::SuperRight; + case XK_Alt_L: return Keyboard::Keycode::AltLeft; + case XK_Alt_R: return Keyboard::Keycode::AltRight; + case XK_space: return Keyboard::Keycode::Space; + case XK_Menu: return Keyboard::Keycode::Menu; + + case XK_A: return Keyboard::Keycode::A; + case XK_B: return Keyboard::Keycode::B; + case XK_C: return Keyboard::Keycode::C; + case XK_D: return Keyboard::Keycode::D; + case XK_E: return Keyboard::Keycode::E; + case XK_F: return Keyboard::Keycode::F; + case XK_G: return Keyboard::Keycode::G; + case XK_H: return Keyboard::Keycode::H; + case XK_I: return Keyboard::Keycode::I; + case XK_J: return Keyboard::Keycode::J; + case XK_K: return Keyboard::Keycode::K; + case XK_L: return Keyboard::Keycode::L; + case XK_M: return Keyboard::Keycode::M; + case XK_N: return Keyboard::Keycode::N; + case XK_O: return Keyboard::Keycode::O; + case XK_P: return Keyboard::Keycode::P; + case XK_Q: return Keyboard::Keycode::Q; + case XK_R: return Keyboard::Keycode::R; + case XK_S: return Keyboard::Keycode::S; + case XK_T: return Keyboard::Keycode::T; + case XK_U: return Keyboard::Keycode::U; + case XK_V: return Keyboard::Keycode::V; + case XK_W: return Keyboard::Keycode::W; + case XK_X: return Keyboard::Keycode::X; + case XK_Y: return Keyboard::Keycode::Y; + case XK_Z: return Keyboard::Keycode::Z; + + case XK_a: return Keyboard::Keycode::a; + case XK_b: return Keyboard::Keycode::b; + case XK_c: return Keyboard::Keycode::c; + case XK_d: return Keyboard::Keycode::d; + case XK_e: return Keyboard::Keycode::e; + case XK_f: return Keyboard::Keycode::f; + case XK_g: return Keyboard::Keycode::g; + case XK_h: return Keyboard::Keycode::h; + case XK_i: return Keyboard::Keycode::i; + case XK_j: return Keyboard::Keycode::j; + case XK_k: return Keyboard::Keycode::k; + case XK_l: return Keyboard::Keycode::l; + case XK_m: return Keyboard::Keycode::m; + case XK_n: return Keyboard::Keycode::n; + case XK_o: return Keyboard::Keycode::o; + case XK_p: return Keyboard::Keycode::p; + case XK_q: return Keyboard::Keycode::q; + case XK_r: return Keyboard::Keycode::r; + case XK_s: return Keyboard::Keycode::s; + case XK_t: return Keyboard::Keycode::t; + case XK_u: return Keyboard::Keycode::u; + case XK_v: return Keyboard::Keycode::v; + case XK_w: return Keyboard::Keycode::w; + case XK_x: return Keyboard::Keycode::x; + case XK_y: return Keyboard::Keycode::y; + case XK_z: return Keyboard::Keycode::z; + + case XK_Num_Lock: return Keyboard::Keycode::NumLock; + case XK_KP_Divide: return Keyboard::Keycode::Divide; + case XK_KP_Multiply: return Keyboard::Keycode::Multiply; + case XK_KP_Subtract: return Keyboard::Keycode::Subtract; + case XK_KP_Add: return Keyboard::Keycode::Add; + case XK_KP_Enter: return Keyboard::Keycode::Enter; + case XK_KP_Decimal: return Keyboard::Keycode::Point; + + case XK_KP_1: return Keyboard::Keycode::Keypad1; + case XK_KP_2: return Keyboard::Keycode::Keypad2; + case XK_KP_3: return Keyboard::Keycode::Keypad3; + case XK_KP_4: return Keyboard::Keycode::Keypad4; + case XK_KP_5: return Keyboard::Keycode::Keypad5; + case XK_KP_6: return Keyboard::Keycode::Keypad6; + case XK_KP_7: return Keyboard::Keycode::Keypad7; + case XK_KP_8: return Keyboard::Keycode::Keypad8; + case XK_KP_9: return Keyboard::Keycode::Keypad9; + case XK_KP_0: return Keyboard::Keycode::Keypad0; + + case XK_KP_Home: return Keyboard::Keycode::KeypadHome; + case XK_KP_End: return Keyboard::Keycode::KeypadEnd; + case XK_KP_Page_Up: return Keyboard::Keycode::KeypadPageUp; + case XK_KP_Page_Down: return Keyboard::Keycode::KeypadPageDown; + case XK_KP_Up: return Keyboard::Keycode::KeypadUp; + case XK_KP_Down: return Keyboard::Keycode::KeypadDown; + case XK_KP_Left: return Keyboard::Keycode::KeypadLeft; + case XK_KP_Right: return Keyboard::Keycode::KeypadRight; + case XK_KP_Begin: return Keyboard::Keycode::KeypadCenter; + case XK_KP_Insert: return Keyboard::Keycode::KeypadInsert; + case XK_KP_Delete: return Keyboard::Keycode::KeypadDelete; + } + return Keyboard::Keycode::None; +} +*/ + +} diff --git a/qt/widget/button.cpp b/qt/widget/button.cpp new file mode 100644 index 0000000..1bfb50b --- /dev/null +++ b/qt/widget/button.cpp @@ -0,0 +1,66 @@ +#if defined(Hiro_Button) + +namespace hiro { + +auto pButton::construct() -> void { + qtWidget = qtButton = new QtButton(*this); + qtButton->setToolButtonStyle(Qt::ToolButtonTextOnly); + qtButton->connect(qtButton, SIGNAL(released()), SLOT(onActivate())); + + setBordered(state().bordered); + setIcon(state().icon); + setOrientation(state().orientation); + setText(state().text); + + pWidget::construct(); +} + +auto pButton::destruct() -> void { + delete qtButton; + qtWidget = qtButton = nullptr; +} + +auto pButton::minimumSize() const -> Size { + auto size = pFont::size(qtWidget->font(), state().text ? 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 ? 20 : 12), size.height() + 12}; +} + +auto pButton::setBordered(bool bordered) -> void { + qtButton->setAutoRaise(!bordered); +} + +auto pButton::setIcon(const image& icon) -> void { + qtButton->setIconSize(QSize(icon.width(), icon.height())); + qtButton->setIcon(CreateIcon(icon)); + qtButton->setStyleSheet("text-align: top;"); +} + +auto pButton::setOrientation(Orientation orientation) -> void { + switch(orientation) { + case Orientation::Horizontal: qtButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); break; + case Orientation::Vertical: qtButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); break; + } +} + +auto pButton::setText(const string& text) -> void { + qtButton->setText(QString::fromUtf8(text)); +} + +auto QtButton::onActivate() -> void { + p.self().doActivate(); +} + +} + +#endif diff --git a/qt/widget/button.hpp b/qt/widget/button.hpp new file mode 100644 index 0000000..2cc25b0 --- /dev/null +++ b/qt/widget/button.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_Button) + +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; + + QtButton* qtButton = nullptr; +}; + +} + +#endif diff --git a/qt/widget/canvas.cpp b/qt/widget/canvas.cpp new file mode 100644 index 0000000..fff7fa1 --- /dev/null +++ b/qt/widget/canvas.cpp @@ -0,0 +1,160 @@ +#if defined(Hiro_Canvas) + +namespace hiro { + +auto pCanvas::construct() -> void { + qtWidget = qtCanvas = new QtCanvas(*this); + qtCanvas->setMouseTracking(true); + + pWidget::construct(); + _rasterize(); + qtCanvas->update(); +} + +auto pCanvas::destruct() -> void { + _release(); + delete qtCanvas; + qtWidget = qtCanvas = nullptr; +} + +auto pCanvas::minimumSize() const -> Size { + if(auto& icon = state().icon) return {(int)icon.width(), (int)icon.height()}; + return {0, 0}; +} + +auto pCanvas::setColor(Color color) -> void { + update(); +} + +auto pCanvas::setDroppable(bool droppable) -> void { + qtCanvas->setAcceptDrops(droppable); +} + +auto pCanvas::setGeometry(Geometry geometry) -> void { + update(); + pWidget::setGeometry(geometry); +} + +auto pCanvas::setGradient(Gradient gradient) -> void { + update(); +} + +auto pCanvas::setIcon(const image& icon) -> void { + update(); +} + +auto pCanvas::update() -> void { + _rasterize(); + qtCanvas->update(); +} + +auto pCanvas::_rasterize() -> void { + int width = 0; + int height = 0; + + if(auto& icon = state().icon) { + width = icon.width(); + height = icon.height(); + } else { + width = pSizable::state().geometry.width(); + height = pSizable::state().geometry.height(); + } + if(width <= 0 || height <= 0) return; + + if(width != qtImageWidth || height != qtImageHeight) _release(); + qtImageWidth = width; + qtImageHeight = height; + + if(!qtImage) qtImage = new QImage(width, height, QImage::Format_ARGB32); + auto buffer = (uint32*)qtImage->bits(); + + if(auto& icon = state().icon) { + memory::copy(buffer, state().icon.data(), width * height * sizeof(uint32)); + } else if(auto& gradient = state().gradient) { + auto& colors = gradient.state.colors; + image fill; + fill.allocate(width, height); + fill.gradient(colors[0].value(), colors[1].value(), colors[2].value(), colors[3].value()); + memory::copy(buffer, fill.data(), fill.size()); + } else { + uint32 color = state().color.value(); + for(auto n : range(width * height)) buffer[n] = color; + } +} + +auto pCanvas::_release() -> void { + if(qtImage) { + delete qtImage; + qtImage = nullptr; + } + qtImageWidth = 0; + qtImageHeight = 0; +} + +auto QtCanvas::dragEnterEvent(QDragEnterEvent* event) -> void { + if(event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + } +} + +auto QtCanvas::dropEvent(QDropEvent* event) -> void { + if(auto paths = DropPaths(event)) p.self().doDrop(paths); +} + +auto QtCanvas::leaveEvent(QEvent* event) -> void { + p.self().doMouseLeave(); +} + +auto QtCanvas::mouseMoveEvent(QMouseEvent* event) -> void { + p.self().doMouseMove({event->pos().x(), event->pos().y()}); +} + +auto QtCanvas::mousePressEvent(QMouseEvent* event) -> void { + switch(event->button()) { + case Qt::LeftButton: p.self().doMousePress(Mouse::Button::Left); break; + case Qt::MidButton: p.self().doMousePress(Mouse::Button::Middle); break; + case Qt::RightButton: p.self().doMousePress(Mouse::Button::Right); break; + } +} + +auto QtCanvas::mouseReleaseEvent(QMouseEvent* event) -> void { + switch(event->button()) { + case Qt::LeftButton: p.self().doMouseRelease(Mouse::Button::Left); break; + case Qt::MidButton: p.self().doMouseRelease(Mouse::Button::Middle); break; + case Qt::RightButton: p.self().doMouseRelease(Mouse::Button::Right); break; + } +} + +auto QtCanvas::paintEvent(QPaintEvent* event) -> void { + if(!p.qtImage) return; + + signed sx = 0, sy = 0, dx = 0, dy = 0; + signed width = p.qtImageWidth; + signed height = p.qtImageHeight; + auto geometry = p.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(); + } + + QPainter painter(p.qtCanvas); + painter.drawImage(dx, dy, *p.qtImage, sx, sy, width, height); +} + +} + +#endif diff --git a/qt/widget/canvas.hpp b/qt/widget/canvas.hpp new file mode 100644 index 0000000..347d907 --- /dev/null +++ b/qt/widget/canvas.hpp @@ -0,0 +1,27 @@ +#if defined(Hiro_Canvas) + +namespace hiro { + +struct pCanvas : pWidget { + Declare(Canvas, Widget) + + auto minimumSize() const -> Size; + auto setColor(Color color) -> void; + auto setDroppable(bool droppable) -> void; + auto setGeometry(Geometry geometry) -> void; + auto setGradient(Gradient gradient) -> void; + auto setIcon(const image& icon) -> void; + auto update() -> void; + + auto _rasterize() -> void; + auto _release() -> void; + + QtCanvas* qtCanvas = nullptr; + QImage* qtImage = nullptr; + unsigned qtImageWidth = 0; + unsigned qtImageHeight = 0; +}; + +} + +#endif diff --git a/qt/widget/check-button.cpp b/qt/widget/check-button.cpp new file mode 100644 index 0000000..6c4e87b --- /dev/null +++ b/qt/widget/check-button.cpp @@ -0,0 +1,78 @@ +#if defined(Hiro_CheckButton) + +namespace hiro { + +auto pCheckButton::construct() -> void { + qtWidget = qtCheckButton = new QtCheckButton(*this); + qtCheckButton->setCheckable(true); + qtCheckButton->setToolButtonStyle(Qt::ToolButtonTextOnly); + qtCheckButton->connect(qtCheckButton, SIGNAL(toggled(bool)), SLOT(onToggle(bool))); + + pWidget::construct(); + _setState(); +} + +auto pCheckButton::destruct() -> void { + delete qtCheckButton; + qtCheckButton = nullptr; +} + +auto pCheckButton::minimumSize() const -> Size { + auto size = pFont::size(qtWidget->font(), 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() + 20, size.height() + 12}; +} + +auto pCheckButton::setBordered(bool bordered) -> void { + _setState(); +} + +auto pCheckButton::setChecked(bool checked) -> void { + _setState(); +} + +auto pCheckButton::setIcon(const image& icon) -> void { + _setState(); +} + +auto pCheckButton::setOrientation(Orientation orientation) -> void { + _setState(); +} + +auto pCheckButton::setText(const string& text) -> void { + _setState(); +} + +auto pCheckButton::_setState() -> void { + lock(); + qtCheckButton->setAutoRaise(!state().bordered); + qtCheckButton->setChecked(state().checked); + qtCheckButton->setIconSize(QSize(state().icon.width(), state().icon.height())); + qtCheckButton->setIcon(CreateIcon(state().icon)); + qtCheckButton->setStyleSheet("text-align: top;"); + switch(state().orientation) { + case Orientation::Horizontal: qtCheckButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); break; + case Orientation::Vertical: qtCheckButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); break; + } + qtCheckButton->setText(QString::fromUtf8(state().text)); + unlock(); +} + +auto QtCheckButton::onToggle(bool checked) -> void { + p.state().checked = checked; + if(!p.locked()) p.self().doToggle(); +} + +} + +#endif diff --git a/qt/widget/check-button.hpp b/qt/widget/check-button.hpp new file mode 100644 index 0000000..092c802 --- /dev/null +++ b/qt/widget/check-button.hpp @@ -0,0 +1,22 @@ +#if defined(Hiro_CheckButton) + +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; + + auto _setState() -> void; + + QtCheckButton* qtCheckButton = nullptr; +}; + +} + +#endif diff --git a/qt/widget/check-label.cpp b/qt/widget/check-label.cpp new file mode 100644 index 0000000..d5b9de2 --- /dev/null +++ b/qt/widget/check-label.cpp @@ -0,0 +1,45 @@ +#if defined(Hiro_CheckLabel) + +namespace hiro { + +auto pCheckLabel::construct() -> void { + qtWidget = qtCheckLabel = new QtCheckLabel(*this); + qtCheckLabel->connect(qtCheckLabel, SIGNAL(stateChanged(int)), SLOT(onToggle())); + + pWidget::construct(); + _setState(); +} + +auto pCheckLabel::destruct() -> void { + delete qtCheckLabel; + qtWidget = qtCheckLabel = nullptr; +} + +auto pCheckLabel::minimumSize() const -> Size { + auto size = pFont::size(qtWidget->font(), state().text); + return {size.width() + 26, size.height() + 6}; +} + +auto pCheckLabel::setChecked(bool checked) -> void { + _setState(); +} + +auto pCheckLabel::setText(const string& text) -> void { + _setState(); +} + +auto pCheckLabel::_setState() -> void { + lock(); + qtCheckLabel->setChecked(state().checked); + qtCheckLabel->setText(QString::fromUtf8(state().text)); + unlock(); +} + +auto QtCheckLabel::onToggle() -> void { + p.state().checked = p.qtCheckLabel->isChecked(); + if(!p.locked()) p.self().doToggle(); +} + +} + +#endif diff --git a/qt/widget/check-label.hpp b/qt/widget/check-label.hpp new file mode 100644 index 0000000..7bd53ab --- /dev/null +++ b/qt/widget/check-label.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_CheckLabel) + +namespace hiro { + +struct pCheckLabel : pWidget { + Declare(CheckLabel, Widget) + + auto minimumSize() const -> Size override; + auto setChecked(bool checked) -> void; + auto setText(const string& text) -> void; + + auto _setState() -> void; + + QtCheckLabel* qtCheckLabel = nullptr; +}; + +} + +#endif diff --git a/qt/widget/combo-button-item.cpp b/qt/widget/combo-button-item.cpp new file mode 100644 index 0000000..a38266a --- /dev/null +++ b/qt/widget/combo-button-item.cpp @@ -0,0 +1,51 @@ +#if defined(Hiro_ComboButton) + +namespace hiro { + +auto pComboButtonItem::construct() -> void { + if(auto parent = _parent()) { + parent->lock(); + parent->qtComboButton->addItem(""); + _setState(); + parent->unlock(); + } +} + +auto pComboButtonItem::destruct() -> void { + if(auto parent = _parent()) { + parent->lock(); + parent->qtComboButton->removeItem(self().offset()); + parent->unlock(); + } +} + +auto pComboButtonItem::setIcon(const image& icon) -> void { + _setState(); +} + +auto pComboButtonItem::setSelected() -> void { + _setState(); +} + +auto pComboButtonItem::setText(const string& text) -> void { + _setState(); +} + +auto pComboButtonItem::_parent() -> maybe { + if(auto parent = self().parentComboButton()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pComboButtonItem::_setState() -> void { + if(auto parent = _parent()) { + parent->qtComboButton->setItemIcon(self().offset(), CreateIcon(state().icon)); + if(state().selected) parent->qtComboButton->setCurrentIndex(self().offset()); + parent->qtComboButton->setItemText(self().offset(), QString::fromUtf8(state().text)); + } +} + +} + +#endif diff --git a/qt/widget/combo-button-item.hpp b/qt/widget/combo-button-item.hpp new file mode 100644 index 0000000..11e65a4 --- /dev/null +++ b/qt/widget/combo-button-item.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_ComboButton) + +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() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/qt/widget/combo-button.cpp b/qt/widget/combo-button.cpp new file mode 100644 index 0000000..88b75f3 --- /dev/null +++ b/qt/widget/combo-button.cpp @@ -0,0 +1,50 @@ +#if defined(Hiro_ComboButton) + +namespace hiro { + +auto pComboButton::construct() -> void { + qtWidget = qtComboButton = new QtComboButton(*this); + qtComboButton->connect(qtComboButton, SIGNAL(currentIndexChanged(int)), SLOT(onChange(int))); + + pWidget::construct(); +} + +auto pComboButton::destruct() -> void { + delete qtComboButton; + qtWidget = qtComboButton = nullptr; +} + +auto pComboButton::append(sComboButtonItem item) -> void { +} + +auto pComboButton::minimumSize() const -> Size { + signed maximumWidth = 0; + for(auto& item : state().items) { + maximumWidth = max(maximumWidth, pFont::size(qtWidget->font(), item->state.text).width()); + } + auto size = pFont::size(qtWidget->font(), " "); + return {maximumWidth + 32, size.height() + 12}; +} + +auto pComboButton::remove(sComboButtonItem item) -> void { +} + +auto pComboButton::reset() -> void { + lock(); + while(qtComboButton->count()) qtComboButton->removeItem(0); + unlock(); +} + +auto QtComboButton::onChange(int offset) -> void { + for(auto& item : p.state().items) { + item->state.selected = false; + } + if(auto item = p.self().item(offset)) { + item->state.selected = true; + } + if(!p.locked()) p.self().doChange(); +} + +} + +#endif diff --git a/qt/widget/combo-button.hpp b/qt/widget/combo-button.hpp new file mode 100644 index 0000000..e1cb035 --- /dev/null +++ b/qt/widget/combo-button.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_ComboButton) + +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; + + QtComboButton* qtComboButton = nullptr; +}; + +} + +#endif diff --git a/qt/widget/console.cpp b/qt/widget/console.cpp new file mode 100644 index 0000000..cbce951 --- /dev/null +++ b/qt/widget/console.cpp @@ -0,0 +1,56 @@ +#if defined(Hiro_Console) + +namespace hiro { + +void pConsole::print(string text) { +} + +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) { +} + +void pConsole::constructor() { + qtWidget = qtConsole = new QtConsole(*this); + + pWidget::synchronizeState(); +} + +void pConsole::destructor() { + delete qtConsole; + qtWidget = qtConsole = nullptr; +} + +void pConsole::orphan() { + destructor(); + constructor(); +} + +void pConsole::keyPressEvent(QKeyEvent* event) { +} + +void pConsole::QtConsole::keyPressEvent(QKeyEvent* event) { + self.keyPressEvent(event); +} + +void pConsole::QtConsole::keyPressEventAcknowledge(QKeyEvent* event) { + QTextEdit::keyPressEvent(event); +} + +} + +#endif diff --git a/qt/widget/frame.cpp b/qt/widget/frame.cpp new file mode 100644 index 0000000..2ffd807 --- /dev/null +++ b/qt/widget/frame.cpp @@ -0,0 +1,64 @@ +#if defined(Hiro_Frame) + +namespace hiro { + +auto pFrame::construct() -> void { + qtWidget = qtFrame = new QGroupBox; + if(QApplication::style()->objectName() == "gtk+") { + //QGtkStyle (gtk+) theme disrespects font weight and omits the border, even if native GTK+ theme does not + //bold Label controls already exist; so this style sheet forces QGtkStyle to look like a Frame instead + qtFrame->setStyleSheet( + "QGroupBox { border: 1px solid #aaa; border-radius: 5px; margin-top: 0.5em; }\n" + "QGroupBox::title { left: 5px; subcontrol-origin: margin; }\n" + ); + } + + pWidget::construct(); + _setState(); +} + +auto pFrame::destruct() -> void { + delete qtFrame; + qtWidget = qtFrame = nullptr; +} + +auto pFrame::append(sLayout layout) -> void { +} + +auto pFrame::remove(sLayout layout) -> void { +} + +auto pFrame::setEnabled(bool enabled) -> void { + if(auto layout = state().layout) layout->setEnabled(layout->enabled(true)); + pWidget::setEnabled(enabled); +} + +auto pFrame::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + if(auto layout = state().layout) { + auto size = pFont::size(qtFrame->font(), state().text); + if(!state().text) size.setHeight(8); + layout->setGeometry({ + 4, size.height(), + geometry.width() - 8, + geometry.height() - size.height() - 4 + }); + } +} + +auto pFrame::setText(const string& text) -> void { + _setState(); +} + +auto pFrame::setVisible(bool visible) -> void { + if(auto layout = state().layout) layout->setVisible(layout->visible(true)); + pWidget::setVisible(visible); +} + +auto pFrame::_setState() -> void { + qtFrame->setTitle(QString::fromUtf8(state().text)); +} + +} + +#endif diff --git a/qt/widget/frame.hpp b/qt/widget/frame.hpp new file mode 100644 index 0000000..b58e304 --- /dev/null +++ b/qt/widget/frame.hpp @@ -0,0 +1,22 @@ +#if defined(Hiro_Frame) + +namespace hiro { + +struct pFrame : pWidget { + Declare(Frame, Widget) + + auto append(sLayout layout) -> void; + auto remove(sLayout layout) -> void; + auto setEnabled(bool enabled) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _setState() -> void; + + QGroupBox* qtFrame = nullptr; +}; + +} + +#endif diff --git a/qt/widget/hex-edit.cpp b/qt/widget/hex-edit.cpp new file mode 100644 index 0000000..a410a69 --- /dev/null +++ b/qt/widget/hex-edit.cpp @@ -0,0 +1,307 @@ +#if defined(Hiro_HexEdit) + +namespace hiro { + +auto pHexEdit::construct() -> void { + qtWidget = qtHexEdit = new QtHexEdit(*this); + + qtHexEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + qtHexEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + qtHexEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse); + + qtLayout = new QHBoxLayout; + qtLayout->setAlignment(Qt::AlignRight); + qtLayout->setMargin(0); + qtLayout->setSpacing(0); + qtHexEdit->setLayout(qtLayout); + + qtScrollBar = new QtHexEditScrollBar(*this); + qtScrollBar->setSingleStep(1); + qtLayout->addWidget(qtScrollBar); + + qtScrollBar->connect(qtScrollBar, SIGNAL(actionTriggered(int)), SLOT(onScroll())); + + pWidget::construct(); + _setState(); +} + +auto pHexEdit::destruct() -> void { + delete qtScrollBar; + delete qtLayout; + delete qtHexEdit; + qtWidget = qtHexEdit = nullptr; + qtLayout = nullptr; + qtScrollBar = nullptr; +} + +auto pHexEdit::setAddress(unsigned address) -> void { + _setState(); +} + +auto pHexEdit::setBackgroundColor(Color color) -> void { + _setState(); +} + +auto pHexEdit::setColumns(unsigned columns) -> void { + _setState(); +} + +auto pHexEdit::setForegroundColor(Color color) -> void { + _setState(); +} + +auto pHexEdit::setLength(unsigned length) -> void { + _setState(); +} + +auto pHexEdit::setRows(unsigned rows) -> void { + _setState(); +} + +auto pHexEdit::update() -> void { + if(!state().onRead) { + qtHexEdit->setPlainText(""); + return; + } + + unsigned cursorPosition = qtHexEdit->textCursor().position(); + + string output; + unsigned address = state().address; + for(unsigned row = 0; row < state().rows; row++) { + output.append(hex(address, 8L)); + output.append(" "); + + string hexdata; + string ansidata = " "; + + for(unsigned column = 0; column < state().columns; column++) { + if(address < state().length) { + uint8_t data = self().doRead(address++); + hexdata.append(hex(data, 2L)); + hexdata.append(" "); + ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.'); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(address >= state().length) break; + if(row != state().rows - 1) output.append("\n"); + } + + qtHexEdit->setPlainText(QString::fromUtf8(output)); + QTextCursor cursor = qtHexEdit->textCursor(); + cursor.setPosition(cursorPosition); + qtHexEdit->setTextCursor(cursor); +} + +auto pHexEdit::_keyPressEvent(QKeyEvent* event) -> void { + if(!state().onRead) return; + + //allow Ctrl+C (copy) + if(event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier) { + qtHexEdit->keyPressEventAcknowledge(event); + return; + } + + //disallow other text operations (cut, paste, etc) + if(event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) return; + + QTextCursor cursor = qtHexEdit->textCursor(); + signed lineWidth = 10 + (state().columns * 3) + 1 + state().columns + 1; + signed cursorY = cursor.position() / lineWidth; + signed cursorX = cursor.position() % lineWidth; + + unsigned nibble = 0; + switch(event->key()) { + default: return; + + case Qt::Key_Left: + if(cursorX > 0) { + cursor.setPosition(cursor.position() - 1); + qtHexEdit->setTextCursor(cursor); + } + return; + + case Qt::Key_Right: + if(cursorX < lineWidth - 1) { + cursor.setPosition(cursor.position() + 1); + qtHexEdit->setTextCursor(cursor); + } + return; + + case Qt::Key_Home: + cursor.setPosition(cursorY * lineWidth + 10); + qtHexEdit->setTextCursor(cursor); + return; + + case Qt::Key_End: + cursor.setPosition(cursorY * lineWidth + 57); + qtHexEdit->setTextCursor(cursor); + return; + + case Qt::Key_Up: + if(cursorY > 0) { + cursor.setPosition(cursor.position() - lineWidth); + qtHexEdit->setTextCursor(cursor); + } else { + _scrollTo(qtScrollBar->sliderPosition() - 1); + } + return; + + case Qt::Key_Down: + if(cursorY >= _rows() - 1) { + //cannot scroll down further + } else if(cursorY < state().rows - 1) { + cursor.setPosition(cursor.position() + lineWidth); + qtHexEdit->setTextCursor(cursor); + } else { + _scrollTo(qtScrollBar->sliderPosition() + 1); + } + return; + + case Qt::Key_PageUp: + _scrollTo(qtScrollBar->sliderPosition() - state().rows); + return; + + case Qt::Key_PageDown: + _scrollTo(qtScrollBar->sliderPosition() + state().rows); + return; + + case Qt::Key_0: nibble = 0; break; + case Qt::Key_1: nibble = 1; break; + case Qt::Key_2: nibble = 2; break; + case Qt::Key_3: nibble = 3; break; + case Qt::Key_4: nibble = 4; break; + case Qt::Key_5: nibble = 5; break; + case Qt::Key_6: nibble = 6; break; + case Qt::Key_7: nibble = 7; break; + case Qt::Key_8: nibble = 8; break; + case Qt::Key_9: nibble = 9; break; + case Qt::Key_A: nibble = 10; break; + case Qt::Key_B: nibble = 11; break; + case Qt::Key_C: nibble = 12; break; + case Qt::Key_D: nibble = 13; break; + case Qt::Key_E: nibble = 14; break; + case Qt::Key_F: nibble = 15; break; + } + + if(cursorX >= 10) { + //not on an offset + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < state().columns) { + //not in ANSI region + unsigned address = state().address + (cursorY * state().columns + cursorX); + + if(address >= state().length) return; //do not edit past end of file + uint8_t data = self().doRead(address); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (nibble << 0); + } else { + data = (data & 0x0f) | (nibble << 4); + } + self().doWrite(address, data); + + //auto-advance cursor to next nibble/byte + unsigned step = 1; + if(cursorNibble && cursorX != state().columns - 1) step = 2; + cursor.setPosition(cursor.position() + step); + qtHexEdit->setTextCursor(cursor); + + //refresh output to reflect modified data + update(); + } + } + } +} + +//number of actual rows +auto pHexEdit::_rows() -> signed { + return (max(1u, state().length) + state().columns - 1) / state().columns; +} + +//number of scrollable row positions +auto pHexEdit::_rowsScrollable() -> signed { + return max(0u, _rows() - state().rows); +} + +auto pHexEdit::_scrollTo(signed position) -> void { + if(position > _rowsScrollable()) position = _rowsScrollable(); + if(position < 0) position = 0; + qtScrollBar->setSliderPosition(position); +} + +auto pHexEdit::_setState() -> void { + lock(); + if(auto color = state().backgroundColor) { + QPalette palette = qtHexEdit->palette(); + palette.setColor(QPalette::Base, QColor(color.red(), color.green(), color.blue())); + qtHexEdit->setPalette(palette); + qtHexEdit->setAutoFillBackground(true); + } else { + //todo + } + if(auto color = state().foregroundColor) { + QPalette palette = qtHexEdit->palette(); + palette.setColor(QPalette::Text, QColor(color.red(), color.green(), color.blue())); + qtHexEdit->setPalette(palette); + } else { + //todo + } + //add one if last row is not equal to column length (eg only part of the row is present) + bool indivisible = state().columns == 0 || (state().length % state().columns) != 0; + qtScrollBar->setRange(0, state().length / state().columns + indivisible - state().rows); + qtScrollBar->setSliderPosition(state().address / state().columns); + qtScrollBar->setPageStep(state().rows); + update(); + unlock(); +} + +auto QtHexEdit::keyPressEvent(QKeyEvent* event) -> void { + p._keyPressEvent(event); +} + +auto QtHexEdit::keyPressEventAcknowledge(QKeyEvent* event) -> void { + QTextEdit::keyPressEvent(event); +} + +auto QtHexEdit::wheelEvent(QWheelEvent* event) -> void { + if(event->orientation() == Qt::Vertical) { + signed offset = event->delta() < 0 ? +1 : -1; + p._scrollTo(p.qtScrollBar->sliderPosition() + offset); + event->accept(); + } +} + +auto QtHexEditScrollBar::event(QEvent* event) -> bool { + if(event->type() == QEvent::Wheel) { + auto wheelEvent = (QWheelEvent*)event; + if(wheelEvent->orientation() == Qt::Vertical) { + signed offset = wheelEvent->delta() < 0 ? +1 : -1; + p._scrollTo(sliderPosition() + offset); + return true; + } + } + return QScrollBar::event(event); +} + +auto QtHexEditScrollBar::onScroll() -> void { + if(p.locked()) return; + unsigned address = sliderPosition(); + p.state().address = address * p.state().columns; + p.update(); +} + +} + +#endif diff --git a/qt/widget/hex-edit.hpp b/qt/widget/hex-edit.hpp new file mode 100644 index 0000000..3718a84 --- /dev/null +++ b/qt/widget/hex-edit.hpp @@ -0,0 +1,29 @@ +#if defined(Hiro_HexEdit) + +namespace hiro { + +struct pHexEdit : pWidget { + Declare(HexEdit, Widget) + + auto setAddress(unsigned address) -> void; + auto setBackgroundColor(Color color) -> void; + auto setColumns(unsigned columns) -> void; + auto setForegroundColor(Color color) -> void; + auto setLength(unsigned length) -> void; + auto setRows(unsigned rows) -> void; + auto update() -> void; + + auto _keyPressEvent(QKeyEvent*) -> void; + auto _rows() -> signed; + auto _rowsScrollable() -> signed; + auto _scrollTo(signed position) -> void; + auto _setState() -> void; + + QtHexEdit* qtHexEdit = nullptr; + QHBoxLayout* qtLayout = nullptr; + QtHexEditScrollBar* qtScrollBar = nullptr; +}; + +} + +#endif diff --git a/qt/widget/horizontal-scroll-bar.cpp b/qt/widget/horizontal-scroll-bar.cpp new file mode 100644 index 0000000..284e79e --- /dev/null +++ b/qt/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,46 @@ +#if defined(Hiro_HorizontalScrollBar) + +namespace hiro { + +auto pHorizontalScrollBar::construct() -> void { + qtWidget = qtHorizontalScrollBar = new QtHorizontalScrollBar(*this); + qtHorizontalScrollBar->setRange(0, 100); + qtHorizontalScrollBar->setPageStep(101 >> 3); + qtHorizontalScrollBar->connect(qtHorizontalScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::construct(); + _setState(); +} + +auto pHorizontalScrollBar::destruct() -> void { + delete qtHorizontalScrollBar; + qtWidget = qtHorizontalScrollBar = nullptr; +} + +auto pHorizontalScrollBar::minimumSize() const -> Size { + return {0, 15}; +} + +auto pHorizontalScrollBar::setLength(unsigned length) -> void { + _setState(); +} + +auto pHorizontalScrollBar::setPosition(unsigned position) -> void { + _setState(); +} + +auto pHorizontalScrollBar::_setState() -> void { + signed length = state().length + (state().length == 0); + qtHorizontalScrollBar->setRange(0, length - 1); + qtHorizontalScrollBar->setPageStep(length >> 3); + qtHorizontalScrollBar->setValue(state().position); +} + +auto QtHorizontalScrollBar::onChange() -> void { + p.state().position = value(); + p.self().doChange(); +} + +} + +#endif diff --git a/qt/widget/horizontal-scroll-bar.hpp b/qt/widget/horizontal-scroll-bar.hpp new file mode 100644 index 0000000..f8766f0 --- /dev/null +++ b/qt/widget/horizontal-scroll-bar.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_HorizontalScrollBar) + +namespace hiro { + +struct pHorizontalScrollBar : pWidget { + Declare(HorizontalScrollBar, Widget) + + auto minimumSize() const -> Size override; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; + + auto _setState() -> void; + + QtHorizontalScrollBar* qtHorizontalScrollBar = nullptr; +}; + +} + +#endif diff --git a/qt/widget/horizontal-slider.cpp b/qt/widget/horizontal-slider.cpp new file mode 100644 index 0000000..672a042 --- /dev/null +++ b/qt/widget/horizontal-slider.cpp @@ -0,0 +1,46 @@ +#if defined(Hiro_HorizontalSlider) + +namespace hiro { + +auto pHorizontalSlider::minimumSize() const -> Size { + return {0, 20}; +} + +auto pHorizontalSlider::setLength(unsigned length) -> void { + _setState(); +} + +auto pHorizontalSlider::setPosition(unsigned position) -> void { + _setState(); +} + +auto pHorizontalSlider::construct() -> void { + qtWidget = qtHorizontalSlider = new QtHorizontalSlider(*this); + qtHorizontalSlider->setRange(0, 100); + qtHorizontalSlider->setPageStep(101 >> 3); + qtHorizontalSlider->connect(qtHorizontalSlider, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::construct(); + _setState(); +} + +auto pHorizontalSlider::destruct() -> void { + delete qtHorizontalSlider; + qtWidget = qtHorizontalSlider = nullptr; +} + +auto pHorizontalSlider::_setState() -> void { + signed length = state().length + (state().length == 0); + qtHorizontalSlider->setRange(0, length - 1); + qtHorizontalSlider->setPageStep(length >> 3); + qtHorizontalSlider->setValue(state().position); +} + +auto QtHorizontalSlider::onChange() -> void { + p.state().position = value(); + p.self().doChange(); +} + +} + +#endif diff --git a/qt/widget/horizontal-slider.hpp b/qt/widget/horizontal-slider.hpp new file mode 100644 index 0000000..e1dea2f --- /dev/null +++ b/qt/widget/horizontal-slider.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_HorizontalSlider) + +namespace hiro { + +struct pHorizontalSlider : pWidget { + Declare(HorizontalSlider, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; + + auto _setState() -> void; + + QtHorizontalSlider* qtHorizontalSlider = nullptr; +}; + +} + +#endif diff --git a/qt/widget/icon-view.cpp b/qt/widget/icon-view.cpp new file mode 100644 index 0000000..773669a --- /dev/null +++ b/qt/widget/icon-view.cpp @@ -0,0 +1,152 @@ +#if defined(Hiro_IconView) + +namespace hiro { + +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); +} + +} + +#endif diff --git a/qt/widget/label.cpp b/qt/widget/label.cpp new file mode 100644 index 0000000..efc52ae --- /dev/null +++ b/qt/widget/label.cpp @@ -0,0 +1,35 @@ +#if defined(Hiro_Label) + +namespace hiro { + +auto pLabel::construct() -> void { + qtWidget = qtLabel = new QLabel; + + setAlignment(state().alignment); + setText(state().text); + + pWidget::construct(); +} + +auto pLabel::destruct() -> void { + delete qtLabel; + qtWidget = qtLabel = nullptr; +} + +auto pLabel::minimumSize() const -> Size { + auto size = pFont::size(qtWidget->font(), state().text); + return {size.width(), size.height()}; +} + +auto pLabel::setAlignment(Alignment alignment) -> void { + if(!alignment) alignment = {0.0, 0.5}; + qtLabel->setAlignment((Qt::Alignment)CalculateAlignment(alignment)); +} + +auto pLabel::setText(const string& text) -> void { + qtLabel->setText(QString::fromUtf8(text)); +} + +} + +#endif diff --git a/qt/widget/label.hpp b/qt/widget/label.hpp new file mode 100644 index 0000000..7cd3656 --- /dev/null +++ b/qt/widget/label.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_Label) + +namespace hiro { + +struct pLabel : pWidget { + Declare(Label, Widget) + + auto minimumSize() const -> Size override; + auto setAlignment(Alignment alignment) -> void; + auto setText(const string& text) -> void; + + QLabel* qtLabel = nullptr; +}; + +} + +#endif diff --git a/qt/widget/line-edit.cpp b/qt/widget/line-edit.cpp new file mode 100644 index 0000000..55a01b0 --- /dev/null +++ b/qt/widget/line-edit.cpp @@ -0,0 +1,71 @@ +#if defined(Hiro_LineEdit) + +namespace hiro { + +auto pLineEdit::construct() -> void { + qtWidget = qtLineEdit = new QtLineEdit(*this); + qtLineEdit->connect(qtLineEdit, SIGNAL(returnPressed()), SLOT(onActivate())); + qtLineEdit->connect(qtLineEdit, SIGNAL(textEdited(const QString&)), SLOT(onChange())); + + pWidget::construct(); + _setState(); +} + +auto pLineEdit::destruct() -> void { + delete qtLineEdit; + qtWidget = qtLineEdit = nullptr; +} + +auto pLineEdit::minimumSize() const -> Size { + auto size = pFont::size(qtWidget->font(), state().text); + return {size.width() + 12, size.height() + 12}; +} + +auto pLineEdit::setBackgroundColor(Color color) -> void { + _setState(); +} + +auto pLineEdit::setEditable(bool editable) -> void { + _setState(); +} + +auto pLineEdit::setForegroundColor(Color color) -> void { + _setState(); +} + +auto pLineEdit::setText(const string& text) -> void { + _setState(); +} + +auto pLineEdit::_setState() -> void { + if(auto color = state().backgroundColor) { + QPalette palette = qtLineEdit->palette(); + palette.setColor(QPalette::Base, QColor(color.red(), color.green(), color.blue())); + qtLineEdit->setPalette(palette); + qtLineEdit->setAutoFillBackground(true); + } else { + //todo + } + qtLineEdit->setReadOnly(!state().editable); + if(auto color = state().foregroundColor) { + QPalette palette = qtLineEdit->palette(); + palette.setColor(QPalette::Text, QColor(color.red(), color.green(), color.blue())); + qtLineEdit->setPalette(palette); + } else { + //todo + } + qtLineEdit->setText(QString::fromUtf8(state().text)); +} + +auto QtLineEdit::onActivate() -> void { + p.self().doActivate(); +} + +auto QtLineEdit::onChange() -> void { + p.state().text = text().toUtf8().constData(); + p.self().doChange(); +} + +} + +#endif diff --git a/qt/widget/line-edit.hpp b/qt/widget/line-edit.hpp new file mode 100644 index 0000000..b229a04 --- /dev/null +++ b/qt/widget/line-edit.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_LineEdit) + +namespace hiro { + +struct pLineEdit : pWidget { + Declare(LineEdit, Widget) + + auto minimumSize() const -> Size override; + auto setBackgroundColor(Color color) -> void; + auto setEditable(bool editable) -> void; + auto setForegroundColor(Color color) -> void; + auto setText(const string& text) -> void; + + auto _setState() -> void; + + QtLineEdit* qtLineEdit = nullptr; +}; + +} + +#endif diff --git a/qt/widget/list-view-cell.cpp b/qt/widget/list-view-cell.cpp new file mode 100644 index 0000000..6469ca6 --- /dev/null +++ b/qt/widget/list-view-cell.cpp @@ -0,0 +1,73 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewCell::construct() -> void { +} + +auto pListViewCell::destruct() -> void { +} + +auto pListViewCell::setAlignment(Alignment alignment) -> void { + _setState(); +} + +auto pListViewCell::setBackgroundColor(Color color) -> void { + _setState(); +} + +auto pListViewCell::setCheckable(bool checkable) -> void { + _setState(); +} + +auto pListViewCell::setChecked(bool checked) -> void { + _setState(); +} + +auto pListViewCell::setFont(const string& font) -> void { + _setState(); +} + +auto pListViewCell::setForegroundColor(Color color) -> void { + _setState(); +} + +auto pListViewCell::setIcon(const image& icon) -> void { + _setState(); +} + +auto pListViewCell::setText(const string& text) -> void { + _setState(); +} + +auto pListViewCell::_parent() -> maybe { + if(auto parent = self().parentListViewItem()) { + if(auto delegate = parent->self()) return *delegate; + } + return nothing; +} + +auto pListViewCell::_setState() -> void { + if(auto parent = _parent()) { + if(auto grandparent = parent->_parent()) { + grandparent->lock(); + parent->qtItem->setBackground(self().offset(), CreateBrush(self().backgroundColor(true))); + if(state().checkable) { + parent->qtItem->setCheckState(self().offset(), state().checked ? Qt::Checked : Qt::Unchecked); + } else { + //extremely unintuitive; but this is the only way to remove an existing checkbox from a cell + parent->qtItem->setData(self().offset(), Qt::CheckStateRole, QVariant()); + } + parent->qtItem->setFont(self().offset(), pFont::create(self().font(true))); + parent->qtItem->setForeground(self().offset(), CreateBrush(self().foregroundColor(true))); + parent->qtItem->setIcon(self().offset(), CreateIcon(state().icon)); + parent->qtItem->setText(self().offset(), QString::fromUtf8(state().text)); + parent->qtItem->setTextAlignment(self().offset(), CalculateAlignment(self().alignment(true))); + grandparent->unlock(); + } + } +} + +} + +#endif diff --git a/qt/widget/list-view-cell.hpp b/qt/widget/list-view-cell.hpp new file mode 100644 index 0000000..4eddcc5 --- /dev/null +++ b/qt/widget/list-view-cell.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewCell : pObject { + Declare(ListViewCell, Object) + + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; + auto setChecked(bool checked) -> void; + auto setFont(const string& font) -> void; + auto setForegroundColor(Color color) -> void; + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + auto _parent() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/qt/widget/list-view-column.cpp b/qt/widget/list-view-column.cpp new file mode 100644 index 0000000..1ba29f2 --- /dev/null +++ b/qt/widget/list-view-column.cpp @@ -0,0 +1,99 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewColumn::construct() -> void { +} + +auto pListViewColumn::destruct() -> void { +} + +auto pListViewColumn::setActive() -> void { + //unsupported +} + +auto pListViewColumn::setAlignment(Alignment alignment) -> void { + _setState(); +} + +auto pListViewColumn::setBackgroundColor(Color color) -> void { + _setState(); +} + +auto pListViewColumn::setEditable(bool editable) -> void { + //unsupported +} + +auto pListViewColumn::setExpandable(bool expandable) -> void { + _setState(); +} + +auto pListViewColumn::setFont(const Font& font) -> void { + _setState(); +} + +auto pListViewColumn::setForegroundColor(Color color) -> void { + _setState(); +} + +auto pListViewColumn::setHorizontalAlignment(double alignment) -> void { + _setState(); +} + +auto pListViewColumn::setIcon(const image& icon) -> void { + //unsupported +} + +auto pListViewColumn::setResizable(bool resizable) -> void { + _setState(); +} + +auto pListViewColumn::setSortable(bool sortable) -> void { + _setState(); +} + +auto pListViewColumn::setText(const string& text) -> void { + _setState(); +} + +auto pListViewColumn::setVerticalAlignment(double alignment) -> void { + _setState(); +} + +auto pListViewColumn::setVisible(bool visible) -> void { + _setState(); +} + +auto pListViewColumn::setWidth(signed width) -> void { + _setState(); +} + +auto pListViewColumn::_parent() -> maybe { + if(auto parent = self().parentListViewHeader()) { + if(auto delegate = parent->self()) return *delegate; + } + return nothing; +} + +auto pListViewColumn::_setState() -> void { + if(auto header = _parent()) { + if(auto parent = header->_parent()) { + parent->qtListView->header()->setResizeMode(self().offset(), state().resizable ? QHeaderView::Interactive : QHeaderView::Fixed); + bool clickable = false; + for(auto& column : header->state().columns) clickable |= column->state.sortable; + parent->qtListView->header()->setClickable(clickable); + parent->qtListView->headerItem()->setText(self().offset(), QString::fromUtf8(state().text)); + parent->qtListView->setColumnHidden(self().offset(), !self().visible()); + + for(auto& item : parent->state().items) { + if(auto cell = item->cell(self().offset())) { + if(auto self = cell->self()) self->_setState(); + } + } + } + } +} + +} + +#endif diff --git a/qt/widget/list-view-column.hpp b/qt/widget/list-view-column.hpp new file mode 100644 index 0000000..f130ea4 --- /dev/null +++ b/qt/widget/list-view-column.hpp @@ -0,0 +1,30 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewColumn : pObject { + Declare(ListViewColumn, Object) + + auto setActive() -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setEditable(bool editable) -> void; + auto setExpandable(bool expandable) -> void; + auto setFont(const Font& 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; + auto setWidth(signed width) -> void; + + auto _parent() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/qt/widget/list-view-header.cpp b/qt/widget/list-view-header.cpp new file mode 100644 index 0000000..ead448a --- /dev/null +++ b/qt/widget/list-view-header.cpp @@ -0,0 +1,43 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewHeader::construct() -> void { +} + +auto pListViewHeader::destruct() -> void { +} + +auto pListViewHeader::append(sListViewColumn column) -> void { + _setState(); +} + +auto pListViewHeader::remove(sListViewColumn column) -> void { + _setState(); +} + +auto pListViewHeader::setVisible(bool visible) -> void { + _setState(); +} + +auto pListViewHeader::_parent() -> maybe { + if(auto parent = self().parentListView()) { + if(auto delegate = parent->self()) return *delegate; + } + return nothing; +} + +auto pListViewHeader::_setState() -> void { + if(auto parent = _parent()) { + //parent->qtListView->setAlternatingRowColors(self().columnCount() >= 2); + parent->qtListView->setColumnCount(self().columnCount()); + parent->qtListView->setHeaderHidden(!self().visible()); + for(auto& column : state().columns) { + if(auto self = column->self()) self->_setState(); + } + } +} + +} + +#endif diff --git a/qt/widget/list-view-header.hpp b/qt/widget/list-view-header.hpp new file mode 100644 index 0000000..a46855b --- /dev/null +++ b/qt/widget/list-view-header.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewHeader : pObject { + Declare(ListViewHeader, Object) + + auto append(sListViewColumn column) -> void; + auto remove(sListViewColumn column) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/qt/widget/list-view-item.cpp b/qt/widget/list-view-item.cpp new file mode 100644 index 0000000..b3e7106 --- /dev/null +++ b/qt/widget/list-view-item.cpp @@ -0,0 +1,64 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewItem::construct() -> void { +} + +auto pListViewItem::destruct() -> void { + if(auto parent = _parent()) parent->lock(); + if(qtItem) { + delete qtItem; + qtItem = nullptr; + } + if(auto parent = _parent()) parent->unlock(); +} + +auto pListViewItem::append(sListViewCell cell) -> void { +} + +auto pListViewItem::remove(sListViewCell cell) -> void { +} + +auto pListViewItem::setAlignment(Alignment alignment) -> void { + _setState(); +} + +auto pListViewItem::setBackgroundColor(Color color) -> void { + _setState(); +} + +auto pListViewItem::setFont(const Font& font) -> void { + _setState(); +} + +auto pListViewItem::setForegroundColor(Color color) -> void { + _setState(); +} + +auto pListViewItem::setSelected(bool selected) -> void { + _setState(); +} + +auto pListViewItem::_parent() -> maybe { + if(auto parent = self().parentListView()) { + if(auto delegate = parent->self()) return *delegate; + } + return nothing; +} + +auto pListViewItem::_setState() -> void { + if(auto parent = _parent()) { + qtItem->setSelected(state().selected); + if(state().selected) { + parent->qtListView->setCurrentItem(qtItem); + } + for(auto& cell : state().cells) { + if(auto self = cell->self()) self->_setState(); + } + } +} + +} + +#endif diff --git a/qt/widget/list-view-item.hpp b/qt/widget/list-view-item.hpp new file mode 100644 index 0000000..eb51d30 --- /dev/null +++ b/qt/widget/list-view-item.hpp @@ -0,0 +1,24 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewItem : pObject { + Declare(ListViewItem, Object) + + auto append(sListViewCell cell) -> void; + auto remove(sListViewCell cell) -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setFont(const Font& font) -> void override; + auto setForegroundColor(Color color) -> void; + auto setSelected(bool selected) -> void; + + auto _parent() -> maybe; + auto _setState() -> void; + + QTreeWidgetItem* qtItem = nullptr; +}; + +} + +#endif diff --git a/qt/widget/list-view.cpp b/qt/widget/list-view.cpp new file mode 100644 index 0000000..3bd27a3 --- /dev/null +++ b/qt/widget/list-view.cpp @@ -0,0 +1,256 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListView::construct() -> void { + qtWidget = qtListView = new QtListView(*this); + qtListView->setAllColumnsShowFocus(true); + qtListView->setContextMenuPolicy(Qt::CustomContextMenu); + qtListView->setRootIsDecorated(false); + qtListView->setHeaderHidden(true); + qtListView->header()->setMovable(false); + + qtListViewDelegate = new QtListViewDelegate(*this); + qtListView->setItemDelegate(qtListViewDelegate); + + qtListView->connect(qtListView, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate())); + qtListView->connect(qtListView, SIGNAL(itemSelectionChanged()), SLOT(onChange())); + qtListView->connect(qtListView, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(onContext())); + qtListView->connect(qtListView->header(), SIGNAL(sectionClicked(int)), SLOT(onSort(int))); + qtListView->connect(qtListView, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onToggle(QTreeWidgetItem*, int))); + + setBackgroundColor(state().backgroundColor); + setBatchable(state().batchable); + setBordered(state().bordered); + setForegroundColor(state().foregroundColor); + + pWidget::construct(); +} + +auto pListView::destruct() -> void { + delete qtListViewDelegate; + delete qtListView; + qtWidget = qtListView = nullptr; + qtListViewDelegate = nullptr; +} + +auto pListView::append(sListViewHeader header) -> void { + lock(); + if(auto self = header->self()) { + self->_setState(); + } + unlock(); +} + +auto pListView::append(sListViewItem item) -> void { + lock(); + if(auto self = item->self()) { + self->qtItem = new QTreeWidgetItem(qtListView); + self->_setState(); + } + unlock(); +} + +auto pListView::remove(sListViewHeader header) -> void { +} + +auto pListView::remove(sListViewItem item) -> void { +} + +auto pListView::resizeColumns() -> void { + lock(); + + if(auto& header = state().header) { + vector widths; + signed minimumWidth = 0; + signed expandable = 0; + for(auto column : range(header->columnCount())) { + signed width = _width(column); + widths.append(width); + minimumWidth += width; + if(header->column(column).expandable()) expandable++; + } + + signed maximumWidth = self().geometry().width() - 6; + if(auto scrollBar = qtListView->verticalScrollBar()) { + if(scrollBar->isVisible()) maximumWidth -= scrollBar->geometry().width(); + } + + signed expandWidth = 0; + if(expandable && maximumWidth > minimumWidth) { + expandWidth = (maximumWidth - minimumWidth) / expandable; + } + + for(auto column : range(header->columnCount())) { + signed width = widths[column]; + if(header->column(column).expandable()) width += expandWidth; + qtListView->setColumnWidth(column, width); + } + } + + unlock(); +} + +auto pListView::setAlignment(Alignment alignment) -> void { +} + +auto pListView::setBackgroundColor(Color color) -> void { + if(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); + } else { + //todo: set default color + } +} + +auto pListView::setBatchable(bool batchable) -> void { + lock(); + qtListView->setSelectionMode(batchable ? QAbstractItemView::ExtendedSelection : QAbstractItemView::SingleSelection); + unlock(); +} + +auto pListView::setBordered(bool bordered) -> void { + qtListView->repaint(); +} + +auto pListView::setForegroundColor(Color color) -> void { + if(color) { + QPalette palette = qtListView->palette(); + palette.setColor(QPalette::Text, QColor(color.red(), color.green(), color.blue())); + qtListView->setPalette(palette); + } else { + //todo: set default color + } +} + +//called on resize/show events +auto pListView::_onSize() -> void { + //resize columns only if at least one column is expandable + if(auto& header = state().header) { + for(auto& column : header->state.columns) { + if(column->expandable()) return resizeColumns(); + } + } +} + +auto pListView::_width(unsigned column) -> unsigned { + if(auto& header = state().header) { + if(auto width = header->column(column).width()) return width; + unsigned width = 1; + if(!header->column(column).visible()) return width; + if(header->visible()) width = max(width, _widthOfColumn(column)); + for(auto row : range(state().items)) { + width = max(width, _widthOfCell(row, column)); + } + return width; + } + return 1; +} + +auto pListView::_widthOfColumn(unsigned _column) -> unsigned { + unsigned width = 8; + if(auto& header = state().header) { + if(auto column = header->column(_column)) { + if(auto& icon = column->state.icon) { + width += icon.width() + 2; + } + if(auto& text = column->state.text) { + width += pFont::size(column->font(true), text).width(); + } + } + } + return width; +} + +auto pListView::_widthOfCell(unsigned _row, unsigned _column) -> unsigned { + unsigned width = 8; + if(auto item = self().item(_row)) { + if(auto cell = item->cell(_column)) { + if(cell->state.checkable) { + width += 16 + 2; + } + if(auto& icon = cell->state.icon) { + width += icon.width() + 2; + } + if(auto& text = cell->state.text) { + width += pFont::size(cell->font(true), text).width(); + } + } + } + return width; +} + +auto QtListView::onActivate() -> void { + if(!p.locked()) p.self().doActivate(); +} + +auto QtListView::onChange() -> void { + for(auto& item : p.state().items) { + item->state.selected = false; + if(auto self = item->self()) { + if(self->qtItem->isSelected()) item->state.selected = true; + } + } + if(!p.locked()) p.self().doChange(); +} + +auto QtListView::onContext() -> void { + if(!p.locked()) p.self().doContext(); +} + +auto QtListView::onSort(int columnNumber) -> void { + if(auto& header = p.state().header) { + if(auto column = header->column(columnNumber)) { + if(!p.locked() && column.sortable()) p.self().doSort(column); + } + } +} + +auto QtListView::onToggle(QTreeWidgetItem* qtItem, int column) -> void { + for(auto& item : p.state().items) { + if(auto self = item->self()) { + if(qtItem == self->qtItem) { + if(auto cell = item->cell(column)) { + cell->state.checked = (qtItem->checkState(column) == Qt::Checked); + if(!p.locked()) p.self().doToggle(cell); + } + } + } + } +} + +auto QtListView::mousePressEvent(QMouseEvent* event) -> void { + QTreeWidget::mousePressEvent(event); + if(event->button() == Qt::RightButton) onContext(); +} + +auto QtListView::resizeEvent(QResizeEvent* event) -> void { + QTreeWidget::resizeEvent(event); + p._onSize(); +} + +auto QtListView::showEvent(QShowEvent* event) -> void { + QTreeWidget::showEvent(event); + p._onSize(); +} + +QtListViewDelegate::QtListViewDelegate(pListView& p) : QStyledItemDelegate(p.qtListView), p(p) { +} + +auto QtListViewDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const -> void { + QStyledItemDelegate::paint(painter, option, index); + if(p.state().bordered) { + QPen pen; + pen.setColor(QColor(160, 160, 160)); + pen.setWidth(1); + painter->setPen(pen); + painter->drawRect(option.rect); + } +} + +} + +#endif diff --git a/qt/widget/list-view.hpp b/qt/widget/list-view.hpp new file mode 100644 index 0000000..20bac6b --- /dev/null +++ b/qt/widget/list-view.hpp @@ -0,0 +1,30 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListView : pWidget { + Declare(ListView, Widget) + + auto append(sListViewHeader header) -> void; + auto append(sListViewItem item) -> void; + auto remove(sListViewHeader header) -> void; + auto remove(sListViewItem item) -> void; + auto resizeColumns() -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setBatchable(bool batchable) -> void; + auto setBordered(bool bordered) -> void; + auto setForegroundColor(Color color) -> void; + + auto _onSize() -> void; + auto _width(unsigned column) -> unsigned; + auto _widthOfColumn(unsigned column) -> unsigned; + auto _widthOfCell(unsigned row, unsigned column) -> unsigned; + + QtListView* qtListView = nullptr; + QtListViewDelegate* qtListViewDelegate = nullptr; +}; + +} + +#endif diff --git a/qt/widget/progress-bar.cpp b/qt/widget/progress-bar.cpp new file mode 100644 index 0000000..995f5e2 --- /dev/null +++ b/qt/widget/progress-bar.cpp @@ -0,0 +1,33 @@ +#if defined(Hiro_ProgressBar) + +namespace hiro { + +auto pProgressBar::construct() -> void { + qtWidget = qtProgressBar = new QProgressBar; + qtProgressBar->setRange(0, 100); + qtProgressBar->setTextVisible(false); + + pWidget::construct(); + _setState(); +} + +auto pProgressBar::destruct() -> void { + delete qtProgressBar; + qtWidget = qtProgressBar = nullptr; +} + +auto pProgressBar::minimumSize() const -> Size { + return {0, 25}; +} + +auto pProgressBar::setPosition(unsigned position) -> void { + _setState(); +} + +auto pProgressBar::_setState() -> void { + qtProgressBar->setValue(state().position); +} + +} + +#endif diff --git a/qt/widget/progress-bar.hpp b/qt/widget/progress-bar.hpp new file mode 100644 index 0000000..9e12bdd --- /dev/null +++ b/qt/widget/progress-bar.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_ProgressBar) + +namespace hiro { + +struct pProgressBar : pWidget { + Declare(ProgressBar, Widget) + + auto minimumSize() const -> Size override; + auto setPosition(unsigned position) -> void; + + auto _setState() -> void; + + QProgressBar* qtProgressBar = nullptr; +}; + +} + +#endif diff --git a/qt/widget/radio-button.cpp b/qt/widget/radio-button.cpp new file mode 100644 index 0000000..9ec2f67 --- /dev/null +++ b/qt/widget/radio-button.cpp @@ -0,0 +1,110 @@ +#if defined(Hiro_RadioButton) + +namespace hiro { + +auto pRadioButton::construct() -> void { + qtWidget = qtRadioButton = new QtRadioButton(*this); + qtRadioButton->setCheckable(true); + qtRadioButton->setToolButtonStyle(Qt::ToolButtonTextOnly); + qtRadioButton->connect(qtRadioButton, SIGNAL(toggled(bool)), SLOT(onActivate())); + + pWidget::construct(); + setGroup(state().group); + _setState(); +} + +auto pRadioButton::destruct() -> void { + if(qtRadioButton) delete qtRadioButton; + qtWidget = qtRadioButton = nullptr; +} + +auto pRadioButton::minimumSize() const -> Size { + auto size = pFont::size(qtWidget->font(), 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() + 20, size.height() + 12}; +} + +auto pRadioButton::setBordered(bool bordered) -> void { +} + +auto pRadioButton::setChecked() -> void { + _setState(); +} + +auto pRadioButton::setGroup(sGroup group) -> void { + bool first = true; + if(auto& group = state().group) { + group->self()->lock(); + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioButton = dynamic_cast(object.data())) { + if(auto self = radioButton->self()) { + self->qtRadioButton->setChecked(radioButton->state.checked = first); + first = false; + } + } + } + } + group->self()->unlock(); + } +} + +auto pRadioButton::setIcon(const image& icon) -> void { + _setState(); +} + +auto pRadioButton::setOrientation(Orientation orientation) -> void { + _setState(); +} + +auto pRadioButton::setText(const string& text) -> void { + _setState(); +} + +auto pRadioButton::_setState() -> void { + if(auto& group = state().group) { + group->self()->lock(); + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioButton = dynamic_cast(object.data())) { + if(auto self = radioButton->self()) { + self->qtRadioButton->setChecked(radioButton->state.checked); + } + } + } + } + group->self()->unlock(); + } + qtRadioButton->setIconSize(QSize(state().icon.width(), state().icon.height())); + qtRadioButton->setIcon(CreateIcon(state().icon)); + qtRadioButton->setStyleSheet("text-align: top;"); + switch(state().orientation) { + case Orientation::Horizontal: qtRadioButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); break; + case Orientation::Vertical: qtRadioButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); break; + } + qtRadioButton->setText(QString::fromUtf8(state().text)); +} + +auto QtRadioButton::onActivate() -> void { + if(auto& group = p.state().group) { + if(!group->self()->locked()) { + bool wasChecked = p.state().checked; + p.self().setChecked(); + if(!wasChecked) p.self().doActivate(); + } + } +} + +} + +#endif diff --git a/qt/widget/radio-button.hpp b/qt/widget/radio-button.hpp new file mode 100644 index 0000000..2aec616 --- /dev/null +++ b/qt/widget/radio-button.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_RadioButton) + +namespace hiro { + +struct pRadioButton : pWidget { + Declare(RadioButton, Widget) + + auto minimumSize() const -> Size override; + auto setBordered(bool bordered) -> void; + auto setChecked() -> void; + auto setGroup(sGroup group) -> void; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + + auto _setState() -> void; + + QtRadioButton* qtRadioButton = nullptr; +}; + +} + +#endif diff --git a/qt/widget/radio-label.cpp b/qt/widget/radio-label.cpp new file mode 100644 index 0000000..4fb310f --- /dev/null +++ b/qt/widget/radio-label.cpp @@ -0,0 +1,80 @@ +#if defined(Hiro_RadioLabel) + +namespace hiro { + +auto pRadioLabel::construct() -> void { + qtWidget = qtRadioLabel = new QtRadioLabel(*this); + qtRadioLabel->setAutoExclusive(false); + qtRadioLabel->connect(qtRadioLabel, SIGNAL(toggled(bool)), SLOT(onActivate())); + + pWidget::construct(); + setGroup(state().group); + _setState(); +} + +auto pRadioLabel::destruct() -> void { + if(qtRadioLabel) delete qtRadioLabel; + qtWidget = qtRadioLabel = nullptr; +} + +auto pRadioLabel::minimumSize() const -> Size { + auto size = pFont::size(qtWidget->font(), state().text); + return {size.width() + 26, size.height() + 6}; +} + +auto pRadioLabel::setChecked() -> void { + _setState(); +} + +auto pRadioLabel::setGroup(sGroup group) -> void { + bool first = true; + if(auto& group = state().group) { + group->self()->lock(); + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioLabel = dynamic_cast(object.data())) { + if(auto self = radioLabel->self()) { + self->qtRadioLabel->setChecked(radioLabel->state.checked = first); + first = false; + } + } + } + } + group->self()->unlock(); + } +} + +auto pRadioLabel::setText(const string& text) -> void { + _setState(); +} + +auto pRadioLabel::_setState() -> void { + if(auto& group = state().group) { + group->self()->lock(); + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioLabel = dynamic_cast(object.data())) { + if(auto self = radioLabel->self()) { + self->qtRadioLabel->setChecked(radioLabel->state.checked); + } + } + } + } + group->self()->unlock(); + } + qtRadioLabel->setText(QString::fromUtf8(state().text)); +} + +auto QtRadioLabel::onActivate() -> void { + if(auto& group = p.state().group) { + if(!group->self()->locked()) { + bool wasChecked = p.state().checked; + p.self().setChecked(); + if(!wasChecked) p.self().doActivate(); + } + } +} + +} + +#endif diff --git a/qt/widget/radio-label.hpp b/qt/widget/radio-label.hpp new file mode 100644 index 0000000..f668843 --- /dev/null +++ b/qt/widget/radio-label.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_RadioLabel) + +namespace hiro { + +struct pRadioLabel : pWidget { + Declare(RadioLabel, Widget) + + auto minimumSize() const -> Size; + auto setChecked() -> void; + auto setGroup(sGroup group) -> void; + auto setText(const string& text) -> void; + + auto _setState() -> void; + + QtRadioLabel* qtRadioLabel = nullptr; +}; + +} + +#endif diff --git a/qt/widget/tab-frame-item.cpp b/qt/widget/tab-frame-item.cpp new file mode 100644 index 0000000..72d8ca7 --- /dev/null +++ b/qt/widget/tab-frame-item.cpp @@ -0,0 +1,82 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +auto pTabFrameItem::construct() -> void { + qtTabFrameItem = new QWidget; + + if(auto parent = _parent()) { + parent->qtTabFrame->addTab(qtTabFrameItem, ""); + } + + _setState(); +} + +auto pTabFrameItem::destruct() -> void { +} + +auto pTabFrameItem::append(sLayout layout) -> void { +} + +auto pTabFrameItem::remove(sLayout layout) -> void { +} + +auto pTabFrameItem::setClosable(bool closable) -> void { +} + +auto pTabFrameItem::setGeometry(Geometry geometry) -> void { + if(auto layout = state().layout) { + auto offset = qtTabFrameItem->geometry(); + geometry.setPosition({0, 0}); + geometry.setWidth(geometry.width() - (geometry.width() - offset.width())); + geometry.setHeight(geometry.height() - (geometry.height() - offset.height())); + layout->setGeometry(geometry); + } +} + +auto pTabFrameItem::setIcon(const image& icon) -> void { + _setState(); +} + +auto pTabFrameItem::setMovable(bool movable) -> void { +} + +auto pTabFrameItem::setSelected() -> void { + _setState(); +} + +auto pTabFrameItem::setText(const string& text) -> void { + _setState(); +} + +auto pTabFrameItem::setVisible(bool visible) -> void { + _setState(); +} + +auto pTabFrameItem::_parent() -> maybe { + if(auto parent = self().parentTabFrame()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pTabFrameItem::_setState() -> void { + if(auto parent = _parent()) { + parent->qtTabFrame->setTabIcon(self().offset(), CreateIcon(state().icon)); + if(state().selected) parent->qtTabFrame->setCurrentIndex(self().offset()); + parent->qtTabFrame->setTabText(self().offset(), QString::fromUtf8(state().text)); + if(auto layout = state().layout) { + auto geometry = parent->self().geometry(); + auto offset = qtTabFrameItem->geometry(); + geometry.setPosition({0, 0}); + geometry.setWidth(geometry.width() - (geometry.width() - offset.width())); + geometry.setHeight(geometry.height() - (geometry.height() - offset.height())); + layout->setGeometry(geometry); + layout->setVisible(layout->visible(true)); + } + } +} + +} + +#endif diff --git a/qt/widget/tab-frame-item.hpp b/qt/widget/tab-frame-item.hpp new file mode 100644 index 0000000..4b8d59c --- /dev/null +++ b/qt/widget/tab-frame-item.hpp @@ -0,0 +1,26 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +struct pTabFrameItem : pObject { + Declare(TabFrameItem, Object) + + auto append(sLayout layout) -> void; + auto remove(sLayout layout) -> void; + auto setClosable(bool closable) -> void; + auto setIcon(const image& icon) -> void; + auto setGeometry(Geometry geometry) -> void; + auto setMovable(bool movable) -> void; + auto setSelected() -> void; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; + auto _setState() -> void; + + QWidget* qtTabFrameItem = nullptr; +}; + +} + +#endif diff --git a/qt/widget/tab-frame.cpp b/qt/widget/tab-frame.cpp new file mode 100644 index 0000000..8967013 --- /dev/null +++ b/qt/widget/tab-frame.cpp @@ -0,0 +1,66 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +auto pTabFrame::construct() -> void { + qtWidget = qtTabFrame = new QtTabFrame(*this); + qtTabFrame->connect(qtTabFrame, SIGNAL(currentChanged(int)), SLOT(onChange(int))); + + pWidget::construct(); + _setState(); +} + +auto pTabFrame::destruct() -> void { + delete qtTabFrame; + qtWidget = qtTabFrame = nullptr; +} + +auto pTabFrame::append(sTabFrameItem item) -> void { + setGeometry(self().geometry()); +} + +auto pTabFrame::remove(sTabFrameItem item) -> void { +} + +auto pTabFrame::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + + for(auto& item : state().items) { + if(auto self = item->self()) self->setGeometry(geometry); + } +} + +auto pTabFrame::setNavigation(Navigation navigation) -> void { + _setState(); +} + +auto pTabFrame::_setState() -> void { + switch(state().navigation) { default: + case Navigation::Top: qtTabFrame->setTabPosition(QTabWidget::TabPosition::North); break; + case Navigation::Bottom: qtTabFrame->setTabPosition(QTabWidget::TabPosition::South); break; + case Navigation::Left: qtTabFrame->setTabPosition(QTabWidget::TabPosition::West); break; + case Navigation::Right: qtTabFrame->setTabPosition(QTabWidget::TabPosition::East); break; + } + + for(auto& item : state().items) { + if(auto self = item->self()) self->_setState(); + } +} + +auto QtTabFrame::showEvent(QShowEvent* event) -> void { + QTabWidget::showEvent(event); + p._setState(); //needed to capture geometry of TabFrame for TabFrameItem layouts +} + +auto QtTabFrame::onChange(int selection) -> void { + //geometry of tab frames is only valid once said tab frame is visible + //as such, as need to call _setState() to update the TabFrameItem's geometry here + if(auto item = p.self().item(selection)) { + if(auto self = item->self()) self->_setState(); + } + if(!p.locked()) p.self().doChange(); +} + +} + +#endif diff --git a/qt/widget/tab-frame.hpp b/qt/widget/tab-frame.hpp new file mode 100644 index 0000000..e87cdc3 --- /dev/null +++ b/qt/widget/tab-frame.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +struct pTabFrame : pWidget { + Declare(TabFrame, Widget) + + auto append(sTabFrameItem item) -> void; + auto remove(sTabFrameItem item) -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setNavigation(Navigation navigation) -> void; + + auto _setState() -> void; + + QtTabFrame* qtTabFrame = nullptr; +}; + +} + +#endif diff --git a/qt/widget/text-edit.cpp b/qt/widget/text-edit.cpp new file mode 100644 index 0000000..f5d5531 --- /dev/null +++ b/qt/widget/text-edit.cpp @@ -0,0 +1,83 @@ +#if defined(Hiro_TextEdit) + +namespace hiro { + +auto pTextEdit::construct() -> void { + qtWidget = qtTextEdit = new QtTextEdit(*this); + qtTextEdit->connect(qtTextEdit, SIGNAL(textChanged()), SLOT(onChange())); + + pWidget::construct(); + _setState(); +} + +auto pTextEdit::destruct() -> void { + delete qtTextEdit; + qtWidget = qtTextEdit = nullptr; +} + +auto pTextEdit::setBackgroundColor(Color color) -> void { + _setState(); +} + +auto pTextEdit::setCursor(Cursor cursor) -> void { + _setState(); +} + +auto pTextEdit::setEditable(bool editable) -> void { + _setState(); +} + +auto pTextEdit::setForegroundColor(Color color) -> void { + _setState(); +} + +auto pTextEdit::setText(const string& text) -> void { + qtTextEdit->setPlainText(QString::fromUtf8(text)); +} + +auto pTextEdit::setWordWrap(bool wordWrap) -> void { + _setState(); +} + +auto pTextEdit::text() const -> string { + return qtTextEdit->toPlainText().toUtf8().constData(); +} + +auto pTextEdit::_setState() -> void { + if(auto color = state().backgroundColor) { + QPalette palette = qtTextEdit->palette(); + palette.setColor(QPalette::Base, QColor(color.red(), color.green(), color.blue())); + qtTextEdit->setPalette(palette); + qtTextEdit->setAutoFillBackground(true); + } else { + //todo + } + QTextCursor cursor = qtTextEdit->textCursor(); + signed lastCharacter = strlen(qtTextEdit->toPlainText().toUtf8().constData()); + cursor.setPosition(max(0, min(lastCharacter, state().cursor.offset()))); + cursor.setPosition(max(0, min(lastCharacter, state().cursor.offset() + state().cursor.length())), QTextCursor::KeepAnchor); + qtTextEdit->setTextCursor(cursor); + qtTextEdit->setTextInteractionFlags(state().editable + ? Qt::TextEditorInteraction + : Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse + ); + if(auto color = state().foregroundColor) { + QPalette palette = qtTextEdit->palette(); + palette.setColor(QPalette::Text, QColor(color.red(), color.green(), color.blue())); + qtTextEdit->setPalette(palette); + } else { + //todo + } + qtTextEdit->setWordWrapMode(state().wordWrap ? QTextOption::WordWrap : QTextOption::NoWrap); + qtTextEdit->setHorizontalScrollBarPolicy(state().wordWrap ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAlwaysOn); + qtTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); +} + +auto QtTextEdit::onChange() -> void { +//p.state().text = text(); + p.self().doChange(); +} + +} + +#endif diff --git a/qt/widget/text-edit.hpp b/qt/widget/text-edit.hpp new file mode 100644 index 0000000..a810a3e --- /dev/null +++ b/qt/widget/text-edit.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_TextEdit) + +namespace hiro { + +struct pTextEdit : pWidget { + Declare(TextEdit, Widget) + + auto setBackgroundColor(Color color) -> void; + auto setCursor(Cursor cursor) -> 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; + + auto _setState() -> void; + + QtTextEdit* qtTextEdit = nullptr; +}; + +} + +#endif diff --git a/qt/widget/vertical-scroll-bar.cpp b/qt/widget/vertical-scroll-bar.cpp new file mode 100644 index 0000000..b470ffd --- /dev/null +++ b/qt/widget/vertical-scroll-bar.cpp @@ -0,0 +1,46 @@ +#if defined(Hiro_VerticalScrollBar) + +namespace hiro { + +auto pVerticalScrollBar::construct() -> void { + qtWidget = qtVerticalScrollBar = new QtVerticalScrollBar(*this); + qtVerticalScrollBar->setRange(0, 100); + qtVerticalScrollBar->setPageStep(101 >> 3); + qtVerticalScrollBar->connect(qtVerticalScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::construct(); + _setState(); +} + +auto pVerticalScrollBar::destruct() -> void { + delete qtVerticalScrollBar; + qtWidget = qtVerticalScrollBar = nullptr; +} + +auto pVerticalScrollBar::minimumSize() const -> Size { + return {15, 0}; +} + +auto pVerticalScrollBar::setLength(unsigned length) -> void { + _setState(); +} + +auto pVerticalScrollBar::setPosition(unsigned position) -> void { + _setState(); +} + +auto pVerticalScrollBar::_setState() -> void { + signed length = state().length + (state().length == 0); + qtVerticalScrollBar->setRange(0, length - 1); + qtVerticalScrollBar->setPageStep(length >> 3); + qtVerticalScrollBar->setValue(state().position); +} + +auto QtVerticalScrollBar::onChange() -> void { + p.state().position = value(); + p.self().doChange(); +} + +} + +#endif diff --git a/qt/widget/vertical-scroll-bar.hpp b/qt/widget/vertical-scroll-bar.hpp new file mode 100644 index 0000000..9a8f761 --- /dev/null +++ b/qt/widget/vertical-scroll-bar.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_VerticalScrollBar) + +namespace hiro { + +struct pVerticalScrollBar : pWidget { + Declare(VerticalScrollBar, Widget) + + auto minimumSize() const -> Size override; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; + + auto _setState() -> void; + + QtVerticalScrollBar* qtVerticalScrollBar = nullptr; +}; + +} + +#endif diff --git a/qt/widget/vertical-slider.cpp b/qt/widget/vertical-slider.cpp new file mode 100644 index 0000000..56e27c4 --- /dev/null +++ b/qt/widget/vertical-slider.cpp @@ -0,0 +1,47 @@ +#if defined(Hiro_VerticalSlider) + +namespace hiro { + +auto pVerticalSlider::minimumSize() const -> Size { + return {20, 0}; +} + +auto pVerticalSlider::setLength(unsigned length) -> void { + _setState(); +} + +auto pVerticalSlider::setPosition(unsigned position) -> void { + _setState(); +} + +auto pVerticalSlider::construct() -> void { + qtWidget = qtVerticalSlider = new QtVerticalSlider(*this); + qtVerticalSlider->setInvertedAppearance(true); + qtVerticalSlider->setRange(0, 100); + qtVerticalSlider->setPageStep(101 >> 3); + qtVerticalSlider->connect(qtVerticalSlider, SIGNAL(valueChanged(int)), SLOT(onChange())); + + pWidget::construct(); + _setState(); +} + +auto pVerticalSlider::destruct() -> void { + delete qtVerticalSlider; + qtWidget = qtVerticalSlider = nullptr; +} + +auto pVerticalSlider::_setState() -> void { + signed length = state().length + (state().length == 0); + qtVerticalSlider->setRange(0, length - 1); + qtVerticalSlider->setPageStep(length >> 3); + qtVerticalSlider->setValue(state().position); +} + +auto QtVerticalSlider::onChange() -> void { + p.state().position = value(); + p.self().doChange(); +} + +} + +#endif diff --git a/qt/widget/vertical-slider.hpp b/qt/widget/vertical-slider.hpp new file mode 100644 index 0000000..5d126ae --- /dev/null +++ b/qt/widget/vertical-slider.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_VerticalSlider) + +namespace hiro { + +struct pVerticalSlider : pWidget { + Declare(VerticalSlider, Widget) + + auto minimumSize() const -> Size override; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; + + auto _setState() -> void; + + QtVerticalSlider* qtVerticalSlider = nullptr; +}; + +} + +#endif diff --git a/qt/widget/viewport.cpp b/qt/widget/viewport.cpp new file mode 100644 index 0000000..8edc159 --- /dev/null +++ b/qt/widget/viewport.cpp @@ -0,0 +1,68 @@ +#if defined(Hiro_Viewport) + +namespace hiro { + +auto pViewport::construct() -> void { + qtWidget = qtViewport = new QtViewport(*this); + qtViewport->setMouseTracking(true); + qtViewport->setAttribute(Qt::WA_PaintOnScreen, true); + qtViewport->setStyleSheet("background: #000000"); + + pWidget::construct(); + _setState(); +} + +auto pViewport::destruct() -> void { + delete qtViewport; + qtWidget = qtViewport = nullptr; +} + +auto pViewport::handle() const -> uintptr_t { + return (uintptr_t)qtViewport->winId(); +} + +auto pViewport::setDroppable(bool droppable) -> void { + _setState(); +} + +auto pViewport::_setState() -> void { + qtViewport->setAcceptDrops(state().droppable); +} + +auto QtViewport::dragEnterEvent(QDragEnterEvent* event) -> void { + if(event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + } +} + +auto QtViewport::dropEvent(QDropEvent* event) -> void { + if(auto paths = DropPaths(event)) p.self().doDrop(paths); +} + +auto QtViewport::leaveEvent(QEvent* event) -> void { + p.self().doMouseLeave(); +} + +auto QtViewport::mouseMoveEvent(QMouseEvent* event) -> void { + p.self().doMouseMove({event->pos().x(), event->pos().y()}); +} + +auto QtViewport::mousePressEvent(QMouseEvent* event) -> void { + switch(event->button()) { + case Qt::LeftButton: p.self().doMousePress(Mouse::Button::Left); break; + case Qt::MidButton: p.self().doMousePress(Mouse::Button::Middle); break; + case Qt::RightButton: p.self().doMousePress(Mouse::Button::Right); break; + } +} + +auto QtViewport::mouseReleaseEvent(QMouseEvent* event) -> void { + switch(event->button()) { + case Qt::LeftButton: p.self().doMouseRelease(Mouse::Button::Left); break; + case Qt::MidButton: p.self().doMouseRelease(Mouse::Button::Middle); break; + case Qt::RightButton: p.self().doMouseRelease(Mouse::Button::Right); break; + } +} + +} + +#endif diff --git a/qt/widget/viewport.hpp b/qt/widget/viewport.hpp new file mode 100644 index 0000000..82a90dc --- /dev/null +++ b/qt/widget/viewport.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_Viewport) + +namespace hiro { + +struct pViewport : pWidget { + Declare(Viewport, Widget) + + auto handle() const -> uintptr_t; + auto setDroppable(bool droppable) -> void; + + auto _setState() -> void; + + QtViewport* qtViewport = nullptr; +}; + +} + +#endif diff --git a/qt/widget/widget.cpp b/qt/widget/widget.cpp new file mode 100644 index 0000000..0366691 --- /dev/null +++ b/qt/widget/widget.cpp @@ -0,0 +1,77 @@ +#if defined(Hiro_Widget) + +namespace hiro { + +static auto ParentContainer(mObject& object) -> QWidget* { + if(auto frame = object.parentFrame()) { + if(auto self = frame->self()) return self->qtFrame; + } + if(auto tabFrameItem = object.parentTabFrameItem()) { + if(auto self = tabFrameItem->self()) return self->qtTabFrameItem; + } + if(auto window = object.parentWindow()) { + if(auto self = window->self()) return self->qtContainer; + } + if(auto parent = object.parent()) { + return ParentContainer(*parent); + } + return nullptr; +} + +auto pWidget::construct() -> void { + if(!qtWidget) return; + + if(auto container = ParentContainer(self())) { + qtWidget->setParent(container); + } + + setFont(self().font(true)); + setVisible(self().visible(true)); +} + +auto pWidget::destruct() -> void { +} + +auto pWidget::focused() const -> bool { + if(!qtWidget) return false; + return qtWidget->hasFocus(); +} + +auto pWidget::setEnabled(bool enabled) -> void { + if(!qtWidget) return; + qtWidget->setEnabled(enabled); +} + +auto pWidget::setFocused() -> void { + if(!qtWidget) return; + qtWidget->setFocus(Qt::OtherFocusReason); +} + +auto pWidget::setFont(const Font& font) -> void { + if(!qtWidget) return; + qtWidget->setFont(pFont::create(font)); +} + +auto pWidget::setGeometry(Geometry geometry) -> void { + if(!qtWidget) return; +// Position displacement = GetDisplacement(&widget); +// geometry.x -= displacement.x; +// geometry.y -= displacement.y; + qtWidget->setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height()); + self().doSize(); +} + +auto pWidget::setVisible(bool visible) -> void { + if(!qtWidget) return; + qtWidget->setVisible(visible); +} + +//pWidget::constructor() called before p{Derived}::constructor(); ergo qtWidget is not yet valid +//pWidget::synchronizeState() is called to finish construction of p{Derived}::constructor() +//void pWidget::synchronizeState() { +// setFont(widget.font()); +//} + +} + +#endif diff --git a/qt/widget/widget.hpp b/qt/widget/widget.hpp new file mode 100644 index 0000000..080c2a1 --- /dev/null +++ b/qt/widget/widget.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_Widget) + +namespace hiro { + +struct pWidget : pSizable { + Declare(Widget, Sizable) + + auto focused() const -> bool override; + auto setEnabled(bool enabled) -> void override; + auto setFocused() -> void override; + auto setFont(const Font& font) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setVisible(bool visible) -> void override; + + QWidget* qtWidget = nullptr; +}; + +} + +#endif diff --git a/qt/window.cpp b/qt/window.cpp new file mode 100644 index 0000000..5ae1120 --- /dev/null +++ b/qt/window.cpp @@ -0,0 +1,315 @@ +#if defined(Hiro_Window) + +namespace hiro { + +auto pWindow::construct() -> void { + qtWindow = new QtWindow(*this); + qtWindow->setWindowTitle(" "); + + //if program was given a name, try and set the window taskbar icon to a matching pixmap image + if(auto name = Application::state.name) { + if(file::exists({userpath(), ".local/share/icons/", name, ".png"})) { + qtWindow->setWindowIcon(QIcon(QString::fromUtf8(string{userpath(), ".local/share/icons/", name, ".png"}))); + } else if(file::exists({"/usr/local/share/pixmaps/", name, ".png"})) { + qtWindow->setWindowIcon(QIcon(QString::fromUtf8(string{"/usr/local/share/pixmaps/", name, ".png"}))); + } else if(file::exists({"/usr/share/pixmaps/", name, ".png"})) { + qtWindow->setWindowIcon(QIcon(QString::fromUtf8(string{"/usr/share/pixmaps/", name, ".png"}))); + } + } + + qtLayout = new QVBoxLayout(qtWindow); + qtLayout->setMargin(0); + qtLayout->setSpacing(0); + qtWindow->setLayout(qtLayout); + + qtMenuBar = new QMenuBar(qtWindow); + qtMenuBar->setVisible(false); + qtLayout->addWidget(qtMenuBar); + + qtContainer = new QWidget(qtWindow); + qtContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + qtContainer->setVisible(true); + qtLayout->addWidget(qtContainer); + + qtStatusBar = new QStatusBar(qtWindow); + qtStatusBar->setSizeGripEnabled(true); + qtStatusBar->setVisible(false); + qtLayout->addWidget(qtStatusBar); + + setBackgroundColor(state().backgroundColor); + setDroppable(state().droppable); + setGeometry(state().geometry); + setResizable(state().resizable); + setTitle(state().title); +} + +auto pWindow::destruct() -> void { + delete qtStatusBar; + delete qtContainer; + delete qtMenuBar; + delete qtLayout; + delete qtWindow; +} + +auto pWindow::append(sLayout layout) -> void { +} + +auto pWindow::append(sMenuBar menuBar) -> void { +} + +auto pWindow::append(sStatusBar statusBar) -> void { +} + +auto pWindow::focused() const -> bool { + return qtWindow->isActiveWindow() && !qtWindow->isMinimized(); +} + +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(sLayout layout) -> void { +} + +auto pWindow::remove(sMenuBar menuBar) -> void { + //QMenuBar::removeMenu() does not exist + //qtMenu->clear(); + //for(auto& menu : window.state.menu) append(menu); +} + +auto pWindow::remove(sStatusBar statusBar) -> void { +} + +auto pWindow::setBackgroundColor(Color color) -> void { + if(color) { + QPalette palette; + palette.setColor(QPalette::Background, QColor(color.red(), color.green(), color.blue() /*, color.alpha() */)); + qtContainer->setPalette(palette); + qtContainer->setAutoFillBackground(true); + //translucency results are very unpleasant without a compositor; so disable for now + //qtWindow->setAttribute(Qt::WA_TranslucentBackground, color.alpha() != 255); + } +} + +auto pWindow::setDroppable(bool droppable) -> void { + qtWindow->setAcceptDrops(droppable); +} + +auto pWindow::setEnabled(bool enabled) -> void { +} + +auto pWindow::setFocused() -> void { + qtWindow->raise(); + qtWindow->activateWindow(); +} + +auto pWindow::setFullScreen(bool fullScreen) -> void { + lock(); + if(fullScreen) { + windowedGeometry = state().geometry; + qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint); + qtContainer->setFixedSize(Desktop::size().width() - frameMargin().width(), Desktop::size().height() - frameMargin().height()); + qtWindow->showFullScreen(); + state().geometry = Monitor::geometry(Monitor::primary()); + } else { + setResizable(state().resizable); + qtWindow->showNormal(); + qtWindow->adjustSize(); + self().setGeometry(windowedGeometry); + } + unlock(); +} + +auto pWindow::setGeometry(Geometry geometry) -> void { + lock(); + Application::processEvents(); + QApplication::syncX(); + + setResizable(state().resizable); + qtWindow->move(geometry.x() - frameMargin().x(), geometry.y() - frameMargin().y()); + //qtWindow->adjustSize() fails if larger than 2/3rds screen size + qtWindow->resize(qtWindow->sizeHint()); + if(state().resizable) { + //required to allow shrinking window from default size + qtWindow->setMinimumSize(1, 1); + qtContainer->setMinimumSize(1, 1); + } + +// for(auto& layout : window.state.layout) { +// geometry.x = geometry.y = 0; +// layout.setGeometry(geometry); +// } + unlock(); +} + +auto pWindow::setModal(bool modal) -> void { + if(modal) { + //windowModality can only be enabled while window is invisible + setVisible(false); + qtWindow->setWindowModality(Qt::ApplicationModal); + setVisible(true); + while(!Application::state.quit && state().modal) { + if(Application::state.onMain) { + Application::doMain(); + } else { + usleep(20 * 1000); + } + Application::processEvents(); + } + qtWindow->setWindowModality(Qt::NonModal); + } +} + +auto pWindow::setResizable(bool resizable) -> void { + if(resizable) { + qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint); + qtContainer->setMinimumSize(state().geometry.width(), state().geometry.height()); + } else { + qtLayout->setSizeConstraint(QLayout::SetFixedSize); + qtContainer->setFixedSize(state().geometry.width(), state().geometry.height()); + } + qtStatusBar->setSizeGripEnabled(resizable); +} + +auto pWindow::setTitle(const string& text) -> void { + qtWindow->setWindowTitle(QString::fromUtf8(text)); +} + +auto pWindow::setVisible(bool visible) -> void { + lock(); + qtWindow->setVisible(visible); + if(visible) { + _updateFrameGeometry(); + setGeometry(state().geometry); + } + unlock(); +} + +/* + if(widget.font().empty() && !window.state.widgetFont.empty()) { + widget.setFont(window.state.widgetFont); + } + if(widget.font().empty()) widget.p.setFont(Font::sans(8)); + if(GetParentWidget(&widget)) { + widget.p.qtWidget->setParent(GetParentWidget(&widget)->p.container(widget)); + } else { + widget.p.qtWidget->setParent(qtContainer); + } + widget.setVisible(widget.visible()); +} +*/ + +auto pWindow::_append(mWidget& widget) -> void { + if(auto self = widget.self()) { + self->qtWidget->setParent(qtContainer); + } +} + +auto pWindow::_menuHeight() const -> signed { + return qtMenuBar->isVisible() ? settings->geometry.menuHeight : 0; +} + +auto pWindow::_statusHeight() const -> signed { + return qtStatusBar->isVisible() ? settings->geometry.statusHeight : 0; +} + +auto pWindow::_updateFrameGeometry() -> void { + pApplication::syncX(); + QRect border = qtWindow->frameGeometry(); + QRect client = qtWindow->geometry(); + + 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(qtMenuBar->isVisible()) { + pApplication::syncX(); + settings->geometry.menuHeight = qtMenuBar->height(); + } + + if(qtStatusBar->isVisible()) { + pApplication::syncX(); + settings->geometry.statusHeight = qtStatusBar->height(); + } + + settings->save(); +} + +auto QtWindow::closeEvent(QCloseEvent* event) -> void { + event->ignore(); + if(p.state().onClose) p.self().doClose(); + else p.self().setVisible(false); + if(p.state().modal && !p.self().visible()) p.self().setModal(false); +} + +auto QtWindow::moveEvent(QMoveEvent* event) -> void { + if(!p.locked() && !p.state().fullScreen && p.qtWindow->isVisible()) { + p.state().geometry.setPosition({ + p.state().geometry.x() + event->pos().x() - event->oldPos().x(), + p.state().geometry.y() + event->pos().y() - event->oldPos().y() + }); + } + + if(!p.locked()) { + p.self().doMove(); + } +} + +auto QtWindow::dragEnterEvent(QDragEnterEvent* event) -> void { + if(event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + } +} + +auto QtWindow::dropEvent(QDropEvent* event) -> void { + if(auto paths = DropPaths(event)) p.self().doDrop(paths); +} + +auto QtWindow::keyPressEvent(QKeyEvent* event) -> void { +// Keyboard::Keycode sym = Keysym(event->nativeVirtualKey()); +// if(sym != Keyboard::Keycode::None && self.window.onKeyPress) self.window.onKeyPress(sym); +} + +auto QtWindow::keyReleaseEvent(QKeyEvent* event) -> void { +// Keyboard::Keycode sym = Keysym(event->nativeVirtualKey()); +// if(sym != Keyboard::Keycode::None && self.window.onKeyRelease) self.window.onKeyRelease(sym); +} + +auto QtWindow::resizeEvent(QResizeEvent*) -> void { + if(!p.locked() && !p.state().fullScreen && p.qtWindow->isVisible()) { + p.state().geometry.setSize({ + p.qtContainer->geometry().width(), + p.qtContainer->geometry().height() + }); + } + + if(auto& layout = p.state().layout) { + layout->setGeometry(p.self().geometry().setPosition(0, 0)); + } + + if(!p.locked()) { + p.self().doSize(); + } +} + +auto QtWindow::sizeHint() const -> QSize { + unsigned width = p.state().geometry.width(); + unsigned height = p.state().geometry.height(); + if(p.qtMenuBar->isVisible()) height += settings->geometry.menuHeight; + if(p.qtStatusBar->isVisible()) height += settings->geometry.statusHeight; + return QSize(width, height); +} + +} + +#endif diff --git a/qt/window.hpp b/qt/window.hpp new file mode 100644 index 0000000..0073689 --- /dev/null +++ b/qt/window.hpp @@ -0,0 +1,42 @@ +#if defined(Hiro_Window) + +namespace hiro { + +struct pWindow : pObject { + Declare(Window, Object) + + auto append(sLayout layout) -> void; + auto append(sMenuBar menuBar) -> void; + auto append(sStatusBar statusBar) -> void; + auto focused() const -> bool override; + auto frameMargin() const -> Geometry; + auto remove(sLayout layout) -> void; + auto remove(sMenuBar menuBar) -> void; + auto remove(sStatusBar 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& text) -> void; + auto setVisible(bool visible) -> void; + + auto _append(mWidget& widget) -> void; + auto _menuHeight() const -> signed; + auto _statusHeight() const -> signed; + auto _updateFrameGeometry() -> void; + + QtWindow* qtWindow = nullptr; + QVBoxLayout* qtLayout = nullptr; + QMenuBar* qtMenuBar = nullptr; + QStatusBar* qtStatusBar = nullptr; + QWidget* qtContainer = nullptr; + Geometry windowedGeometry{128, 128, 256, 256}; +}; + +} + +#endif diff --git a/reference/action/action.cpp b/reference/action/action.cpp new file mode 100644 index 0000000..320911d --- /dev/null +++ b/reference/action/action.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +void pAction::setEnabled(bool enabled) { +} + +void pAction::setVisible(bool visible) { +} + +void pAction::constructor() { +} + +void pAction::destructor() { +} + +} diff --git a/reference/action/action.hpp b/reference/action/action.hpp new file mode 100644 index 0000000..5e91be2 --- /dev/null +++ b/reference/action/action.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +struct pAction : public pObject { + Action& action; + + void setEnabled(bool enabled); + void setVisible(bool visible); + + pAction(Action& action) : pObject(action), action(action) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/action/check-item.cpp b/reference/action/check-item.cpp new file mode 100644 index 0000000..f7a33af --- /dev/null +++ b/reference/action/check-item.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +void pCheckItem::setChecked(bool checked) { +} + +void pCheckItem::setText(string text) { +} + +void pCheckItem::constructor() { +} + +void pCheckItem::destructor() { +} + +} diff --git a/reference/action/check-item.hpp b/reference/action/check-item.hpp new file mode 100644 index 0000000..3c1da56 --- /dev/null +++ b/reference/action/check-item.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +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(); +}; + +} diff --git a/reference/action/item.cpp b/reference/action/item.cpp new file mode 100644 index 0000000..b010da6 --- /dev/null +++ b/reference/action/item.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +void pItem::setImage(const image& image) { +} + +void pItem::setText(string text) { +} + +void pItem::constructor() { +} + +void pItem::destructor() { +} + +} diff --git a/reference/action/item.hpp b/reference/action/item.hpp new file mode 100644 index 0000000..9e255fb --- /dev/null +++ b/reference/action/item.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +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(); +}; + +} diff --git a/reference/action/menu.cpp b/reference/action/menu.cpp new file mode 100644 index 0000000..157858b --- /dev/null +++ b/reference/action/menu.cpp @@ -0,0 +1,21 @@ +namespace phoenix { + +void pMenu::append(Action& action) { +} + +void pMenu::remove(Action& action) { +} + +void pMenu::setImage(const image& image) { +} + +void pMenu::setText(string text) { +} + +void pMenu::constructor() { +} + +void pMenu::destructor() { +} + +} diff --git a/reference/action/menu.hpp b/reference/action/menu.hpp new file mode 100644 index 0000000..9bcddf6 --- /dev/null +++ b/reference/action/menu.hpp @@ -0,0 +1,16 @@ +namespace phoenix { + +struct pMenu : public pAction { + Menu& menu; + + 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(); +}; + +} diff --git a/reference/action/radio-item.cpp b/reference/action/radio-item.cpp new file mode 100644 index 0000000..e6fc123 --- /dev/null +++ b/reference/action/radio-item.cpp @@ -0,0 +1,18 @@ +namespace phoenix { + +void pRadioItem::setChecked() { +} + +void pRadioItem::setGroup(const group& group) { +} + +void pRadioItem::setText(string text) { +} + +void pRadioItem::constructor() { +} + +void pRadioItem::destructor() { +} + +} diff --git a/reference/action/radio-item.hpp b/reference/action/radio-item.hpp new file mode 100644 index 0000000..c574341 --- /dev/null +++ b/reference/action/radio-item.hpp @@ -0,0 +1,15 @@ +namespace phoenix { + +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(); +}; + +} diff --git a/reference/action/separator.cpp b/reference/action/separator.cpp new file mode 100644 index 0000000..64e2119 --- /dev/null +++ b/reference/action/separator.cpp @@ -0,0 +1,9 @@ +namespace phoenix { + +void pSeparator::constructor() { +} + +void pSeparator::destructor() { +} + +} diff --git a/reference/action/separator.hpp b/reference/action/separator.hpp new file mode 100644 index 0000000..de93d34 --- /dev/null +++ b/reference/action/separator.hpp @@ -0,0 +1,11 @@ +namespace phoenix { + +struct pSeparator : public pAction { + Separator& separator; + + pSeparator(Separator& separator) : pAction(separator), separator(separator) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/application.cpp b/reference/application.cpp new file mode 100644 index 0000000..a05d1c3 --- /dev/null +++ b/reference/application.cpp @@ -0,0 +1,19 @@ +namespace phoenix { + +void pApplication::run() { +} + +bool pApplication::pendingEvents() { + return false; +} + +void pApplication::processEvents() { +} + +void pApplication::quit() { +} + +void pApplication::initialize() { +} + +} diff --git a/reference/application.hpp b/reference/application.hpp new file mode 100644 index 0000000..effab50 --- /dev/null +++ b/reference/application.hpp @@ -0,0 +1,12 @@ +namespace phoenix { + +struct pApplication { + static void run(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + static void initialize(); +}; + +} diff --git a/reference/browser-window.cpp b/reference/browser-window.cpp new file mode 100644 index 0000000..f1885a7 --- /dev/null +++ b/reference/browser-window.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +string pBrowserWindow::directory(BrowserWindow::State& state) { + return ""; +} + +string pBrowserWindow::open(BrowserWindow::State& state) { + return ""; +} + +string pBrowserWindow::save(BrowserWindow::State& state) { + return ""; +} + +} diff --git a/reference/browser-window.hpp b/reference/browser-window.hpp new file mode 100644 index 0000000..56563bc --- /dev/null +++ b/reference/browser-window.hpp @@ -0,0 +1,9 @@ +namespace phoenix { + +struct pBrowserWindow { + static string directory(BrowserWindow::State& state); + static string open(BrowserWindow::State& state); + static string save(BrowserWindow::State& state); +}; + +} diff --git a/reference/desktop.cpp b/reference/desktop.cpp new file mode 100644 index 0000000..ba385d9 --- /dev/null +++ b/reference/desktop.cpp @@ -0,0 +1,11 @@ +namespace phoenix { + +Size pDesktop::size() { + return {0, 0}; +} + +Geometry pDesktop::workspace() { + return {0, 0, 0, 0}; +} + +} diff --git a/reference/desktop.hpp b/reference/desktop.hpp new file mode 100644 index 0000000..fed9ab6 --- /dev/null +++ b/reference/desktop.hpp @@ -0,0 +1,8 @@ +namespace phoenix { + +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +} diff --git a/reference/font.cpp b/reference/font.cpp new file mode 100644 index 0000000..e382add --- /dev/null +++ b/reference/font.cpp @@ -0,0 +1,19 @@ +namespace phoenix { + +string pFont::serif(unsigned size, string style) { + return ""; +} + +string pFont::sans(unsigned size, string style) { + return ""; +} + +string pFont::monospace(unsigned size, string style) { + return ""; +} + +Size pFont::size(string font, string text) { + return {0, 0}; +} + +} diff --git a/reference/font.hpp b/reference/font.hpp new file mode 100644 index 0000000..235806a --- /dev/null +++ b/reference/font.hpp @@ -0,0 +1,10 @@ +namespace phoenix { + +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); +}; + +} diff --git a/reference/header.hpp b/reference/header.hpp new file mode 100644 index 0000000..e69de29 diff --git a/reference/keyboard.cpp b/reference/keyboard.cpp new file mode 100644 index 0000000..9c2f8bb --- /dev/null +++ b/reference/keyboard.cpp @@ -0,0 +1,14 @@ +namespace phoenix { + +bool pKeyboard::pressed(Keyboard::Scancode scancode) { + return false; +} + +vector pKeyboard::state() { + vector output; + output.resize((unsigned)Keyboard::Scancode::Limit); + for(auto& n : output) n = false; + return output; +} + +} diff --git a/reference/keyboard.hpp b/reference/keyboard.hpp new file mode 100644 index 0000000..2c0a42a --- /dev/null +++ b/reference/keyboard.hpp @@ -0,0 +1,8 @@ +namespace phoenix { + +struct pKeyboard { + static bool pressed(Keyboard::Scancode scancode); + static vector state(); +}; + +} diff --git a/reference/message-window.cpp b/reference/message-window.cpp new file mode 100644 index 0000000..0334369 --- /dev/null +++ b/reference/message-window.cpp @@ -0,0 +1,19 @@ +namespace phoenix { + +MessageWindow::Response pMessageWindow::error(MessageWindow::State& state) { + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::information(MessageWindow::State& state) { + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::question(MessageWindow::State& state) { + return MessageWindow::Response::Ok; +} + +MessageWindow::Response pMessageWindow::warning(MessageWindow::State& state) { + return MessageWindow::Response::Ok; +} + +} diff --git a/reference/message-window.hpp b/reference/message-window.hpp new file mode 100644 index 0000000..b73b19e --- /dev/null +++ b/reference/message-window.hpp @@ -0,0 +1,10 @@ +namespace phoenix { + +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); +}; + +} diff --git a/reference/monitor.cpp b/reference/monitor.cpp new file mode 100644 index 0000000..de090e8 --- /dev/null +++ b/reference/monitor.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +unsigned pMonitor::count() { + return 1; +} + +Geometry pMonitor::geometry(unsigned monitor) { + return {0, 0, 0, 0}; +} + +unsigned pMonitor::primary() { + return 0; +} + +} diff --git a/reference/monitor.hpp b/reference/monitor.hpp new file mode 100644 index 0000000..0b5964c --- /dev/null +++ b/reference/monitor.hpp @@ -0,0 +1,9 @@ +namespace phoenix { + +struct pMonitor { + static unsigned count(); + static Geometry geometry(unsigned monitor); + static unsigned primary(); +}; + +} diff --git a/reference/mouse.cpp b/reference/mouse.cpp new file mode 100644 index 0000000..ca5e855 --- /dev/null +++ b/reference/mouse.cpp @@ -0,0 +1,11 @@ +namespace phoenix { + +Position pMouse::position() { + return {0, 0}; +} + +bool pMouse::pressed(Mouse::Button button) { + return false; +} + +} diff --git a/reference/mouse.hpp b/reference/mouse.hpp new file mode 100644 index 0000000..7e21f2e --- /dev/null +++ b/reference/mouse.hpp @@ -0,0 +1,8 @@ +namespace phoenix { + +struct pMouse { + static Position position(); + static bool pressed(Mouse::Button button); +}; + +} diff --git a/reference/object.cpp b/reference/object.cpp new file mode 100644 index 0000000..d1397b1 --- /dev/null +++ b/reference/object.cpp @@ -0,0 +1,9 @@ +namespace phoenix { + +void pObject::constructor() { +} + +void pObject::destructor() { +} + +} diff --git a/reference/object.hpp b/reference/object.hpp new file mode 100644 index 0000000..2c4e013 --- /dev/null +++ b/reference/object.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +struct pObject { + Object& object; + bool locked; + + pObject(Object& object) : object(object), locked(locked) {} + virtual ~pObject() {} + + void constructor(); + void destructor(); +}; + +} diff --git a/reference/platform.cpp b/reference/platform.cpp new file mode 100644 index 0000000..883b0b2 --- /dev/null +++ b/reference/platform.cpp @@ -0,0 +1,45 @@ +#include "platform.hpp" + +#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 "timer.cpp" +#include "window.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 "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/console.cpp" +#include "widget/frame.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroller.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-button.cpp" +#include "widget/radio-label.cpp" +#include "widget/tab-frame.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroller.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +#include "application.cpp" diff --git a/reference/platform.hpp b/reference/platform.hpp new file mode 100644 index 0000000..15cecec --- /dev/null +++ b/reference/platform.hpp @@ -0,0 +1,53 @@ +namespace phoenix { + struct pFont; + struct pWindow; + struct pMenu; + struct pLayout; + struct pWidget; +} + +#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 "timer.hpp" +#include "window.hpp" +#include "popup-menu.hpp" + +#include "action/action.hpp" +#include "action/menu.hpp" +#include "action/separator.hpp" +#include "action/item.hpp" +#include "action/check-item.hpp" +#include "action/radio-item.hpp" + +#include "widget/sizable.hpp" +#include "widget/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/console.hpp" +#include "widget/frame.hpp" +#include "widget/hex-edit.hpp" +#include "widget/horizontal-scroller.hpp" +#include "widget/horizontal-slider.hpp" +#include "widget/label.hpp" +#include "widget/line-edit.hpp" +#include "widget/list-view.hpp" +#include "widget/progress-bar.hpp" +#include "widget/radio-button.hpp" +#include "widget/radio-label.hpp" +#include "widget/tab-frame.hpp" +#include "widget/text-edit.hpp" +#include "widget/vertical-scroller.hpp" +#include "widget/vertical-slider.hpp" +#include "widget/viewport.hpp" + +#include "application.hpp" diff --git a/reference/popup-menu.cpp b/reference/popup-menu.cpp new file mode 100644 index 0000000..1dea8c2 --- /dev/null +++ b/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/reference/popup-menu.hpp b/reference/popup-menu.hpp new file mode 100644 index 0000000..c1eb064 --- /dev/null +++ b/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/reference/timer.cpp b/reference/timer.cpp new file mode 100644 index 0000000..1d24c5a --- /dev/null +++ b/reference/timer.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +void pTimer::setEnabled(bool enabled) { +} + +void pTimer::setInterval(unsigned interval) { +} + +void pTimer::constructor() { +} + +void pTimer::destructor() { +} + +} diff --git a/reference/timer.hpp b/reference/timer.hpp new file mode 100644 index 0000000..a924a9e --- /dev/null +++ b/reference/timer.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +struct pTimer : public pObject { + Timer& timer; + + void setEnabled(bool enabled); + void setInterval(unsigned interval); + + pTimer(Timer& timer) : pObject(timer), timer(timer) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/button.cpp b/reference/widget/button.cpp new file mode 100644 index 0000000..ad7c336 --- /dev/null +++ b/reference/widget/button.cpp @@ -0,0 +1,18 @@ +namespace phoenix { + +void pButton::setBordered(bool bordered) { +} + +void pButton::setImage(const image& image, Orientation orientation) { +} + +void pButton::setText(string text) { +} + +void pButton::constructor() { +} + +void pButton::destructor() { +} + +} diff --git a/reference/widget/button.hpp b/reference/widget/button.hpp new file mode 100644 index 0000000..c4e697b --- /dev/null +++ b/reference/widget/button.hpp @@ -0,0 +1,15 @@ +namespace phoenix { + +struct pButton : public pWidget { + Button& button; + + void setBordered(bool bordered); + void setImage(const image& image, Orientation orientation); + void setText(string text); + + pButton(Button& button) : pWidget(button), button(button) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/canvas.cpp b/reference/widget/canvas.cpp new file mode 100644 index 0000000..b62da56 --- /dev/null +++ b/reference/widget/canvas.cpp @@ -0,0 +1,18 @@ +namespace phoenix { + +void pCanvas::setDroppable(bool droppable) { +} + +void pCanvas::setMode(Canvas::Mode mode) { +} + +void pCanvas::setSize(Size size) { +} + +void pCanvas::constructor() { +} + +void pCanvas::destructor() { +} + +} diff --git a/reference/widget/canvas.hpp b/reference/widget/canvas.hpp new file mode 100644 index 0000000..67167cb --- /dev/null +++ b/reference/widget/canvas.hpp @@ -0,0 +1,15 @@ +namespace phoenix { + +struct pCanvas : public pWidget { + Canvas& canvas; + + void setDroppable(bool droppable); + void setMode(Canvas::Mode mode); + void setSize(Size size); + + pCanvas(Canvas& canvas) : pWidget(canvas), canvas(canvas) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/check-button.cpp b/reference/widget/check-button.cpp new file mode 100644 index 0000000..ff13e27 --- /dev/null +++ b/reference/widget/check-button.cpp @@ -0,0 +1,18 @@ +namespace phoenix { + +void pCheckButton::setChecked(bool checked) { +} + +void pCheckButton::setImage(const image& image, Orientation orientation) { +} + +void pCheckButton::setText(string text) { +} + +void pCheckButton::constructor() { +} + +void pCheckButton::destructor() { +} + +} diff --git a/reference/widget/check-button.hpp b/reference/widget/check-button.hpp new file mode 100644 index 0000000..eae9ad2 --- /dev/null +++ b/reference/widget/check-button.hpp @@ -0,0 +1,15 @@ +namespace phoenix { + +struct pCheckButton : public pWidget { + CheckButton& checkButton; + + 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(); +}; + +} diff --git a/reference/widget/check-label.cpp b/reference/widget/check-label.cpp new file mode 100644 index 0000000..f375120 --- /dev/null +++ b/reference/widget/check-label.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +void pCheckLabel::setChecked(bool checked) { +} + +void pCheckLabel::setText(string text) { +} + +void pCheckLabel::constructor() { +} + +void pCheckLabel::destructor() { +} + +} diff --git a/reference/widget/check-label.hpp b/reference/widget/check-label.hpp new file mode 100644 index 0000000..254092f --- /dev/null +++ b/reference/widget/check-label.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +struct pCheckLabel : public pWidget { + CheckLabel& checkLabel; + + void setChecked(bool checked); + void setText(string text); + + pCheckLabel(CheckLabel& checkLabel) : pWidget(checkLabel), checkLabel(checkLabel) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/combo-button.cpp b/reference/widget/combo-button.cpp new file mode 100644 index 0000000..d9f5d3b --- /dev/null +++ b/reference/widget/combo-button.cpp @@ -0,0 +1,24 @@ +namespace phoenix { + +void pComboButton::append() { +} + +void pComboButton::remove(unsigned selection) { +} + +void pComboButton::reset() { +} + +void pComboButton::setSelected(unsigned selection) { +} + +void pComboButton::setText(unsigned selection, string text) { +} + +void pComboButton::constructor() { +} + +void pComboButton::destructor() { +} + +} diff --git a/reference/widget/combo-button.hpp b/reference/widget/combo-button.hpp new file mode 100644 index 0000000..8b2b303 --- /dev/null +++ b/reference/widget/combo-button.hpp @@ -0,0 +1,17 @@ +namespace phoenix { + +struct pComboButton : public pWidget { + ComboButton& comboButton; + + void append(); + void remove(unsigned selection); + void reset(); + void setSelected(unsigned selection); + void setText(unsigned selection, string text); + + pComboButton(ComboButton& comboButton) : pWidget(comboButton), comboButton(comboButton) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/console.cpp b/reference/widget/console.cpp new file mode 100644 index 0000000..fc27bcf --- /dev/null +++ b/reference/widget/console.cpp @@ -0,0 +1,24 @@ +namespace phoenix { + +void pConsole::print(string text) { +} + +void pConsole::reset() { +} + +void pConsole::setBackgroundColor(Color color) { +} + +void pConsole::setForegroundColor(Color color) { +} + +void pConsole::setPrompt(string prompt) { +} + +void pConsole::constructor() { +} + +void pConsole::destructor() { +} + +} diff --git a/reference/widget/console.hpp b/reference/widget/console.hpp new file mode 100644 index 0000000..50d2ce0 --- /dev/null +++ b/reference/widget/console.hpp @@ -0,0 +1,17 @@ +namespace phoenix { + +struct pConsole : public pWidget { + Console& console; + + 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(); +}; + +} diff --git a/reference/widget/frame.cpp b/reference/widget/frame.cpp new file mode 100644 index 0000000..cfac625 --- /dev/null +++ b/reference/widget/frame.cpp @@ -0,0 +1,12 @@ +namespace phoenix { + +void pFrame::setText(string text) { +} + +void pFrame::constructor() { +} + +void pFrame::destructor() { +} + +} diff --git a/reference/widget/frame.hpp b/reference/widget/frame.hpp new file mode 100644 index 0000000..f447734 --- /dev/null +++ b/reference/widget/frame.hpp @@ -0,0 +1,13 @@ +namespace phoenix { + +struct pFrame : public pWidget { + Frame& frame; + + void setText(string text); + + pFrame(Frame& frame) : pWidget(frame), frame(frame) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/hex-edit.cpp b/reference/widget/hex-edit.cpp new file mode 100644 index 0000000..b816cbc --- /dev/null +++ b/reference/widget/hex-edit.cpp @@ -0,0 +1,30 @@ +namespace phoenix { + +void pHexEdit::setBackgroundColor(Color color) { +} + +void pHexEdit::setColumns(unsigned columns) { +} + +void pHexEdit::setForegroundColor(Color color) { +} + +void pHexEdit::setLength(unsigned length) { +} + +void pHexEdit::setOffset(unsigned offset) { +} + +void pHexEdit::setRows(unsigned rows) { +} + +void pHexEdit::update() { +} + +void pHexEdit::constructor() { +} + +void pHexEdit::destructor() { +} + +} diff --git a/reference/widget/hex-edit.hpp b/reference/widget/hex-edit.hpp new file mode 100644 index 0000000..e79b929 --- /dev/null +++ b/reference/widget/hex-edit.hpp @@ -0,0 +1,19 @@ +namespace phoenix { + +struct pHexEdit : public pWidget { + HexEdit& hexEdit; + + 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(); +}; + +} diff --git a/reference/widget/horizontal-scroller.cpp b/reference/widget/horizontal-scroller.cpp new file mode 100644 index 0000000..6bd66d0 --- /dev/null +++ b/reference/widget/horizontal-scroller.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +void pHorizontalScroller::setLength(unsigned length) { +} + +void pHorizontalScroller::setPosition(unsigned position) { +} + +void pHorizontalScroller::constructor() { +} + +void pHorizontalScroller::destructor() { +} + +} diff --git a/reference/widget/horizontal-scroller.hpp b/reference/widget/horizontal-scroller.hpp new file mode 100644 index 0000000..8649b42 --- /dev/null +++ b/reference/widget/horizontal-scroller.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +struct pHorizontalScroller : public pWidget { + HorizontalScroller& horizontalScroller; + + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalScroller(HorizontalScroller& horizontalScroller) : pWidget(horizontalScroller), horizontalScroller(horizontalScroller) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/horizontal-slider.cpp b/reference/widget/horizontal-slider.cpp new file mode 100644 index 0000000..96c2f8c --- /dev/null +++ b/reference/widget/horizontal-slider.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +void pHorizontalSlider::setLength(unsigned length) { +} + +void pHorizontalSlider::setPosition(unsigned position) { +} + +void pHorizontalSlider::constructor() { +} + +void pHorizontalSlider::destructor() { +} + +} diff --git a/reference/widget/horizontal-slider.hpp b/reference/widget/horizontal-slider.hpp new file mode 100644 index 0000000..2bb7a40 --- /dev/null +++ b/reference/widget/horizontal-slider.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +struct pHorizontalSlider : public pWidget { + HorizontalSlider& horizontalSlider; + + void setLength(unsigned length); + void setPosition(unsigned position); + + pHorizontalSlider(HorizontalSlider& horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/label.cpp b/reference/widget/label.cpp new file mode 100644 index 0000000..cf5af2c --- /dev/null +++ b/reference/widget/label.cpp @@ -0,0 +1,12 @@ +namespace phoenix { + +void pLabel::setText(string text) { +} + +void pLabel::constructor() { +} + +void pLabel::destructor() { +} + +} diff --git a/reference/widget/label.hpp b/reference/widget/label.hpp new file mode 100644 index 0000000..1d6a94f --- /dev/null +++ b/reference/widget/label.hpp @@ -0,0 +1,13 @@ +namespace phoenix { + +struct pLabel : public pWidget { + Label& label; + + void setText(string text); + + pLabel(Label& label) : pWidget(label), label(label) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/layout.hpp b/reference/widget/layout.hpp new file mode 100644 index 0000000..45b0d2d --- /dev/null +++ b/reference/widget/layout.hpp @@ -0,0 +1,9 @@ +namespace phoenix { + +struct pLayout : public pSizable { + Layout& layout; + + pLayout(Layout& layout) : pSizable(layout), layout(layout) {} +}; + +} diff --git a/reference/widget/line-edit.cpp b/reference/widget/line-edit.cpp new file mode 100644 index 0000000..2ccdb29 --- /dev/null +++ b/reference/widget/line-edit.cpp @@ -0,0 +1,24 @@ +namespace phoenix { + +void pLineEdit::setBackgroundColor(Color color) { +} + +void pLineEdit::setEditable(bool editable) { +} + +void pLineEdit::setForegroundColor(Color color) { +} + +void pLineEdit::setText(string text) { +} + +string pLineEdit::text() { +} + +void pLineEdit::constructor() { +} + +void pLineEdit::destructor() { +} + +} diff --git a/reference/widget/line-edit.hpp b/reference/widget/line-edit.hpp new file mode 100644 index 0000000..bf1c319 --- /dev/null +++ b/reference/widget/line-edit.hpp @@ -0,0 +1,17 @@ +namespace phoenix { + +struct pLineEdit : public pWidget { + LineEdit& lineEdit; + + 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(); +}; + +} diff --git a/reference/widget/list-view.cpp b/reference/widget/list-view.cpp new file mode 100644 index 0000000..d774389 --- /dev/null +++ b/reference/widget/list-view.cpp @@ -0,0 +1,69 @@ +namespace phoenix { + +void pListView::append() { +} + +void pListView::autoSizeColumns() { +} + +void pListView::remove(unsigned selection) { +} + +void pListView::reset() { +} + +void pListView::setBackgroundColor(Color color) { +} + +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) { +} + +void pListView::setHeaderText(const lstring& text) { +} + +void pListView::setHeaderVisible(bool visible) { +} + +void pListView::setImage(unsigned selection, unsigned position, const image& image) { +} + +void pListView::setSelected(unsigned selection, bool selected) { +} + +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) { +} + +void pListView::constructor() { +} + +void pListView::destructor() { +} + +} diff --git a/reference/widget/list-view.hpp b/reference/widget/list-view.hpp new file mode 100644 index 0000000..3b2e152 --- /dev/null +++ b/reference/widget/list-view.hpp @@ -0,0 +1,32 @@ +namespace phoenix { + +struct pListView : public pWidget { + ListView& listView; + + 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(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) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/progress-bar.cpp b/reference/widget/progress-bar.cpp new file mode 100644 index 0000000..7697f65 --- /dev/null +++ b/reference/widget/progress-bar.cpp @@ -0,0 +1,12 @@ +namespace phoenix { + +void pProgressBar::setPosition(unsigned position) { +} + +void pProgressBar::constructor() { +} + +void pProgressBar::destructor() { +} + +} diff --git a/reference/widget/progress-bar.hpp b/reference/widget/progress-bar.hpp new file mode 100644 index 0000000..c076708 --- /dev/null +++ b/reference/widget/progress-bar.hpp @@ -0,0 +1,13 @@ +namespace phoenix { + +struct pProgressBar : public pWidget { + ProgressBar& progressBar; + + void setPosition(unsigned position); + + pProgressBar(ProgressBar& progressBar) : pWidget(progressBar), progressBar(progressBar) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/radio-button.cpp b/reference/widget/radio-button.cpp new file mode 100644 index 0000000..457499e --- /dev/null +++ b/reference/widget/radio-button.cpp @@ -0,0 +1,21 @@ +namespace phoenix { + +void pRadioButton::setChecked() { +} + +void pRadioButton::setGroup(const group& group) { +} + +void pRadioButton::setImage(const image& image, Orientation orientation) { +} + +void pRadioButton::setText(string text) { +} + +void pRadioButton::constructor() { +} + +void pRadioButton::destructor() { +} + +} diff --git a/reference/widget/radio-button.hpp b/reference/widget/radio-button.hpp new file mode 100644 index 0000000..d9377bc --- /dev/null +++ b/reference/widget/radio-button.hpp @@ -0,0 +1,16 @@ +namespace phoenix { + +struct pRadioButton : public pWidget { + RadioButton& radioButton; + + 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(); +}; + +} diff --git a/reference/widget/radio-label.cpp b/reference/widget/radio-label.cpp new file mode 100644 index 0000000..6181151 --- /dev/null +++ b/reference/widget/radio-label.cpp @@ -0,0 +1,18 @@ +namespace phoenix { + +void pRadioLabel::setChecked() { +} + +void pRadioLabel::setGroup(const group& group) { +} + +void pRadioLabel::setText(string text) { +} + +void pRadioLabel::constructor() { +} + +void pRadioLabel::destructor() { +} + +} diff --git a/reference/widget/radio-label.hpp b/reference/widget/radio-label.hpp new file mode 100644 index 0000000..ddd6b8a --- /dev/null +++ b/reference/widget/radio-label.hpp @@ -0,0 +1,15 @@ +namespace phoenix { + +struct pRadioLabel : public pWidget { + RadioLabel& radioLabel; + + void setChecked(); + void setGroup(const group& group); + void setText(string text); + + pRadioLabel(RadioLabel& radioLabel) : pWidget(radioLabel), radioLabel(radioLabel) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/sizable.hpp b/reference/widget/sizable.hpp new file mode 100644 index 0000000..afb33e6 --- /dev/null +++ b/reference/widget/sizable.hpp @@ -0,0 +1,9 @@ +namespace phoenix { + +struct pSizable : public pObject { + Sizable& sizable; + + pSizable(Sizable& sizable) : pObject(sizable), sizable(sizable) {} +}; + +} diff --git a/reference/widget/tab-frame.cpp b/reference/widget/tab-frame.cpp new file mode 100644 index 0000000..065a89b --- /dev/null +++ b/reference/widget/tab-frame.cpp @@ -0,0 +1,24 @@ +namespace phoenix { + +void pTabFrame::append() { +} + +void pTabFrame::remove(unsigned selection) { +} + +void pTabFrame::setImage(unsigned selection, const image& image) { +} + +void pTabFrame::setSelected(unsigned selection) { +} + +void pTabFrame::setText(unsigned selection, string text) { +} + +void pTabFrame::constructor() { +} + +void pTabFrame::destructor() { +} + +} diff --git a/reference/widget/tab-frame.hpp b/reference/widget/tab-frame.hpp new file mode 100644 index 0000000..9984ef1 --- /dev/null +++ b/reference/widget/tab-frame.hpp @@ -0,0 +1,17 @@ +namespace phoenix { + +struct pTabFrame : public pWidget { + TabFrame& tabFrame; + + void append(); + void remove(unsigned selection); + void setImage(unsigned selection, const image& image); + void setSelected(unsigned selection); + void setText(unsigned selection, string text); + + pTabFrame(TabFrame& tabFrame) : pWidget(tabFrame), tabFrame(tabFrame) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/text-edit.cpp b/reference/widget/text-edit.cpp new file mode 100644 index 0000000..064e304 --- /dev/null +++ b/reference/widget/text-edit.cpp @@ -0,0 +1,30 @@ +namespace phoenix { + +void pTextEdit::setBackgroundColor(Color color) { +} + +void pTextEdit::setCursorPosition(unsigned position) { +} + +void pTextEdit::setEditable(bool editable) { +} + +void pTextEdit::setForegroundColor(Color color) { +} + +void pTextEdit::setText(string text) { +} + +void pTextEdit::setWordWrap(bool wordWrap) { +} + +string pTextEdit::text() { +} + +void pTextEdit::constructor() { +} + +void pTextEdit::destructor() { +} + +} diff --git a/reference/widget/text-edit.hpp b/reference/widget/text-edit.hpp new file mode 100644 index 0000000..8d4cf77 --- /dev/null +++ b/reference/widget/text-edit.hpp @@ -0,0 +1,19 @@ +namespace phoenix { + +struct pTextEdit : public pWidget { + TextEdit& textEdit; + + 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(); +}; + +} diff --git a/reference/widget/vertical-scroller.cpp b/reference/widget/vertical-scroller.cpp new file mode 100644 index 0000000..533653c --- /dev/null +++ b/reference/widget/vertical-scroller.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +void pVerticalScroller::setLength(unsigned length) { +} + +void pVerticalScroller::setPosition(unsigned position) { +} + +void pVerticalScroller::constructor() { +} + +void pVerticalScroller::destructor() { +} + +} diff --git a/reference/widget/vertical-scroller.hpp b/reference/widget/vertical-scroller.hpp new file mode 100644 index 0000000..77e13a4 --- /dev/null +++ b/reference/widget/vertical-scroller.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +struct pVerticalScroller : public pWidget { + VerticalScroller& verticalScroller; + + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalScroller(VerticalScroller& verticalScroller) : pWidget(verticalScroller), verticalScroller(verticalScroller) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/vertical-slider.cpp b/reference/widget/vertical-slider.cpp new file mode 100644 index 0000000..36d62eb --- /dev/null +++ b/reference/widget/vertical-slider.cpp @@ -0,0 +1,15 @@ +namespace phoenix { + +void pVerticalSlider::setLength(unsigned length) { +} + +void pVerticalSlider::setPosition(unsigned position) { +} + +void pVerticalSlider::constructor() { +} + +void pVerticalSlider::destructor() { +} + +} diff --git a/reference/widget/vertical-slider.hpp b/reference/widget/vertical-slider.hpp new file mode 100644 index 0000000..0cfdf43 --- /dev/null +++ b/reference/widget/vertical-slider.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +struct pVerticalSlider : public pWidget { + VerticalSlider& verticalSlider; + + void setLength(unsigned length); + void setPosition(unsigned position); + + pVerticalSlider(VerticalSlider& verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/viewport.cpp b/reference/widget/viewport.cpp new file mode 100644 index 0000000..7ed229a --- /dev/null +++ b/reference/widget/viewport.cpp @@ -0,0 +1,16 @@ +namespace phoenix { + +uintptr_t pViewport::handle() { + return 0; +} + +void pViewport::setDroppable(bool droppable) { +} + +void pViewport::constructor() { +} + +void pViewport::destructor() { +} + +} diff --git a/reference/widget/viewport.hpp b/reference/widget/viewport.hpp new file mode 100644 index 0000000..75ef63a --- /dev/null +++ b/reference/widget/viewport.hpp @@ -0,0 +1,14 @@ +namespace phoenix { + +struct pViewport : public pWidget { + Viewport& viewport; + + uintptr_t handle(); + void setDroppable(bool droppable); + + pViewport(Viewport& viewport) : pWidget(viewport), viewport(viewport) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/widget/widget.cpp b/reference/widget/widget.cpp new file mode 100644 index 0000000..8589f5d --- /dev/null +++ b/reference/widget/widget.cpp @@ -0,0 +1,36 @@ +namespace phoenix { + +bool pWidget::enabled() { + return false; +} + +bool pWidget::focused() { + return false; +} + +Size pWidget::minimumSize() { + return {0, 0}; +} + +void pWidget::setEnabled(bool enabled) { +} + +void pWidget::setFocused() { +} + +void pWidget::setFont(string font) { +} + +void pWidget::setGeometry(Geometry geometry) { +} + +void pWidget::setVisible(bool visible) { +} + +void pWidget::constructor() { +} + +void pWidget::destructor() { +} + +} diff --git a/reference/widget/widget.hpp b/reference/widget/widget.hpp new file mode 100644 index 0000000..6a624a0 --- /dev/null +++ b/reference/widget/widget.hpp @@ -0,0 +1,20 @@ +namespace phoenix { + +struct pWidget : public pSizable { + Widget& widget; + + bool enabled(); + bool focused(); + Size minimumSize(); + void setEnabled(bool enabled); + void setFocused(); + void setFont(string font); + void setGeometry(Geometry geometry); + void setVisible(bool visible); + + pWidget(Widget& widget) : pSizable(widget), widget(widget) {} + void constructor(); + void destructor(); +}; + +} diff --git a/reference/window.cpp b/reference/window.cpp new file mode 100644 index 0000000..20b63eb --- /dev/null +++ b/reference/window.cpp @@ -0,0 +1,86 @@ +namespace phoenix { + +Window& pWindow::none() { + static Window* window = nullptr; + if(window == nullptr) window = new Window; + return *window; +} + +void pWindow::append(Layout& layout) { +} + +void pWindow::append(Menu& menu) { +} + +void pWindow::append(Widget& widget) { +} + +bool pWindow::focused() { + return false; +} + +Geometry pWindow::frameMargin() { + return {0, 0, 0, 0}; +} + +void pWindow::remove(Layout& layout) { +} + +void pWindow::remove(Menu& menu) { +} + +void pWindow::remove(Widget& widget) { +} + +void pWindow::setBackgroundColor(Color color) { +} + +void pWindow::setDroppable(bool droppable) { +} + +void pWindow::setFocused() { +} + +void pWindow::setFullScreen(bool fullScreen) { +} + +void pWindow::setGeometry(Geometry geometry) { +} + +void pWindow::setMenuFont(string font) { +} + +void pWindow::setMenuVisible(bool visible) { +} + +void pWindow::setModal(bool modal) { +} + +void pWindow::setResizable(bool resizable) { +} + +void pWindow::setStatusFont(string font) { +} + +void pWindow::setStatusText(string text) { +} + +void pWindow::setStatusVisible(bool visible) { +} + +void pWindow::setTitle(string text) { +} + +void pWindow::setVisible(bool visible) { +} + +void pWindow::setWidgetFont(string font) { +} + +void pWindow::constructor() { +} + +void pWindow::destructor() { +} + +} diff --git a/reference/window.hpp b/reference/window.hpp new file mode 100644 index 0000000..b72efc8 --- /dev/null +++ b/reference/window.hpp @@ -0,0 +1,37 @@ +namespace phoenix { + +struct pWindow : public pObject { + Window& window; + + static Window& none(); + + void append(Layout& layout); + void append(Menu& menu); + void append(Widget& widget); + bool focused(); + Geometry frameMargin(); + 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(); + void destructor(); +}; + +} diff --git a/resource/GNUmakefile b/resource/GNUmakefile new file mode 100644 index 0000000..97e085c --- /dev/null +++ b/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/resource/icon/action/add.png b/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/resource/icon/action/attach.png b/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/resource/icon/action/bookmark.png b/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/resource/icon/action/full-screen.png b/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/resource/icon/action/refresh.png b/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/resource/icon/action/save.png b/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/resource/icon/action/search.png b/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/resource/icon/action/settings.png b/resource/icon/action/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..9460dfc746be14e4b2a6a94f91d002fa4a56318f GIT binary patch literal 611 zcmV-p0-XJcP)f=aN=#)Y=sMXW9~6k=xULU18eq^Pwm5>f&c14BZf zYe95nK#JnRiH*==SAxmkLmxdrjL^?BWW`;2x>%z19x#ygF@3}wxCj{ps zol&BI3dr$TBKH?fG@Vgwj@VLE`>*x`sHT~#`1-X0&1|$C>5O7D8g(O`Q4IH5!>UCA z#B@f9T4bxM*W2c190hpr@ILWaLI!dGBA^c595S9hn=kAOg|QenCF1t1xZCGP(7 zj844Dzcfmf65S_zD3%MD6HEfSt3fc5ItMc{ 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/resource/icon/application/calculator.png b/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/resource/icon/application/chat.png b/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&oQAjQodNDi79I5|3(RJen zPo0{EhVu`FIhs1;8#^*ol`_^Ua5ZgRTEO;6WS?JG1xHlIrtQ_)g8XMypD%bh92XZL%@y~j=r?zX#<>_Ay zj?MhVvcApGd@i4rvfN_pU)QGW`q#B_OPRhKo8-;yZEvqm4`R9-*L?7~b=36Kx*Zc}(y&$D=J@HUQ8!MxuejCZ|M!i% z&Q&&tS9kw!Gf+%;qdi-?J-PWx^^%|^_nzBbuuzY(&i>xb{m0@?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/resource/icon/application/monitor.png b/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/resource/icon/application/terminal.png b/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#$#>It74)E>!>k0}e?< zK~y-)Ws*xwTxA@^f8TfSyqLLnU?K?8$|G1EY%rF-;-axT+?a~Nx*!@hCPY`YH6|=g zV;Ucc#zal5HL;66@DWW+qb{%oO;sobI#?^(5$Q~)%nZZKy~7N5zR!(qD4yi(&N=@_ zj$jjx92gnWk{1QyVU!LCLwZ_@8&$P_=AF-8e`T{?Y%um{_;mNaM|-yS#tBEl2mx9{ zaka$ERDw&F=F@}2=Z^I}k_sYql2G!rxxsv4aCpEj8;Vt*gDAdsXNui%jCkNd8aq?X zjm?!eJ-u_)(7&t*w_Qm9jXpj&JYe5gE71N>h-mfgyVkVpEw*lJp?7bNXu~dpz`G5| zr=!3QdE~&z(C&RZc9yh9TUR43TjHC~L`sPe0y7XpvP7kH0;e<+1pR{q2DbOcSuSU3 zZEdEI|A+YFr$}dgcRx!ADqbI+=qHt|a`M9ms(A98snL7Fkua7QLMesMXHj;Ggz79t zUfPD=-pg}sIc(cP$QaUp5W~C4!qmsnp%?mt5~vpfnwlEO7xE~js40!(6gm3d??htV zOiWCmltOETVH%i*1f>PgWdbW&6Dzw_Iy%~^RMt>RQ7jhe?(XL0!>@Af+Er?`8d6HM zQfLiGG_W8A;-XV>So}MUQVP%W@H~%0hYpiSB*QJv%5E8_kF0oOuSo0O-88Yi?mS`RxAv zkNN-nW071T&;4y%2nK=#gCYFB05|{2kiWjd$q&xz*`?X{r{;f}1F{CdOmaH!H~m+Z zu4eW$HN>KAEv->#4UcH#K>>F>S)(m+mZ=t@1%`Q)zt z=kL2`>r-|9x)v#bCe_ X$s}Y37Q!~)00000NkvXXu0mjf?g64A literal 0 HcmV?d00001 diff --git a/resource/icon/device/display.png b/resource/icon/device/display.png new file mode 100644 index 0000000000000000000000000000000000000000..226881fd2577f6a1a09dd34ab90da08dad82f463 GIT binary patch literal 662 zcmV;H0%`q;P)IuR2CK|Gr(s_OsGcg~@t z-EQ+g;X0kp9T9n`s?$0gNNb%WR4uK%AuP^b%AZmHJ+_iDi1`G!>2x}`YPH$}5sg3$FjJ{GSE*LT8UsKP0$G-6KFo)}SJ0r!uJ_4(m*@FH zp63eysv5OUjJ=(2x6fU=c$x8&9smFU07*qoM6N<$f*XM(!~g&Q literal 0 HcmV?d00001 diff --git a/resource/icon/device/joypad.png b/resource/icon/device/joypad.png new file mode 100644 index 0000000000000000000000000000000000000000..9d040ee84356e8c9412d290dd72537c93d012189 GIT binary patch literal 812 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE(~iJd>I%_u3fJNif|Tq zL>4nJa0`PlBg3pY5H=O_Ny%H{9NjrPA;Aa6zVB)jVN)>&&^HED`D_W%`4R{ z&a6sJQOHcr&*QR%11>I&WK9Jl0|R3Puf*)qBn9=X%-r0>WOaq$lGMz+)FK@Pu8fkB z0xNxeh=g8lX>n$9Mq*BmUUC%|S8`EmVhPaL^30M9g_4X^1$R&103Dc?^73-M^vv7> zz5Jr|^seLX3=B+)o-U3d7N@69I-MQtC~~ZR@|`DY*DfvDX!iAD`+^;w8$|v$HB}3C zbu_I|h~PNbx|V;--3~n$F0LjIvDmA-gk3JQ?p6xfEbJnpC2DHAJ@d=6()?#Tc4W?S z+VrB4`S6Fc=KFs>)3Ca7d~?hHRdYP;%mal}rgpIe0%CEWiYw`il@t9Jc@ z4_9(?Za+J=R+EQet!b-MBKPYbmPPq;m+h|{Kas)TCb{6pXa1d`?aa^hlOn|&jdx6K z%=j3!C#+F``TF#TE6acG`qFy-z1_!ECg=XmejnHwlSeO?x>s<5?Ule%B@c*;dJSOJmD|yjJQqd#GG;VOkNkn&C>; n);_kr#}#gG-748lf6K2pz%W1Y*_t!JM9kpn>gTe~DWM4fe9c@A literal 0 HcmV?d00001 diff --git a/resource/icon/device/keyboard.png b/resource/icon/device/keyboard.png new file mode 100644 index 0000000000000000000000000000000000000000..fab414b888c3b35bd85eeca49e39993b7e1268eb GIT binary patch literal 587 zcmV-R0<`^!P)4Cb1OgF$i6E#rRpXMPRdA8izLzw8xejeL9i+kH2bXg$ z=X~G2=kTdgsl;)h50ZMlu8t)zzc8O3hESN^@*a0FbXkR(`dY$tyFHFUtN9N6cO)s zkUrssVTaAHpGYOspa2v~DcbEe`CN`Tj`_0rnQS&sYBZ4b49z@*Xsd_smXJ6x?M73<7ULOcY#HT<9OrgvnN`q;hpT91IITQaN@sWXdnDH ZfnWS_iR7f0nwJ0o002ovPDHLkV1iuP0Vn_f literal 0 HcmV?d00001 diff --git a/resource/icon/device/microphone.png b/resource/icon/device/microphone.png new file mode 100644 index 0000000000000000000000000000000000000000..53a0393179be5826bebc644c40f887850fa842e1 GIT binary patch literal 703 zcmV;w0zmzVP)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/resource/icon/device/mouse.png b/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%y{W;-5;PJdx@v7EBiGj0WoF~ZZl3n1_nk|PZ!4!i_>!_*?J!i5NVq~JLZ%9 z61}@jkKQRfQVaUuEXbu~;dMmo#ghR0OYsUU$*lj|n)CFUEM|zUYP`1UVUQ3zuhgf+ z53=Vg&!4V5x3`ID>$h#T3mkV^ZCY|OVn+OuF!SQs&CA*MtjnIt8nAk{j=8=;&lca6 zoZ;uV7?v_Raqu`No%3ThRAAV#cb|IKKATNFU$^W%e@A4+bh-Ydw(tB$Ut9Q8rnrVx zozK57D%)VuS1+(?gWKZ7RsX7+z1F;Y7?ig8j9_W(Vta|_o2=Z~D_hF69z0vezwtzB zY;^82HB;ZmM>4mkBn4$P8Oo&QP0-+Ix}$u$<@u)_fj_ty-u;YBbU6Nc*ERY2d)u~` zm31?%>HX?^$l%OepNPgo3^n(k@1K-f6Z(bobP0l+XkK`c@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}%0eHNk7R5*>L zlfO?>Q545N=l1obM5qJ7$v;42LIjI|ab)pFSSVPcE+q15I_Us^gfU&M3=N5(sc8bl zg~X_XgNYCqMXZxLu(+7_O!QseJr2g&7K}l^<2j$4d%oX$uc#{jBlD+5emb8Ef*}1* z0}6$S!4&d1j^osU2NVhugK0nWR8_OB^`YQiaC&xmtdsXHO;3hE#`Ct% zGug`BO415Cr|*quH5WYW->6J}X>K4$rhL2X&CksrR+uZ5O4-qoGkBf{KyG%aIC5?2 z=;p%JCkpFme6!7hqV)A0;rOu=sHzN{JVhqcg@^zkLT@6J0Yqg*kkLIEyxDrqyT)4p z8jWqXx3{p?0+4bn0%IbG8utoxNCatS01$>@b7i}0QGUOTU89MpqyVhZ#80Fxcmohd zAz>7vs@T|KW7`A-Q$X~YD(WSv0bo;GPA~vb6tT0j1Hgw*ABk<;8o#HcZ~TPyg2Ico zYgARO*XxOhSR-a}b#>+P_{H(=U%<A@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/resource/icon/edit/clear.png b/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/resource/icon/edit/copy.png b/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/resource/icon/edit/cut.png b/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/resource/icon/edit/delete.png b/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/resource/icon/edit/paste.png b/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/resource/icon/edit/replace.png b/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/resource/icon/emblem/archive.png b/resource/icon/emblem/archive.png new file mode 100644 index 0000000000000000000000000000000000000000..9015426153054c0b529b4d9ebdfa06a221d568ac GIT binary patch literal 540 zcmV+%0^|LOP)Vhlm95D^5CAW0*NO~l4h2`Gn+SSXee3p=k!DITN| zloYWEXca63MGv(U^qPobY>b#9Dp8{0UEbTVcsUg#cu}XB*@6F?*_nZVGy!PT%rNk5 zliHE-nb49(%`}10vsV}N{rqDUTQ;Bo7$dnCNIoxON&^{bA}^laGjk880qPdu^yOBT zEWa_clc&Tx2f*4|8y`gof^!a2aQL`dICk+4OK+dE`@k5lTlYsTutSWPkfmY@o;2kB zMZE(6RQjtR27v0WeY98J5hzgEvJDN{um$>(l@Gjpa+{MEra-d|pH&4=2yN1juSixu z;fgT;7AQWtIU$FSo`duYWUHV7)eJ(4YRG+92Ww!@-u*n7y$)#60)BA&kYbGBD?sJP zdQc>%Uxr2wvM|?-q){`MfcjsaLA`SadgR1;mgk#Ysp6f7xO?jg<1;~QC+VXy zJ@MAA0M19>^MF*i^r8aGC)22;clK1a-4t0{mr8nMj zAHH{dL{-^InH_BdZoB5C8+)IM=rL6chyw_sMioaCqk@1qD64G&S*GX5$4_++^bNBs z*hj(d!}9`+amccWR#c_lT;|b}2mNgU0D}Yj$@@M*5Kt_X2>c;(UXfN*p%yNX_X7~L zBcNKFC$U?^NsW4=OjoW4!68XQqGXdO-T@3oDZc{)zi)3wz2)yeco3#m6|DG^4GjQ7V%x%vUj_11a;(BhT#E787Wn}Vd zX{^gN_wxDPLn7ihuCZ2QP{h4>ZSaEUIgihtIhP+fe3G!a#7gCpvr(Hv6+$z3v%k0J z?)2oX!k*njgv}L}Dj(Sj=K#cYj9eKxTF6KGmG3_nX+`TaqczNSI0buW^u&R}@2$5i zS5umCg(L|v#zPh3D*EBaTw}D@Q!e=a3Tdi@^^AJ0fwk7Sj;t=0e-(4xiHI1YRzzjJ zL1nFx07g`m>FcHYAeXaD`$QyhT$xApa~kU_&~J`so@JRHF-BsA%rWvMP3#+tdHn}< WF%C7a=_bMe0000D1xM5I}MNt#wchYVWS&J@CLX5H%;8IVB^kk0WO-j zVZ#M9-hk1Sapgj)3EEN2454WYwESiIhbS(TW)x<2yvbQUPfqfl10h*lTAiF(czU+D zv^q&dWEku@?)vj*kMSILJxU^@;9_ZqiF(A}?KgcOP9z zbWMXZ=rIf|J9DW-{12DvhX@2hfDnRD#S*5WI6eKz7q^P%xL9^(Dxb?10AvuZ9vq`< z8oK&3?e-7&1&Q7`w?>l;_xA-inFCPgaP7E(t~7)Y2n3B*huXf+-HDrAGZpXNZz2(- z2l@f<9QQRKq-AI3msi%f-W#XYI>B$W`R?tqwOyxNIi%U>P_7)Iq$FkOO$X=dy1sJ2SPsvc||@9~;Fodo>^5?=Y4gB$Z6iYMu}?4V-ed3%`8vWa4;-|!rlq;+FD2zP4? yJEpJ29bOeaU#Kop5S09_EEJAR;2Y<-%KQc&oA5+Zct%YC0000fFDZ*Bm0X>@2HVIW9V zM@1lLWo&RDW^!+BAWC6tbz+882eSYG0q#jeK~y-6g_BKdQ$ZAlpELKS8c@+_v9*XB zYd4C2Kt$a50V=rgM=0W|3m1YvK@==igf1!;Kd{iCoBkWMv2B`=P&LV!nd9Q#o7|>? z2M#j~^FHT2GaNB9>R(rHh{$3H@iZ7_h8chX`~g{yF+9I}=iWNwVP>qZef+-DYFdnO zUk(O++i3i-wJ)o`S3bOboWV!w0Q&v@%(0_2c7N^C>9*NvZ?n~Gu<`R7o7)Y#oenpz z-KtKWn0&JQZfU-3zyYXw076iF@PrVuj1l$9R&x{Q99J%1tsa;-`1H-vt4m`51=uH! zF%V-U#K8McE7a?CE}Xwu#cX~Lz^ek5i+wK4#L*&C(^JgN%`$W56wW#6^?KJ|ynL4I zabWp_ni&QNf|F5Jt5uF1KE&+VbEx`6RVx5#`3;H?zyuIM#F3^hI~SoS7%egacr89P zlM4ur#0iN@M&JVA6^m8^XaR6IXBdJEy_A=1AgKW0`0T7W! zyWN_u)sFMO=yp4RwA5=qYs-v>j~?7kE9rs`1}DwHFvv%`ya%IFnb=m<`-=;&KLh*) X#=1e{xaN@000000NkvXXu0mjfPHr>| literal 0 HcmV?d00001 diff --git a/resource/icon/emblem/folder.png b/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/resource/icon/emblem/font.png b/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/resource/icon/emblem/markup.png b/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/resource/icon/emblem/program.png b/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/resource/icon/emblem/script.png b/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/resource/icon/emblem/video.png b/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*zpi=LK3kbe)ph6$1us|E@0bs(3;j70N?ldxwS=dZZ43B3h07Tynj^2Yc@GQ zog*HPBZLSEeBTewh7gSA^VD1y1GodMPMto({n9-)s&51E$;vZU9zR8k5p<`8FhN|A1evk_=AdpfbrNok-0q9`y@lykUZ{9CDA`)68V_>uX4$tQ( z0GBRKb2S=6>TxbhlkH7H6&U>${F{F7rSIMjqS-ib^#eg962Z1@5{U!?i4YKr#c&*F s0J1DA{1>jzIOV literal 0 HcmV?d00001 diff --git a/resource/icon/go/left.png b/resource/icon/go/left.png new file mode 100644 index 0000000000000000000000000000000000000000..659cd90d7f80488a8a6a2c12f6f9e5ad98720461 GIT binary patch literal 655 zcmV;A0&x9_P)_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/resource/icon/go/up.png b/resource/icon/go/up.png new file mode 100644 index 0000000000000000000000000000000000000000..fa9a7d71b5615dde4c5f702f95df533adadd56e0 GIT binary patch literal 652 zcmV;70(1R|P)5 zlTT<9K@`TnH@h?0jfHw>O#jh>1nt2m6SAzrkW<%*%=Q}tRboP9pC%r$9&(LA+0sq)ybQD9srhR zz3Fxu)^6aqJl)?FN%nOeOgb)4?+M_zJQ@)DvRBSb2FFH|!GH*69hXP{3*flC1BAti zbJNzAm&ca3iTKDR3xq|-Y2`eKx?tij|4I5$vH1yqf%5H^Fb8J54jK)5$VM-C5%i8b<|k&Kxh=#FG>Ox&>r z4?sb}hlkg>1-vahgJcyDBP0eg&{{(&pkA-x@zeQAv9vj35<}`!ZpEItce&w-qk8xH z6RRw9@QrP7!N5#{!3lE@ZdYYZTfgiFi6Lb!&3aDLCbZTHrTP~zgJ5t59%w*hOeL!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/resource/icon/media/eject.png b/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/resource/icon/media/floppy.png b/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/resource/icon/media/next.png b/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/resource/icon/media/optical.png b/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/resource/icon/media/rewind.png b/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/resource/icon/media/stop.png b/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/resource/icon/place/bookmarks.png b/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/resource/icon/place/desktop.png b/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/resource/icon/place/server.png b/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/resource/icon/place/share.png b/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/resource/icon/prompt/error.png b/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/resource/icon/prompt/information.png b/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/resource/icon/prompt/question.png b/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/resource/resource.bml b/resource/resource.bml new file mode 100644 index 0000000..3c3effb --- /dev/null +++ b/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/resource/resource.cpp b/resource/resource.cpp new file mode 100644 index 0000000..19096fb --- /dev/null +++ b/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/resource/resource.hpp b/resource/resource.hpp new file mode 100644 index 0000000..5597d3d --- /dev/null +++ b/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/windows/action/action.cpp b/windows/action/action.cpp new file mode 100644 index 0000000..0a01d87 --- /dev/null +++ b/windows/action/action.cpp @@ -0,0 +1,46 @@ +#if defined(Hiro_Action) + +namespace hiro { + +auto pAction::construct() -> void { +} + +auto pAction::destruct() -> void { +} + +auto pAction::setEnabled(bool enabled) -> void { + _synchronize(); +} + +auto pAction::setVisible(bool visible) -> void { + _synchronize(); +} + +auto pAction::_parentMenu() -> maybe { + if(auto parent = self().parentMenu()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pAction::_parentMenuBar() -> maybe { + if(auto parent = self().parentMenuBar(true)) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pAction::_parentPopupMenu() -> maybe { + if(auto parent = self().parentPopupMenu(true)) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pAction::_synchronize() -> void { + if(auto parent = _parentMenuBar()) parent->_update(); +} + +} + +#endif diff --git a/windows/action/action.hpp b/windows/action/action.hpp new file mode 100644 index 0000000..a7b280f --- /dev/null +++ b/windows/action/action.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_Action) + +namespace hiro { + +struct pAction : pObject { + Declare(Action, Object) + + auto setEnabled(bool enabled) -> void; + auto setVisible(bool visible) -> void; + + auto _parentMenu() -> maybe; + auto _parentMenuBar() -> maybe; + auto _parentPopupMenu() -> maybe; + auto _synchronize() -> void; + + unsigned position = 0; +}; + +} + +#endif diff --git a/windows/action/menu-check-item.cpp b/windows/action/menu-check-item.cpp new file mode 100644 index 0000000..3421432 --- /dev/null +++ b/windows/action/menu-check-item.cpp @@ -0,0 +1,29 @@ +#if defined(Hiro_MenuCheckItem) + +namespace hiro { + +auto pMenuCheckItem::construct() -> void { +} + +auto pMenuCheckItem::destruct() -> void { +} + +auto pMenuCheckItem::setChecked(bool checked) -> void { + if(auto menu = _parentMenu()) { + CheckMenuItem(menu->hmenu, position, MF_BYPOSITION | (checked ? MF_CHECKED : MF_UNCHECKED)); + } +} + +auto pMenuCheckItem::setText(const string& text) -> void { + _synchronize(); +} + +auto pMenuCheckItem::onToggle() -> void { + state().checked = !state().checked; + setChecked(state().checked); + self().doToggle(); +} + +} + +#endif diff --git a/windows/action/menu-check-item.hpp b/windows/action/menu-check-item.hpp new file mode 100644 index 0000000..f3585a3 --- /dev/null +++ b/windows/action/menu-check-item.hpp @@ -0,0 +1,16 @@ +#if defined(Hiro_MenuCheckItem) + +namespace hiro { + +struct pMenuCheckItem : pAction { + Declare(MenuCheckItem, Action) + + auto setChecked(bool checked) -> void; + auto setText(const string& text) -> void; + + auto onToggle() -> void; +}; + +} + +#endif diff --git a/windows/action/menu-item.cpp b/windows/action/menu-item.cpp new file mode 100644 index 0000000..f87dc66 --- /dev/null +++ b/windows/action/menu-item.cpp @@ -0,0 +1,38 @@ +#if defined(Hiro_MenuItem) + +namespace hiro { + +auto pMenuItem::construct() -> void { + _createBitmap(); +} + +auto pMenuItem::destruct() -> void { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; } +} + +auto pMenuItem::setIcon(const image& icon) -> void { + _createBitmap(); + _synchronize(); +} + +auto pMenuItem::setText(const string& text) -> void { + _synchronize(); +} + +auto pMenuItem::onActivate() -> void { + self().doActivate(); +} + +auto pMenuItem::_createBitmap() -> void { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; } + + if(auto icon = state().icon) { + icon.alphaBlend(GetSysColor(COLOR_MENU)); //Windows does not alpha blend menu icons properly (leaves black outline) + icon.scale(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK), Interpolation::Linear); + hbitmap = CreateBitmap(icon); + } +} + +} + +#endif diff --git a/windows/action/menu-item.hpp b/windows/action/menu-item.hpp new file mode 100644 index 0000000..636eef4 --- /dev/null +++ b/windows/action/menu-item.hpp @@ -0,0 +1,20 @@ +#if defined(Hiro_MenuItem) + +namespace hiro { + +struct pMenuItem : pAction { + Declare(MenuItem, Action) + + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + auto onActivate() -> void; + + auto _createBitmap() -> void; + + HBITMAP hbitmap = 0; +}; + +} + +#endif diff --git a/windows/action/menu-radio-item.cpp b/windows/action/menu-radio-item.cpp new file mode 100644 index 0000000..04f12e7 --- /dev/null +++ b/windows/action/menu-radio-item.cpp @@ -0,0 +1,64 @@ +#if defined(Hiro_MenuRadioItem) + +namespace hiro { + +auto pMenuRadioItem::construct() -> void { + setGroup(state().group); +} + +auto pMenuRadioItem::destruct() -> void { +} + +auto pMenuRadioItem::setChecked() -> void { + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto menuRadioItem = dynamic_cast(object.data())) { + if(auto self = menuRadioItem->self()) { + if(auto menu = self->_parentMenu()) { + //CheckMenuRadioItem takes: lo, hi, id; checking only id when lo <= id <= hi + //hiro does not force IDs to be linear, so to uncheck id, we use: lo == hi == id + 1 (out of range) + //to check id, we use: lo == hi == id (only ID, but in range) + CheckMenuRadioItem( + menu->hmenu, + self->position, self->position, self->position + (position != self->position), + MF_BYPOSITION + ); + } + } + } + } + } + } +} + +auto pMenuRadioItem::setGroup(sGroup group) -> void { + bool first = true; + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto menuRadioItem = dynamic_cast(object.data())) { + if(auto self = menuRadioItem->self()) { + menuRadioItem->state.checked = first; + first = false; + } + } + } + } + } + setChecked(); +} + +auto pMenuRadioItem::setText(const string& text) -> void { + _synchronize(); +} + +auto pMenuRadioItem::onActivate() -> void { + if(state().checked) return; + self().setChecked(); + self().doActivate(); +} + +} + +#endif diff --git a/windows/action/menu-radio-item.hpp b/windows/action/menu-radio-item.hpp new file mode 100644 index 0000000..f30ace5 --- /dev/null +++ b/windows/action/menu-radio-item.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_MenuRadioItem) + +namespace hiro { + +struct pMenuRadioItem : pAction { + Declare(MenuRadioItem, Action) + + auto setChecked() -> void; + auto setGroup(sGroup group) -> void override; + auto setText(const string& text) -> void; + + auto onActivate() -> void; +}; + +} + +#endif diff --git a/windows/action/menu-separator.cpp b/windows/action/menu-separator.cpp new file mode 100644 index 0000000..15602b3 --- /dev/null +++ b/windows/action/menu-separator.cpp @@ -0,0 +1,13 @@ +#if defined(Hiro_MenuSeparator) + +namespace hiro { + +auto pMenuSeparator::construct() -> void { +} + +auto pMenuSeparator::destruct() -> void { +} + +} + +#endif diff --git a/windows/action/menu-separator.hpp b/windows/action/menu-separator.hpp new file mode 100644 index 0000000..a94dbf6 --- /dev/null +++ b/windows/action/menu-separator.hpp @@ -0,0 +1,11 @@ +#if defined(Hiro_MenuSeparator) + +namespace hiro { + +struct pMenuSeparator : pAction { + Declare(MenuSeparator, Action) +}; + +} + +#endif diff --git a/windows/action/menu.cpp b/windows/action/menu.cpp new file mode 100644 index 0000000..791d863 --- /dev/null +++ b/windows/action/menu.cpp @@ -0,0 +1,123 @@ +#if defined(Hiro_Menu) + +namespace hiro { + +auto pMenu::construct() -> void { + _createBitmap(); +} + +auto pMenu::destruct() -> void { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; } + if(hmenu) { DestroyMenu(hmenu); hmenu = nullptr; } +} + +auto pMenu::append(sAction action) -> void { + _synchronize(); +} + +auto pMenu::remove(sAction action) -> void { + _synchronize(); +} + +auto pMenu::setIcon(const image& icon) -> void { + _createBitmap(); + _synchronize(); +} + +auto pMenu::setText(const string& text) -> void { + _synchronize(); +} + +auto pMenu::_createBitmap() -> void { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + + if(auto icon = state().icon) { + icon.alphaBlend(GetSysColor(COLOR_MENU)); //Windows does not alpha blend menu icons properly (leaves black outline) + icon.scale(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK), Interpolation::Linear); + hbitmap = CreateBitmap(icon); + } +} + +//Windows actions lack the ability to toggle visibility. +//To support this, menus must be destroyed and recreated when toggling any action's visibility. +auto pMenu::_update() -> void { + if(hmenu) DestroyMenu(hmenu); + hmenu = CreatePopupMenu(); + + MENUINFO mi{sizeof(MENUINFO)}; + mi.fMask = MIM_STYLE; + mi.dwStyle = MNS_NOTIFYBYPOS; //| MNS_MODELESS; + SetMenuInfo(hmenu, &mi); + + unsigned position = 0; + + for(auto& action : state().actions) { + if(!action->self()) continue; + action->self()->position = position; + unsigned enabled = action->enabled() ? 0 : MF_GRAYED; + + MENUITEMINFO mii{sizeof(MENUITEMINFO)}; + mii.fMask = MIIM_DATA; + mii.dwItemData = (ULONG_PTR)action.data(); + + if(auto menu = dynamic_cast(action.data())) { + if(menu->visible()) { + menu->self()->_update(); + AppendMenu(hmenu, MF_STRING | MF_POPUP | enabled, (UINT_PTR)menu->self()->hmenu, utf16_t(menu->text())); + if(auto bitmap = menu->self()->hbitmap) { + //Windows XP and below displays MIIM_BITMAP + hbmpItem in its own column (separate from check/radio marks) + //this causes too much spacing, so use a custom checkmark image instead + mii.fMask |= MIIM_CHECKMARKS; + mii.hbmpUnchecked = bitmap; + } + SetMenuItemInfo(hmenu, position++, true, &mii); + } + } + + #if defined(Hiro_MenuSeparator) + else if(auto menuSeparator = dynamic_cast(action.data())) { + if(menuSeparator->visible()) { + AppendMenu(hmenu, MF_SEPARATOR | enabled, position, L""); + SetMenuItemInfo(hmenu, position++, true, &mii); + } + } + #endif + + #if defined(Hiro_MenuItem) + else if(auto menuItem = dynamic_cast(action.data())) { + if(menuItem->visible()) { + AppendMenu(hmenu, MF_STRING | enabled, position, utf16_t(menuItem->text())); + if(auto bitmap = menuItem->self()->hbitmap) { + mii.fMask |= MIIM_CHECKMARKS; + mii.hbmpUnchecked = bitmap; + } + SetMenuItemInfo(hmenu, position++, true, &mii); + } + } + #endif + + #if defined(Hiro_MenuCheckItem) + else if(auto menuCheckItem = dynamic_cast(action.data())) { + if(menuCheckItem->visible()) { + AppendMenu(hmenu, MF_STRING | enabled, position, utf16_t(menuCheckItem->text())); + SetMenuItemInfo(hmenu, position++, true, &mii); + if(menuCheckItem->checked()) menuCheckItem->setChecked(); + } + } + #endif + + #if defined(Hiro_MenuRadioItem) + else if(auto menuRadioItem = dynamic_cast(action.data())) { + if(menuRadioItem->visible()) { + AppendMenu(hmenu, MF_STRING | enabled, position, utf16_t(menuRadioItem->text())); + SetMenuItemInfo(hmenu, position++, true, &mii); + if(menuRadioItem->checked()) menuRadioItem->setChecked(); + } + } + #endif + } +} + +} + +#endif diff --git a/windows/action/menu.hpp b/windows/action/menu.hpp new file mode 100644 index 0000000..b8caee5 --- /dev/null +++ b/windows/action/menu.hpp @@ -0,0 +1,22 @@ +#if defined(Hiro_Menu) + +namespace hiro { + +struct pMenu : pAction { + Declare(Menu, Action) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + auto _createBitmap() -> void; + auto _update() -> void; + + HMENU hmenu = 0; + HBITMAP hbitmap = 0; +}; + +} + +#endif diff --git a/windows/application.cpp b/windows/application.cpp new file mode 100644 index 0000000..67d2908 --- /dev/null +++ b/windows/application.cpp @@ -0,0 +1,261 @@ +#if defined(Hiro_Application) + +namespace hiro { + +static auto Application_keyboardProc(HWND, UINT, WPARAM, LPARAM) -> bool; +static auto Application_processDialogMessage(MSG&) -> void; +static auto CALLBACK Application_windowProc(HWND, UINT, WPARAM, LPARAM) -> LRESULT; + +auto pApplication::run() -> void { + MSG msg; + if(Application::state.onMain) { + while(!Application::state.quit) { + Application::doMain(); + processEvents(); + } + } else { + MSG msg; + while(GetMessage(&msg, 0, 0, 0)) { + Application_processDialogMessage(msg); + } + } +} + +auto pApplication::pendingEvents() -> bool { + MSG msg; + return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); +} + +auto pApplication::processEvents() -> void { + while(pendingEvents()) { + MSG msg; + if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + Application_processDialogMessage(msg); + } + } +} + +auto Application_processDialogMessage(MSG& msg) -> void { + if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP + || msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP) { + if(Application_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam)) { + DispatchMessage(&msg); + return; + } + } + + if(!IsDialogMessage(GetForegroundWindow(), &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +auto pApplication::quit() -> void { + PostQuitMessage(0); +} + +auto pApplication::initialize() -> void { + CoInitialize(0); + InitCommonControls(); + + WNDCLASS wc; + + #if defined(Hiro_Window) + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2)); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Application_windowProc; + wc.lpszClassName = L"hiroWindow"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + #endif + + #if defined(Hiro_PopupMenu) + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2)); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Menu_windowProc; + wc.lpszClassName = L"hiroPopupMenu"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + #endif + + #if defined(Hiro_Canvas) + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Canvas_windowProc; + wc.lpszClassName = L"hiroCanvas"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + #endif + + #if defined(Hiro_Label) + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Label_windowProc; + wc.lpszClassName = L"hiroLabel"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + #endif + + #if defined(Hiro_Viewport) + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Viewport_windowProc; + wc.lpszClassName = L"hiroViewport"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + #endif + + pKeyboard::initialize(); +} + +static auto Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> bool { + if(msg != WM_KEYDOWN && msg != WM_SYSKEYDOWN && msg != WM_KEYUP && msg != WM_SYSKEYUP) return false; + + GUITHREADINFO info{sizeof(GUITHREADINFO)}; + GetGUIThreadInfo(GetCurrentThreadId(), &info); + + auto object = (mObject*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA); + if(!object) return false; + + if(auto window = dynamic_cast(object)) { + if(auto self = window->self()) { + if(!self->_modalityDisabled()) { + if(auto code = pKeyboard::_translate(wparam, lparam)) { + if(msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) window->doKeyPress(code); + if(msg == WM_KEYUP || msg == WM_SYSKEYUP) window->doKeyRelease(code); + } + } + } + return false; + } + + if(auto window = object->parentWindow(true)) { + if(auto self = window->self()) { + if(self->_modalityDisabled()) return false; + } + } + + if(msg == WM_KEYDOWN) { + if(0); + + #if defined(Hiro_ListView) + else if(auto listView = dynamic_cast(object)) { + if(wparam == VK_RETURN) { + if(listView->selected()) return true; //returning true generates LVN_ITEMACTIVATE message + } + } + #endif + + #if defined(Hiro_LineEdit) + else if(auto lineEdit = dynamic_cast(object)) { + if(wparam == VK_RETURN) { + lineEdit->doActivate(); + } + } + #endif + + #if defined(Hiro_TextEdit) + else if(auto textEdit = dynamic_cast(object)) { + if(wparam == 'A' && GetKeyState(VK_CONTROL) < 0) { + //Ctrl+A = select all text + //note: this is not a standard accelerator on Windows + Edit_SetSel(textEdit->self()->hwnd, 0, ~0); + return true; + } else if(wparam == 'V' && GetKeyState(VK_CONTROL) < 0) { + //Ctrl+V = paste text + //note: this formats Unix (LF) and OS9 (CR) line-endings to Windows (CR+LF) line-endings + //this is necessary as the EDIT control only supports Windows line-endings + OpenClipboard(hwnd); + if(auto handle = GetClipboardData(CF_UNICODETEXT)) { + if(auto text = (wchar_t*)GlobalLock(handle)) { + string data = (const char*)utf8_t(text); + data.replace("\r\n", "\n"); + data.replace("\r", "\n"); + data.replace("\n", "\r\n"); + GlobalUnlock(handle); + utf16_t output(data); + if(auto resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t))) { + if(auto write = (wchar_t*)GlobalLock(resource)) { + wcscpy(write, output); + GlobalUnlock(write); + if(SetClipboardData(CF_UNICODETEXT, resource) == NULL) { + GlobalFree(resource); + } + } + } + } + } + CloseClipboard(); + return false; + } + } + #endif + } + + return false; +} + +/* +case WM_GETMINMAXINFO: { + MINMAXINFO* mmi = (MINMAXINFO*)lparam; + mmi->ptMinTrackSize.x = 256 + window.p.frameMargin().width; + mmi->ptMinTrackSize.y = 256 + window.p.frameMargin().height; + return TRUE; + break; +} +*/ + +static auto CALLBACK Application_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(Application::state.quit) return DefWindowProc(hwnd, msg, wparam, lparam); + + auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!object) return DefWindowProc(hwnd, msg, wparam, lparam); + auto window = dynamic_cast(object); + if(!window) window = object->parentWindow(true); + if(!window) return DefWindowProc(hwnd, msg, wparam, lparam); + auto pWindow = window->self(); + if(!pWindow) return DefWindowProc(hwnd, msg, wparam, lparam); + + if(pWindow->_modalityDisabled()) return DefWindowProc(hwnd, msg, wparam, lparam); + + switch(msg) { + case WM_CLOSE: pWindow->onClose(); return true; + case WM_MOVE: pWindow->onMove(); break; + case WM_SIZE: pWindow->onSize(); break; + case WM_DROPFILES: pWindow->onDrop(wparam); return false; + case WM_ERASEBKGND: if(pWindow->onEraseBackground()) return true; break; + case WM_ENTERMENULOOP: case WM_ENTERSIZEMOVE: pWindow->onModalBegin(); return false; + case WM_EXITMENULOOP: case WM_EXITSIZEMOVE: pWindow->onModalEnd(); return false; + } + + return Shared_windowProc(DefWindowProc, hwnd, msg, wparam, lparam); +} + +} + +#endif diff --git a/windows/application.hpp b/windows/application.hpp new file mode 100644 index 0000000..8e5b1f8 --- /dev/null +++ b/windows/application.hpp @@ -0,0 +1,16 @@ +#if defined(Hiro_Application) + +namespace hiro { + +struct pApplication { + static auto run() -> void; + static auto pendingEvents() -> bool; + static auto processEvents() -> void; + static auto quit() -> void; + + static auto initialize() -> void; +}; + +} + +#endif diff --git a/windows/browser-window.cpp b/windows/browser-window.cpp new file mode 100644 index 0000000..c439c93 --- /dev/null +++ b/windows/browser-window.cpp @@ -0,0 +1,109 @@ +#if defined(Hiro_BrowserWindow) + +namespace hiro { + +static auto CALLBACK BrowserWindowCallbackProc(HWND hwnd, UINT msg, LPARAM lparam, LPARAM lpdata) -> signed { + if(msg == BFFM_INITIALIZED) { + if(lpdata) { + auto state = (BrowserWindow::State*)lpdata; + utf16_t wpath(string{state->path}.transform("/", "\\")); + if(state->title) SetWindowText(hwnd, utf16_t(state->title)); + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(wchar_t*)wpath); + } + } + return 0; +} + +static auto BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) -> string { + string path = string{state.path}.replace("/", "\\"); + + string filters; + for(auto& filter : state.filters) { + lstring part = filter.split("("); + if(part.size() != 2) continue; + part[1].rtrim(")", 1L); + part[1].replace(" ", ""); + part[1].transform(",", ";"); + filters.append(filter, "\t", part[1], "\t"); + } + + utf16_t wfilters(filters); + wchar_t wname[PATH_MAX + 1] = L""; + utf16_t wpath(path); + utf16_t wtitle(state.title); + + wchar_t* p = wfilters; + while(*p != L'\0') { + if(*p == L'\t') *p = L'\0'; + p++; + } + + if(path.empty() == false) { + //clear COMDLG32 MRU (most recently used) file list + //this is required in order for lpstrInitialDir to be honored in Windows 7 and above + registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/LastVisitedPidlMRU/"); + registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/OpenSavePidlMRU/"); + } + + OPENFILENAME ofn; + memset(&ofn, 0, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = state.parent ? state.parent->self()->hwnd : 0; + ofn.lpstrFilter = wfilters; + ofn.lpstrInitialDir = wpath; + ofn.lpstrFile = wname; + ofn.lpstrTitle = wtitle; + ofn.nMaxFile = PATH_MAX; + ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt = L""; + + bool result = (save == false ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)); + if(result == false) return ""; + string name = (const char*)utf8_t(wname); + name.transform("\\", "/"); + return name; +} + +auto pBrowserWindow::directory(BrowserWindow::State& state) -> string { + wchar_t wname[PATH_MAX + 1] = L""; + + BROWSEINFO bi; + bi.hwndOwner = state.parent ? state.parent->self()->hwnd : 0; + bi.pidlRoot = NULL; + bi.pszDisplayName = wname; + bi.lpszTitle = L"\nChoose a directory:"; + bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; + bi.lpfn = BrowserWindowCallbackProc; + bi.lParam = (LPARAM)&state; + bi.iImage = 0; + bool result = false; + LPITEMIDLIST pidl = SHBrowseForFolder(&bi); + if(pidl) { + if(SHGetPathFromIDList(pidl, wname)) { + result = true; + IMalloc *imalloc = 0; + if(SUCCEEDED(SHGetMalloc(&imalloc))) { + imalloc->Free(pidl); + imalloc->Release(); + } + } + } + if(result == false) return ""; + string name = (const char*)utf8_t(wname); + if(!name) return ""; + name.transform("\\", "/"); + if(name.endsWith("/") == false) name.append("/"); + return name; +} + +auto pBrowserWindow::open(BrowserWindow::State& state) -> string { + return BrowserWindow_fileDialog(0, state); +} + +auto pBrowserWindow::save(BrowserWindow::State& state) -> string { + return BrowserWindow_fileDialog(1, state); +} + +} + +#endif diff --git a/windows/browser-window.hpp b/windows/browser-window.hpp new file mode 100644 index 0000000..80e561b --- /dev/null +++ b/windows/browser-window.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_BrowserWindow) + +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; +}; + +} + +#endif diff --git a/windows/desktop.cpp b/windows/desktop.cpp new file mode 100644 index 0000000..2a5f56f --- /dev/null +++ b/windows/desktop.cpp @@ -0,0 +1,17 @@ +#if defined(Hiro_Desktop) + +namespace hiro { + +auto pDesktop::size() -> Size { + return {GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)}; +} + +auto pDesktop::workspace() -> Geometry { + RECT rc; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); + return {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top}; +} + +} + +#endif diff --git a/windows/desktop.hpp b/windows/desktop.hpp new file mode 100644 index 0000000..2c179b6 --- /dev/null +++ b/windows/desktop.hpp @@ -0,0 +1,12 @@ +#if defined(Hiro_Desktop) + +namespace hiro { + +struct pDesktop { + static auto size() -> Size; + static auto workspace() -> Geometry; +}; + +} + +#endif diff --git a/windows/font.cpp b/windows/font.cpp new file mode 100644 index 0000000..f3c8785 --- /dev/null +++ b/windows/font.cpp @@ -0,0 +1,42 @@ +#if defined(Hiro_Font) + +namespace hiro { + +auto pFont::size(const Font& font, const string& text) -> Size { + auto hfont = pFont::create(font); + auto size = pFont::size(hfont, text); + pFont::free(hfont); + return size; +} + +auto pFont::size(HFONT hfont, const string& text) -> Size { + HDC hdc = GetDC(0); + SelectObject(hdc, hfont); + RECT rc = {0, 0, 0, 0}; + DrawText(hdc, utf16_t(text), -1, &rc, DT_CALCRECT); + ReleaseDC(0, hdc); + return {rc.right, rc.bottom}; +} + +auto pFont::family(const string& family) -> string { + if(family == Font::Sans ) return "Tahoma"; + if(family == Font::Serif) return "Georgia"; + if(family == Font::Mono ) return "Lucida Console"; + return family ? family : "Tahoma"; +} + +auto pFont::create(const Font& font) -> HFONT { + return CreateFont( + -((font.size() ? font.size() : 8) * 96.0 / 72.0 + 0.5), + 0, 0, 0, font.bold() ? FW_BOLD : FW_NORMAL, font.italic(), 0, 0, 0, 0, 0, 0, 0, + utf16_t(family(font.family())) + ); +} + +auto pFont::free(HFONT hfont) -> void { + DeleteObject(hfont); +} + +} + +#endif diff --git a/windows/font.hpp b/windows/font.hpp new file mode 100644 index 0000000..1882d55 --- /dev/null +++ b/windows/font.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_Font) + +namespace hiro { + +struct pFont { + static auto size(const Font& font, const string& text) -> Size; + static auto size(HFONT hfont, const string& text) -> Size; + static auto family(const string& family) -> string; + static auto create(const Font& font) -> HFONT; + static auto free(HFONT hfont) -> void; +}; + +} + +#endif diff --git a/windows/group.cpp b/windows/group.cpp new file mode 100644 index 0000000..cbf387f --- /dev/null +++ b/windows/group.cpp @@ -0,0 +1,13 @@ +#if defined(Hiro_Group) + +namespace hiro { + +auto pGroup::construct() -> void { +} + +auto pGroup::destruct() -> void { +} + +} + +#endif diff --git a/windows/group.hpp b/windows/group.hpp new file mode 100644 index 0000000..a2ac6d7 --- /dev/null +++ b/windows/group.hpp @@ -0,0 +1,11 @@ +#if defined(Hiro_Group) + +namespace hiro { + +struct pGroup : pObject { + Declare(Group, Object) +}; + +} + +#endif diff --git a/windows/header.hpp b/windows/header.hpp new file mode 100644 index 0000000..a555e27 --- /dev/null +++ b/windows/header.hpp @@ -0,0 +1,82 @@ +#define UNICODE +#define WINVER 0x0601 +#define _WIN32_WINNT WINVER +#define _WIN32_IE WINVER +#define __MSVCRT_VERSION__ WINVER +#define NOMINMAX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//MinGW/32-bit has painfully outdated platform headers ... + +#if !defined(Button_SetImageList) + typedef struct { + HIMAGELIST himl; + RECT margin; + UINT uAlign; + } BUTTON_IMAGELIST, *PBUTTON_IMAGELIST; + + #define BUTTON_IMAGELIST_ALIGN_LEFT 0 + #define BUTTON_IMAGELIST_ALIGN_RIGHT 1 + #define BUTTON_IMAGELIST_ALIGN_TOP 2 + #define BUTTON_IMAGELIST_ALIGN_BOTTOM 3 + #define BUTTON_IMAGELIST_ALIGN_CENTER 4 + + #define BCM_FIRST 0x1600 + #define BCM_SETIMAGELIST (BCM_FIRST+2) + #define Button_SetImageList(hwnd, pbuttonImagelist) (WINBOOL)SNDMSG((hwnd),BCM_SETIMAGELIST,0,(LPARAM)(pbuttonImagelist)) +#endif + +#if !defined(BP_PUSHBUTTON) + #define BP_PUSHBUTTON 1 +#endif + +#if !defined(PBS_NORMAL) + #define PBS_NORMAL 1 +#endif + +#if !defined(PBS_HOT) + #define PBS_HOT 2 +#endif + +#if !defined(PBS_PRESSED) + #define PBS_PRESSED 3 +#endif + +#if !defined(PBS_DISABLED) + #define PBS_DISABLED 4 +#endif + +#if !defined(PBS_DEFAULTED) + #define PBS_DEFAULTED 5 +#endif + +#if !defined(BP_CHECKBOX) + #define BP_CHECKBOX 3 +#endif + +#if !defined(CBS_UNCHECKEDNORMAL) + #define CBS_UNCHECKEDNORMAL 1 +#endif + +#if !defined(CBS_CHECKEDNORMAL) + #define CBS_CHECKEDNORMAL 5 +#endif + +#if !defined(LVCFMT_FIXED_WIDTH) + #define LVCFMT_FIXED_WIDTH 0x0100 +#endif + +#if !defined(TBS_TRANSPARENTBKGND) + #define TBS_TRANSPARENTBKGND 0x1000 +#endif diff --git a/windows/hiro.Manifest b/windows/hiro.Manifest new file mode 100644 index 0000000..a7e39c8 --- /dev/null +++ b/windows/hiro.Manifest @@ -0,0 +1,14 @@ + + + + + + + + + + + true + + + diff --git a/windows/hiro.rc b/windows/hiro.rc new file mode 100644 index 0000000..25c6e7d --- /dev/null +++ b/windows/hiro.rc @@ -0,0 +1 @@ +1 24 "hiro.Manifest" diff --git a/windows/keyboard.cpp b/windows/keyboard.cpp new file mode 100644 index 0000000..c269ba3 --- /dev/null +++ b/windows/keyboard.cpp @@ -0,0 +1,99 @@ +#if defined(Hiro_Keyboard) + +namespace hiro { + +vector pKeyboard::keycodes; + +auto pKeyboard::poll() -> vector { + vector result; + for(auto& code : keycodes) result.append(pressed(code)); + return result; +} + +auto pKeyboard::pressed(unsigned code) -> bool { + uint8_t lo = code >> 0; + uint8_t hi = code >> 8; + if(lo && GetAsyncKeyState(lo) & 0x8000) return true; + if(hi && GetAsyncKeyState(hi) & 0x8000) return true; + return false; +} + +auto pKeyboard::initialize() -> void { + auto append = [](unsigned lo, unsigned hi = 0) { + keycodes.append(lo << 0 | hi << 8); + }; + + #define map(name, ...) if(key == name) { append(__VA_ARGS__); continue; } + for(auto& key : Keyboard::keys) { + #include + //print("[hiro/windows] warning: unhandled key: ", key, "\n"); + append(0); + } + #undef map +} + +auto pKeyboard::_translate(unsigned code, unsigned flags) -> signed { + bool numLock = GetKeyState(VK_NUMLOCK); + bool capsLock = GetKeyState(VK_CAPITAL); + bool shifted = (GetAsyncKeyState(VK_LSHIFT) & 0x8000) || (GetAsyncKeyState(VK_RSHIFT) & 0x8000); + bool pressed = GetAsyncKeyState(code) & 0x8000; + bool extended = flags & (1 << 24); + + switch(code) { + case VK_OEM_3: return !shifted ? '`' : '~'; + case '1': return !shifted ? '1' : '!'; + case '2': return !shifted ? '2' : '@'; + case '3': return !shifted ? '3' : '#'; + case '4': return !shifted ? '4' : '$'; + case '5': return !shifted ? '5' : '%'; + case '6': return !shifted ? '6' : '^'; + case '7': return !shifted ? '7' : '&'; + case '8': return !shifted ? '8' : '*'; + case '9': return !shifted ? '9' : '('; + case '0': return !shifted ? '0' : ')'; + case VK_OEM_MINUS: return !shifted ? '-' : '_'; + case VK_OEM_PLUS: return !shifted ? '=' : '+'; + case VK_BACK: return '\b'; + + case VK_TAB: return '\t'; + case VK_RETURN: return '\n'; + case VK_SPACE: return ' '; + + case VK_OEM_4: return !shifted ? '[' : '{'; + case VK_OEM_6: return !shifted ? ']' : '}'; + case VK_OEM_5: return !shifted ? '\\' : '|'; + case VK_OEM_1: return !shifted ? ';' : ':'; + case VK_OEM_7: return !shifted ? '\'' : '\"'; + case VK_OEM_COMMA: return !shifted ? ',' : '<'; + case VK_OEM_PERIOD: return !shifted ? '.' : '>'; + case VK_OEM_2: return !shifted ? '/' : '?'; + + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': + case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': + if(capsLock) return !shifted ? code : code + 32; + else return !shifted ? code + 32 : code; + + case VK_DIVIDE: return '/'; + case VK_MULTIPLY: return '*'; + case VK_SUBTRACT: return '-'; + case VK_ADD: return '+'; + case VK_DECIMAL: return '.'; + + case VK_NUMPAD1: return numLock ? '1' : 0; + case VK_NUMPAD2: return numLock ? '2' : 0; + case VK_NUMPAD3: return numLock ? '3' : 0; + case VK_NUMPAD4: return numLock ? '4' : 0; + case VK_NUMPAD5: return numLock ? '5' : 0; + case VK_NUMPAD6: return numLock ? '6' : 0; + case VK_NUMPAD7: return numLock ? '7' : 0; + case VK_NUMPAD8: return numLock ? '8' : 0; + case VK_NUMPAD9: return numLock ? '9' : 0; + case VK_NUMPAD0: return numLock ? '0' : 0; + } + + return 0; +} + +} + +#endif diff --git a/windows/keyboard.hpp b/windows/keyboard.hpp new file mode 100644 index 0000000..5cf00c8 --- /dev/null +++ b/windows/keyboard.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_Keyboard) + +namespace hiro { + +struct pKeyboard { + static auto poll() -> vector; + static auto pressed(unsigned code) -> bool; + + static auto initialize() -> void; + + static auto _translate(unsigned code, unsigned flags) -> signed; + + static vector keycodes; +}; + +} + +#endif diff --git a/windows/layout.cpp b/windows/layout.cpp new file mode 100644 index 0000000..fbd3dcd --- /dev/null +++ b/windows/layout.cpp @@ -0,0 +1,31 @@ +#if defined(Hiro_Layout) + +namespace hiro { + +auto pLayout::construct() -> void { +} + +auto pLayout::destruct() -> void { +} + +auto pLayout::setEnabled(bool enabled) -> void { + for(auto& sizable : state().sizables) { + if(auto self = sizable->self()) self->setEnabled(sizable->enabled(true)); + } +} + +auto pLayout::setFont(const Font& font) -> void { + for(auto& sizable : state().sizables) { + if(auto self = sizable->self()) self->setFont(sizable->font(true)); + } +} + +auto pLayout::setVisible(bool visible) -> void { + for(auto& sizable : state().sizables) { + if(auto self = sizable->self()) self->setVisible(sizable->visible(true)); + } +} + +} + +#endif diff --git a/windows/layout.hpp b/windows/layout.hpp new file mode 100644 index 0000000..dba1183 --- /dev/null +++ b/windows/layout.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_Layout) + +namespace hiro { + +struct pLayout : pSizable { + Declare(Layout, Sizable) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; +}; + +} + +#endif diff --git a/windows/menu-bar.cpp b/windows/menu-bar.cpp new file mode 100644 index 0000000..fc2c5bc --- /dev/null +++ b/windows/menu-bar.cpp @@ -0,0 +1,83 @@ +#if defined(Hiro_MenuBar) + +namespace hiro { + +auto pMenuBar::construct() -> void { + _update(); +} + +auto pMenuBar::destruct() -> void { + if(hmenu) { DestroyMenu(hmenu); hmenu = nullptr; } + if(auto parent = _parent()) { + SetMenu(parent->hwnd, nullptr); + } +} + +auto pMenuBar::append(sMenu) -> void { + _update(); +} + +auto pMenuBar::remove(sMenu) -> void { + _update(); +} + +auto pMenuBar::setEnabled(bool enabled) -> void { + _update(); +} + +auto pMenuBar::setFont(const Font& font) -> void { + //unsupported +} + +auto pMenuBar::setVisible(bool visible) -> void { + if(auto parent = _parent()) { + SetMenu(parent->hwnd, visible ? hmenu : nullptr); + parent->setGeometry(parent->state().geometry); + } +} + +auto pMenuBar::_parent() -> maybe { + if(auto parent = self().parentWindow(true)) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pMenuBar::_update() -> void { + if(hmenu) DestroyMenu(hmenu); + hmenu = CreateMenu(); + + MENUINFO mi{sizeof(MENUINFO)}; + mi.fMask = MIM_STYLE; + mi.dwStyle = MNS_NOTIFYBYPOS; //| MNS_MODELESS; + SetMenuInfo(hmenu, &mi); + + unsigned position = 0; + + #if defined(Hiro_Menu) + for(auto& menu : state().menus) { + unsigned enabled = menu->enabled() ? 0 : MF_GRAYED; + + MENUITEMINFO mii{sizeof(MENUITEMINFO)}; + mii.fMask = MIIM_DATA; + mii.dwItemData = (ULONG_PTR)menu.data(); + + if(menu->visible()) { + if(auto self = menu->self()) { + self->_update(); + AppendMenu(hmenu, MF_STRING | MF_POPUP | enabled, (UINT_PTR)self->hmenu, utf16_t(menu->text())); + SetMenuItemInfo(hmenu, position++, true, &mii); + } + } + } + #endif + + if(auto parent = _parent()) { + SetMenu(parent->hwnd, self().visible(true) ? hmenu : nullptr); + parent->setGeometry(parent->state().geometry); + } +} + +} + +#endif diff --git a/windows/menu-bar.hpp b/windows/menu-bar.hpp new file mode 100644 index 0000000..b804f25 --- /dev/null +++ b/windows/menu-bar.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_MenuBar) + +namespace hiro { + +struct pMenuBar : pObject { + Declare(MenuBar, Object) + + auto append(sMenu menu) -> void; + auto remove(sMenu menu) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; + auto _update() -> void; + + HMENU hmenu = 0; + vector objects; +}; + +} + +#endif diff --git a/windows/message-window.cpp b/windows/message-window.cpp new file mode 100644 index 0000000..cee1f36 --- /dev/null +++ b/windows/message-window.cpp @@ -0,0 +1,58 @@ +#if defined(Hiro_MessageWindow) + +namespace hiro { + +static auto MessageWindow_response(MessageWindow::Buttons buttons, UINT response) -> MessageWindow::Response { + if(response == IDOK) return MessageWindow::Response::Ok; + if(response == IDCANCEL) return MessageWindow::Response::Cancel; + if(response == IDYES) return MessageWindow::Response::Yes; + if(response == IDNO) return MessageWindow::Response::No; + + //default responses if window was closed without a button selected + if(buttons == MessageWindow::Buttons::Ok) return MessageWindow::Response::Ok; + if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; + if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; + if(buttons == MessageWindow::Buttons::YesNoCancel) return MessageWindow::Response::Cancel; + + throw; +} + +static auto MessageWindow_buttons(MessageWindow::Buttons buttons) -> UINT { + if(buttons == MessageWindow::Buttons::Ok) return MB_OK; + if(buttons == MessageWindow::Buttons::OkCancel) return MB_OKCANCEL; + if(buttons == MessageWindow::Buttons::YesNo) return MB_YESNO; + if(buttons == MessageWindow::Buttons::YesNoCancel) return MB_YESNOCANCEL; + throw; +} + +auto pMessageWindow::error(MessageWindow::State& state) -> MessageWindow::Response { + UINT flags = MB_ICONERROR | MessageWindow_buttons(state.buttons); + return MessageWindow_response(state.buttons, MessageBox( + state.parent ? state.parent->self()->hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags + )); +} + +auto pMessageWindow::information(MessageWindow::State& state) -> MessageWindow::Response { + UINT flags = MB_ICONINFORMATION | MessageWindow_buttons(state.buttons); + return MessageWindow_response(state.buttons, MessageBox( + state.parent ? state.parent->self()->hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags + )); +} + +auto pMessageWindow::question(MessageWindow::State& state) -> MessageWindow::Response { + UINT flags = MB_ICONQUESTION | MessageWindow_buttons(state.buttons); + return MessageWindow_response(state.buttons, MessageBox( + state.parent ? state.parent->self()->hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags + )); +} + +auto pMessageWindow::warning(MessageWindow::State& state) -> MessageWindow::Response { + UINT flags = MB_ICONWARNING | MessageWindow_buttons(state.buttons); + return MessageWindow_response(state.buttons, MessageBox( + state.parent ? state.parent->self()->hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags + )); +} + +} + +#endif diff --git a/windows/message-window.hpp b/windows/message-window.hpp new file mode 100644 index 0000000..b8b26af --- /dev/null +++ b/windows/message-window.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_MessageWindow) + +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; +}; + +} + +#endif diff --git a/windows/monitor.cpp b/windows/monitor.cpp new file mode 100644 index 0000000..84a90c5 --- /dev/null +++ b/windows/monitor.cpp @@ -0,0 +1,47 @@ +#if defined(Hiro_Monitor) + +namespace hiro { + +struct MonitorInfo { + unsigned monitor = 0; + unsigned primary = 0; + unsigned index = 0; + Geometry geometry; +}; + +static auto CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL { + MonitorInfo& info = *(MonitorInfo*)dwData; + MONITORINFOEX mi; + memset(&mi, 0, sizeof(MONITORINFOEX)); + mi.cbSize = sizeof(MONITORINFOEX); + GetMonitorInfo(hMonitor, &mi); + string displayName = (const char*)utf8_t(mi.szDevice); + if(displayName.beginsWith(R"(\\.\DISPLAYV)")) return TRUE; //ignore pseudo-monitors + if(mi.dwFlags & MONITORINFOF_PRIMARY) info.primary = info.index; + if(info.monitor == info.index) { + info.geometry = {lprcMonitor->left, lprcMonitor->top, lprcMonitor->right - lprcMonitor->left, lprcMonitor->bottom - lprcMonitor->top}; + } + info.index++; + return TRUE; +} + +auto pMonitor::count() -> unsigned { + return GetSystemMetrics(SM_CMONITORS); +} + +auto pMonitor::geometry(unsigned monitor) -> Geometry { + MonitorInfo info; + info.monitor = monitor; + EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&info); + return info.geometry; +} + +auto pMonitor::primary() -> unsigned { + MonitorInfo info; + EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&info); + return info.primary; +} + +} + +#endif diff --git a/windows/monitor.hpp b/windows/monitor.hpp new file mode 100644 index 0000000..2ec7626 --- /dev/null +++ b/windows/monitor.hpp @@ -0,0 +1,13 @@ +#if defined(Hiro_Monitor) + +namespace hiro { + +struct pMonitor { + static auto count() -> unsigned; + static auto geometry(unsigned monitor) -> Geometry; + static auto primary() -> unsigned; +}; + +} + +#endif diff --git a/windows/mouse.cpp b/windows/mouse.cpp new file mode 100644 index 0000000..89898ad --- /dev/null +++ b/windows/mouse.cpp @@ -0,0 +1,22 @@ +#if defined(Hiro_Mouse) + +namespace hiro { + +auto pMouse::position() -> Position { + POINT point{0}; + GetCursorPos(&point); + return {point.x, point.y}; +} + +auto pMouse::pressed(Mouse::Button button) -> bool { + switch(button) { + case Mouse::Button::Left: return GetAsyncKeyState(VK_LBUTTON) & 0x8000; + case Mouse::Button::Middle: return GetAsyncKeyState(VK_MBUTTON) & 0x8000; + case Mouse::Button::Right: return GetAsyncKeyState(VK_RBUTTON) & 0x8000; + } + return false; +} + +} + +#endif diff --git a/windows/mouse.hpp b/windows/mouse.hpp new file mode 100644 index 0000000..72a5605 --- /dev/null +++ b/windows/mouse.hpp @@ -0,0 +1,12 @@ +#if defined(Hiro_Mouse) + +namespace hiro { + +struct pMouse { + static auto position() -> Position; + static auto pressed(Mouse::Button button) -> bool; +}; + +} + +#endif diff --git a/windows/object.cpp b/windows/object.cpp new file mode 100644 index 0000000..4cf170d --- /dev/null +++ b/windows/object.cpp @@ -0,0 +1,41 @@ +#if defined(Hiro_Object) + +namespace hiro { + +auto pObject::construct() -> void { +} + +auto pObject::destruct() -> void { +} + +auto pObject::reconstruct() -> 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 Font& font) -> void { +} + +auto pObject::setGroup(sGroup group) -> void { +} + +auto pObject::setVisible(bool visible) -> void { +} + +} + +#endif diff --git a/windows/object.hpp b/windows/object.hpp new file mode 100644 index 0000000..c30c8ad --- /dev/null +++ b/windows/object.hpp @@ -0,0 +1,31 @@ +#if defined(Hiro_Object) + +namespace hiro { + +struct pObject { + pObject(mObject& reference) : reference(reference) {} + virtual ~pObject() = default; + virtual auto construct() -> void; + virtual auto destruct() -> void; + virtual auto reconstruct() -> 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 Font& font) -> void; + virtual auto setGroup(sGroup group) -> 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; +}; + +} + +#endif diff --git a/windows/platform.cpp b/windows/platform.cpp new file mode 100644 index 0000000..42dac19 --- /dev/null +++ b/windows/platform.cpp @@ -0,0 +1,59 @@ +#include "platform.hpp" +#include "utility.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 "group.cpp" + +#include "font.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/frame.cpp" +#include "widget/hex-edit.cpp" +#include "widget/horizontal-scroll-bar.cpp" +#include "widget/horizontal-slider.cpp" +#include "widget/label.cpp" +#include "widget/line-edit.cpp" +#include "widget/list-view.cpp" +#include "widget/list-view-header.cpp" +#include "widget/list-view-column.cpp" +#include "widget/list-view-item.cpp" +#include "widget/list-view-cell.cpp" +#include "widget/progress-bar.cpp" +#include "widget/radio-button.cpp" +#include "widget/radio-label.cpp" +#include "widget/tab-frame.cpp" +#include "widget/tab-frame-item.cpp" +#include "widget/text-edit.cpp" +#include "widget/vertical-scroll-bar.cpp" +#include "widget/vertical-slider.cpp" +#include "widget/viewport.cpp" + +#include "application.cpp" diff --git a/windows/platform.hpp b/windows/platform.hpp new file mode 100644 index 0000000..7c6be74 --- /dev/null +++ b/windows/platform.hpp @@ -0,0 +1,90 @@ +namespace hiro { + +struct pFont; +struct pObject; +struct pWindow; +struct pMenu; +struct pLayout; +struct pWidget; + +struct AppMessage { + enum : unsigned { + None = WM_APP, + ListView_doPaint, + ListView_onActivate, + ListView_onChange, + }; +}; + +using WindowProc = auto CALLBACK (*)(HWND, UINT, WPARAM, LPARAM) -> LRESULT; + +static vector windows; + +} + +#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; \ + auto reconstruct() -> void override { destruct(), construct(); } \ + +#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 "group.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/frame.hpp" +#include "widget/hex-edit.hpp" +#include "widget/horizontal-scroll-bar.hpp" +#include "widget/horizontal-slider.hpp" +#include "widget/label.hpp" +#include "widget/line-edit.hpp" +#include "widget/list-view.hpp" +#include "widget/list-view-header.hpp" +#include "widget/list-view-column.hpp" +#include "widget/list-view-item.hpp" +#include "widget/list-view-cell.hpp" +#include "widget/progress-bar.hpp" +#include "widget/radio-button.hpp" +#include "widget/radio-label.hpp" +#include "widget/tab-frame.hpp" +#include "widget/tab-frame-item.hpp" +#include "widget/text-edit.hpp" +#include "widget/vertical-scroll-bar.hpp" +#include "widget/vertical-slider.hpp" +#include "widget/viewport.hpp" + +#include "application.hpp" + +#undef Declare diff --git a/windows/popup-menu.cpp b/windows/popup-menu.cpp new file mode 100644 index 0000000..001fbfb --- /dev/null +++ b/windows/popup-menu.cpp @@ -0,0 +1,109 @@ +#if defined(Hiro_PopupMenu) + +namespace hiro { + +auto pPopupMenu::construct() -> void { + hwnd = CreateWindow(L"hiroPopupMenu", L"", ResizableStyle, 0, 0, 0, 0, 0, 0, GetModuleHandle(0), 0); +} + +auto pPopupMenu::destruct() -> void { + if(hmenu) { DestroyMenu(hmenu); hmenu = nullptr; } + DestroyWindow(hwnd); +} + +auto pPopupMenu::append(sAction action) -> void { +} + +auto pPopupMenu::remove(sAction action) -> void { +} + +auto pPopupMenu::setFont(const Font& font) -> void { +} + +auto pPopupMenu::setVisible(bool visible) -> void { + if(!visible) return; + + if(hmenu) DestroyMenu(hmenu); + hmenu = CreatePopupMenu(); + + MENUINFO mi{sizeof(MENUINFO)}; + mi.fMask = MIM_STYLE; + mi.dwStyle = MNS_NOTIFYBYPOS; //| MNS_MODELESS; + SetMenuInfo(hmenu, &mi); + + unsigned position = 0; + + for(auto& action : state().actions) { + if(!action->self()) continue; + action->self()->position = position; + unsigned enabled = action->enabled() ? 0 : MF_GRAYED; + + MENUITEMINFO mii{sizeof(MENUITEMINFO)}; + mii.fMask = MIIM_DATA; + mii.dwItemData = (ULONG_PTR)action.data(); + + if(auto menu = dynamic_cast(action.data())) { + if(menu->visible()) { + menu->self()->_update(); + AppendMenu(hmenu, MF_STRING | MF_POPUP | enabled, (UINT_PTR)menu->self()->hmenu, utf16_t(menu->text())); + if(auto bitmap = menu->self()->hbitmap) { + //Windows XP and below displays MIIM_BITMAP + hbmpItem in its own column (separate from check/radio marks) + //this causes too much spacing, so use a custom checkmark image instead + mii.fMask |= MIIM_CHECKMARKS; + mii.hbmpUnchecked = bitmap; + } + SetMenuItemInfo(hmenu, position++, true, &mii); + } + } + + #if defined(Hiro_MenuSeparator) + else if(auto menuSeparator = dynamic_cast(action.data())) { + if(menuSeparator->visible()) { + AppendMenu(hmenu, MF_SEPARATOR | enabled, position, L""); + SetMenuItemInfo(hmenu, position++, true, &mii); + } + } + #endif + + #if defined(Hiro_MenuItem) + else if(auto menuItem = dynamic_cast(action.data())) { + if(menuItem->visible()) { + AppendMenu(hmenu, MF_STRING | enabled, position, utf16_t(menuItem->text())); + if(auto bitmap = menuItem->self()->hbitmap) { + mii.fMask |= MIIM_CHECKMARKS; + mii.hbmpUnchecked = bitmap; + } + SetMenuItemInfo(hmenu, position++, true, &mii); + } + } + #endif + + #if defined(Hiro_MenuCheckItem) + else if(auto menuCheckItem = dynamic_cast(action.data())) { + if(menuCheckItem->visible()) { + AppendMenu(hmenu, MF_STRING | enabled, position, utf16_t(menuCheckItem->text())); + SetMenuItemInfo(hmenu, position++, true, &mii); + if(menuCheckItem->checked()) menuCheckItem->setChecked(); + } + } + #endif + + #if defined(Hiro_MenuRadioItem) + else if(auto menuRadioItem = dynamic_cast(action.data())) { + if(menuRadioItem->visible()) { + AppendMenu(hmenu, MF_STRING | enabled, position, utf16_t(menuRadioItem->text())); + SetMenuItemInfo(hmenu, position++, true, &mii); + if(menuRadioItem->checked()) menuRadioItem->setChecked(); + } + } + #endif + } + + POINT point{0}; + GetCursorPos(&point); + TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_TOPALIGN, point.x, point.y, 0, hwnd, nullptr); +} + +} + +#endif diff --git a/windows/popup-menu.hpp b/windows/popup-menu.hpp new file mode 100644 index 0000000..a51cedf --- /dev/null +++ b/windows/popup-menu.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_PopupMenu) + +namespace hiro { + +struct pPopupMenu : pObject { + Declare(PopupMenu, Object) + + auto append(sAction action) -> void; + auto remove(sAction action) -> void; + auto setFont(const Font& font) -> void override; + auto setVisible(bool visible) -> void override; + + HWND hwnd = nullptr; + HMENU hmenu = nullptr; +}; + +} + +#endif diff --git a/windows/sizable.cpp b/windows/sizable.cpp new file mode 100644 index 0000000..4e793ab --- /dev/null +++ b/windows/sizable.cpp @@ -0,0 +1,20 @@ +#if defined(Hiro_Sizable) + +namespace hiro { + +auto pSizable::construct() -> void { +} + +auto pSizable::destruct() -> void { +} + +auto pSizable::minimumSize() const -> Size { + return {0, 0}; +} + +auto pSizable::setGeometry(Geometry geometry) -> void { +} + +} + +#endif diff --git a/windows/sizable.hpp b/windows/sizable.hpp new file mode 100644 index 0000000..5270283 --- /dev/null +++ b/windows/sizable.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_Sizable) + +namespace hiro { + +struct pSizable : pObject { + Declare(Sizable, Object) + + virtual auto minimumSize() const -> Size; + virtual auto setGeometry(Geometry geometry) -> void; +}; + +} + +#endif diff --git a/windows/status-bar.cpp b/windows/status-bar.cpp new file mode 100644 index 0000000..68ef63c --- /dev/null +++ b/windows/status-bar.cpp @@ -0,0 +1,54 @@ +#if defined(Hiro_StatusBar) + +namespace hiro { + +auto pStatusBar::construct() -> void { + if(auto parent = _parent()) { + hwnd = CreateWindow(STATUSCLASSNAME, L"", WS_CHILD | WS_DISABLED, 0, 0, 0, 0, parent->hwnd, nullptr, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + setEnabled(self().enabled(true)); + setFont(self().font(true)); + setText(self().text()); + setVisible(self().visible(true)); + } +} + +auto pStatusBar::destruct() -> void { + if(hfont) { DeleteObject(hfont); hfont = nullptr; } + if(hwnd) { DestroyWindow(hwnd); hwnd = nullptr; } + if(auto parent = _parent()) { + parent->setGeometry(parent->state().geometry); + } +} + +auto pStatusBar::setEnabled(bool enabled) -> void { + //unsupported +} + +auto pStatusBar::setFont(const Font& font) -> void { + if(hfont) DeleteObject(hfont); + hfont = pFont::create(font); + if(hwnd) SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); +} + +auto pStatusBar::setText(const string& text) -> void { + if(hwnd) SendMessage(hwnd, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text)); +} + +auto pStatusBar::setVisible(bool visible) -> void { + if(hwnd) ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); + if(auto parent = _parent()) { + parent->setGeometry(parent->state().geometry); + } +} + +auto pStatusBar::_parent() -> maybe { + if(auto parent = self().parentWindow(true)) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/windows/status-bar.hpp b/windows/status-bar.hpp new file mode 100644 index 0000000..618e026 --- /dev/null +++ b/windows/status-bar.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_StatusBar) + +namespace hiro { + +struct pStatusBar : pObject { + Declare(StatusBar, Object) + + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; + + HWND hwnd = 0; + HFONT hfont = 0; +}; + +} + +#endif diff --git a/windows/timer.cpp b/windows/timer.cpp new file mode 100644 index 0000000..c046389 --- /dev/null +++ b/windows/timer.cpp @@ -0,0 +1,39 @@ +#if defined(Hiro_Timer) + +namespace hiro { + +static vector timers; + +static auto CALLBACK Timer_timeoutProc(HWND hwnd, UINT msg, UINT_PTR timerID, DWORD time) -> void { + for(auto& timer : timers) { + if(timer->htimer == timerID) return timer->self().doActivate(); + } +} + +auto pTimer::construct() -> void { + timers.append(this); + htimer = 0; +} + +auto pTimer::destruct() -> void { +} + +auto pTimer::setEnabled(bool enabled) -> void { + if(htimer) { + KillTimer(NULL, htimer); + htimer = 0; + } + + if(enabled == true) { + htimer = SetTimer(NULL, 0u, state().interval, Timer_timeoutProc); + } +} + +auto pTimer::setInterval(unsigned interval) -> void { + //destroy and recreate timer if interval changed + setEnabled(self().enabled(true)); +} + +} + +#endif diff --git a/windows/timer.hpp b/windows/timer.hpp new file mode 100644 index 0000000..c4207f8 --- /dev/null +++ b/windows/timer.hpp @@ -0,0 +1,16 @@ +#if defined(Hiro_Timer) + +namespace hiro { + +struct pTimer : pObject { + Declare(Timer, Object) + + auto setEnabled(bool enabled) -> void override; + auto setInterval(unsigned interval) -> void; + + UINT_PTR htimer; +}; + +} + +#endif diff --git a/windows/utility.cpp b/windows/utility.cpp new file mode 100644 index 0000000..ff1b77e --- /dev/null +++ b/windows/utility.cpp @@ -0,0 +1,397 @@ +namespace hiro { + +static const uint Windows2000 = 0x0500; +static const uint WindowsXP = 0x0501; +static const uint WindowsVista = 0x0600; +static const uint Windows7 = 0x0601; + +static auto Button_CustomDraw(HWND, PAINTSTRUCT&, bool, bool, bool, unsigned, const Font&, const image&, Orientation, const string&) -> void; + +static auto OsVersion() -> unsigned { + OSVERSIONINFO versionInfo{0}; + versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&versionInfo); + return (versionInfo.dwMajorVersion << 8) + (versionInfo.dwMajorVersion << 0); +} + +static auto CreateBitmap(image icon) -> HBITMAP { + icon.alphaMultiply(); //Windows AlphaBlend() requires premultiplied image data + icon.transform(); + HDC hdc = GetDC(0); + BITMAPINFO bitmapInfo; + memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = icon.width(); + bitmapInfo.bmiHeader.biHeight = -(signed)icon.height(); //bitmaps are stored upside down unless we negate height + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = icon.size(); + void* bits = nullptr; + HBITMAP hbitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0); + if(bits) memory::copy(bits, icon.data(), icon.size()); + ReleaseDC(0, hdc); + return hbitmap; +} + +static auto CreateRGB(const Color& color) -> COLORREF { + return RGB(color.red(), color.green(), color.blue()); +} + +static auto DropPaths(WPARAM wparam) -> lstring { + auto dropList = HDROP(wparam); + auto fileCount = DragQueryFile(dropList, ~0u, nullptr, 0); + + lstring paths; + for(auto n : range(fileCount)) { + auto length = DragQueryFile(dropList, n, nullptr, 0); + auto buffer = new wchar_t[length + 1]; + + if(DragQueryFile(dropList, n, buffer, length + 1)) { + string path = (const char*)utf8_t(buffer); + path.transform("\\", "/"); + if(directory::exists(path) && !path.endsWith("/")) path.append("/"); + paths.append(path); + } + + delete[] buffer; + } + + return paths; +} + +static auto GetWindowZOrder(HWND hwnd) -> unsigned { + unsigned z = 0; + for(HWND next = hwnd; next != NULL; next = GetWindow(next, GW_HWNDPREV)) z++; + return z; +} + +static auto ImageList_Append(HIMAGELIST imageList, image icon, unsigned scale) -> void { + if(icon) { + icon.scale(scale, scale); + } else { + icon.allocate(scale, scale); + icon.fill(GetSysColor(COLOR_WINDOW)); + } + HBITMAP bitmap = CreateBitmap(icon); + ImageList_Add(imageList, bitmap, nullptr); + DeleteObject(bitmap); +} + +//post message only if said message is not already pending in the queue +static auto PostMessageOnce(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam) -> void { + MSG msg; + if(!PeekMessage(&msg, hwnd, id, id, PM_NOREMOVE)) { + PostMessage(hwnd, id, wparam, lparam); + } +} + +static auto ScrollEvent(HWND hwnd, WPARAM wparam) -> unsigned { + SCROLLINFO info; + memset(&info, 0, sizeof(SCROLLINFO)); + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_ALL; + GetScrollInfo(hwnd, SB_CTL, &info); + + switch(LOWORD(wparam)) { + case SB_LEFT: info.nPos = info.nMin; break; + case SB_RIGHT: info.nPos = info.nMax; break; + case SB_LINELEFT: info.nPos--; break; + case SB_LINERIGHT: info.nPos++; break; + case SB_PAGELEFT: info.nPos -= info.nMax >> 3; break; + case SB_PAGERIGHT: info.nPos += info.nMax >> 3; break; + case SB_THUMBTRACK: info.nPos = info.nTrackPos; break; + } + + info.fMask = SIF_POS; + SetScrollInfo(hwnd, SB_CTL, &info, TRUE); + + //Windows may clamp position to scrollbar range + GetScrollInfo(hwnd, SB_CTL, &info); + return info.nPos; +} + +//separate because PopupMenu HWND does not contain GWLP_USERDATA pointing at Window needed for Shared_windowProc +static auto CALLBACK Menu_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + switch(msg) { + case WM_MENUCOMMAND: { + MENUITEMINFO mii{sizeof(MENUITEMINFO)}; + mii.fMask = MIIM_DATA; + GetMenuItemInfo((HMENU)lparam, wparam, true, &mii); + + auto object = (mObject*)mii.dwItemData; + if(!object) break; + + #if defined(Hiro_MenuItem) + if(auto menuItem = dynamic_cast(object)) { + return menuItem->self()->onActivate(), false; + } + #endif + + #if defined(Hiro_MenuCheckItem) + if(auto menuCheckItem = dynamic_cast(object)) { + return menuCheckItem->self()->onToggle(), false; + } + #endif + + #if defined(Hiro_MenuRadioItem) + if(auto menuRadioItem = dynamic_cast(object)) { + return menuRadioItem->self()->onActivate(), false; + } + #endif + + break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +static auto CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(Application::state.quit) return DefWindowProc(hwnd, msg, wparam, lparam); + + auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!object) return DefWindowProc(hwnd, msg, wparam, lparam); + auto window = dynamic_cast(object); + if(!window) window = object->parentWindow(true); + if(!window) return DefWindowProc(hwnd, msg, wparam, lparam); + auto pWindow = window->self(); + if(!pWindow) return DefWindowProc(hwnd, msg, wparam, lparam); + + if(pWindow->_modalityDisabled()) return DefWindowProc(hwnd, msg, wparam, lparam); + + switch(msg) { + case WM_CTLCOLORBTN: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: { + auto object = (mObject*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA); + if(!object) break; + + //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 defined(Hiro_Window) && defined(Hiro_TabFrame) + if(!object->parentTabFrame(true) && window->self()->hbrush) { + SetBkColor((HDC)wparam, window->self()->hbrushColor); + return (LRESULT)window->self()->hbrush; + } + #endif + + #if defined(Hiro_HexEdit) + if(auto hexEdit = dynamic_cast(object)) { + if(auto background = hexEdit->backgroundColor()) SetBkColor((HDC)wparam, CreateRGB(background)); + if(auto foreground = hexEdit->foregroundColor()) SetTextColor((HDC)wparam, CreateRGB(foreground)); + return (LRESULT)hexEdit->self()->backgroundBrush; + } + #endif + + #if defined(Hiro_LineEdit) + if(auto lineEdit = dynamic_cast(object)) { + if(auto background = lineEdit->backgroundColor()) SetBkColor((HDC)wparam, CreateRGB(background)); + if(auto foreground = lineEdit->foregroundColor()) SetTextColor((HDC)wparam, CreateRGB(foreground)); + return (LRESULT)lineEdit->self()->backgroundBrush; + } + #endif + + #if defined(Hiro_TextEdit) + if(auto textEdit = dynamic_cast(object)) { + if(auto background = textEdit->backgroundColor()) SetBkColor((HDC)wparam, CreateRGB(background)); + if(auto foreground = textEdit->foregroundColor()) SetTextColor((HDC)wparam, CreateRGB(foreground)); + return (LRESULT)textEdit->self()->backgroundBrush; + } + #endif + + break; + } + + case WM_DRAWITEM: { + auto drawItem = (LPDRAWITEMSTRUCT)lparam; + auto object = (mObject*)GetWindowLongPtr((HWND)drawItem->hwndItem, GWLP_USERDATA); + if(!object) break; + + #if defined(Hiro_TabFrame) + if(auto tabFrame = dynamic_cast(object)) { + return tabFrame->self()->onDrawItem(lparam), true; + } + #endif + + break; + } + + case WM_MENUCOMMAND: { + return Menu_windowProc(hwnd, msg, wparam, lparam); + } + + case WM_COMMAND: { + if(!lparam) break; + auto object = (mObject*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA); + if(!object) break; + + #if defined(Hiro_Button) + if(auto button = dynamic_cast(object)) { + return button->self()->onActivate(), false; + } + #endif + + #if defined(Hiro_CheckButton) + if(auto checkButton = dynamic_cast(object)) { + return checkButton->self()->onToggle(), false; + } + #endif + + #if defined(Hiro_CheckLabel) + if(auto checkLabel = dynamic_cast(object)) { + return checkLabel->self()->onToggle(), false; + } + #endif + + #if defined(Hiro_ComboButton) + if(auto comboButton = dynamic_cast(object)) { + if(HIWORD(wparam) == CBN_SELCHANGE) { + return comboButton->self()->onChange(), false; + } + } + #endif + + #if defined(Hiro_LineEdit) + if(auto lineEdit = dynamic_cast(object)) { + if(HIWORD(wparam) == EN_CHANGE) { + return lineEdit->self()->onChange(), false; + } + } + #endif + + #if defined(Hiro_RadioButton) + if(auto radioButton = dynamic_cast(object)) { + return radioButton->self()->onActivate(), false; + } + #endif + + #if defined(Hiro_RadioLabel) + if(auto radioLabel = dynamic_cast(object)) { + return radioLabel->self()->onActivate(), false; + } + #endif + + #if defined(Hiro_TextEdit) + if(auto textEdit = dynamic_cast(object)) { + if(HIWORD(wparam) == EN_CHANGE) { + return textEdit->self()->onChange(), false; + } + } + #endif + + break; + } + + case WM_NOTIFY: { + //Widgets inside a TabFrame must be parented to it rather than the Window. + //This is critical for proper inheritance of styles and message passing. + //However, by doing this, some WM_NOTIFY messages end up being sent to both + //the TabFrame and the Window; while others are only sent to the TabFrame. + //To save code, hiro uses a shared callback for both of these cases. + //So when a message is sent to both, we ignore the TabFrame message. + bool isWindowCallback = (object == window); + + auto header = (LPNMHDR)lparam; + auto object = (mObject*)GetWindowLongPtr((HWND)header->hwndFrom, GWLP_USERDATA); + if(!object) break; + + #if defined(Hiro_ListView) + if(auto listView = dynamic_cast(object)) { + if(header->code == LVN_ITEMACTIVATE) { + listView->self()->onActivate(lparam); + break; + } + if(header->code == LVN_ITEMCHANGED) { + listView->self()->onChange(lparam); + break; + } + if(header->code == LVN_COLUMNCLICK) { + if(isWindowCallback) listView->self()->onSort(lparam); + break; + } + if(header->code == NM_CLICK || header->code == NM_DBLCLK) { + //onToggle performs the test to ensure the ListViewItem clicked was checkable + if(isWindowCallback) listView->self()->onToggle(lparam); + break; + } + if(header->code == NM_RCLICK) { + if(isWindowCallback) listView->self()->onContext(lparam); + break; + } + if(header->code == NM_CUSTOMDRAW) { + return listView->self()->onCustomDraw(lparam); + } + } + #endif + + #if defined(Hiro_TabFrame) + if(auto tabFrame = dynamic_cast(object)) { + if(header->code == TCN_SELCHANGE) { + tabFrame->self()->onChange(); + break; + } + } + #endif + + break; + } + + #if defined(Hiro_ListView) + case AppMessage::ListView_doPaint: { + if(auto listView = (mListView*)lparam) { + if(auto self = listView->self()) InvalidateRect(self->hwnd, nullptr, true); + } + break; + } + + case AppMessage::ListView_onActivate: { + if(auto listView = (mListView*)lparam) listView->doActivate(); + break; + } + + case AppMessage::ListView_onChange: { + if(auto listView = (mListView*)lparam) listView->doChange(); + } + #endif + + case WM_HSCROLL: + case WM_VSCROLL: { + if(!lparam) break; + auto object = (mObject*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA); + if(!object) break; + + #if defined(Hiro_HorizontalScrollBar) + if(auto horizontalScrollBar = dynamic_cast(object)) { + return horizontalScrollBar->self()->onChange(wparam), true; + } + #endif + + #if defined(Hiro_HorizontalSlider) + if(auto horizontalSlider = dynamic_cast(object)) { + return horizontalSlider->self()->onChange(), true; + } + #endif + + #if defined(Hiro_VerticalScrollBar) + if(auto verticalScrollBar = dynamic_cast(object)) { + return verticalScrollBar->self()->onChange(wparam), true; + } + #endif + + #if defined(Hiro_VerticalSlider) + if(auto verticalSlider = dynamic_cast(object)) { + return verticalSlider->self()->onChange(), true; + } + #endif + + break; + } + } + + return windowProc(hwnd, msg, wparam, lparam); +} + +} diff --git a/windows/widget/button.cpp b/windows/widget/button.cpp new file mode 100644 index 0000000..4a2b8ed --- /dev/null +++ b/windows/widget/button.cpp @@ -0,0 +1,184 @@ +#if defined(Hiro_Button) + +namespace hiro { + +static auto Button_paintProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, + bool bordered, bool checked, bool enabled, const Font& font, const image& icon, Orientation orientation, const string& text +) -> LRESULT { + if(msg == WM_PAINT) { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + auto state = Button_GetState(hwnd); + Button_CustomDraw(hwnd, ps, bordered, checked, enabled, state, font, icon, orientation, text); + EndPaint(hwnd, &ps); + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +//BUTTON cannot draw borderless buttons on its own +//BS_OWNERDRAW will send WM_DRAWITEM; but will disable hot-tracking notifications +//to gain hot-tracking plus borderless buttons; BUTTON is superclassed and WM_PAINT is hijacked +//note: letting hiro paint bordered buttons will lose the fade animations on Vista+; +//however, it will allow placing icons immediately next to text (original forces icon left alignment) +static auto CALLBACK Button_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) { + if(auto button = dynamic_cast(object)) { + if(auto self = button->self()) { + if(msg == WM_ERASEBKGND) return DefWindowProc(hwnd, msg, wparam, lparam); + if(msg == WM_PAINT) return Button_paintProc(hwnd, msg, wparam, lparam, + button->state.bordered, false, button->enabled(true), button->font(true), + button->state.icon, button->state.orientation, button->state.text + ); + return self->windowProc(hwnd, msg, wparam, lparam); + } + } + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +auto pButton::construct() -> void { + hwnd = CreateWindow( + L"BUTTON", L"", WS_CHILD | WS_TABSTOP, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)Button_windowProc); + pWidget::_setState(); + _setState(); +} + +auto pButton::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pButton::minimumSize() const -> Size { + Size icon = {(int)state().icon.width(), (int)state().icon.height()}; + Size text = state().text ? pFont::size(self().font(true), state().text) : Size{}; + Size size; + if(state().orientation == Orientation::Horizontal) { + size.setWidth(icon.width() + (icon && text ? 5 : 0) + text.width()); + size.setHeight(max(icon.height(), text.height())); + } + if(state().orientation == Orientation::Vertical) { + size.setWidth(max(icon.width(), text.width())); + size.setHeight(icon.height() + (icon && text ? 5 : 0) + text.height()); + } + size.setHeight(max(size.height(), pFont::size(self().font(true), " ").height())); + return {size.width() + (state().bordered && text ? 20 : 10), size.height() + 10}; +} + +auto pButton::setBordered(bool bordered) -> void { + _setState(); +} + +auto pButton::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + _setState(); +} + +auto pButton::setFont(const Font& font) -> void { + pWidget::setFont(font); + _setState(); +} + +auto pButton::setIcon(const image& icon) -> void { + _setState(); +} + +auto pButton::setOrientation(Orientation orientation) -> void { + _setState(); +} + +auto pButton::setText(const string& text) -> void { + _setState(); +} + +auto pButton::setVisible(bool visible) -> void { + pWidget::setVisible(visible); + _setState(); +} + +auto pButton::onActivate() -> void { + self().doActivate(); +} + +auto pButton::_setState() -> void { + InvalidateRect(hwnd, 0, false); +} + +//this function is designed to be used with Button, CheckButton, and RadioButton +auto Button_CustomDraw(HWND hwnd, PAINTSTRUCT& ps, bool bordered, bool checked, bool enabled, unsigned state, const Font& font, const image& icon, Orientation orientation, const string& text) -> void { + RECT rc; + GetClientRect(hwnd, &rc); + Geometry geometry{rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top}, iconGeometry, textGeometry; + if(icon) iconGeometry.setSize({(int)icon.width(), (int)icon.height()}); + if(text) textGeometry.setSize(pFont::size(font, text)); + + Position position; + Size size; + + switch(orientation) { + case Orientation::Horizontal: + size = {iconGeometry.width() + (icon && text ? 5 : 0) + textGeometry.width(), max(iconGeometry.height(), textGeometry.height())}; + position = {(geometry.width() - size.width()) / 2, (geometry.height() - size.height()) / 2}; + iconGeometry.setPosition({position.x(), position.y() + (size.height() - iconGeometry.height()) / 2}); + textGeometry.setPosition({position.x() + size.width() - textGeometry.width(), position.y() + (size.height() - textGeometry.height()) / 2}); + break; + case Orientation::Vertical: + size = {max(iconGeometry.width(), textGeometry.width()), iconGeometry.height() + (icon && text ? 5 : 0) + textGeometry.height()}; + position = {(geometry.width() - size.width()) / 2, (geometry.height() - size.height()) / 2}; + iconGeometry.setPosition({position.x() + (size.width() - iconGeometry.width()) / 2, position.y()}); + textGeometry.setPosition({position.x() + (size.width() - textGeometry.width()) / 2, position.y() + size.height() - textGeometry.height()}); + break; + } + + if(auto theme = OpenThemeData(hwnd, L"BUTTON")) { + DrawThemeParentBackground(hwnd, ps.hdc, &rc); + unsigned flags = 0; + if(state & BST_PUSHED || checked) flags = PBS_PRESSED; + else if(state & BST_HOT) flags = PBS_HOT; + else if(bordered) flags = enabled ? PBS_NORMAL : PBS_DISABLED; + if(bordered || flags) DrawThemeBackground(theme, ps.hdc, BP_PUSHBUTTON, flags, &rc, &ps.rcPaint); + CloseThemeData(theme); + } else { + //Windows Classic + FillRect(ps.hdc, &rc, GetSysColorBrush(COLOR_3DFACE)); + unsigned flags = (state & BST_PUSHED || checked) ? DFCS_PUSHED : 0; + if(bordered || flags) DrawFrameControl(ps.hdc, &rc, DFC_BUTTON, DFCS_BUTTONPUSH | flags | (enabled ? 0 : DFCS_INACTIVE)); + } + + if(GetFocus() == hwnd) { + signed offset = state ? 4 : 1; + RECT rcFocus{rc.left + offset, rc.top + offset, rc.right - offset, rc.bottom - offset}; + if(!(state & BST_PUSHED) && !(state & BST_HOT)) DrawFocusRect(ps.hdc, &rcFocus); + } + + if(icon) { + HDC hdcSource = CreateCompatibleDC(ps.hdc); + auto bitmap = CreateBitmap(icon); + SelectBitmap(hdcSource, bitmap); + BLENDFUNCTION blend{AC_SRC_OVER, 0, (BYTE)(IsWindowEnabled(hwnd) ? 255 : 128), AC_SRC_ALPHA}; + AlphaBlend( + ps.hdc, iconGeometry.x(), iconGeometry.y(), icon.width(), icon.height(), + hdcSource, 0, 0, icon.width(), icon.height(), blend + ); + DeleteObject(bitmap); + DeleteDC(hdcSource); + } + + if(text) { + utf16_t wText(text); + SetBkMode(ps.hdc, TRANSPARENT); + SetTextColor(ps.hdc, GetSysColor(IsWindowEnabled(hwnd) ? COLOR_BTNTEXT : COLOR_GRAYTEXT)); + auto hFont = pFont::create(font); + SelectObject(ps.hdc, hFont); + RECT rcText{textGeometry.x(), textGeometry.y(), textGeometry.x() + textGeometry.width(), textGeometry.y() + textGeometry.height()}; + DrawText(ps.hdc, wText, -1, &rcText, DT_NOPREFIX | DT_END_ELLIPSIS); + DeleteObject(hFont); + } +} + +} + +#endif diff --git a/windows/widget/button.hpp b/windows/widget/button.hpp new file mode 100644 index 0000000..44bd313 --- /dev/null +++ b/windows/widget/button.hpp @@ -0,0 +1,26 @@ +#if defined(Hiro_Button) + +namespace hiro { + +struct pButton : pWidget { + Declare(Button, Widget) + + auto minimumSize() const -> Size override; + auto setBordered(bool bordered) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto onActivate() -> void; + + auto _setState() -> void; + + WindowProc windowProc = nullptr; +}; + +} + +#endif diff --git a/windows/widget/canvas.cpp b/windows/widget/canvas.cpp new file mode 100644 index 0000000..f4f2312 --- /dev/null +++ b/windows/widget/canvas.cpp @@ -0,0 +1,176 @@ +#if defined(Hiro_Canvas) + +namespace hiro { + +static auto CALLBACK Canvas_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!object) return DefWindowProc(hwnd, msg, wparam, lparam); + auto canvas = dynamic_cast(object); + if(!canvas) return DefWindowProc(hwnd, msg, wparam, lparam); + + if(msg == WM_DROPFILES) { + if(auto paths = DropPaths(wparam)) canvas->doDrop(paths); + return false; + } + + if(msg == WM_GETDLGCODE) { + return DLGC_STATIC | DLGC_WANTCHARS; + } + + if(msg == WM_ERASEBKGND) { + //background is erased during WM_PAINT to prevent flickering + return true; + } + + if(msg == WM_PAINT) { + if(auto self = canvas->self()) self->_paint(); + return true; + } + + if(msg == WM_MOUSEMOVE) { + TRACKMOUSEEVENT tracker{sizeof(TRACKMOUSEEVENT), TME_LEAVE, hwnd}; + TrackMouseEvent(&tracker); + canvas->doMouseMove({(int16_t)LOWORD(lparam), (int16_t)HIWORD(lparam)}); + } + + if(msg == WM_MOUSELEAVE) { + canvas->doMouseLeave(); + } + + if(msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) { + switch(msg) { + case WM_LBUTTONDOWN: canvas->doMousePress(Mouse::Button::Left); break; + case WM_MBUTTONDOWN: canvas->doMousePress(Mouse::Button::Middle); break; + case WM_RBUTTONDOWN: canvas->doMousePress(Mouse::Button::Right); break; + } + } + + if(msg == WM_LBUTTONUP || msg == WM_MBUTTONUP || msg == WM_RBUTTONUP) { + switch(msg) { + case WM_LBUTTONUP: canvas->doMouseRelease(Mouse::Button::Left); break; + case WM_MBUTTONUP: canvas->doMouseRelease(Mouse::Button::Middle); break; + case WM_RBUTTONUP: canvas->doMouseRelease(Mouse::Button::Right); break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +auto pCanvas::construct() -> void { + hwnd = CreateWindow(L"hiroCanvas", L"", WS_CHILD, 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setDroppable(state().droppable); + update(); +} + +auto pCanvas::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pCanvas::minimumSize() const -> Size { + if(auto& icon = state().icon) return {(int)icon.width(), (int)icon.height()}; + return {0, 0}; +} + +auto pCanvas::setColor(Color color) -> void { + update(); +} + +auto pCanvas::setDroppable(bool droppable) -> void { + DragAcceptFiles(hwnd, droppable); +} + +auto pCanvas::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + update(); +} + +auto pCanvas::setGradient(Gradient gradient) -> void { + update(); +} + +auto pCanvas::setIcon(const image& icon) -> void { + update(); +} + +auto pCanvas::update() -> void { + _rasterize(); + _redraw(); +} + +auto pCanvas::_paint() -> void { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + + HDC hdc = CreateCompatibleDC(ps.hdc); + BITMAPINFO bmi; + memset(&bmi, 0, sizeof(BITMAPINFO)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; //GDI stores bitmaps upside now; negative height flips bitmap + bmi.bmiHeader.biSizeImage = pixels.size() * sizeof(uint32); + void* bits = nullptr; + HBITMAP bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &bits, nullptr, 0); + if(bits) { + auto source = (const uint8*)pixels.data(); + auto target = (uint8*)bits; + for(auto n : range(width * height)) { + target[0] = (source[0] * source[3]) / 255; + target[1] = (source[1] * source[3]) / 255; + target[2] = (source[2] * source[3]) / 255; + target[3] = (source[3]); + source += 4, target += 4; + } + } + SelectObject(hdc, bitmap); + + RECT rc; + GetClientRect(hwnd, &rc); + DrawThemeParentBackground(hwnd, ps.hdc, &rc); + + BLENDFUNCTION bf{AC_SRC_OVER, 0, (BYTE)255, AC_SRC_ALPHA}; + AlphaBlend(ps.hdc, 0, 0, width, height, hdc, 0, 0, width, height, bf); + + DeleteObject(bitmap); + DeleteDC(hdc); + + EndPaint(hwnd, &ps); +} + +auto pCanvas::_rasterize() -> void { + if(auto& icon = state().icon) { + width = icon.width(); + height = icon.height(); + } else { + width = self().geometry().width(); + height = self().geometry().height(); + } + if(width <= 0 || height <= 0) return; + + pixels.reallocate(width * height); + + if(auto& icon = state().icon) { + memory::copy(pixels.data(), icon.data(), width * height * sizeof(uint32)); + } else if(auto& gradient = state().gradient) { + auto& colors = gradient.state.colors; + image fill; + fill.allocate(width, height); + fill.gradient(colors[0].value(), colors[1].value(), colors[2].value(), colors[3].value()); + memory::copy(pixels.data(), fill.data(), fill.size()); + } else { + uint32 color = state().color.value(); + for(auto& pixel : pixels) pixel = color; + } +} + +auto pCanvas::_redraw() -> void { + InvalidateRect(hwnd, 0, false); +} + +} + +#endif diff --git a/windows/widget/canvas.hpp b/windows/widget/canvas.hpp new file mode 100644 index 0000000..1adcd9a --- /dev/null +++ b/windows/widget/canvas.hpp @@ -0,0 +1,27 @@ +#if defined(Hiro_Canvas) + +namespace hiro { + +struct pCanvas : pWidget { + Declare(Canvas, Widget) + + auto minimumSize() const -> Size override; + auto setColor(Color color) -> void; + auto setDroppable(bool droppable) -> void; + auto setGeometry(Geometry geometry) -> void override; + auto setGradient(Gradient gradient) -> void; + auto setIcon(const image& icon) -> void; + auto update() -> void; + + auto _paint() -> void; + auto _rasterize() -> void; + auto _redraw() -> void; + + vector pixels; + signed width = 0; + signed height = 0; +}; + +} + +#endif diff --git a/windows/widget/check-button.cpp b/windows/widget/check-button.cpp new file mode 100644 index 0000000..ef5e93b --- /dev/null +++ b/windows/widget/check-button.cpp @@ -0,0 +1,100 @@ +#if defined(Hiro_CheckButton) + +namespace hiro { + +static auto CALLBACK CheckButton_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) { + if(auto button = dynamic_cast(object)) { + if(auto self = button->self()) { + if(msg == WM_ERASEBKGND) return DefWindowProc(hwnd, msg, wparam, lparam); + if(msg == WM_PAINT) return Button_paintProc(hwnd, msg, wparam, lparam, + button->state.bordered, button->state.checked, button->enabled(true), button->font(true), + button->state.icon, button->state.orientation, button->state.text + ); + return self->windowProc(hwnd, msg, wparam, lparam); + } + } + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +auto pCheckButton::construct() -> void { + hwnd = CreateWindow(L"BUTTON", L"", + WS_CHILD | WS_TABSTOP | BS_CHECKBOX | BS_PUSHLIKE, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)CheckButton_windowProc); + pWidget::_setState(); + _setState(); + setChecked(state().checked); +} + +auto pCheckButton::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pCheckButton::minimumSize() const -> Size { + Size icon = {(int)state().icon.width(), (int)state().icon.height()}; + Size text = state().text ? pFont::size(self().font(true), state().text) : Size{}; + Size size; + if(state().orientation == Orientation::Horizontal) { + size.setWidth(icon.width() + (icon && text ? 5 : 0) + text.width()); + size.setHeight(max(icon.height(), text.height())); + } + if(state().orientation == Orientation::Vertical) { + size.setWidth(max(icon.width(), text.width())); + size.setHeight(icon.height() + (icon && text ? 5 : 0) + text.height()); + } + size.setHeight(max(size.height(), pFont::size(self().font(true), " ").height())); + return {size.width() + (state().bordered && text ? 20 : 10), size.height() + 10}; +} + +auto pCheckButton::setBordered(bool bordered) -> void { + _setState(); +} + +auto pCheckButton::setChecked(bool checked) -> void { + SendMessage(hwnd, BM_SETCHECK, (WPARAM)checked, 0); +} + +auto pCheckButton::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + _setState(); +} + +auto pCheckButton::setFont(const Font& font) -> void { + pWidget::setFont(font); + _setState(); +} + +auto pCheckButton::setIcon(const image& icon) -> void { + _setState(); +} + +auto pCheckButton::setOrientation(Orientation orientation) -> void { + _setState(); +} + +auto pCheckButton::setText(const string& text) -> void { + _setState(); +} + +auto pCheckButton::setVisible(bool visible) -> void { + pWidget::setVisible(visible); + _setState(); +} + +auto pCheckButton::onToggle() -> void { + state().checked = !state().checked; + setChecked(state().checked); + self().doToggle(); +} + +auto pCheckButton::_setState() -> void { + InvalidateRect(hwnd, 0, false); +} + +} + +#endif diff --git a/windows/widget/check-button.hpp b/windows/widget/check-button.hpp new file mode 100644 index 0000000..1de6eed --- /dev/null +++ b/windows/widget/check-button.hpp @@ -0,0 +1,27 @@ +#if defined(Hiro_CheckButton) + +namespace hiro { + +struct pCheckButton : pWidget { + Declare(CheckButton, Widget) + + auto minimumSize() const -> Size override; + auto setBordered(bool bordered) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setChecked(bool checked) -> void; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto onToggle() -> void; + + auto _setState() -> void; + + WindowProc windowProc = nullptr; +}; + +} + +#endif diff --git a/windows/widget/check-label.cpp b/windows/widget/check-label.cpp new file mode 100644 index 0000000..7aa1250 --- /dev/null +++ b/windows/widget/check-label.cpp @@ -0,0 +1,42 @@ +#if defined(Hiro_CheckLabel) + +namespace hiro { + +auto pCheckLabel::construct() -> void { + hwnd = CreateWindow( + L"BUTTON", L"", + WS_CHILD | WS_TABSTOP | BS_CHECKBOX, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setChecked(state().checked); + setText(state().text); +} + +auto pCheckLabel::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pCheckLabel::minimumSize() const -> Size { + auto size = pFont::size(self().font(true), state().text ? state().text : " "); + return {size.width() + 20, size.height() + 4}; +} + +auto pCheckLabel::setChecked(bool checked) -> void { + SendMessage(hwnd, BM_SETCHECK, (WPARAM)checked, 0); +} + +auto pCheckLabel::setText(const string& text) -> void { + SetWindowText(hwnd, utf16_t(text)); +} + +auto pCheckLabel::onToggle() -> void { + state().checked = !state().checked; + setChecked(state().checked); + self().doToggle(); +} + +} + +#endif diff --git a/windows/widget/check-label.hpp b/windows/widget/check-label.hpp new file mode 100644 index 0000000..9b6f3a9 --- /dev/null +++ b/windows/widget/check-label.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_CheckLabel) + +namespace hiro { + +struct pCheckLabel : pWidget { + Declare(CheckLabel, Widget) + + auto minimumSize() const -> Size override; + auto setChecked(bool checked) -> void; + auto setText(const string& text) -> void; + + auto onToggle() -> void; +}; + +} + +#endif diff --git a/windows/widget/combo-button-item.cpp b/windows/widget/combo-button-item.cpp new file mode 100644 index 0000000..0b8b1a0 --- /dev/null +++ b/windows/widget/combo-button-item.cpp @@ -0,0 +1,42 @@ +#if defined(Hiro_ComboButton) + +namespace hiro { + +auto pComboButtonItem::construct() -> void { +} + +auto pComboButtonItem::destruct() -> void { +} + +auto pComboButtonItem::setIcon(const image& icon) -> void { + //unsupported +} + +auto pComboButtonItem::setSelected() -> void { + if(auto parent = _parent()) { + parent->lock(); + SendMessage(parent->hwnd, CB_SETCURSEL, self().offset(), 0); + parent->unlock(); + } +} + +auto pComboButtonItem::setText(const string& text) -> void { + if(auto parent = _parent()) { + parent->lock(); + SendMessage(parent->hwnd, CB_DELETESTRING, self().offset(), 0); + SendMessage(parent->hwnd, CB_INSERTSTRING, self().offset(), (LPARAM)(wchar_t*)utf16_t(state().text)); + if(state().selected) setSelected(); + parent->unlock(); + } +} + +auto pComboButtonItem::_parent() -> maybe { + if(auto parent = self().parentComboButton()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/windows/widget/combo-button-item.hpp b/windows/widget/combo-button-item.hpp new file mode 100644 index 0000000..335e489 --- /dev/null +++ b/windows/widget/combo-button-item.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_ComboButton) + +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() -> maybe; +}; + +} + +#endif diff --git a/windows/widget/combo-button.cpp b/windows/widget/combo-button.cpp new file mode 100644 index 0000000..65cefb6 --- /dev/null +++ b/windows/widget/combo-button.cpp @@ -0,0 +1,67 @@ +#if defined(Hiro_ComboButton) + +namespace hiro { + +auto pComboButton::construct() -> void { + hwnd = CreateWindow( + L"COMBOBOX", L"", + WS_CHILD | WS_TABSTOP | CBS_DROPDOWNLIST | CBS_HASSTRINGS, + 0, 0, 0, 0, + _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + for(auto& item : state().items) append(item); +} + +auto pComboButton::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pComboButton::append(sComboButtonItem item) -> void { + lock(); + SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16_t(item->state.text)); + if(item->state.selected) SendMessage(hwnd, CB_SETCURSEL, item->offset(), 0); + if(SendMessage(hwnd, CB_GETCURSEL, 0, 0) == CB_ERR) item->setSelected(); + unlock(); +} + +auto pComboButton::minimumSize() const -> Size { + signed width = 0; + for(auto& item : state().items) { + width = max(width, pFont::size(hfont, item->state.text).width()); + } + return {width + 24, pFont::size(hfont, " ").height() + 10}; +} + +auto pComboButton::remove(sComboButtonItem item) -> void { + lock(); + SendMessage(hwnd, CB_DELETESTRING, item->offset(), 0); + if(item->state.selected) SendMessage(hwnd, CB_SETCURSEL, 0, 0); + unlock(); +} + +auto pComboButton::reset() -> void { + SendMessage(hwnd, CB_RESETCONTENT, 0, 0); +} + +auto pComboButton::setGeometry(Geometry geometry) -> void { + //height = minimum drop-down list height; use CB_SETITEMHEIGHT to control actual widget height + pWidget::setGeometry({geometry.x(), geometry.y(), geometry.width(), 1}); + RECT rc; + GetWindowRect(hwnd, &rc); + unsigned adjustedHeight = geometry.height() - ((rc.bottom - rc.top) - SendMessage(hwnd, CB_GETITEMHEIGHT, (WPARAM)-1, 0)); + SendMessage(hwnd, CB_SETITEMHEIGHT, (WPARAM)-1, adjustedHeight); +} + +auto pComboButton::onChange() -> void { + signed offset = SendMessage(hwnd, CB_GETCURSEL, 0, 0); + if(offset == CB_ERR) return; + for(auto& item : state().items) item->state.selected = false; + if(auto item = self().item(offset)) item->setSelected(); + self().doChange(); +} + +} + +#endif diff --git a/windows/widget/combo-button.hpp b/windows/widget/combo-button.hpp new file mode 100644 index 0000000..c03e234 --- /dev/null +++ b/windows/widget/combo-button.hpp @@ -0,0 +1,19 @@ +#if defined(Hiro_ComboButton) + +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 setGeometry(Geometry geometry) -> void override; + + auto onChange() -> void; +}; + +} + +#endif diff --git a/windows/widget/frame.cpp b/windows/widget/frame.cpp new file mode 100644 index 0000000..e844c11 --- /dev/null +++ b/windows/widget/frame.cpp @@ -0,0 +1,60 @@ +#if defined(Hiro_Frame) + +namespace hiro { + +auto pFrame::construct() -> void { + hwnd = CreateWindow(L"BUTTON", L"", + WS_CHILD | BS_GROUPBOX, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setText(state().text); +} + +auto pFrame::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pFrame::append(sLayout layout) -> void { +} + +auto pFrame::remove(sLayout layout) -> void { +} + +auto pFrame::setEnabled(bool enabled) -> void { + if(auto layout = state().layout) layout->setEnabled(layout->enabled()); + pWidget::setEnabled(enabled); +} + +auto pFrame::setGeometry(Geometry geometry) -> void { + bool empty = !state().text; + auto size = pFont::size(hfont, state().text); + pWidget::setGeometry({ + geometry.x(), + geometry.y() - (empty ? size.height() >> 1 : 0), + geometry.width(), + geometry.height() + (empty ? size.height() >> 1 : 0) + }); + if(auto layout = state().layout) { + if(empty) size.setHeight(1); + layout->setGeometry({ + geometry.x() + 1, + geometry.y() + size.height(), + geometry.width() - 2, + geometry.height() - (size.height() + 2) + }); + } +} + +auto pFrame::setText(const string& text) -> void { + SetWindowText(hwnd, utf16_t(text)); +} + +auto pFrame::setVisible(bool visible) -> void { + if(auto layout = state().layout) layout->setVisible(layout->visible()); + pWidget::setVisible(visible); +} + +} + +#endif diff --git a/windows/widget/frame.hpp b/windows/widget/frame.hpp new file mode 100644 index 0000000..7587893 --- /dev/null +++ b/windows/widget/frame.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_Frame) + +namespace hiro { + +struct pFrame : pWidget { + Declare(Frame, Widget) + + auto append(sLayout layout) -> void; + auto remove(sLayout layout) -> void; + auto setEnabled(bool enabled) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; +}; + +} + +#endif diff --git a/windows/widget/hex-edit.cpp b/windows/widget/hex-edit.cpp new file mode 100644 index 0000000..7ef58ec --- /dev/null +++ b/windows/widget/hex-edit.cpp @@ -0,0 +1,258 @@ +#if defined(Hiro_HexEdit) + +namespace hiro { + +static auto CALLBACK HexEdit_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!object) return DefWindowProc(hwnd, msg, wparam, lparam); + auto hexEdit = dynamic_cast(object); + if(!hexEdit) return DefWindowProc(hwnd, msg, wparam, lparam); + auto self = hexEdit->self(); + if(!self) return DefWindowProc(hwnd, msg, wparam, lparam); + + switch(msg) { + case WM_KEYDOWN: + if(self->keyPress(wparam)) return 0; + break; + + case WM_MOUSEWHEEL: { + signed offset = -((int16_t)HIWORD(wparam) / WHEEL_DELTA); + self->scrollTo(self->scrollPosition() + offset); + return true; + } + + case WM_SIZE: { + RECT rc; + GetClientRect(self->hwnd, &rc); + SetWindowPos(self->scrollBar, HWND_TOP, rc.right - 18, 0, 18, rc.bottom, SWP_SHOWWINDOW); + break; + } + + case WM_VSCROLL: { + SCROLLINFO info{sizeof(SCROLLINFO)}; + info.fMask = SIF_ALL; + GetScrollInfo((HWND)lparam, SB_CTL, &info); + switch(LOWORD(wparam)) { + case SB_LEFT: info.nPos = info.nMin; break; + case SB_RIGHT: info.nPos = info.nMax; break; + case SB_LINELEFT: info.nPos--; break; + case SB_LINERIGHT: info.nPos++; break; + case SB_PAGELEFT: info.nPos -= info.nMax >> 3; break; + case SB_PAGERIGHT: info.nPos += info.nMax >> 3; break; + case SB_THUMBTRACK: info.nPos = info.nTrackPos; break; + } + + info.fMask = SIF_POS; + SetScrollInfo((HWND)lparam, SB_CTL, &info, TRUE); + GetScrollInfo((HWND)lparam, SB_CTL, &info); //get clamped position + + self->scrollTo(info.nPos); + return true; + } + } + + return self->windowProc(hwnd, msg, wparam, lparam); +} + +auto pHexEdit::construct() -> void { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | ES_AUTOHSCROLL | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + + scrollBar = CreateWindowEx( + 0, L"SCROLLBAR", L"", + WS_VISIBLE | WS_CHILD | SBS_VERT, + 0, 0, 0, 0, hwnd, nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(scrollBar, GWLP_USERDATA, (LONG_PTR)&reference); + + windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)HexEdit_windowProc); + + pWidget::_setState(); + setAddress(state().address); + setBackgroundColor(state().backgroundColor); + setLength(state().length); + update(); + PostMessage(hwnd, EM_SETSEL, 10, 10); +} + +auto pHexEdit::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pHexEdit::setAddress(unsigned address) -> void { + SetScrollPos(scrollBar, SB_CTL, address / state().columns, true); + update(); +} + +auto pHexEdit::setBackgroundColor(Color color) -> void { + if(backgroundBrush) DeleteObject(backgroundBrush); + backgroundBrush = CreateSolidBrush(color ? CreateRGB(color) : GetSysColor(COLOR_WINDOW)); +} + +auto pHexEdit::setColumns(unsigned columns) -> void { + update(); +} + +auto pHexEdit::setForegroundColor(Color color) -> void { +} + +auto pHexEdit::setLength(unsigned length) -> void { + SetScrollRange(scrollBar, SB_CTL, 0, rowsScrollable(), true); + EnableWindow(scrollBar, rowsScrollable() > 0); + update(); +} + +auto pHexEdit::setRows(unsigned rows) -> void { + update(); +} + +auto pHexEdit::update() -> void { + if(!state().onRead) { + SetWindowText(hwnd, L""); + return; + } + + unsigned cursorPosition = Edit_GetSel(hwnd); + + string output; + unsigned address = state().address; + for(auto row : range(state().rows)) { + output.append(hex(address, 8L)); + output.append(" "); + + string hexdata; + string ansidata = " "; + for(auto column : range(state().columns)) { + if(address < state().length) { + uint8_t data = self().doRead(address++); + hexdata.append(hex(data, 2L)); + hexdata.append(" "); + ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.'); + } else { + hexdata.append(" "); + ansidata.append(" "); + } + } + + output.append(hexdata); + output.append(ansidata); + if(address >= state().length) break; + if(row != state().rows - 1) output.append("\r\n"); + } + + SetWindowText(hwnd, utf16_t(output)); + Edit_SetSel(hwnd, LOWORD(cursorPosition), HIWORD(cursorPosition)); +} + +bool pHexEdit::keyPress(unsigned scancode) { + if(!state().onRead) return false; + + signed position = LOWORD(Edit_GetSel(hwnd)); + signed lineWidth = 10 + (state().columns * 3) + 1 + state().columns + 2; + signed cursorY = position / lineWidth; + signed cursorX = position % lineWidth; + + if(scancode == VK_HOME) { + signed offset = cursorY * lineWidth + 10; + Edit_SetSel(hwnd, offset, offset); + return true; + } + + if(scancode == VK_END) { + signed offset = cursorY * lineWidth + 57; + Edit_SetSel(hwnd, offset, offset); + return true; + } + + if(scancode == VK_UP) { + if(cursorY > 0) return false; + scrollTo(scrollPosition() - 1); + return true; + } + + if(scancode == VK_DOWN) { + if(cursorY >= rows() - 1) return true; + if(cursorY < state().rows - 1) return false; + scrollTo(scrollPosition() + 1); + return true; + } + + if(scancode == VK_PRIOR) { + scrollTo(scrollPosition() - state().rows); + return true; + } + + if(scancode == VK_NEXT) { + scrollTo(scrollPosition() + state().rows); + return true; + } + + //convert scancode to hex nibble + if(scancode >= '0' && scancode <= '9') scancode = scancode - '0'; + else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10; + else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10; + else return false; + + if(cursorX >= 10) { + //not on an address + cursorX -= 10; + if((cursorX % 3) != 2) { + //not on a space + bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low + cursorX /= 3; + if(cursorX < state().columns) { + //not in ANSI region + unsigned address = state().address + (cursorY * state().columns + cursorX); + + if(address >= state().length) return false; //do not edit past end of data + uint8_t data = self().doRead(address); + + //write modified value + if(cursorNibble == 1) { + data = (data & 0xf0) | (scancode << 0); + } else { + data = (data & 0x0f) | (scancode << 4); + } + self().doWrite(address, data); + + //auto-advance cursor to next nibble or byte + position++; + if(cursorNibble && cursorX != state().columns - 1) position++; + Edit_SetSel(hwnd, position, position); + + //refresh output to reflect modified data + update(); + } + } + } + + return true; +} + +signed pHexEdit::rows() { + return (max(1u, state().length) + state().columns - 1) / state().columns; +} + +signed pHexEdit::rowsScrollable() { + return max(0u, rows() - state().rows); +} + +signed pHexEdit::scrollPosition() { + return state().address / state().columns; +} + +void pHexEdit::scrollTo(signed position) { + if(position > rowsScrollable()) position = rowsScrollable(); + if(position < 0) position = 0; + if(position == scrollPosition()) return; + self().setAddress(position * state().columns); +} + +} + +#endif diff --git a/windows/widget/hex-edit.hpp b/windows/widget/hex-edit.hpp new file mode 100644 index 0000000..ce2240a --- /dev/null +++ b/windows/widget/hex-edit.hpp @@ -0,0 +1,29 @@ +#if defined(Hiro_HexEdit) + +namespace hiro { + +struct pHexEdit : pWidget { + Declare(HexEdit, Widget) + + auto setAddress(unsigned address) -> void; + auto setBackgroundColor(Color color) -> void; + auto setColumns(unsigned columns) -> void; + auto setForegroundColor(Color color) -> void; + auto setLength(unsigned length) -> void; + auto setRows(unsigned rows) -> void; + auto update() -> void; + + auto keyPress(unsigned key) -> bool; + auto rows() -> signed; + auto rowsScrollable() -> signed; + auto scrollPosition() -> signed; + auto scrollTo(signed position) -> void; + + WindowProc windowProc = nullptr; + HWND scrollBar = nullptr; + HBRUSH backgroundBrush = nullptr; +}; + +} + +#endif diff --git a/windows/widget/horizontal-scroll-bar.cpp b/windows/widget/horizontal-scroll-bar.cpp new file mode 100644 index 0000000..ab34754 --- /dev/null +++ b/windows/widget/horizontal-scroll-bar.cpp @@ -0,0 +1,42 @@ +#if defined(Hiro_HorizontalScrollBar) + +namespace hiro { + +auto pHorizontalScrollBar::construct() -> void { + hwnd = CreateWindow( + L"SCROLLBAR", L"", WS_CHILD | WS_TABSTOP | SBS_HORZ, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setLength(state().length); + setPosition(state().position); +} + +auto pHorizontalScrollBar::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pHorizontalScrollBar::minimumSize() const -> Size { + return {0, 18}; +} + +auto pHorizontalScrollBar::setLength(unsigned length) -> void { + length += (length == 0); + SetScrollRange(hwnd, SB_CTL, 0, length - 1, TRUE); +} + +auto pHorizontalScrollBar::setPosition(unsigned position) -> void { + SetScrollPos(hwnd, SB_CTL, position, TRUE); +} + +auto pHorizontalScrollBar::onChange(WPARAM wparam) -> void { + unsigned position = ScrollEvent(hwnd, wparam); + if(position == state().position) return; + state().position = position; + self().doChange(); +} + +} + +#endif diff --git a/windows/widget/horizontal-scroll-bar.hpp b/windows/widget/horizontal-scroll-bar.hpp new file mode 100644 index 0000000..180249f --- /dev/null +++ b/windows/widget/horizontal-scroll-bar.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_HorizontalScrollBar) + +namespace hiro { + +struct pHorizontalScrollBar : pWidget { + Declare(HorizontalScrollBar, Widget) + + auto minimumSize() const -> Size override; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; + + auto onChange(WPARAM wparam) -> void; +}; + +} + +#endif diff --git a/windows/widget/horizontal-slider.cpp b/windows/widget/horizontal-slider.cpp new file mode 100644 index 0000000..605104e --- /dev/null +++ b/windows/widget/horizontal-slider.cpp @@ -0,0 +1,43 @@ +#if defined(Hiro_HorizontalSlider) + +namespace hiro { + +auto pHorizontalSlider::construct() -> void { + hwnd = CreateWindow( + TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_TRANSPARENTBKGND | TBS_NOTICKS | TBS_BOTH | TBS_HORZ, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setLength(state().length); + setPosition(state().position); +} + +auto pHorizontalSlider::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pHorizontalSlider::minimumSize() const -> Size { + return {0, 25}; +} + +auto pHorizontalSlider::setLength(unsigned length) -> void { + length += (length == 0); + SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1)); + SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3)); +} + +auto pHorizontalSlider::setPosition(unsigned position) -> void { + SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)position); +} + +auto pHorizontalSlider::onChange() -> void { + unsigned position = SendMessage(hwnd, TBM_GETPOS, 0, 0); + if(position == state().position) return; + state().position = position; + self().doChange(); +} + +} + +#endif diff --git a/windows/widget/horizontal-slider.hpp b/windows/widget/horizontal-slider.hpp new file mode 100644 index 0000000..6a81777 --- /dev/null +++ b/windows/widget/horizontal-slider.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_HorizontalSlider) + +namespace hiro { + +struct pHorizontalSlider : pWidget { + Declare(HorizontalSlider, Widget) + + auto minimumSize() const -> Size override; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; + + auto onChange() -> void; +}; + +} + +#endif diff --git a/windows/widget/label.cpp b/windows/widget/label.cpp new file mode 100644 index 0000000..552639e --- /dev/null +++ b/windows/widget/label.cpp @@ -0,0 +1,70 @@ +#if defined(Hiro_Label) + +namespace hiro { + +auto pLabel::construct() -> void { + hwnd = CreateWindow(L"hiroLabel", L"", + WS_CHILD, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setAlignment(state().alignment); + setText(state().text); +} + +auto pLabel::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pLabel::minimumSize() const -> Size { + auto size = pFont::size(hfont, state().text); + return {size.width(), size.height()}; +} + +auto pLabel::setAlignment(Alignment alignment) -> void { + InvalidateRect(hwnd, 0, false); +} + +auto pLabel::setText(const string& text) -> void { + SetWindowText(hwnd, utf16_t(text)); + InvalidateRect(hwnd, 0, false); +} + +static auto CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + auto label = (mLabel*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!label) return DefWindowProc(hwnd, msg, wparam, lparam); + auto window = label->parentWindow(true); + if(!window) return DefWindowProc(hwnd, msg, wparam, lparam); + + switch(msg) { + case WM_GETDLGCODE: return DLGC_STATIC | DLGC_WANTCHARS; + case WM_ERASEBKGND: return true; + case WM_PAINT: { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + RECT rc; + GetClientRect(hwnd, &rc); + DrawThemeParentBackground(hwnd, ps.hdc, &rc); + SetBkMode(ps.hdc, TRANSPARENT); + SelectObject(ps.hdc, label->self()->hfont); + unsigned length = GetWindowTextLength(hwnd); + wchar_t text[length + 1]; + GetWindowText(hwnd, text, length + 1); + text[length] = 0; + DrawText(ps.hdc, text, -1, &rc, DT_CALCRECT | DT_END_ELLIPSIS); + unsigned height = rc.bottom; + GetClientRect(hwnd, &rc); + rc.top = (rc.bottom - height) / 2; + rc.bottom = rc.top + height; + DrawText(ps.hdc, text, -1, &rc, DT_LEFT | DT_END_ELLIPSIS); + EndPaint(hwnd, &ps); + return false; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +} + +#endif diff --git a/windows/widget/label.hpp b/windows/widget/label.hpp new file mode 100644 index 0000000..91e99f6 --- /dev/null +++ b/windows/widget/label.hpp @@ -0,0 +1,15 @@ +#if defined(Hiro_Label) + +namespace hiro { + +struct pLabel : pWidget { + Declare(Label, Widget) + + auto minimumSize() const -> Size override; + auto setAlignment(Alignment alignment) -> void; + auto setText(const string& text) -> void; +}; + +} + +#endif diff --git a/windows/widget/line-edit.cpp b/windows/widget/line-edit.cpp new file mode 100644 index 0000000..81311ee --- /dev/null +++ b/windows/widget/line-edit.cpp @@ -0,0 +1,61 @@ +#if defined(Hiro_LineEdit) + +namespace hiro { + +auto pLineEdit::construct() -> void { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | ES_AUTOHSCROLL | ES_AUTOVSCROLL, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setBackgroundColor(state().backgroundColor); + setEditable(state().editable); + setText(state().text); +} + +auto pLineEdit::destruct() -> void { + if(backgroundBrush) { DeleteObject(backgroundBrush); backgroundBrush = 0; } + DestroyWindow(hwnd); +} + +auto pLineEdit::minimumSize() const -> Size { + auto size = pFont::size(hfont, state().text ? state().text : " "); + return {size.width() + 12, size.height() + 10}; +} + +auto pLineEdit::setBackgroundColor(Color color) -> void { + if(backgroundBrush) { DeleteObject(backgroundBrush); backgroundBrush = 0; } + backgroundBrush = CreateSolidBrush(color ? CreateRGB(color) : GetSysColor(COLOR_WINDOW)); +} + +auto pLineEdit::setEditable(bool editable) -> void { + SendMessage(hwnd, EM_SETREADONLY, editable == false, 0); +} + +auto pLineEdit::setForegroundColor(Color color) -> void { +} + +auto pLineEdit::setText(const string& text) -> void { + lock(); + SetWindowText(hwnd, utf16_t(text)); + unlock(); +} + +auto pLineEdit::onChange() -> void { + state().text = _text(); + if(!locked()) self().doChange(); +} + +auto pLineEdit::_text() -> string { + unsigned length = GetWindowTextLength(hwnd); + wchar_t text[length + 1]; + GetWindowText(hwnd, text, length + 1); + text[length] = 0; + return (const char*)utf8_t(text); +} + +} + +#endif diff --git a/windows/widget/line-edit.hpp b/windows/widget/line-edit.hpp new file mode 100644 index 0000000..577028c --- /dev/null +++ b/windows/widget/line-edit.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_LineEdit) + +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; + + auto onChange() -> void; + + auto _text() -> string; + + HBRUSH backgroundBrush = nullptr; +}; + +} + +#endif diff --git a/windows/widget/list-view-cell.cpp b/windows/widget/list-view-cell.cpp new file mode 100644 index 0000000..0b912aa --- /dev/null +++ b/windows/widget/list-view-cell.cpp @@ -0,0 +1,72 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewCell::construct() -> void { +} + +auto pListViewCell::destruct() -> void { +} + +auto pListViewCell::setAlignment(Alignment alignment) -> void { +} + +auto pListViewCell::setBackgroundColor(Color color) -> void { + _repaint(); +} + +auto pListViewCell::setCheckable(bool checkable) -> void { + _repaint(); +} + +auto pListViewCell::setChecked(bool checked) -> void { + _repaint(); +} + +auto pListViewCell::setForegroundColor(Color color) -> void { + _repaint(); +} + +auto pListViewCell::setIcon(const image& icon) -> void { + _repaint(); +} + +auto pListViewCell::setText(const string& text) -> void { + _repaint(); +} + +auto pListViewCell::_parent() -> maybe { + if(auto parent = self().parentListViewItem()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pListViewCell::_repaint() -> void { + if(auto parent = _parent()) { + if(auto listView = parent->_parent()) { + //ListView uses a custom drawing routine; so we need to tell the control to repaint itself manually + PostMessageOnce(listView->_parentHandle(), AppMessage::ListView_doPaint, 0, (LPARAM)&listView->reference); + } + } +} + +auto pListViewCell::_setState() -> void { + if(auto item = _parent()) { + if(auto parent = item->_parent()) { + parent->lock(); + wchar_t text[] = L""; + LVITEM lvItem; + lvItem.mask = LVIF_TEXT; + lvItem.iItem = item->self().offset(); + lvItem.iSubItem = self().offset(); + lvItem.pszText = text; + ListView_SetItem(parent->hwnd, &lvItem); + parent->unlock(); + } + } +} + +} + +#endif diff --git a/windows/widget/list-view-cell.hpp b/windows/widget/list-view-cell.hpp new file mode 100644 index 0000000..d5c6292 --- /dev/null +++ b/windows/widget/list-view-cell.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewCell : pObject { + Declare(ListViewCell, Object) + + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; + auto setChecked(bool checked) -> void; + auto setForegroundColor(Color color) -> void; + auto setIcon(const image& icon) -> void; + auto setText(const string& text) -> void; + + auto _parent() -> maybe; + auto _repaint() -> void; + auto _setState() -> void; +}; + +} + +#endif diff --git a/windows/widget/list-view-column.cpp b/windows/widget/list-view-column.cpp new file mode 100644 index 0000000..ef2871b --- /dev/null +++ b/windows/widget/list-view-column.cpp @@ -0,0 +1,109 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewColumn::construct() -> void { + if(auto grandparent = _grandparent()) { + grandparent->lock(); + wchar_t text[] = L""; + LVCOLUMN lvColumn{0}; + lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM; + lvColumn.fmt = LVCFMT_LEFT; + lvColumn.iSubItem = self().offset(); + lvColumn.pszText = text; + ListView_InsertColumn(grandparent->hwnd, self().offset(), &lvColumn); + _setState(); + grandparent->unlock(); + } +} + +auto pListViewColumn::destruct() -> void { + if(auto grandparent = _grandparent()) { + grandparent->lock(); + ListView_DeleteColumn(grandparent->hwnd, self().offset()); + grandparent->unlock(); + } +} + +auto pListViewColumn::setActive() -> void { + //unsupported +} + +auto pListViewColumn::setAlignment(Alignment alignment) -> void { +} + +auto pListViewColumn::setBackgroundColor(Color color) -> void { +} + +auto pListViewColumn::setEditable(bool editable) -> void { + //unsupported +} + +auto pListViewColumn::setExpandable(bool expandable) -> void { +} + +auto pListViewColumn::setForegroundColor(Color color) -> void { +} + +auto pListViewColumn::setHorizontalAlignment(double alignment) -> void { + _setState(); +} + +auto pListViewColumn::setIcon(const image& icon) -> void { + _setState(); +} + +auto pListViewColumn::setResizable(bool resizable) -> void { + _setState(); +} + +auto pListViewColumn::setSortable(bool sortable) -> void { +} + +auto pListViewColumn::setText(const string& text) -> void { + _setState(); +} + +auto pListViewColumn::setVerticalAlignment(double alignment) -> void { +} + +auto pListViewColumn::setWidth(signed width) -> void { + _setState(); +} + +auto pListViewColumn::_grandparent() -> maybe { + if(auto parent = _parent()) return parent->_parent(); + return nothing; +} + +auto pListViewColumn::_parent() -> maybe { + if(auto parent = self().parentListViewHeader()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pListViewColumn::_setState() -> void { + if(auto grandparent = _grandparent()) { + grandparent->lock(); + grandparent->_setIcons(); + utf16_t text(state().text); + LVCOLUMN lvColumn; + lvColumn.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; + lvColumn.fmt = LVCFMT_CENTER; + lvColumn.iSubItem = self().offset(); + lvColumn.iImage = self().offset(); + lvColumn.pszText = text; + lvColumn.cx = _width; + if(state().horizontalAlignment < 0.333) lvColumn.fmt = LVCFMT_LEFT; + if(state().horizontalAlignment > 0.666) lvColumn.fmt = LVCFMT_RIGHT; + if(state().icon) lvColumn.mask |= LVCF_IMAGE; + if(!state().resizable) lvColumn.fmt |= LVCFMT_FIXED_WIDTH; + ListView_SetColumn(grandparent->hwnd, self().offset(), &lvColumn); + grandparent->unlock(); + } +} + +} + +#endif diff --git a/windows/widget/list-view-column.hpp b/windows/widget/list-view-column.hpp new file mode 100644 index 0000000..2c00c65 --- /dev/null +++ b/windows/widget/list-view-column.hpp @@ -0,0 +1,31 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewColumn : pObject { + Declare(ListViewColumn, Object) + + auto setActive() -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setEditable(bool editable) -> void; + auto setExpandable(bool expandable) -> void; + 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 setWidth(signed width) -> void; + + auto _grandparent() -> maybe; + auto _parent() -> maybe; + auto _setState() -> void; + + signed _width = 128; //computed width (via ListView::resizeColumns) +}; + +} + +#endif diff --git a/windows/widget/list-view-header.cpp b/windows/widget/list-view-header.cpp new file mode 100644 index 0000000..fbce80c --- /dev/null +++ b/windows/widget/list-view-header.cpp @@ -0,0 +1,42 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewHeader::construct() -> void { + _setState(); +} + +auto pListViewHeader::destruct() -> void { +} + +auto pListViewHeader::append(sListViewColumn column) -> void { +} + +auto pListViewHeader::remove(sListViewColumn column) -> void { +} + +auto pListViewHeader::setVisible(bool visible) -> void { + _setState(); +} + +auto pListViewHeader::_parent() -> maybe { + if(auto parent = self().parentListView()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pListViewHeader::_setState() -> void { + if(auto parent = _parent()) { + auto style = GetWindowLong(parent->hwnd, GWL_STYLE); + self().visible() ? style &=~ LVS_NOCOLUMNHEADER : style |= LVS_NOCOLUMNHEADER; + SetWindowLong(parent->hwnd, GWL_STYLE, style); + for(auto& column : state().columns) { + if(auto self = column->self()) self->_setState(); + } + } +} + +} + +#endif diff --git a/windows/widget/list-view-header.hpp b/windows/widget/list-view-header.hpp new file mode 100644 index 0000000..a46855b --- /dev/null +++ b/windows/widget/list-view-header.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewHeader : pObject { + Declare(ListViewHeader, Object) + + auto append(sListViewColumn column) -> void; + auto remove(sListViewColumn column) -> void; + auto setVisible(bool visible) -> void override; + + auto _parent() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/windows/widget/list-view-item.cpp b/windows/widget/list-view-item.cpp new file mode 100644 index 0000000..b956286 --- /dev/null +++ b/windows/widget/list-view-item.cpp @@ -0,0 +1,75 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +auto pListViewItem::construct() -> void { + if(auto parent = _parent()) { + parent->lock(); + wchar_t text[] = L""; + LVITEM lvItem{0}; + lvItem.mask = LVIF_TEXT; + lvItem.iItem = self().offset(); + lvItem.iSubItem = 0; + lvItem.pszText = text; + ListView_InsertItem(parent->hwnd, &lvItem); + _setState(); + parent->unlock(); + } +} + +auto pListViewItem::destruct() -> void { + if(auto parent = _parent()) { + parent->lock(); + ListView_DeleteItem(parent->hwnd, self().offset()); + parent->unlock(); + } +} + +auto pListViewItem::append(sListViewCell cell) -> void { +} + +auto pListViewItem::remove(sListViewCell cell) -> void { +} + +auto pListViewItem::setAlignment(Alignment alignment) -> void { +} + +auto pListViewItem::setBackgroundColor(Color color) -> void { +} + +auto pListViewItem::setFocused() -> void { + if(auto parent = _parent()) { + parent->lock(); + ListView_SetItemState(parent->hwnd, self().offset(), LVIS_FOCUSED, LVIS_FOCUSED); + parent->unlock(); + } +} + +auto pListViewItem::setForegroundColor(Color color) -> void { +} + +auto pListViewItem::setSelected(bool selected) -> void { + _setState(); +} + +auto pListViewItem::_parent() -> maybe { + if(auto parent = self().parentListView()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pListViewItem::_setState() -> void { + if(auto parent = _parent()) { + parent->lock(); + ListView_SetItemState(parent->hwnd, self().offset(), state().selected ? LVIS_SELECTED : 0, LVIS_SELECTED); + for(auto& cell : state().cells) { + if(auto self = cell->self()) self->_setState(); + } + parent->unlock(); + } +} + +} + +#endif diff --git a/windows/widget/list-view-item.hpp b/windows/widget/list-view-item.hpp new file mode 100644 index 0000000..bc0d3c2 --- /dev/null +++ b/windows/widget/list-view-item.hpp @@ -0,0 +1,22 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListViewItem : pObject { + Declare(ListViewItem, Object) + + auto append(sListViewCell cell) -> void; + auto remove(sListViewCell cell) -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setFocused() -> void; + auto setForegroundColor(Color color) -> void; + auto setSelected(bool selected) -> void; + + auto _parent() -> maybe; + auto _setState() -> void; +}; + +} + +#endif diff --git a/windows/widget/list-view.cpp b/windows/widget/list-view.cpp new file mode 100644 index 0000000..fa561b2 --- /dev/null +++ b/windows/widget/list-view.cpp @@ -0,0 +1,440 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +static auto CALLBACK ListView_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) { + if(auto listView = dynamic_cast(object)) { + if(auto self = listView->self()) { + if(!listView->enabled(true)) { + if(msg == WM_KEYDOWN || msg == WM_KEYUP || msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) { + //WC_LISTVIEW responds to key messages even when its HWND is disabled + //the control should be inactive when disabled; so we intercept the messages here + return false; + } + } + return self->windowProc(hwnd, msg, wparam, lparam); + } + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +auto pListView::construct() -> void { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE | LVS_EX_DOUBLEBUFFER, WC_LISTVIEW, L"", + WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_SHOWSELALWAYS, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)&ListView_windowProc); + ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES); + pWidget::_setState(); + setBackgroundColor(state().backgroundColor); + setBatchable(state().batchable); + setBordered(state().bordered); + _setIcons(); + _setSortable(); + resizeColumns(); +} + +auto pListView::destruct() -> void { + if(imageList) { ImageList_Destroy(imageList); imageList = nullptr; } + DestroyWindow(hwnd); +} + +auto pListView::append(sListViewHeader header) -> void { +} + +auto pListView::append(sListViewItem item) -> void { +} + +auto pListView::remove(sListViewHeader header) -> void { + LVCOLUMN lvColumn{LVCF_WIDTH}; + while(ListView_GetColumn(hwnd, 0, &lvColumn)) { + ListView_DeleteColumn(hwnd, 0); + } +} + +auto pListView::remove(sListViewItem item) -> void { +} + +auto pListView::resizeColumns() -> void { + lock(); + + if(auto& header = state().header) { + vector widths; + signed minimumWidth = 0; + signed expandable = 0; + for(auto column : range(header->columnCount())) { + signed width = _width(column); + widths.append(width); + minimumWidth += width; + if(header->column(column).expandable()) expandable++; + } + + signed maximumWidth = self().geometry().width() - 4; + SCROLLBARINFO sbInfo{sizeof(SCROLLBARINFO)}; + if(GetScrollBarInfo(hwnd, OBJID_VSCROLL, &sbInfo)) { + if(!(sbInfo.rgstate[0] & STATE_SYSTEM_INVISIBLE)) { + maximumWidth -= sbInfo.rcScrollBar.right - sbInfo.rcScrollBar.left; + } + } + + signed expandWidth = 0; + if(expandable && maximumWidth > minimumWidth) { + expandWidth = (maximumWidth - minimumWidth) / expandable; + } + + for(auto column : range(header->columnCount())) { + if(auto self = header->state.columns[column]->self()) { + signed width = widths[column]; + if(self->state().expandable) width += expandWidth; + self->_width = width; + self->_setState(); + } + } + } + + unlock(); +} + +auto pListView::setAlignment(Alignment alignment) -> void { +} + +auto pListView::setBackgroundColor(Color color) -> void { + if(!color) color = {255, 255, 255}; + ListView_SetBkColor(hwnd, RGB(color.red(), color.green(), color.blue())); +} + +auto pListView::setBatchable(bool batchable) -> void { + auto style = GetWindowLong(hwnd, GWL_STYLE); + !batchable ? style |= LVS_SINGLESEL : style &=~ LVS_SINGLESEL; + SetWindowLong(hwnd, GWL_STYLE, style); +} + +auto pListView::setBordered(bool bordered) -> void { + //rendered via onCustomDraw +} + +auto pListView::setForegroundColor(Color color) -> void { +} + +auto pListView::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + if(auto& header = state().header) { + for(auto& column : header->state.columns) { + if(column->state.expandable) return resizeColumns(); + } + } +} + +auto pListView::onActivate(LPARAM lparam) -> void { + auto nmlistview = (LPNMLISTVIEW)lparam; + if(ListView_GetSelectedCount(hwnd) == 0) return; + if(!locked()) { + //LVN_ITEMACTIVATE is not re-entrant until DispatchMessage() completes + //thus, we don't call self().doActivate() here + PostMessageOnce(_parentHandle(), AppMessage::ListView_onActivate, 0, (LPARAM)&reference); + } +} + +auto pListView::onChange(LPARAM lparam) -> void { + auto nmlistview = (LPNMLISTVIEW)lparam; + if(!(nmlistview->uChanged & LVIF_STATE)) return; + + bool modified = false; + for(auto& item : state().items) { + bool selected = ListView_GetItemState(hwnd, item->offset(), LVIS_SELECTED) & LVIS_SELECTED; + if(item->state.selected != selected) { + modified = true; + item->state.selected = selected; + } + } + if(modified && !locked()) { + //state event change messages are sent for every item + //so when doing a batch select/deselect; this can generate several messages + //we use a delayed AppMessage so that only one callback event is fired off + PostMessageOnce(_parentHandle(), AppMessage::ListView_onChange, 0, (LPARAM)&reference); + } +} + +auto pListView::onContext(LPARAM lparam) -> void { + auto nmitemactivate = (LPNMITEMACTIVATE)lparam; + return self().doContext(); +} + +auto pListView::onCustomDraw(LPARAM lparam) -> LRESULT { + auto lvcd = (LPNMLVCUSTOMDRAW)lparam; + + switch(lvcd->nmcd.dwDrawStage) { + default: return CDRF_DODEFAULT; + case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW; + case CDDS_ITEMPREPAINT: return CDRF_NOTIFYSUBITEMDRAW | CDRF_NOTIFYPOSTPAINT; + case CDDS_ITEMPREPAINT | CDDS_SUBITEM: return CDRF_SKIPDEFAULT; + case CDDS_ITEMPOSTPAINT: { + HDC hdc = lvcd->nmcd.hdc; + HDC hdcSource = CreateCompatibleDC(hdc); + unsigned row = lvcd->nmcd.dwItemSpec; + auto& header = state().header; + if(!header) break; + for(auto column : range(header->columnCount())) { + RECT rc, rcLabel; + ListView_GetSubItemRect(hwnd, row, column, LVIR_BOUNDS, &rc); + ListView_GetSubItemRect(hwnd, row, column, LVIR_LABEL, &rcLabel); + rc.right = rcLabel.right; //bounds of column 0 returns width of entire item + signed iconSize = rc.bottom - rc.top - 1; + bool selected = state().items(row)->state.selected; + + if(auto cell = self().item(row)->cell(column)) { + auto backgroundColor = cell->backgroundColor(true); + HBRUSH brush = CreateSolidBrush( + selected ? GetSysColor(COLOR_HIGHLIGHT) + : backgroundColor ? CreateRGB(backgroundColor) + : GetSysColor(COLOR_WINDOW) + ); + FillRect(hdc, &rc, brush); + DeleteObject(brush); + + if(cell->state.checkable) { + if(auto htheme = OpenThemeData(hwnd, L"BUTTON")) { + unsigned state = cell->state.checked ? CBS_CHECKEDNORMAL : CBS_UNCHECKEDNORMAL; + SIZE size; + GetThemePartSize(htheme, hdc, BP_CHECKBOX, state, nullptr, TS_TRUE, &size); + signed center = max(0, (rc.bottom - rc.top - size.cy) / 2); + RECT rd{rc.left + center, rc.top + center, rc.left + center + size.cx, rc.top + center + size.cy}; + DrawThemeBackground(htheme, hdc, BP_CHECKBOX, state, &rd, nullptr); + CloseThemeData(htheme); + } else { + //Windows Classic + rc.left += 2; + RECT rd{rc.left, rc.top, rc.left + iconSize, rc.top + iconSize}; + DrawFrameControl(hdc, &rd, DFC_BUTTON, DFCS_BUTTONCHECK | (cell->state.checked ? DFCS_CHECKED : 0)); + } + rc.left += iconSize + 2; + } else { + rc.left += 2; + } + + if(auto& icon = cell->state.icon) { + auto bitmap = CreateBitmap(icon); + SelectBitmap(hdcSource, bitmap); + BLENDFUNCTION blend{AC_SRC_OVER, 0, (BYTE)(selected ? 128 : 255), AC_SRC_ALPHA}; + AlphaBlend(hdc, rc.left, rc.top, iconSize, iconSize, hdcSource, 0, 0, icon.width(), icon.height(), blend); + DeleteObject(bitmap); + rc.left += iconSize + 2; + } + + if(auto text = cell->state.text) { + auto alignment = cell->alignment(true); + if(!alignment) alignment = {0.0, 0.5}; + utf16_t wText(text); + SetBkMode(hdc, TRANSPARENT); + auto foregroundColor = cell->foregroundColor(true); + SetTextColor(hdc, + selected ? GetSysColor(COLOR_HIGHLIGHTTEXT) + : foregroundColor ? CreateRGB(foregroundColor) + : GetSysColor(COLOR_WINDOWTEXT) + ); + auto style = DT_SINGLELINE | DT_NOPREFIX | DT_END_ELLIPSIS; + style |= alignment.horizontal() < 0.333 ? DT_LEFT : alignment.horizontal() > 0.666 ? DT_RIGHT : DT_CENTER; + style |= alignment.vertical() < 0.333 ? DT_TOP : alignment.vertical() > 0.666 ? DT_BOTTOM : DT_VCENTER; + rc.right -= 2; + auto font = pFont::create(cell->font(true)); + SelectObject(hdc, font); + DrawText(hdc, wText, -1, &rc, style); + DeleteObject(font); + } + } else { + auto backgroundColor = state().backgroundColor; + HBRUSH brush = CreateSolidBrush( + selected ? GetSysColor(COLOR_HIGHLIGHT) + : backgroundColor ? CreateRGB(backgroundColor) + : GetSysColor(COLOR_WINDOW) + ); + FillRect(hdc, &rc, brush); + DeleteObject(brush); + } + + if(state().bordered) { + ListView_GetSubItemRect(hwnd, row, column, LVIR_BOUNDS, &rc); + rc.top = rc.bottom - 1; + FillRect(hdc, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); + ListView_GetSubItemRect(hwnd, row, column, LVIR_LABEL, &rc); + rc.left = rc.right - 1; + FillRect(hdc, &rc, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); + } + } + DeleteDC(hdcSource); + return CDRF_SKIPDEFAULT; + } + } + + return CDRF_SKIPDEFAULT; +} + +auto pListView::onSort(LPARAM lparam) -> void { + auto nmlistview = (LPNMLISTVIEW)lparam; + if(auto& header = state().header) { + if(auto column = header->column(nmlistview->iSubItem)) { + if(column->sortable()) self().doSort(column); + } + } +} + +auto pListView::onToggle(LPARAM lparam) -> void { + auto itemActivate = (LPNMITEMACTIVATE)lparam; + LVHITTESTINFO hitTestInfo{0}; + hitTestInfo.pt = itemActivate->ptAction; + ListView_SubItemHitTest(hwnd, &hitTestInfo); + + if(auto cell = self().item(hitTestInfo.iItem).cell(hitTestInfo.iSubItem)) { + if(cell->state.checkable) { + cell->state.checked = !cell->state.checked; + if(!locked()) self().doToggle(cell); + //todo: try to find a way to only repaint this cell instead of the entire control to reduce flickering + PostMessageOnce(_parentHandle(), AppMessage::ListView_doPaint, 0, (LPARAM)&reference); + } + } +} + +auto pListView::_backgroundColor(unsigned _row, unsigned _column) -> Color { + if(auto item = self().item(_row)) { + if(auto cell = item->cell(_column)) { + if(auto color = cell->backgroundColor()) return color; + } + if(auto color = item->backgroundColor()) return color; + } +// if(auto column = self().column(_column)) { +// if(auto color = column->backgroundColor()) return color; +// } + if(auto color = self().backgroundColor()) return color; +// if(state().columns.size() >= 2 && _row % 2) return {240, 240, 240}; + return {255, 255, 255}; +} + +auto pListView::_cellWidth(unsigned _row, unsigned _column) -> unsigned { + unsigned width = 6; + if(auto item = self().item(_row)) { + if(auto cell = item->cell(_column)) { + if(cell->state.checkable) { + width += 16 + 2; + } + if(auto& icon = cell->state.icon) { + width += 16 + 2; + } + if(auto& text = cell->state.text) { + width += pFont::size(_font(_row, _column), text).width(); + } + } + } + return width; +} + +auto pListView::_columnWidth(unsigned _column) -> unsigned { + unsigned width = 12; + if(auto header = state().header) { + if(auto column = header->column(_column)) { + if(auto& icon = column->state.icon) { + width += 16 + 12; //yes; icon spacing in column headers is excessive + } + if(auto& text = column->state.text) { + width += pFont::size(self().font(true), text).width(); + } + } + } + return width; +} + +auto pListView::_font(unsigned _row, unsigned _column) -> Font { + if(auto item = self().item(_row)) { + if(auto cell = item->cell(_column)) { + if(auto font = cell->font()) return font; + } + if(auto font = item->font()) return font; + } +// if(auto column = self().column(_column)) { +// if(auto font = column->font()) return font; +// } + if(auto font = self().font(true)) return font; + return {}; +} + +auto pListView::_foregroundColor(unsigned _row, unsigned _column) -> Color { + if(auto item = self().item(_row)) { + if(auto cell = item->cell(_column)) { + if(auto color = cell->foregroundColor()) return color; + } + if(auto color = item->foregroundColor()) return color; + } +// if(auto column = self().column(_column)) { +// if(auto color = column->foregroundColor()) return color; +// } + if(auto color = self().foregroundColor()) return color; + return {0, 0, 0}; +} + +auto pListView::_setIcons() -> void { + ListView_SetImageList(hwnd, nullptr, LVSIL_SMALL); + if(imageList) ImageList_Destroy(imageList); + imageList = ImageList_Create(16, 16, ILC_COLOR32, 1, 0); + ListView_SetImageList(hwnd, imageList, LVSIL_SMALL); + + if(auto& header = state().header) { + for(auto column : range(header->columnCount())) { + image icon; + if(auto& sourceIcon = header->state.columns[column]->state.icon) { + icon.allocate(sourceIcon.width(), sourceIcon.height()); + memory::copy(icon.data(), sourceIcon.data(), icon.size()); + icon.scale(16, 16); + } else { + icon.allocate(16, 16); + icon.fill(0x00ffffff); + } + auto bitmap = CreateBitmap(icon); + ImageList_Add(imageList, bitmap, nullptr); + DeleteObject(bitmap); + } + } + + //empty icon used for ListViewItems (drawn manually via onCustomDraw) + image icon; + icon.allocate(16, 16); + icon.fill(0x00ffffff); + auto bitmap = CreateBitmap(icon); + ImageList_Add(imageList, bitmap, nullptr); + DeleteObject(bitmap); +} + +auto pListView::_setSortable() -> void { + bool sortable = false; + if(auto& header = state().header) { + for(auto& column : header->state.columns) { + if(column->sortable()) sortable = true; + } + } + + //note: this won't change the visual style: WC_LISTVIEW caches this in CreateWindow + auto style = GetWindowLong(hwnd, GWL_STYLE); + !sortable ? style |= LVS_NOSORTHEADER : style &=~ LVS_NOSORTHEADER; + SetWindowLong(hwnd, GWL_STYLE, style); +} + +auto pListView::_width(unsigned column) -> unsigned { + if(auto& header = state().header) { + if(auto width = header->state.columns[column]->width()) return width; + unsigned width = 1; + if(header->visible()) width = max(width, _columnWidth(column)); + for(auto row : range(state().items)) { + width = max(width, _cellWidth(row, column)); + } + return width; + } + return 1; +} + +} + +#endif diff --git a/windows/widget/list-view.hpp b/windows/widget/list-view.hpp new file mode 100644 index 0000000..3e3af01 --- /dev/null +++ b/windows/widget/list-view.hpp @@ -0,0 +1,43 @@ +#if defined(Hiro_ListView) + +namespace hiro { + +struct pListView : pWidget { + Declare(ListView, Widget) + + auto append(sListViewHeader header) -> void; + auto append(sListViewItem item) -> void; + auto remove(sListViewHeader header) -> void; + auto remove(sListViewItem item) -> void; + auto resizeColumns() -> void; + auto setAlignment(Alignment alignment) -> void; + auto setBackgroundColor(Color color) -> void; + auto setBatchable(bool batchable) -> void; + auto setBordered(bool bordered) -> void; + auto setForegroundColor(Color color) -> void; + auto setGeometry(Geometry geometry) -> void override; + + auto onActivate(LPARAM lparam) -> void; + auto onChange(LPARAM lparam) -> void; + auto onContext(LPARAM lparam) -> void; + auto onCustomDraw(LPARAM lparam) -> LRESULT; + auto onSort(LPARAM lparam) -> void; + auto onToggle(LPARAM lparam) -> void; + + auto _backgroundColor(unsigned row, unsigned column) -> Color; + auto _cellWidth(unsigned row, unsigned column) -> unsigned; + auto _columnWidth(unsigned column) -> unsigned; + auto _font(unsigned row, unsigned column) -> Font; + auto _foregroundColor(unsigned row, unsigned column) -> Color; + auto _setIcons() -> void; + auto _setSortable() -> void; + auto _width(unsigned column) -> unsigned; + + WindowProc windowProc = nullptr; + HIMAGELIST imageList = 0; + vector icons; +}; + +} + +#endif diff --git a/windows/widget/progress-bar.cpp b/windows/widget/progress-bar.cpp new file mode 100644 index 0000000..deff42b --- /dev/null +++ b/windows/widget/progress-bar.cpp @@ -0,0 +1,30 @@ +#if defined(Hiro_ProgressBar) + +namespace hiro { + +auto pProgressBar::construct() -> void { + hwnd = CreateWindow(PROGRESS_CLASS, L"", + WS_CHILD | PBS_SMOOTH, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + SendMessage(hwnd, PBM_SETSTEP, MAKEWPARAM(1, 0), 0); + setPosition(state().position); +} + +auto pProgressBar::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pProgressBar::minimumSize() const -> Size { + return {0, 23}; +} + +auto pProgressBar::setPosition(unsigned position) -> void { + SendMessage(hwnd, PBM_SETPOS, (WPARAM)position, 0); +} + +} + +#endif diff --git a/windows/widget/progress-bar.hpp b/windows/widget/progress-bar.hpp new file mode 100644 index 0000000..fc462a9 --- /dev/null +++ b/windows/widget/progress-bar.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_ProgressBar) + +namespace hiro { + +struct pProgressBar : pWidget { + Declare(ProgressBar, Widget) + + auto minimumSize() const -> Size override; + auto setPosition(unsigned position) -> void; +}; + +} + +#endif diff --git a/windows/widget/radio-button.cpp b/windows/widget/radio-button.cpp new file mode 100644 index 0000000..d084048 --- /dev/null +++ b/windows/widget/radio-button.cpp @@ -0,0 +1,126 @@ +#if defined(Hiro_RadioButton) + +namespace hiro { + +static auto CALLBACK RadioButton_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) { + if(auto button = dynamic_cast(object)) { + if(auto self = button->self()) { + if(msg == WM_ERASEBKGND) return DefWindowProc(hwnd, msg, wparam, lparam); + if(msg == WM_PAINT) return Button_paintProc(hwnd, msg, wparam, lparam, + button->state.bordered, button->state.checked, button->enabled(true), button->font(true), + button->state.icon, button->state.orientation, button->state.text + ); + return self->windowProc(hwnd, msg, wparam, lparam); + } + } + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +auto pRadioButton::construct() -> void { + hwnd = CreateWindow(L"BUTTON", L"", + WS_CHILD | WS_TABSTOP | BS_CHECKBOX | BS_PUSHLIKE, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RadioButton_windowProc); + pWidget::_setState(); + setGroup(state().group); + _setState(); +} + +auto pRadioButton::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pRadioButton::minimumSize() const -> Size { + Size icon = {(int)state().icon.width(), (int)state().icon.height()}; + Size text = state().text ? pFont::size(self().font(true), state().text) : Size{}; + Size size; + if(state().orientation == Orientation::Horizontal) { + size.setWidth(icon.width() + (icon && text ? 5 : 0) + text.width()); + size.setHeight(max(icon.height(), text.height())); + } + if(state().orientation == Orientation::Vertical) { + size.setWidth(max(icon.width(), text.width())); + size.setHeight(icon.height() + (icon && text ? 5 : 0) + text.height()); + } + size.setHeight(max(size.height(), pFont::size(self().font(true), " ").height())); + return {size.width() + (state().bordered && text ? 20 : 10), size.height() + 10}; +} + +auto pRadioButton::setBordered(bool bordered) -> void { + _setState(); +} + +auto pRadioButton::setChecked() -> void { + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioButton = dynamic_cast(object.data())) { + if(auto self = radioButton->self()) { + SendMessage(self->hwnd, BM_SETCHECK, (WPARAM)(&self->reference == &reference), 0); + } + } + } + } + } +} + +auto pRadioButton::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + _setState(); +} + +auto pRadioButton::setFont(const Font& font) -> void { + pWidget::setFont(font); + _setState(); +} + +auto pRadioButton::setGroup(sGroup group) -> void { + bool first = true; + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioButton = dynamic_cast(object.data())) { + if(auto self = radioButton->self()) { + SendMessage(self->hwnd, BM_SETCHECK, (WPARAM)(radioButton->state.checked = first), 0); + first = false; + } + } + } + } + } +} + +auto pRadioButton::setIcon(const image& icon) -> void { + _setState(); +} + +auto pRadioButton::setOrientation(Orientation orientation) -> void { + _setState(); +} + +auto pRadioButton::setText(const string& text) -> void { + _setState(); +} + +auto pRadioButton::setVisible(bool visible) -> void { + pWidget::setVisible(visible); + _setState(); +} + +auto pRadioButton::onActivate() -> void { + if(state().checked) return; + self().setChecked(); + self().doActivate(); +} + +auto pRadioButton::_setState() -> void { + InvalidateRect(hwnd, 0, false); +} + +} + +#endif diff --git a/windows/widget/radio-button.hpp b/windows/widget/radio-button.hpp new file mode 100644 index 0000000..dc0c5b3 --- /dev/null +++ b/windows/widget/radio-button.hpp @@ -0,0 +1,28 @@ +#if defined(Hiro_RadioButton) + +namespace hiro { + +struct pRadioButton : pWidget { + Declare(RadioButton, Widget) + + auto minimumSize() const -> Size override; + auto setBordered(bool bordered) -> void; + auto setChecked() -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setGroup(sGroup group) -> void override; + auto setIcon(const image& icon) -> void; + auto setOrientation(Orientation orientation) -> void; + auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; + + auto onActivate() -> void; + + auto _setState() -> void; + + WindowProc windowProc = nullptr; +}; + +} + +#endif diff --git a/windows/widget/radio-label.cpp b/windows/widget/radio-label.cpp new file mode 100644 index 0000000..90db50b --- /dev/null +++ b/windows/widget/radio-label.cpp @@ -0,0 +1,67 @@ +#if defined(Hiro_RadioLabel) + +namespace hiro { + +auto pRadioLabel::construct() -> void { + hwnd = CreateWindow( + L"BUTTON", L"", WS_CHILD | WS_TABSTOP | BS_RADIOBUTTON, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setGroup(state().group); + setText(state().text); +} + +auto pRadioLabel::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pRadioLabel::minimumSize() const -> Size { + auto size = pFont::size(self().font(true), state().text ? state().text : " "); + return {size.width() + 20, size.height() + 4}; +} + +auto pRadioLabel::setChecked() -> void { + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioLabel = dynamic_cast(object.data())) { + if(auto self = radioLabel->self()) { + SendMessage(self->hwnd, BM_SETCHECK, (WPARAM)(&self->reference == &reference), 0); + } + } + } + } + } +} + +auto pRadioLabel::setGroup(sGroup group) -> void { + bool first = true; + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioLabel = dynamic_cast(object.data())) { + if(auto self = radioLabel->self()) { + SendMessage(self->hwnd, BM_SETCHECK, (WPARAM)(radioLabel->state.checked = first), 0); + first = false; + } + } + } + } + } +} + +auto pRadioLabel::setText(const string& text) -> void { + SetWindowText(hwnd, utf16_t(text)); +} + +auto pRadioLabel::onActivate() -> void { + if(state().checked) return; + self().setChecked(); + self().doActivate(); +} + +} + +#endif diff --git a/windows/widget/radio-label.hpp b/windows/widget/radio-label.hpp new file mode 100644 index 0000000..28f1b29 --- /dev/null +++ b/windows/widget/radio-label.hpp @@ -0,0 +1,18 @@ +#if defined(Hiro_RadioLabel) + +namespace hiro { + +struct pRadioLabel : pWidget { + Declare(RadioLabel, Widget) + + auto minimumSize() const -> Size override; + auto setChecked() -> void; + auto setGroup(sGroup group) -> void override; + auto setText(const string& text) -> void; + + auto onActivate() -> void; +}; + +} + +#endif diff --git a/windows/widget/tab-frame-item.cpp b/windows/widget/tab-frame-item.cpp new file mode 100644 index 0000000..2583d64 --- /dev/null +++ b/windows/widget/tab-frame-item.cpp @@ -0,0 +1,63 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +auto pTabFrameItem::construct() -> void { +} + +auto pTabFrameItem::destruct() -> void { +} + +auto pTabFrameItem::append(sLayout layout) -> void { + if(auto parent = _parent()) { + parent->_synchronizeLayout(); + } +} + +auto pTabFrameItem::remove(sLayout layout) -> void { + if(auto parent = _parent()) { + parent->_synchronizeLayout(); + } +} + +auto pTabFrameItem::setClosable(bool closable) -> void { + //unsupported +} + +auto pTabFrameItem::setIcon(const image& icon) -> void { + if(auto parent = _parent()) { + parent->_buildImageList(); + } +} + +auto pTabFrameItem::setMovable(bool movable) -> void { + //unsupported +} + +auto pTabFrameItem::setSelected() -> void { + if(auto parent = _parent()) { + TabCtrl_SetCurSel(parent->hwnd, self().offset()); + parent->_synchronizeLayout(); + } +} + +auto pTabFrameItem::setText(const string& text) -> void { + if(auto parent = _parent()) { + utf16_t wText(text); + TCITEM tcItem; + tcItem.mask = TCIF_TEXT; + tcItem.pszText = (wchar_t*)wText; + TabCtrl_SetItem(parent->hwnd, self().offset(), &tcItem); + } +} + +auto pTabFrameItem::_parent() -> maybe { + if(auto parent = self().parentTabFrame()) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +} + +#endif diff --git a/windows/widget/tab-frame-item.hpp b/windows/widget/tab-frame-item.hpp new file mode 100644 index 0000000..d08a269 --- /dev/null +++ b/windows/widget/tab-frame-item.hpp @@ -0,0 +1,21 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +struct pTabFrameItem : pObject { + Declare(TabFrameItem, Object) + + auto append(sLayout layout) -> void; + auto remove(sLayout layout) -> void; + 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() -> maybe; +}; + +} + +#endif diff --git a/windows/widget/tab-frame.cpp b/windows/widget/tab-frame.cpp new file mode 100644 index 0000000..09c246d --- /dev/null +++ b/windows/widget/tab-frame.cpp @@ -0,0 +1,149 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +static auto CALLBACK TabFrame_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) { + if(auto tabFrame = dynamic_cast(object)) { + if(auto self = tabFrame->self()) { + return Shared_windowProc(self->windowProc, hwnd, msg, wparam, lparam); + } + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +auto pTabFrame::construct() -> void { + hwnd = CreateWindow( + WC_TABCONTROL, L"", WS_CHILD | WS_TABSTOP, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)TabFrame_windowProc); + pWidget::_setState(); + for(auto& item : state().items) append(item); +} + +auto pTabFrame::destruct() -> void { + if(imageList) { ImageList_Destroy(imageList); imageList = nullptr; } + DestroyWindow(hwnd); +} + +auto pTabFrame::append(sTabFrameItem item) -> void { + wchar_t text[] = L""; + TCITEM tcItem; + tcItem.mask = TCIF_TEXT; + tcItem.pszText = text; + TabCtrl_InsertItem(hwnd, item->offset(), &tcItem); + if(auto self = item->self()) { + self->setClosable(item->state.closable); + self->setIcon(item->state.icon); + self->setMovable(item->state.movable); + self->setText(item->state.text); + if(item->selected()) self->setSelected(); + } + _buildImageList(); + _synchronizeLayout(); +} + +auto pTabFrame::remove(sTabFrameItem item) -> void { + TabCtrl_DeleteItem(hwnd, item->offset()); + _buildImageList(); +} + +auto pTabFrame::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + for(auto& item : state().items) { + if(auto layout = item->state.layout) { + if(auto self = layout->self()) self->setEnabled(layout->enabled(true)); + } + } +} + +auto pTabFrame::setGeometry(Geometry geometry) -> void { + pWidget::setGeometry(geometry); + geometry.setX(geometry.x() + 1); + geometry.setY(geometry.y() + 21); + geometry.setWidth(geometry.width() - 4); + geometry.setHeight(geometry.height() - 23); + for(auto& item : state().items) { + if(auto layout = item->state.layout) { + layout->setGeometry(geometry); + } + } +} + +auto pTabFrame::setNavigation(Navigation navigation) -> void { + //unsupported +} + +auto pTabFrame::setVisible(bool visible) -> void { + pWidget::setVisible(visible); + for(auto& item : state().items) { + if(auto layout = item->state.layout) { + if(auto self = layout->self()) self->setVisible(layout->visible(true)); + } + } +} + +auto pTabFrame::_buildImageList() -> void { + unsigned size = pFont::size(hfont, " ").height(); + + if(imageList) { ImageList_Destroy(imageList); imageList = nullptr; } + imageList = ImageList_Create(size, size, ILC_COLOR32, 1, 0); + for(auto& item : state().items) { + ImageList_Append(imageList, item->state.icon, size); + } + TabCtrl_SetImageList(hwnd, imageList); + for(auto offset : range(state().items)) { + TCITEM tcItem; + tcItem.mask = TCIF_IMAGE; + tcItem.iImage = state().items[offset]->state.icon ? offset : -1; + TabCtrl_SetItem(hwnd, offset, &tcItem); + } +} + +auto pTabFrame::_synchronizeLayout() -> void { + for(auto& item : state().items) { + if(auto layout = item->state.layout) { + layout->setVisible(item->selected()); + } + } +} + +auto pTabFrame::onChange() -> void { + unsigned selected = TabCtrl_GetCurSel(hwnd); + for(auto& item : state().items) item->state.selected = false; + if(auto item = self().item(selected)) item->state.selected = true; + _synchronizeLayout(); + self().doChange(); +} + +//called only if TCS_OWNERDRAWFIXED style is used +//this style disables XP/Vista theming of the TabFrame +auto pTabFrame::onDrawItem(LPARAM lparam) -> void { +/* + auto item = (LPDRAWITEMSTRUCT)lparam; + FillRect(item->hDC, &item->rcItem, GetSysColorBrush(COLOR_3DFACE)); + SetBkMode(item->hDC, TRANSPARENT); + SetTextColor(item->hDC, GetSysColor(COLOR_BTNTEXT)); + + unsigned selection = item->itemID; + if(selection < tabFrame.state.text.size()) { + string text = tabFrame.state.text[selection]; + Size size = pFont::size(hfont, text); + unsigned width = item->rcItem.right - item->rcItem.left + 1; + if(!tabFrame.state.image[selection].empty()) { + width += size.height + 2; + ImageList_Draw(imageList, selection, item->hDC, item->rcItem.left + (width - size.width) / 2 - (size.height + 3), item->rcItem.top + 2, ILD_NORMAL); + } + TextOut(item->hDC, item->rcItem.left + (width - size.width) / 2, item->rcItem.top + 2, utf16_t(text), text.size()); + } +*/ +} + +} + +#endif diff --git a/windows/widget/tab-frame.hpp b/windows/widget/tab-frame.hpp new file mode 100644 index 0000000..e2356a6 --- /dev/null +++ b/windows/widget/tab-frame.hpp @@ -0,0 +1,27 @@ +#if defined(Hiro_TabFrame) + +namespace hiro { + +struct pTabFrame : pWidget { + Declare(TabFrame, Widget) + + auto append(sTabFrameItem item) -> void; + auto remove(sTabFrameItem item) -> void; + auto setEnabled(bool enabled) -> void override; + auto setGeometry(Geometry geometry) -> void override; + auto setNavigation(Navigation navigation) -> void; + auto setVisible(bool visible) -> void override; + + auto onChange() -> void; + auto onDrawItem(LPARAM lparam) -> void; + + auto _buildImageList() -> void; + auto _synchronizeLayout() -> void; + + WindowProc windowProc = nullptr; + HIMAGELIST imageList = nullptr; +}; + +} + +#endif diff --git a/windows/widget/text-edit.cpp b/windows/widget/text-edit.cpp new file mode 100644 index 0000000..2ddb830 --- /dev/null +++ b/windows/widget/text-edit.cpp @@ -0,0 +1,75 @@ +#if defined(Hiro_TextEdit) + +namespace hiro { + +auto pTextEdit::construct() -> void { + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | WS_VSCROLL | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN | (!state().wordWrap ? WS_HSCROLL | ES_AUTOHSCROLL : 0), + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setBackgroundColor(state().backgroundColor); + setEditable(state().editable); + setText(state().text); + setCursor(state().cursor); +} + +auto pTextEdit::destruct() -> void { + state().text = text(); + if(backgroundBrush) { DeleteObject(backgroundBrush); backgroundBrush = 0; } + DestroyWindow(hwnd); +} + +auto pTextEdit::setBackgroundColor(Color color) -> void { + if(backgroundBrush) { DeleteObject(backgroundBrush); backgroundBrush = 0; } + backgroundBrush = CreateSolidBrush(color ? CreateRGB(color) : GetSysColor(COLOR_WINDOW)); +} + +auto pTextEdit::setCursor(Cursor cursor) -> void { + signed end = GetWindowTextLength(hwnd); + signed offset = max(0, min(end, cursor.offset())); + signed length = max(0, min(end, cursor.offset() + cursor.length())); + Edit_SetSel(hwnd, offset, length); + Edit_ScrollCaret(hwnd); +} + +auto pTextEdit::setEditable(bool editable) -> void { + SendMessage(hwnd, EM_SETREADONLY, editable == false, (LPARAM)0); +} + +auto pTextEdit::setForegroundColor(Color color) -> void { +} + +auto pTextEdit::setText(string text) -> void { + lock(); + text.replace("\r", ""); + text.replace("\n", "\r\n"); + SetWindowText(hwnd, utf16_t(text)); + unlock(); +} + +auto pTextEdit::setWordWrap(bool wordWrap) -> void { + //ES_AUTOHSCROLL cannot be changed after widget creation. + //As a result, we must destroy and re-create widget to change this setting. + reconstruct(); +} + +auto pTextEdit::text() const -> string { + unsigned length = GetWindowTextLength(hwnd); + wchar_t buffer[length + 1]; + GetWindowText(hwnd, buffer, length + 1); + buffer[length] = 0; + string text = (const char*)utf8_t(buffer); + text.replace("\r", ""); + return text; +} + +auto pTextEdit::onChange() -> void { + if(!locked()) self().doChange(); +} + +} + +#endif diff --git a/windows/widget/text-edit.hpp b/windows/widget/text-edit.hpp new file mode 100644 index 0000000..e360547 --- /dev/null +++ b/windows/widget/text-edit.hpp @@ -0,0 +1,23 @@ +#if defined(Hiro_TextEdit) + +namespace hiro { + +struct pTextEdit : pWidget { + Declare(TextEdit, Widget) + + auto setBackgroundColor(Color color) -> void; + auto setCursor(Cursor cursor) -> void; + auto setEditable(bool editable) -> void; + auto setForegroundColor(Color color) -> void; + auto setText(string text) -> void; + auto setWordWrap(bool wordWrap) -> void; + auto text() const -> string; + + auto onChange() -> void; + + HBRUSH backgroundBrush = nullptr; +}; + +} + +#endif diff --git a/windows/widget/vertical-scroll-bar.cpp b/windows/widget/vertical-scroll-bar.cpp new file mode 100644 index 0000000..9dd9370 --- /dev/null +++ b/windows/widget/vertical-scroll-bar.cpp @@ -0,0 +1,42 @@ +#if defined(Hiro_VerticalScrollBar) + +namespace hiro { + +auto pVerticalScrollBar::construct() -> void { + hwnd = CreateWindow( + L"SCROLLBAR", L"", WS_CHILD | SBS_VERT, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setLength(state().length); + setPosition(state().position); +} + +auto pVerticalScrollBar::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pVerticalScrollBar::minimumSize() const -> Size { + return {18, 0}; +} + +auto pVerticalScrollBar::setLength(unsigned length) -> void { + length += (length == 0); + SetScrollRange(hwnd, SB_CTL, 0, length - 1, TRUE); +} + +auto pVerticalScrollBar::setPosition(unsigned position) -> void { + SetScrollPos(hwnd, SB_CTL, position, TRUE); +} + +auto pVerticalScrollBar::onChange(WPARAM wparam) -> void { + unsigned position = ScrollEvent(hwnd, wparam); + if(position == state().position) return; + state().position = position; + self().doChange(); +} + +} + +#endif diff --git a/windows/widget/vertical-scroll-bar.hpp b/windows/widget/vertical-scroll-bar.hpp new file mode 100644 index 0000000..e849a91 --- /dev/null +++ b/windows/widget/vertical-scroll-bar.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_VerticalScrollBar) + +namespace hiro { + +struct pVerticalScrollBar : pWidget { + Declare(VerticalScrollBar, Widget) + + auto minimumSize() const -> Size override; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; + + auto onChange(WPARAM wparam) -> void; +}; + +} + +#endif diff --git a/windows/widget/vertical-slider.cpp b/windows/widget/vertical-slider.cpp new file mode 100644 index 0000000..9a31e86 --- /dev/null +++ b/windows/widget/vertical-slider.cpp @@ -0,0 +1,43 @@ +#if defined(Hiro_VerticalSlider) + +namespace hiro { + +auto pVerticalSlider::construct() -> void { + hwnd = CreateWindow( + TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_TRANSPARENTBKGND | TBS_NOTICKS | TBS_BOTH | TBS_VERT, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setLength(state().length); + setPosition(state().position); +} + +auto pVerticalSlider::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pVerticalSlider::minimumSize() const -> Size { + return {25, 0}; +} + +auto pVerticalSlider::setLength(unsigned length) -> void { + length += (length == 0); + SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1)); + SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3)); +} + +auto pVerticalSlider::setPosition(unsigned position) -> void { + SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)position); +} + +auto pVerticalSlider::onChange() -> void { + unsigned position = SendMessage(hwnd, TBM_GETPOS, 0, 0); + if(position == state().position) return; + state().position = position; + self().doChange(); +} + +} + +#endif diff --git a/windows/widget/vertical-slider.hpp b/windows/widget/vertical-slider.hpp new file mode 100644 index 0000000..bfb4b9f --- /dev/null +++ b/windows/widget/vertical-slider.hpp @@ -0,0 +1,17 @@ +#if defined(Hiro_VerticalSlider) + +namespace hiro { + +struct pVerticalSlider : pWidget { + Declare(VerticalSlider, Widget) + + auto minimumSize() const -> Size; + auto setLength(unsigned length) -> void; + auto setPosition(unsigned position) -> void; + + auto onChange() -> void; +}; + +} + +#endif diff --git a/windows/widget/viewport.cpp b/windows/widget/viewport.cpp new file mode 100644 index 0000000..d93b076 --- /dev/null +++ b/windows/widget/viewport.cpp @@ -0,0 +1,72 @@ +#if defined(Hiro_Viewport) + +namespace hiro { + +static auto CALLBACK Viewport_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(!object) return DefWindowProc(hwnd, msg, wparam, lparam); + auto viewport = dynamic_cast(object); + if(!viewport) return DefWindowProc(hwnd, msg, wparam, lparam); + + if(msg == WM_DROPFILES) { + if(auto paths = DropPaths(wparam)) viewport->doDrop(paths); + return false; + } + + if(msg == WM_GETDLGCODE) { + return DLGC_STATIC | DLGC_WANTCHARS; + } + + if(msg == WM_MOUSEMOVE) { + TRACKMOUSEEVENT tracker{sizeof(TRACKMOUSEEVENT), TME_LEAVE, hwnd}; + TrackMouseEvent(&tracker); + viewport->doMouseMove({(int16_t)LOWORD(lparam), (int16_t)HIWORD(lparam)}); + } + + if(msg == WM_MOUSELEAVE) { + viewport->doMouseLeave(); + } + + if(msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) { + switch(msg) { + case WM_LBUTTONDOWN: viewport->doMousePress(Mouse::Button::Left); break; + case WM_MBUTTONDOWN: viewport->doMousePress(Mouse::Button::Middle); break; + case WM_RBUTTONDOWN: viewport->doMousePress(Mouse::Button::Right); break; + } + } + + if(msg == WM_LBUTTONUP || msg == WM_MBUTTONUP || msg == WM_RBUTTONUP) { + switch(msg) { + case WM_LBUTTONUP: viewport->doMouseRelease(Mouse::Button::Left); break; + case WM_MBUTTONUP: viewport->doMouseRelease(Mouse::Button::Middle); break; + case WM_RBUTTONUP: viewport->doMouseRelease(Mouse::Button::Right); break; + } + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +auto pViewport::construct() -> void { + hwnd = CreateWindow(L"hiroViewport", L"", + WS_CHILD | WS_DISABLED, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + pWidget::_setState(); + setDroppable(state().droppable); +} + +auto pViewport::destruct() -> void { + DestroyWindow(hwnd); +} + +auto pViewport::handle() const -> uintptr_t { + return (uintptr_t)hwnd; +} + +auto pViewport::setDroppable(bool droppable) -> void { + DragAcceptFiles(hwnd, droppable); +} + +} + +#endif diff --git a/windows/widget/viewport.hpp b/windows/widget/viewport.hpp new file mode 100644 index 0000000..ed0b17f --- /dev/null +++ b/windows/widget/viewport.hpp @@ -0,0 +1,14 @@ +#if defined(Hiro_Viewport) + +namespace hiro { + +struct pViewport : pWidget { + Declare(Viewport, Widget) + + auto handle() const -> uintptr_t; + auto setDroppable(bool droppable) -> void; +}; + +} + +#endif diff --git a/windows/widget/widget.cpp b/windows/widget/widget.cpp new file mode 100644 index 0000000..5edde98 --- /dev/null +++ b/windows/widget/widget.cpp @@ -0,0 +1,93 @@ +#if defined(Hiro_Widget) + +namespace hiro { + +auto pWidget::construct() -> void { + abstract = true; + //todo: create hiroWidget + hwnd = CreateWindow(L"hiroLabel", L"", WS_CHILD, 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + _setState(); +} + +auto pWidget::destruct() -> void { + DeleteObject(hfont); + DestroyWindow(hwnd); +} + +auto pWidget::focused() const -> bool { + auto focused = GetFocus(); + return hwnd == focused || IsChild(hwnd, focused); +} + +auto pWidget::minimumSize() -> Size { + return {0, 0}; +} + +auto pWidget::setEnabled(bool enabled) -> void { + if(!self().parentWindow(true)) enabled = false; + if(!self().enabled(true)) enabled = false; + if(abstract) enabled = false; + EnableWindow(hwnd, enabled); +} + +auto pWidget::setFocused() -> void { + SetFocus(hwnd); +} + +auto pWidget::setFont(const Font&) -> void { + if(hfont) DeleteObject(hfont); + hfont = pFont::create(self().font(true)); + SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); +} + +auto pWidget::setGeometry(Geometry geometry) -> void { + if(auto parent = _parentWidget()) { + auto displacement = parent->self().geometry().position(); + geometry.setX(geometry.x() - displacement.x()); + geometry.setY(geometry.y() - displacement.y()); + } + SetWindowPos(hwnd, nullptr, geometry.x(), geometry.y(), geometry.width(), geometry.height(), SWP_NOZORDER); + self().doSize(); +} + +auto pWidget::setVisible(bool visible) -> void { + if(!self().parentWindow(true)) visible = false; + if(!self().visible(true)) visible = false; + if(abstract) visible = false; + ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); +} + +// + +auto pWidget::_parentHandle() -> HWND { + if(auto parent = _parentWidget()) return parent->hwnd; + if(auto parent = _parentWindow()) return parent->hwnd; + return nullptr; +} + +auto pWidget::_parentWidget() -> maybe { + #if defined(Hiro_TabFrame) + if(auto parent = self().parentTabFrame(true)) { + if(auto self = parent->self()) return *self; + } + #endif + return nothing; +} + +auto pWidget::_parentWindow() -> maybe { + if(auto parent = self().parentWindow(true)) { + if(auto self = parent->self()) return *self; + } + return nothing; +} + +auto pWidget::_setState() -> void { + setEnabled(self().enabled()); + setFont(self().font()); + setVisible(self().visible()); +} + +} + +#endif diff --git a/windows/widget/widget.hpp b/windows/widget/widget.hpp new file mode 100644 index 0000000..2f2926a --- /dev/null +++ b/windows/widget/widget.hpp @@ -0,0 +1,28 @@ +#if defined(Hiro_Widget) + +namespace hiro { + +struct pWidget : pSizable { + Declare(Widget, Sizable) + + auto focused() const -> bool override; + virtual auto minimumSize() -> Size; + auto setEnabled(bool enabled) -> void override; + auto setFocused() -> void; + auto setFont(const Font& font) -> void override; + virtual auto setGeometry(Geometry geometry) -> void; + auto setVisible(bool visible) -> void override; + + auto _parentHandle() -> HWND; + auto _parentWidget() -> maybe; + auto _parentWindow() -> maybe; + auto _setState() -> void; + + bool abstract = false; + HWND hwnd = 0; + HFONT hfont = 0; +}; + +} + +#endif diff --git a/windows/window.cpp b/windows/window.cpp new file mode 100644 index 0000000..393020f --- /dev/null +++ b/windows/window.cpp @@ -0,0 +1,281 @@ +#if defined(Hiro_Window) + +namespace hiro { + +static const unsigned FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER | WS_CLIPCHILDREN; +static const unsigned ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN; + +auto pWindow::construct() -> void { + hwnd = CreateWindow(L"hiroWindow", L"", ResizableStyle, 128, 128, 256, 256, 0, 0, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + setDroppable(state().droppable); + setGeometry({128, 128, 256, 256}); + + windows.append(self().instance); +} + +auto pWindow::destruct() -> void { + if(auto position = windows.find(self().instance)) windows.remove(*position); + + if(hbrush) { DeleteObject(hbrush); hbrush = nullptr; } + DestroyWindow(hwnd); +} + +auto pWindow::append(sLayout layout) -> void { +} + +auto pWindow::append(sMenuBar menuBar) -> void { +} + +auto pWindow::append(sStatusBar statusBar) -> void { +} + +auto pWindow::focused() const -> bool { + return (GetForegroundWindow() == hwnd); +} + +auto pWindow::frameMargin() const -> Geometry { + unsigned style = state().resizable ? ResizableStyle : FixedStyle; + if(state().fullScreen) style = 0; + RECT rc{0, 0, 640, 480}; + AdjustWindowRect(&rc, style, (bool)GetMenu(hwnd)); + signed statusHeight = 0; + if(auto statusBar = state().statusBar) { + if(auto self = statusBar->self()) { + if(statusBar->visible()) { + RECT src; + GetClientRect(self->hwnd, &src); + statusHeight = src.bottom - src.top; + } + } + } + return {abs(rc.left), abs(rc.top), (rc.right - rc.left) - 640, (rc.bottom - rc.top) + statusHeight - 480}; +} + +auto pWindow::remove(sLayout layout) -> void { +} + +auto pWindow::remove(sMenuBar menuBar) -> void { +} + +auto pWindow::remove(sStatusBar statusBar) -> void { +} + +auto pWindow::setBackgroundColor(Color color) -> void { + hbrushColor = CreateRGB(color); + if(hbrush) { DeleteObject(hbrush); hbrush = nullptr; } + if(color) hbrush = CreateSolidBrush(hbrushColor); +} + +auto pWindow::setDroppable(bool droppable) -> void { + DragAcceptFiles(hwnd, droppable); +} + +auto pWindow::setEnabled(bool enabled) -> void { + if(auto layout = state().layout) { + if(auto self = layout->self()) self->setEnabled(layout->enabled(true)); + } +} + +auto pWindow::setFocused() -> void { + if(!self().visible()) self().setVisible(true); + SetFocus(hwnd); +} + +auto pWindow::setFont(const Font& font) -> void { + if(auto layout = state().layout) { + if(auto self = layout->self()) self->setFont(layout->font(true)); + } +} + +auto pWindow::setFullScreen(bool fullScreen) -> void { + auto style = GetWindowLongPtr(hwnd, GWL_STYLE) & WS_VISIBLE; + lock(); + if(fullScreen) { + windowedGeometry = self().geometry(); + HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + MONITORINFOEX info; + memset(&info, 0, sizeof(MONITORINFOEX)); + info.cbSize = sizeof(MONITORINFOEX); + GetMonitorInfo(monitor, &info); + RECT rc = info.rcMonitor; + Geometry geometry = {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top}; + SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_POPUP); + Geometry margin = frameMargin(); + self().setGeometry({ + geometry.x() + margin.x(), geometry.y() + margin.y(), + geometry.width() - margin.width(), geometry.height() - margin.height() + }); + } else { + SetWindowLongPtr(hwnd, GWL_STYLE, style | (state().resizable ? ResizableStyle : FixedStyle)); + self().setGeometry(windowedGeometry); + } + unlock(); +} + +auto pWindow::setGeometry(Geometry geometry) -> void { + lock(); + Geometry margin = frameMargin(); + SetWindowPos( + hwnd, nullptr, + geometry.x() - margin.x(), geometry.y() - margin.y(), + geometry.width() + margin.width(), geometry.height() + margin.height(), + SWP_NOZORDER | SWP_FRAMECHANGED + ); + if(auto statusBar = state().statusBar) { + if(auto self = statusBar->self()) { + SetWindowPos(self->hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED); + } + } + if(auto layout = state().layout) { + layout->setGeometry(geometry.setPosition(0, 0)); + } + unlock(); +} + +auto pWindow::setModal(bool modality) -> void { + if(modality) { + _modalityUpdate(); + while(state().modal) { + Application::processEvents(); + if(Application::state.onMain) { + Application::doMain(); + } else { + usleep(20 * 1000); + } + } + _modalityUpdate(); + } +} + +auto pWindow::setResizable(bool resizable) -> void { + auto style = GetWindowLongPtr(hwnd, GWL_STYLE) & WS_VISIBLE; + SetWindowLongPtr(hwnd, GWL_STYLE, style | (state().resizable ? ResizableStyle : FixedStyle)); + setGeometry(state().geometry); +} + +auto pWindow::setTitle(string text) -> void { + SetWindowText(hwnd, utf16_t(text)); +} + +auto pWindow::setVisible(bool visible) -> void { + ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); + if(!visible) setModal(false); + + if(auto layout = state().layout) { + if(auto self = layout->self()) self->setVisible(layout->visible(true)); + } +} + +// + +auto pWindow::onClose() -> void { + if(state().onClose) self().doClose(); + else self().setVisible(false); + if(state().modal && !self().visible()) self().setModal(false); +} + +auto pWindow::onDrop(WPARAM wparam) -> void { + lstring paths = DropPaths(wparam); + if(paths.empty()) return; + self().doDrop(paths); +} + +auto pWindow::onEraseBackground() -> bool { + if(hbrush == 0) return false; + RECT rc; + GetClientRect(hwnd, &rc); + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + FillRect(ps.hdc, &rc, hbrush); + EndPaint(hwnd, &ps); + return true; +} + +auto pWindow::onModalBegin() -> void { + Application::Windows::doModalChange(true); +} + +auto pWindow::onModalEnd() -> void { + Application::Windows::doModalChange(false); +} + +auto pWindow::onMove() -> void { + if(locked()) return; + state().geometry.setPosition(_geometry().position()); + self().doMove(); +} + +auto pWindow::onSize() -> void { + if(locked()) return; + if(auto statusBar = state().statusBar) { + if(auto self = statusBar->self()) { + SetWindowPos(self->hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED); + } + } + state().geometry.setSize(_geometry().size()); + if(auto layout = state().layout) { + layout->setGeometry(_geometry().setPosition(0, 0)); + } + self().doSize(); +} + +// + +auto pWindow::_geometry() -> Geometry { + Geometry margin = frameMargin(); + + RECT rc; + if(IsIconic(hwnd)) { + //GetWindowRect returns -32000(x),-32000(y) when window is minimized + WINDOWPLACEMENT wp; + GetWindowPlacement(hwnd, &wp); + rc = wp.rcNormalPosition; + } else { + GetWindowRect(hwnd, &rc); + } + + signed x = rc.left + margin.x(); + signed y = rc.top + margin.y(); + signed width = (rc.right - rc.left) - margin.width(); + signed height = (rc.bottom - rc.top) - margin.height(); + + return {x, y, width, height}; +} + +auto pWindow::_modalityCount() -> unsigned { + unsigned modalWindows = 0; + for(auto& weak : windows) { + if(auto object = weak.acquire()) { + if(auto window = dynamic_cast(object.data())) { + if(window->modal()) modalWindows++; + } + } + } + return modalWindows; +} + +auto pWindow::_modalityDisabled() -> bool { + if(_modalityCount() == 0) return false; + return !state().modal; +} + +auto pWindow::_modalityUpdate() -> void { + unsigned modalWindows = _modalityCount(); + for(auto& weak : windows) { + if(auto object = weak.acquire()) { + if(auto window = dynamic_cast(object.data())) { + if(auto self = window->self()) { + bool enabled = !modalWindows || window->modal(); + if(IsWindowEnabled(self->hwnd) != enabled) { + EnableWindow(self->hwnd, enabled); + } + } + } + } + } +} + +} + +#endif diff --git a/windows/window.hpp b/windows/window.hpp new file mode 100644 index 0000000..e42397a --- /dev/null +++ b/windows/window.hpp @@ -0,0 +1,50 @@ +#if defined(Hiro_Window) + +namespace hiro { + +struct pWindow : pObject { + Declare(Window, Object) + + auto append(sLayout layout) -> void; + auto append(sMenuBar menuBar) -> void; + auto append(sStatusBar statusBar) -> void; + auto focused() const -> bool override; + auto frameMargin() const -> Geometry; + auto remove(sLayout layout) -> void; + auto remove(sMenuBar menuBar) -> void; + auto remove(sStatusBar statusBar) -> void; + auto setBackgroundColor(Color color) -> void; + auto setDroppable(bool droppable) -> void; + auto setEnabled(bool enabled) -> void; + auto setFocused() -> void; + auto setFont(const Font& font) -> void override; + auto setFullScreen(bool fullScreen) -> void; + auto setGeometry(Geometry geometry) -> void; + auto setModal(bool modal) -> void; + auto setResizable(bool resizable) -> void; + auto setTitle(string text) -> void; + auto setVisible(bool visible) -> void; + + auto onClose() -> void; + auto onDrop(WPARAM wparam) -> void; + auto onEraseBackground() -> bool; + auto onModalBegin() -> void; + auto onModalEnd() -> void; + auto onMove() -> void; + auto onSize() -> void; + + auto _geometry() -> Geometry; + auto _modalityCount() -> unsigned; + auto _modalityDisabled() -> bool; + auto _modalityUpdate() -> void; + + HWND hwnd = nullptr; + HFONT hstatusfont = nullptr; + HBRUSH hbrush = nullptr; + COLORREF hbrushColor = 0; + Geometry windowedGeometry{128, 128, 256, 256}; +}; + +} + +#endif