zui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Components/Builtins/Accordion.qml +208 -0
- data/Components/Builtins/Action.qml +43 -0
- data/Components/Builtins/ActionButton.qml +19 -0
- data/Components/Builtins/ActionGroup.qml +81 -0
- data/Components/Builtins/AlertDialog.qml +398 -0
- data/Components/Builtins/AnchorAnimation.qml +3 -0
- data/Components/Builtins/AnchorChanges.qml +11 -0
- data/Components/Builtins/AnimatedImage.qml +39 -0
- data/Components/Builtins/Animation.qml +3 -0
- data/Components/Builtins/AnimationController.qml +11 -0
- data/Components/Builtins/ApplicationWindow.qml +103 -0
- data/Components/Builtins/AreaChart.qml +70 -0
- data/Components/Builtins/AspectRatio.qml +30 -0
- data/Components/Builtins/Audio.qml +85 -0
- data/Components/Builtins/AudioInput.qml +10 -0
- data/Components/Builtins/AudioOutput.qml +10 -0
- data/Components/Builtins/Avatar.qml +46 -0
- data/Components/Builtins/Badge.qml +38 -0
- data/Components/Builtins/Banner.qml +133 -0
- data/Components/Builtins/BarChart.qml +67 -0
- data/Components/Builtins/BarIconButton.qml +30 -0
- data/Components/Builtins/BarIndicator.qml +26 -0
- data/Components/Builtins/Behavior.qml +13 -0
- data/Components/Builtins/Blur.qml +14 -0
- data/Components/Builtins/BorderImage.qml +38 -0
- data/Components/Builtins/BorderOverlay.qml +25 -0
- data/Components/Builtins/BottomSheet.qml +211 -0
- data/Components/Builtins/Breadcrumb.qml +169 -0
- data/Components/Builtins/BubbleChart.qml +3 -0
- data/Components/Builtins/BusyIndicator.qml +24 -0
- data/Components/Builtins/Button.qml +55 -0
- data/Components/Builtins/ButtonGroup.qml +18 -0
- data/Components/Builtins/Calendar.qml +55 -0
- data/Components/Builtins/Camera.qml +18 -0
- data/Components/Builtins/CandlestickChart.qml +3 -0
- data/Components/Builtins/Canvas.qml +159 -0
- data/Components/Builtins/CaptureSession.qml +19 -0
- data/Components/Builtins/Card.qml +23 -0
- data/Components/Builtins/Carousel.qml +72 -0
- data/Components/Builtins/Center.qml +20 -0
- data/Components/Builtins/CheckDelegate.qml +132 -0
- data/Components/Builtins/Checkbox.qml +62 -0
- data/Components/Builtins/Chip.qml +65 -0
- data/Components/Builtins/Circle.qml +35 -0
- data/Components/Builtins/Clipboard.qml +29 -0
- data/Components/Builtins/ColorAnimation.qml +3 -0
- data/Components/Builtins/ColorPicker.qml +70 -0
- data/Components/Builtins/Colorize.qml +14 -0
- data/Components/Builtins/Column.qml +17 -0
- data/Components/Builtins/ColumnLayout.qml +13 -0
- data/Components/Builtins/ConfirmDialog.qml +20 -0
- data/Components/Builtins/ConstrainedBox.qml +28 -0
- data/Components/Builtins/Container.qml +30 -0
- data/Components/Builtins/ContextMenu.qml +140 -0
- data/Components/Builtins/CursorSurface.qml +18 -0
- data/Components/Builtins/DataTable.qml +69 -0
- data/Components/Builtins/DatePicker.qml +180 -0
- data/Components/Builtins/DayOfWeekRow.qml +11 -0
- data/Components/Builtins/DelayButton.qml +47 -0
- data/Components/Builtins/DelegateModel.qml +10 -0
- data/Components/Builtins/DelegateModelGroup.qml +10 -0
- data/Components/Builtins/Dial.qml +42 -0
- data/Components/Builtins/Dialog.qml +128 -0
- data/Components/Builtins/DialogButtonBox.qml +137 -0
- data/Components/Builtins/Divider.qml +26 -0
- data/Components/Builtins/DonutChart.qml +3 -0
- data/Components/Builtins/DoubleSpinBox.qml +58 -0
- data/Components/Builtins/DragArea.qml +43 -0
- data/Components/Builtins/Drawer.qml +107 -0
- data/Components/Builtins/DropArea.qml +19 -0
- data/Components/Builtins/DropShadow.qml +16 -0
- data/Components/Builtins/Dropdown.qml +19 -0
- data/Components/Builtins/ExpansionPanel.qml +157 -0
- data/Components/Builtins/FilePicker.qml +140 -0
- data/Components/Builtins/FittedBox.qml +40 -0
- data/Components/Builtins/Flickable.qml +40 -0
- data/Components/Builtins/Flipable.qml +45 -0
- data/Components/Builtins/Flow.qml +16 -0
- data/Components/Builtins/FocusScope.qml +29 -0
- data/Components/Builtins/FolderListModel.qml +9 -0
- data/Components/Builtins/FolderPicker.qml +93 -0
- data/Components/Builtins/FontLoader.qml +21 -0
- data/Components/Builtins/FontPicker.qml +91 -0
- data/Components/Builtins/Frame.qml +71 -0
- data/Components/Builtins/FrameAnimation.qml +13 -0
- data/Components/Builtins/Gauge.qml +3 -0
- data/Components/Builtins/Glow.qml +15 -0
- data/Components/Builtins/Gradient.qml +93 -0
- data/Components/Builtins/Grid.qml +16 -0
- data/Components/Builtins/GridLayout.qml +16 -0
- data/Components/Builtins/GridView.qml +226 -0
- data/Components/Builtins/GroupBox.qml +95 -0
- data/Components/Builtins/Heatmap.qml +3 -0
- data/Components/Builtins/Histogram.qml +3 -0
- data/Components/Builtins/HorizontalHeader.qml +23 -0
- data/Components/Builtins/HorizontalHeaderDelegate.qml +39 -0
- data/Components/Builtins/HoverArea.qml +19 -0
- data/Components/Builtins/Icon.qml +16 -0
- data/Components/Builtins/Image.qml +110 -0
- data/Components/Builtins/ImageCapture.qml +14 -0
- data/Components/Builtins/ItemDelegate.qml +152 -0
- data/Components/Builtins/KeyCatcher.qml +25 -0
- data/Components/Builtins/Label.qml +43 -0
- data/Components/Builtins/LayoutItemProxy.qml +51 -0
- data/Components/Builtins/Legend.qml +86 -0
- data/Components/Builtins/Line.qml +28 -0
- data/Components/Builtins/LineChart.qml +87 -0
- data/Components/Builtins/ListModel.qml +8 -0
- data/Components/Builtins/ListView.qml +65 -0
- data/Components/Builtins/Loader.qml +33 -0
- data/Components/Builtins/Markdown.qml +23 -0
- data/Components/Builtins/MediaDevices.qml +10 -0
- data/Components/Builtins/MediaPlayer.qml +27 -0
- data/Components/Builtins/MediaRecorder.qml +16 -0
- data/Components/Builtins/Menu.qml +119 -0
- data/Components/Builtins/MenuBar.qml +128 -0
- data/Components/Builtins/MenuItem.qml +77 -0
- data/Components/Builtins/MenuSeparator.qml +30 -0
- data/Components/Builtins/MessageDialog.qml +104 -0
- data/Components/Builtins/ModalSheet.qml +222 -0
- data/Components/Builtins/ModelView3d.qml +50 -0
- data/Components/Builtins/MonthGrid.qml +23 -0
- data/Components/Builtins/MultiEffect.qml +48 -0
- data/Components/Builtins/MultiSelect.qml +23 -0
- data/Components/Builtins/NavigationRail.qml +154 -0
- data/Components/Builtins/NumberAnimation.qml +3 -0
- data/Components/Builtins/NumberField.qml +18 -0
- data/Components/Builtins/OpacityAnimator.qml +3 -0
- data/Components/Builtins/OpacityMask.qml +21 -0
- data/Components/Builtins/OpticalGlyph.qml +16 -0
- data/Components/Builtins/Page.qml +111 -0
- data/Components/Builtins/PageIndicator.qml +63 -0
- data/Components/Builtins/Pagination.qml +158 -0
- data/Components/Builtins/Pane.qml +72 -0
- data/Components/Builtins/PanelHero.qml +15 -0
- data/Components/Builtins/ParallelAnimation.qml +3 -0
- data/Components/Builtins/ParentAnimation.qml +3 -0
- data/Components/Builtins/ParentChange.qml +10 -0
- data/Components/Builtins/ParticleSystem.qml +81 -0
- data/Components/Builtins/PasswordField.qml +58 -0
- data/Components/Builtins/Path.qml +35 -0
- data/Components/Builtins/PathAnimation.qml +3 -0
- data/Components/Builtins/PauseAnimation.qml +3 -0
- data/Components/Builtins/PieChart.qml +3 -0
- data/Components/Builtins/PinchArea.qml +23 -0
- data/Components/Builtins/Popup.qml +130 -0
- data/Components/Builtins/Progress.qml +15 -0
- data/Components/Builtins/ProgressRing.qml +120 -0
- data/Components/Builtins/PropertyAction.qml +11 -0
- data/Components/Builtins/PropertyAnimation.qml +3 -0
- data/Components/Builtins/PropertyChanges.qml +10 -0
- data/Components/Builtins/RadarChart.qml +3 -0
- data/Components/Builtins/RadialGauge.qml +3 -0
- data/Components/Builtins/RadioButton.qml +46 -0
- data/Components/Builtins/RadioDelegate.qml +115 -0
- data/Components/Builtins/RadioGroup.qml +58 -0
- data/Components/Builtins/RangeSlider.qml +39 -0
- data/Components/Builtins/Rectangle.qml +23 -0
- data/Components/Builtins/RectangularShadow.qml +23 -0
- data/Components/Builtins/ReorderableList.qml +204 -0
- data/Components/Builtins/RichText.qml +23 -0
- data/Components/Builtins/RotationAnimation.qml +3 -0
- data/Components/Builtins/RotationAnimator.qml +3 -0
- data/Components/Builtins/RoundButton.qml +42 -0
- data/Components/Builtins/Row.qml +17 -0
- data/Components/Builtins/RowLayout.qml +13 -0
- data/Components/Builtins/ScaleAnimator.qml +3 -0
- data/Components/Builtins/ScatterChart.qml +3 -0
- data/Components/Builtins/ScreenCapture.qml +78 -0
- data/Components/Builtins/ScriptAction.qml +15 -0
- data/Components/Builtins/Scroll.qml +18 -0
- data/Components/Builtins/ScrollBar.qml +18 -0
- data/Components/Builtins/ScrollIndicator.qml +15 -0
- data/Components/Builtins/SearchField.qml +178 -0
- data/Components/Builtins/SearchableDropdown.qml +21 -0
- data/Components/Builtins/SectionHeader.qml +14 -0
- data/Components/Builtins/SelectableText.qml +33 -0
- data/Components/Builtins/SelectionRectangle.qml +17 -0
- data/Components/Builtins/Separator.qml +13 -0
- data/Components/Builtins/SequentialAnimation.qml +3 -0
- data/Components/Builtins/Settings.qml +10 -0
- data/Components/Builtins/ShaderEffect.qml +115 -0
- data/Components/Builtins/ShaderEffectSource.qml +61 -0
- data/Components/Builtins/Shaders/grayscale.frag +14 -0
- data/Components/Builtins/Shaders/grayscale.frag.qsb +0 -0
- data/Components/Builtins/Shaders/passthrough.frag +11 -0
- data/Components/Builtins/Shaders/passthrough.frag.qsb +0 -0
- data/Components/Builtins/Shaders/pixelate.frag +16 -0
- data/Components/Builtins/Shaders/pixelate.frag.qsb +0 -0
- data/Components/Builtins/Shaders/vignette.frag +18 -0
- data/Components/Builtins/Shaders/vignette.frag.qsb +0 -0
- data/Components/Builtins/Shaders/wave.frag +18 -0
- data/Components/Builtins/Shaders/wave.frag.qsb +0 -0
- data/Components/Builtins/Shape.qml +53 -0
- data/Components/Builtins/Skeleton.qml +78 -0
- data/Components/Builtins/Slider.qml +21 -0
- data/Components/Builtins/SmoothedAnimation.qml +3 -0
- data/Components/Builtins/Snackbar.qml +181 -0
- data/Components/Builtins/SortFilterProxyModel.qml +16 -0
- data/Components/Builtins/SoundEffect.qml +10 -0
- data/Components/Builtins/Spacer.qml +13 -0
- data/Components/Builtins/Sparkline.qml +3 -0
- data/Components/Builtins/SpinBox.qml +44 -0
- data/Components/Builtins/SplitView.qml +31 -0
- data/Components/Builtins/SpringAnimation.qml +3 -0
- data/Components/Builtins/Stack.qml +14 -0
- data/Components/Builtins/StackLayout.qml +19 -0
- data/Components/Builtins/StackView.qml +122 -0
- data/Components/Builtins/StackedBarChart.qml +3 -0
- data/Components/Builtins/StandardPaths.qml +9 -0
- data/Components/Builtins/State.qml +13 -0
- data/Components/Builtins/StateGroup.qml +11 -0
- data/Components/Builtins/Support/AnimationDriver.qml +79 -0
- data/Components/Builtins/Support/AnimationGroupDriver.qml +32 -0
- data/Components/Builtins/Support/ChartCanvas.qml +629 -0
- data/Components/Builtins/Support/ModelView3dScene.qml +292 -0
- data/Components/Builtins/Support/OptionalModuleState.js +5 -0
- data/Components/Builtins/SwipeDelegate.qml +231 -0
- data/Components/Builtins/SwipeView.qml +69 -0
- data/Components/Builtins/SwitchDelegate.qml +140 -0
- data/Components/Builtins/TabBar.qml +117 -0
- data/Components/Builtins/TabButton.qml +105 -0
- data/Components/Builtins/TableView.qml +388 -0
- data/Components/Builtins/TableViewDelegate.qml +17 -0
- data/Components/Builtins/Tabs.qml +138 -0
- data/Components/Builtins/Text.qml +24 -0
- data/Components/Builtins/TextArea.qml +59 -0
- data/Components/Builtins/TextField.qml +21 -0
- data/Components/Builtins/TextMetrics.qml +39 -0
- data/Components/Builtins/TimePicker.qml +213 -0
- data/Components/Builtins/Timer.qml +13 -0
- data/Components/Builtins/Toast.qml +213 -0
- data/Components/Builtins/Toggle.qml +19 -0
- data/Components/Builtins/ToggleSwitch.qml +22 -0
- data/Components/Builtins/ToolBar.qml +61 -0
- data/Components/Builtins/ToolButton.qml +41 -0
- data/Components/Builtins/ToolSeparator.qml +36 -0
- data/Components/Builtins/Tooltip.qml +20 -0
- data/Components/Builtins/Transition.qml +3 -0
- data/Components/Builtins/TreeView.qml +423 -0
- data/Components/Builtins/TreeViewDelegate.qml +46 -0
- data/Components/Builtins/Tumbler.qml +18 -0
- data/Components/Builtins/UniformAnimator.qml +3 -0
- data/Components/Builtins/VectorAnimation.qml +3 -0
- data/Components/Builtins/VectorImage.qml +62 -0
- data/Components/Builtins/VerticalHeader.qml +21 -0
- data/Components/Builtins/VerticalHeaderDelegate.qml +35 -0
- data/Components/Builtins/Video.qml +54 -0
- data/Components/Builtins/VideoOutput.qml +54 -0
- data/Components/Builtins/WebView.qml +57 -0
- data/Components/Builtins/WeekNumberColumn.qml +13 -0
- data/Components/Builtins/WidgetButton.qml +26 -0
- data/Components/Builtins/Window.qml +90 -0
- data/Components/Builtins/WindowCapture.qml +11 -0
- data/Components/Builtins/Wrap.qml +18 -0
- data/Components/Builtins/XAnimator.qml +3 -0
- data/Components/Builtins/YAnimator.qml +3 -0
- data/Components/README.md +45 -0
- data/ControlNode.qml +1369 -0
- data/Controls/BarIconButton.qml +27 -0
- data/Controls/BarIndicator.qml +22 -0
- data/Controls/BorderOverlay.qml +10 -0
- data/Controls/BorderSurface.qml +10 -0
- data/Controls/Button.qml +78 -0
- data/Controls/ButtonGroup.qml +19 -0
- data/Controls/ConfirmDialog.qml +37 -0
- data/Controls/CursorSurface.qml +29 -0
- data/Controls/Dropdown.qml +59 -0
- data/Controls/MultiSelect.qml +32 -0
- data/Controls/NumberField.qml +24 -0
- data/Controls/OpticalGlyph.qml +14 -0
- data/Controls/PanelActionButton.qml +10 -0
- data/Controls/PanelHero.qml +18 -0
- data/Controls/PanelKeyCatcher.qml +25 -0
- data/Controls/PanelSectionHeader.qml +11 -0
- data/Controls/PanelSeparator.qml +10 -0
- data/Controls/PanelSlider.qml +36 -0
- data/Controls/PanelToolTip.qml +13 -0
- data/Controls/SearchableDropdown.qml +11 -0
- data/Controls/TextField.qml +25 -0
- data/Controls/Toggle.qml +22 -0
- data/Controls/ToggleSwitch.qml +26 -0
- data/Controls/WidgetButton.qml +35 -0
- data/Controls/qmldir +25 -0
- data/Desktop.qml +76 -0
- data/LICENSE +22 -0
- data/README.md +112 -0
- data/Service.qml +430 -0
- data/Theme/Border.qml +22 -0
- data/Theme/Color.qml +22 -0
- data/Theme/Style.qml +47 -0
- data/Theme/Util.qml +6 -0
- data/Theme/qmldir +5 -0
- data/bin/zui +7 -0
- data/lib/zui/animation.rb +24 -0
- data/lib/zui/application.rb +327 -0
- data/lib/zui/builder.rb +725 -0
- data/lib/zui/cli.rb +91 -0
- data/lib/zui/command.rb +101 -0
- data/lib/zui/component_registry.rb +91 -0
- data/lib/zui/components.rb +262 -0
- data/lib/zui/distribution.rb +200 -0
- data/lib/zui/generator.rb +84 -0
- data/lib/zui/host.rb +123 -0
- data/lib/zui/node.rb +30 -0
- data/lib/zui/platform.rb +40 -0
- data/lib/zui/protocol.rb +29 -0
- data/lib/zui/runner.rb +37 -0
- data/lib/zui/runtime.rb +23 -0
- data/lib/zui/scheduler.rb +136 -0
- data/lib/zui/source_bundle.rb +63 -0
- data/lib/zui/state_store.rb +100 -0
- data/lib/zui/value.rb +44 -0
- data/lib/zui.rb +33 -0
- data/native/CMakeLists.txt +45 -0
- data/native/ZuiClipboard.cpp +16 -0
- data/native/ZuiClipboard.h +16 -0
- data/native/ZuiProcess.cpp +84 -0
- data/native/ZuiProcess.h +34 -0
- data/native/main.cpp +64 -0
- data/vendor/host/linux-x86_64/PROVENANCE.md +15 -0
- data/vendor/host/linux-x86_64/zui-host +0 -0
- data/vendor/host/linux-x86_64/zui-host.sha256 +1 -0
- metadata +365 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Zui
|
|
4
|
+
class Task
|
|
5
|
+
attr_reader :kind, :interval, :block
|
|
6
|
+
|
|
7
|
+
def initialize(kind:, interval:, immediate:, block:)
|
|
8
|
+
@kind = kind
|
|
9
|
+
@interval = interval
|
|
10
|
+
@immediate = immediate
|
|
11
|
+
@block = block
|
|
12
|
+
@mutex = Mutex.new
|
|
13
|
+
@condition = ConditionVariable.new
|
|
14
|
+
@cancelled = false
|
|
15
|
+
@thread = nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def start(evaluator, on_error)
|
|
19
|
+
@mutex.synchronize do
|
|
20
|
+
return self if @cancelled || @thread
|
|
21
|
+
if Object.const_defined?(:Thread)
|
|
22
|
+
@thread = Thread.new { run(evaluator, on_error) }
|
|
23
|
+
@thread.name = "zui-#{kind}" if @thread.respond_to?(:name=)
|
|
24
|
+
else
|
|
25
|
+
@thread = :cooperative
|
|
26
|
+
@evaluator = evaluator
|
|
27
|
+
@on_error = on_error
|
|
28
|
+
@next_due = Time.now.to_f + ((kind == :async || @immediate) ? 0 : interval)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def cancel
|
|
35
|
+
@mutex.synchronize do
|
|
36
|
+
@cancelled = true
|
|
37
|
+
@condition.broadcast
|
|
38
|
+
end
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def join(timeout = nil)
|
|
43
|
+
thread = @mutex.synchronize { @thread }
|
|
44
|
+
thread.join(timeout) if thread && thread != :cooperative
|
|
45
|
+
self
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def tick(now = Time.now.to_f)
|
|
49
|
+
return unless @thread == :cooperative || !Object.const_defined?(:Thread)
|
|
50
|
+
return if cancelled? || now < @next_due
|
|
51
|
+
invoke(@evaluator, @on_error)
|
|
52
|
+
if kind == :every
|
|
53
|
+
@next_due = now + interval
|
|
54
|
+
else
|
|
55
|
+
cancel
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def cancelled?
|
|
60
|
+
@mutex.synchronize { @cancelled }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def run(evaluator, on_error)
|
|
66
|
+
case kind
|
|
67
|
+
when :async then invoke(evaluator, on_error)
|
|
68
|
+
when :after then invoke(evaluator, on_error) if wait(interval)
|
|
69
|
+
when :every
|
|
70
|
+
invoke(evaluator, on_error) if @immediate && !cancelled?
|
|
71
|
+
while wait(interval)
|
|
72
|
+
invoke(evaluator, on_error)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def wait(seconds)
|
|
78
|
+
@mutex.synchronize do
|
|
79
|
+
@condition.wait(@mutex, seconds) unless @cancelled
|
|
80
|
+
!@cancelled
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def invoke(evaluator, on_error)
|
|
85
|
+
evaluator.call(block) unless cancelled?
|
|
86
|
+
rescue StandardError => error
|
|
87
|
+
on_error.call(error)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class Scheduler
|
|
92
|
+
def initialize(evaluator:, on_error:)
|
|
93
|
+
@evaluator = evaluator
|
|
94
|
+
@on_error = on_error
|
|
95
|
+
@tasks = []
|
|
96
|
+
@lock = Mutex.new
|
|
97
|
+
@started = false
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def schedule(kind, interval: 0, immediate: false, &block)
|
|
101
|
+
raise ArgumentError, "task requires a block" unless block
|
|
102
|
+
seconds = Float(interval)
|
|
103
|
+
raise ArgumentError, "task interval must be positive" if kind != :async && !seconds.positive?
|
|
104
|
+
task = Task.new(kind:, interval: seconds, immediate:, block:)
|
|
105
|
+
@lock.synchronize do
|
|
106
|
+
@tasks << task
|
|
107
|
+
task.start(@evaluator, @on_error) if @started
|
|
108
|
+
end
|
|
109
|
+
task
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def start
|
|
113
|
+
@lock.synchronize do
|
|
114
|
+
@started = true
|
|
115
|
+
@tasks.each { |task| task.start(@evaluator, @on_error) }
|
|
116
|
+
end
|
|
117
|
+
self
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def stop
|
|
121
|
+
tasks = @lock.synchronize do
|
|
122
|
+
@started = false
|
|
123
|
+
@tasks.dup
|
|
124
|
+
end
|
|
125
|
+
tasks.each(&:cancel)
|
|
126
|
+
tasks.each { |task| task.join(1) }
|
|
127
|
+
self
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def tick(now = Time.now.to_f)
|
|
131
|
+
tasks = @lock.synchronize { @tasks.dup }
|
|
132
|
+
tasks.each { |task| task.tick(now) }
|
|
133
|
+
self
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Zui
|
|
4
|
+
class SourceBundle
|
|
5
|
+
REQUIRE_RELATIVE = /\A\s*require_relative\s*(?:\(\s*)?["']([^"']+)["']\s*\)?\s*(?:#.*)?\z/
|
|
6
|
+
|
|
7
|
+
def initialize(entrypoint, root: File.dirname(entrypoint), embedded_frameworks: ["zui"])
|
|
8
|
+
@entrypoint = File.expand_path(entrypoint)
|
|
9
|
+
@root = File.expand_path(root)
|
|
10
|
+
frameworks = Array(embedded_frameworks).map(&:to_s)
|
|
11
|
+
raise ArgumentError, "embedded framework names cannot be empty" if frameworks.any?(&:empty?)
|
|
12
|
+
|
|
13
|
+
names = frameworks.map { |name| Regexp.escape(name) }.join("|")
|
|
14
|
+
@embedded_framework_require = /\A\s*require\s*(?:\(\s*)?["'](?:#{names})["']\s*\)?\s*(?:#.*)?\z/
|
|
15
|
+
@loaded = {}
|
|
16
|
+
@loading = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call
|
|
20
|
+
expand(@entrypoint)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def expand(path)
|
|
26
|
+
path = ruby_path(File.expand_path(path))
|
|
27
|
+
ensure_inside_root!(path)
|
|
28
|
+
return "" if @loaded[path]
|
|
29
|
+
raise ArgumentError, "circular require_relative: #{relative(path)}" if @loading.include?(path)
|
|
30
|
+
raise ArgumentError, "required Ruby file not found: #{relative(path)}" unless File.file?(path)
|
|
31
|
+
|
|
32
|
+
@loading << path
|
|
33
|
+
source = File.readlines(path, chomp: true).map do |line|
|
|
34
|
+
match = REQUIRE_RELATIVE.match(line)
|
|
35
|
+
if match
|
|
36
|
+
expand(File.expand_path(match[1], File.dirname(path)))
|
|
37
|
+
elsif @embedded_framework_require.match?(line)
|
|
38
|
+
""
|
|
39
|
+
else
|
|
40
|
+
line
|
|
41
|
+
end
|
|
42
|
+
end.join("\n")
|
|
43
|
+
@loaded[path] = true
|
|
44
|
+
"# source: #{relative(path)}\n#{source}\n"
|
|
45
|
+
ensure
|
|
46
|
+
@loading.pop if @loading.last == path
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def ruby_path(path)
|
|
50
|
+
File.extname(path).empty? ? "#{path}.rb" : path
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def ensure_inside_root!(path)
|
|
54
|
+
return if path == @root || path.start_with?("#{@root}#{File::SEPARATOR}")
|
|
55
|
+
|
|
56
|
+
raise ArgumentError, "require_relative escapes the application directory: #{path}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def relative(path)
|
|
60
|
+
path.delete_prefix("#{@root}#{File::SEPARATOR}")
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Zui
|
|
4
|
+
class StateStore
|
|
5
|
+
def initialize(on_change)
|
|
6
|
+
@values = {}
|
|
7
|
+
@on_change = on_change
|
|
8
|
+
@lock = Mutex.new
|
|
9
|
+
@transaction_depth = 0
|
|
10
|
+
@pending = {}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def define(name, initial)
|
|
14
|
+
key = name.to_sym
|
|
15
|
+
@lock.synchronize do
|
|
16
|
+
raise ArgumentError, "state already defined: #{key}" if @values.key?(key)
|
|
17
|
+
@values[key] = initial
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def [](name)
|
|
22
|
+
@lock.synchronize { @values.fetch(name.to_sym) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def []=(name, value)
|
|
26
|
+
write(name.to_sym, value)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def update(name)
|
|
30
|
+
raise ArgumentError, "update requires a block" unless block_given?
|
|
31
|
+
key = name.to_sym
|
|
32
|
+
change, value = @lock.synchronize do
|
|
33
|
+
raise NoMethodError, "unknown state: #{key}" unless @values.key?(key)
|
|
34
|
+
next_value = yield(@values[key])
|
|
35
|
+
[store_locked(key, next_value), next_value]
|
|
36
|
+
end
|
|
37
|
+
@on_change.call(*change) if change
|
|
38
|
+
value
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def method_missing(name, *arguments)
|
|
42
|
+
raw = name.to_s
|
|
43
|
+
if raw.end_with?("=")
|
|
44
|
+
raise ArgumentError, "expected one value" unless arguments.length == 1
|
|
45
|
+
|
|
46
|
+
return write(raw.delete_suffix("=").to_sym, arguments.first)
|
|
47
|
+
end
|
|
48
|
+
if arguments.empty?
|
|
49
|
+
found, value = @lock.synchronize { [@values.key?(name), @values[name]] }
|
|
50
|
+
return value if found
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
super
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def respond_to_missing?(name, include_private = false)
|
|
57
|
+
key = name.to_s.delete_suffix("=").to_sym
|
|
58
|
+
@lock.synchronize { @values.key?(key) } || super
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def transaction
|
|
62
|
+
raise ArgumentError, "transaction requires a block" unless block_given?
|
|
63
|
+
@lock.synchronize { @transaction_depth += 1 }
|
|
64
|
+
yield self
|
|
65
|
+
ensure
|
|
66
|
+
changes = @lock.synchronize do
|
|
67
|
+
@transaction_depth -= 1
|
|
68
|
+
next [] unless @transaction_depth.zero?
|
|
69
|
+
flushed = @pending.values
|
|
70
|
+
@pending.clear
|
|
71
|
+
flushed
|
|
72
|
+
end
|
|
73
|
+
changes.each { |change| @on_change.call(*change) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def write(key, value)
|
|
79
|
+
change = @lock.synchronize do
|
|
80
|
+
raise NoMethodError, "unknown state: #{key}" unless @values.key?(key)
|
|
81
|
+
store_locked(key, value)
|
|
82
|
+
end
|
|
83
|
+
@on_change.call(*change) if change
|
|
84
|
+
value
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def store_locked(key, value)
|
|
88
|
+
return nil if @values[key] == value
|
|
89
|
+
previous = @values[key]
|
|
90
|
+
@values[key] = value
|
|
91
|
+
if @transaction_depth.positive?
|
|
92
|
+
@pending[key] ||= [key, previous, value]
|
|
93
|
+
@pending[key][2] = value
|
|
94
|
+
nil
|
|
95
|
+
else
|
|
96
|
+
[key, previous, value]
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
data/lib/zui/value.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Zui
|
|
4
|
+
module Value
|
|
5
|
+
MAX_DEPTH = 32
|
|
6
|
+
MAX_ITEMS = 10_000
|
|
7
|
+
def normalize(value, property: nil, depth: 0, seen: {}, count: [0])
|
|
8
|
+
raise ArgumentError, "property value exceeds #{MAX_DEPTH} levels: #{property}" if depth > MAX_DEPTH
|
|
9
|
+
count[0] += 1
|
|
10
|
+
raise ArgumentError, "property value exceeds #{MAX_ITEMS} items: #{property}" if count[0] > MAX_ITEMS
|
|
11
|
+
|
|
12
|
+
case value
|
|
13
|
+
when Symbol then value.to_s
|
|
14
|
+
when String, TrueClass, FalseClass, NilClass, Integer then value
|
|
15
|
+
when Float
|
|
16
|
+
raise ArgumentError, "property number must be finite: #{property}" unless value.finite?
|
|
17
|
+
value
|
|
18
|
+
when Array
|
|
19
|
+
guard_cycle(value, property, seen) do
|
|
20
|
+
value.map { |item| normalize(item, property:, depth: depth + 1, seen:, count:) }
|
|
21
|
+
end
|
|
22
|
+
when Hash
|
|
23
|
+
guard_cycle(value, property, seen) do
|
|
24
|
+
value.each_with_object({}) do |(key, item), result|
|
|
25
|
+
result[key.to_s] = normalize(item, property:, depth: depth + 1, seen:, count:)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
raise ArgumentError, "unsupported property value for #{property}: #{value.class}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def guard_cycle(value, property, seen)
|
|
34
|
+
identity = value.object_id
|
|
35
|
+
raise ArgumentError, "cyclic property value: #{property}" if seen[identity]
|
|
36
|
+
seen[identity] = true
|
|
37
|
+
yield
|
|
38
|
+
ensure
|
|
39
|
+
seen.delete(identity)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module_function :normalize, :guard_cycle
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/zui.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "zui/protocol"
|
|
4
|
+
require_relative "zui/value"
|
|
5
|
+
require_relative "zui/state_store"
|
|
6
|
+
require_relative "zui/node"
|
|
7
|
+
require_relative "zui/animation"
|
|
8
|
+
require_relative "zui/scheduler"
|
|
9
|
+
require_relative "zui/command"
|
|
10
|
+
require_relative "zui/component_registry"
|
|
11
|
+
require_relative "zui/components"
|
|
12
|
+
require_relative "zui/builder"
|
|
13
|
+
require_relative "zui/application"
|
|
14
|
+
require_relative "zui/source_bundle"
|
|
15
|
+
require_relative "zui/platform"
|
|
16
|
+
require_relative "zui/runtime"
|
|
17
|
+
require_relative "zui/host"
|
|
18
|
+
require_relative "zui/runner"
|
|
19
|
+
require_relative "zui/generator"
|
|
20
|
+
require_relative "zui/distribution"
|
|
21
|
+
|
|
22
|
+
module Zui
|
|
23
|
+
VERSION = "0.0.1"
|
|
24
|
+
FRAMEWORK_ROOT = File.expand_path("..", __dir__)
|
|
25
|
+
|
|
26
|
+
def self.app(&definition)
|
|
27
|
+
Application.new(&definition).run
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class << self
|
|
31
|
+
alias application app
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.21)
|
|
2
|
+
project(zui-host VERSION 0.1.0 LANGUAGES CXX)
|
|
3
|
+
|
|
4
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
5
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
6
|
+
set(CMAKE_AUTOMOC ON)
|
|
7
|
+
|
|
8
|
+
find_package(Qt6 6.8 REQUIRED COMPONENTS
|
|
9
|
+
Core
|
|
10
|
+
Gui
|
|
11
|
+
Multimedia
|
|
12
|
+
Qml
|
|
13
|
+
Quick
|
|
14
|
+
QuickControls2
|
|
15
|
+
QuickVectorImage
|
|
16
|
+
)
|
|
17
|
+
find_package(Qt6 6.8 QUIET COMPONENTS WebEngineQuick)
|
|
18
|
+
|
|
19
|
+
qt_add_executable(zui-host
|
|
20
|
+
main.cpp
|
|
21
|
+
ZuiClipboard.cpp
|
|
22
|
+
ZuiClipboard.h
|
|
23
|
+
ZuiProcess.cpp
|
|
24
|
+
ZuiProcess.h
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
target_link_libraries(zui-host PRIVATE
|
|
28
|
+
Qt6::Core
|
|
29
|
+
Qt6::Gui
|
|
30
|
+
Qt6::Multimedia
|
|
31
|
+
Qt6::Qml
|
|
32
|
+
Qt6::Quick
|
|
33
|
+
Qt6::QuickControls2
|
|
34
|
+
Qt6::QuickVectorImage
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if(TARGET Qt6::WebEngineQuick)
|
|
38
|
+
target_link_libraries(zui-host PRIVATE Qt6::WebEngineQuick)
|
|
39
|
+
target_compile_definitions(zui-host PRIVATE ZUI_HAS_WEBENGINE=1)
|
|
40
|
+
endif()
|
|
41
|
+
|
|
42
|
+
install(TARGETS zui-host
|
|
43
|
+
BUNDLE DESTINATION .
|
|
44
|
+
RUNTIME DESTINATION bin
|
|
45
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#include "ZuiClipboard.h"
|
|
2
|
+
|
|
3
|
+
#include <QGuiApplication>
|
|
4
|
+
#include <QClipboard>
|
|
5
|
+
|
|
6
|
+
ZuiClipboard::ZuiClipboard(QObject *parent) : QObject(parent) {
|
|
7
|
+
connect(QGuiApplication::clipboard(), &QClipboard::dataChanged, this, &ZuiClipboard::textChanged);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
QString ZuiClipboard::text() const { return QGuiApplication::clipboard()->text(); }
|
|
11
|
+
|
|
12
|
+
void ZuiClipboard::setText(const QString &text) {
|
|
13
|
+
if (this->text() == text)
|
|
14
|
+
return;
|
|
15
|
+
QGuiApplication::clipboard()->setText(text);
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <QObject>
|
|
4
|
+
|
|
5
|
+
class ZuiClipboard final : public QObject {
|
|
6
|
+
Q_OBJECT
|
|
7
|
+
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
|
|
8
|
+
|
|
9
|
+
public:
|
|
10
|
+
explicit ZuiClipboard(QObject *parent = nullptr);
|
|
11
|
+
QString text() const;
|
|
12
|
+
void setText(const QString &text);
|
|
13
|
+
|
|
14
|
+
signals:
|
|
15
|
+
void textChanged();
|
|
16
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#include "ZuiProcess.h"
|
|
2
|
+
|
|
3
|
+
#include <QProcessEnvironment>
|
|
4
|
+
#include <QTimer>
|
|
5
|
+
|
|
6
|
+
ZuiProcess::ZuiProcess(QObject *parent) : QObject(parent) {
|
|
7
|
+
connect(&m_process, &QProcess::stateChanged, this, [this] { emit runningChanged(); });
|
|
8
|
+
connect(&m_process, &QProcess::readyReadStandardOutput, this, [this] {
|
|
9
|
+
m_stdoutBuffer += m_process.readAllStandardOutput();
|
|
10
|
+
consume(m_stdoutBuffer, false);
|
|
11
|
+
});
|
|
12
|
+
connect(&m_process, &QProcess::readyReadStandardError, this, [this] {
|
|
13
|
+
m_stderrBuffer += m_process.readAllStandardError();
|
|
14
|
+
consume(m_stderrBuffer, true);
|
|
15
|
+
});
|
|
16
|
+
connect(&m_process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError) {
|
|
17
|
+
emit errorLineReceived(m_process.errorString());
|
|
18
|
+
});
|
|
19
|
+
connect(&m_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
|
|
20
|
+
[this](int exitCode, QProcess::ExitStatus) {
|
|
21
|
+
m_stdoutBuffer += m_process.readAllStandardOutput();
|
|
22
|
+
m_stderrBuffer += m_process.readAllStandardError();
|
|
23
|
+
flush(m_stdoutBuffer, false);
|
|
24
|
+
flush(m_stderrBuffer, true);
|
|
25
|
+
emit exited(exitCode);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
ZuiProcess::~ZuiProcess() { stop(); }
|
|
30
|
+
|
|
31
|
+
bool ZuiProcess::running() const { return m_process.state() != QProcess::NotRunning; }
|
|
32
|
+
|
|
33
|
+
void ZuiProcess::start(const QString &executable, const QString &program,
|
|
34
|
+
const QString &workingDirectory, const QString &loadPath) {
|
|
35
|
+
if (running() || executable.isEmpty() || program.isEmpty())
|
|
36
|
+
return;
|
|
37
|
+
|
|
38
|
+
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
|
|
39
|
+
environment.insert(QStringLiteral("ZUI_PROJECT_DIR"), workingDirectory);
|
|
40
|
+
m_process.setProcessEnvironment(environment);
|
|
41
|
+
m_process.setWorkingDirectory(workingDirectory);
|
|
42
|
+
m_process.setProcessChannelMode(QProcess::SeparateChannels);
|
|
43
|
+
|
|
44
|
+
QStringList arguments;
|
|
45
|
+
if (!loadPath.isEmpty())
|
|
46
|
+
arguments << QStringLiteral("-I") << loadPath;
|
|
47
|
+
arguments << program;
|
|
48
|
+
m_process.start(executable, arguments, QIODevice::ReadWrite);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void ZuiProcess::write(const QString &data) {
|
|
52
|
+
if (!running())
|
|
53
|
+
return;
|
|
54
|
+
m_process.write(data.toUtf8());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
void ZuiProcess::stop() {
|
|
58
|
+
if (!running())
|
|
59
|
+
return;
|
|
60
|
+
m_process.closeWriteChannel();
|
|
61
|
+
m_process.terminate();
|
|
62
|
+
if (!m_process.waitForFinished(1000)) {
|
|
63
|
+
m_process.kill();
|
|
64
|
+
m_process.waitForFinished(1000);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void ZuiProcess::consume(QByteArray &buffer, bool errorStream) {
|
|
69
|
+
qsizetype newline = -1;
|
|
70
|
+
while ((newline = buffer.indexOf('\n')) >= 0) {
|
|
71
|
+
const QString line = QString::fromUtf8(buffer.left(newline));
|
|
72
|
+
buffer.remove(0, newline + 1);
|
|
73
|
+
errorStream ? emit errorLineReceived(line) : emit lineReceived(line);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
void ZuiProcess::flush(QByteArray &buffer, bool errorStream) {
|
|
78
|
+
consume(buffer, errorStream);
|
|
79
|
+
if (buffer.isEmpty())
|
|
80
|
+
return;
|
|
81
|
+
const QString line = QString::fromUtf8(buffer);
|
|
82
|
+
buffer.clear();
|
|
83
|
+
errorStream ? emit errorLineReceived(line) : emit lineReceived(line);
|
|
84
|
+
}
|
data/native/ZuiProcess.h
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <QObject>
|
|
4
|
+
#include <QProcess>
|
|
5
|
+
|
|
6
|
+
class ZuiProcess final : public QObject {
|
|
7
|
+
Q_OBJECT
|
|
8
|
+
Q_PROPERTY(bool running READ running NOTIFY runningChanged)
|
|
9
|
+
|
|
10
|
+
public:
|
|
11
|
+
explicit ZuiProcess(QObject *parent = nullptr);
|
|
12
|
+
~ZuiProcess() override;
|
|
13
|
+
|
|
14
|
+
bool running() const;
|
|
15
|
+
|
|
16
|
+
Q_INVOKABLE void start(const QString &executable, const QString &program,
|
|
17
|
+
const QString &workingDirectory, const QString &loadPath);
|
|
18
|
+
Q_INVOKABLE void write(const QString &data);
|
|
19
|
+
Q_INVOKABLE void stop();
|
|
20
|
+
|
|
21
|
+
signals:
|
|
22
|
+
void runningChanged();
|
|
23
|
+
void lineReceived(const QString &line);
|
|
24
|
+
void errorLineReceived(const QString &line);
|
|
25
|
+
void exited(int exitCode);
|
|
26
|
+
|
|
27
|
+
private:
|
|
28
|
+
void consume(QByteArray &buffer, bool errorStream);
|
|
29
|
+
void flush(QByteArray &buffer, bool errorStream);
|
|
30
|
+
|
|
31
|
+
QProcess m_process;
|
|
32
|
+
QByteArray m_stdoutBuffer;
|
|
33
|
+
QByteArray m_stderrBuffer;
|
|
34
|
+
};
|
data/native/main.cpp
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#include "ZuiClipboard.h"
|
|
2
|
+
#include "ZuiProcess.h"
|
|
3
|
+
|
|
4
|
+
#include <QCommandLineParser>
|
|
5
|
+
#include <QDir>
|
|
6
|
+
#include <QFileInfo>
|
|
7
|
+
#include <QGuiApplication>
|
|
8
|
+
#include <QQmlApplicationEngine>
|
|
9
|
+
#include <QQmlContext>
|
|
10
|
+
#include <QQuickStyle>
|
|
11
|
+
|
|
12
|
+
#ifdef ZUI_HAS_WEBENGINE
|
|
13
|
+
#include <QtWebEngineQuick/qtwebenginequickglobal.h>
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
int main(int argc, char *argv[]) {
|
|
17
|
+
#ifdef ZUI_HAS_WEBENGINE
|
|
18
|
+
QtWebEngineQuick::initialize();
|
|
19
|
+
#endif
|
|
20
|
+
QGuiApplication application(argc, argv);
|
|
21
|
+
QCoreApplication::setApplicationName(QStringLiteral("Zui"));
|
|
22
|
+
QCoreApplication::setOrganizationName(QStringLiteral("Zui"));
|
|
23
|
+
QQuickStyle::setStyle(QStringLiteral("Fusion"));
|
|
24
|
+
|
|
25
|
+
QCommandLineParser parser;
|
|
26
|
+
parser.setApplicationDescription(QStringLiteral("Zui cross-platform Qt host"));
|
|
27
|
+
parser.addHelpOption();
|
|
28
|
+
parser.addOption({QStringLiteral("qml-root"), QStringLiteral("Zui QML runtime directory"), QStringLiteral("path")});
|
|
29
|
+
parser.addOption({QStringLiteral("project"), QStringLiteral("Application project directory"), QStringLiteral("path")});
|
|
30
|
+
parser.addOption({QStringLiteral("program"), QStringLiteral("Ruby application entrypoint"), QStringLiteral("path")});
|
|
31
|
+
parser.addOption({QStringLiteral("ruby"), QStringLiteral("Ruby executable"), QStringLiteral("path"), QStringLiteral("ruby")});
|
|
32
|
+
parser.addOption({QStringLiteral("load-path"), QStringLiteral("Ruby framework load path"), QStringLiteral("path")});
|
|
33
|
+
parser.addOption({QStringLiteral("name"), QStringLiteral("Application name"), QStringLiteral("name"), QStringLiteral("Zui Application")});
|
|
34
|
+
parser.process(application);
|
|
35
|
+
|
|
36
|
+
const QString qmlRootValue = parser.value(QStringLiteral("qml-root"));
|
|
37
|
+
const QString projectValue = parser.value(QStringLiteral("project"));
|
|
38
|
+
const QString programValue = parser.value(QStringLiteral("program"));
|
|
39
|
+
const QString qmlRoot = QFileInfo(qmlRootValue).absoluteFilePath();
|
|
40
|
+
const QString project = QFileInfo(projectValue).absoluteFilePath();
|
|
41
|
+
const QString program = QFileInfo(programValue).absoluteFilePath();
|
|
42
|
+
const QFileInfo desktopFile(QDir(qmlRoot).filePath(QStringLiteral("Desktop.qml")));
|
|
43
|
+
if (qmlRootValue.isEmpty() || projectValue.isEmpty() || programValue.isEmpty()
|
|
44
|
+
|| !desktopFile.isFile() || !QFileInfo(project).isDir() || !QFileInfo(program).isFile())
|
|
45
|
+
parser.showHelp(64);
|
|
46
|
+
|
|
47
|
+
ZuiProcess process;
|
|
48
|
+
ZuiClipboard clipboard;
|
|
49
|
+
QQmlApplicationEngine engine;
|
|
50
|
+
engine.rootContext()->setContextProperty(QStringLiteral("zuiProcess"), &process);
|
|
51
|
+
engine.rootContext()->setContextProperty(QStringLiteral("zuiClipboard"), &clipboard);
|
|
52
|
+
engine.rootContext()->setContextProperty(QStringLiteral("zuiProjectDir"), project);
|
|
53
|
+
engine.rootContext()->setContextProperty(QStringLiteral("zuiComponentDir"), QDir(qmlRoot).filePath(QStringLiteral("Components/Builtins")));
|
|
54
|
+
engine.rootContext()->setContextProperty(QStringLiteral("zuiRubyExecutable"), parser.value(QStringLiteral("ruby")));
|
|
55
|
+
engine.rootContext()->setContextProperty(QStringLiteral("zuiRubyProgram"), program);
|
|
56
|
+
engine.rootContext()->setContextProperty(QStringLiteral("zuiRubyLoadPath"), parser.value(QStringLiteral("load-path")));
|
|
57
|
+
engine.rootContext()->setContextProperty(QStringLiteral("zuiApplicationName"), parser.value(QStringLiteral("name")));
|
|
58
|
+
engine.addImportPath(qmlRoot);
|
|
59
|
+
|
|
60
|
+
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &application,
|
|
61
|
+
[] { QCoreApplication::exit(1); }, Qt::QueuedConnection);
|
|
62
|
+
engine.load(QUrl::fromLocalFile(QDir(qmlRoot).filePath(QStringLiteral("Desktop.qml"))));
|
|
63
|
+
return application.exec();
|
|
64
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Zui Linux host provenance
|
|
2
|
+
|
|
3
|
+
- Target: Linux x86-64
|
|
4
|
+
- Source: `native/` in this repository
|
|
5
|
+
- Framework version: Zui 0.1.0
|
|
6
|
+
- Compiler: GNU C++ 16.2.1
|
|
7
|
+
- Qt: 6.11.2
|
|
8
|
+
- Build type: CMake `Release`
|
|
9
|
+
|
|
10
|
+
The binary is reproducible from the checked-in C++ sources with:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
cmake -S native -B build -DCMAKE_BUILD_TYPE=Release
|
|
14
|
+
cmake --build build --parallel
|
|
15
|
+
```
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
de446bb598f922a7a58fe30127d88cae9602cf54bd819aa2b5c84447a51da7a4 zui-host
|