Skip to content

Commit

Permalink
Add example projects
Browse files Browse the repository at this point in the history
Chronometer:
  * QML front-end to a .NET module with a well-defined "business logic".

EmbeddedWindow:
  * WPF window containing an embedded QML view, which runs in-process.

QtAzureIoT:
  * Integrating Qt and .NET in a non-Windows setting.

Change-Id: I4dff485b95835a3d880fe03f110c46c457a419b3
Reviewed-by: Joerg Bornemann <[email protected]>
  • Loading branch information
micosta committed Jun 12, 2023
1 parent a1c6a7c commit 19c593f
Show file tree
Hide file tree
Showing 59 changed files with 4,475 additions and 0 deletions.
232 changes: 232 additions & 0 deletions examples/Chronometer/Chronometer/Chronometer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/***************************************************************************************************
Copyright (C) 2023 The Qt Company Ltd.
SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
***************************************************************************************************/

using System.ComponentModel;
using System.Diagnostics;

namespace WatchModels
{
public interface ILapRecorder
{
void Mark(int hours, int minutes, int seconds, int milliseconds);
}

public class Chronometer : INotifyPropertyChanged
{
public double Hours
{
get => hours;
private set => SetProperty(ref hours, value, nameof(Hours));
}
public double Minutes
{
get => minutes;
private set => SetProperty(ref minutes, value, nameof(Minutes));
}
public double Seconds
{
get => seconds;
private set => SetProperty(ref seconds, value, nameof(Seconds));
}

public int Day
{
get => day;
private set => SetProperty(ref day, value, nameof(Day));
}

public double ElapsedHours
{
get => elapsedHours;
private set => SetProperty(ref elapsedHours, value, nameof(ElapsedHours));
}

public double ElapsedMinutes
{
get => elapsedMinutes;
private set => SetProperty(ref elapsedMinutes, value, nameof(ElapsedMinutes));
}

public double ElapsedSeconds
{
get => elapsedSeconds;
private set => SetProperty(ref elapsedSeconds, value, nameof(ElapsedSeconds));
}

public double ElapsedMilliseconds
{
get => elapsedMilliseconds;
private set => SetProperty(ref elapsedMilliseconds, value, nameof(ElapsedMilliseconds));
}

public bool Started
{
get => Stopwatch.IsRunning;
private set
{
if (value == Stopwatch.IsRunning)
return;
if (value)
Stopwatch.Start();
else
Stopwatch.Stop();
NotifyPropertyChanged(nameof(Started));
}
}

public bool AdjustDayMode
{
get => adjustDayMode;
set
{
if (value == adjustDayMode)
return;
adjustDayMode = value;
if (adjustDayMode) {
if (adjustTimeMode) {
adjustTimeMode = false;
NotifyPropertyChanged(nameof(AdjustTimeMode));
}
Started = false;
Reset();
Time.Stop();
baseTime = baseTime.Add(Time.Elapsed);
Time.Reset();
} else if (!adjustTimeMode) {
Time.Start();
}
NotifyPropertyChanged(nameof(AdjustDayMode));
}
}

public bool AdjustTimeMode
{
get => adjustTimeMode;
set
{
if (value == adjustTimeMode)
return;
adjustTimeMode = value;
if (adjustTimeMode) {
if (adjustDayMode) {
adjustDayMode = false;
NotifyPropertyChanged(nameof(AdjustDayMode));
}
Started = false;
Reset();
Time.Stop();
baseTime = baseTime.Add(Time.Elapsed);
Time.Reset();
} else if (!adjustDayMode) {
Time.Start();
}
NotifyPropertyChanged(nameof(AdjustTimeMode));
}
}

public ILapRecorder LapRecorder { get; set; }

public Chronometer()
{
Mechanism = new Task(async () => await MechanismLoopAsync(), MechanismLoop.Token);
Mechanism.Start();
baseTime = DateTime.Now;
Time.Start();
}

public void StartStop()
{
if (AdjustTimeMode || AdjustDayMode)
return;
Started = !Started;
}

public void Reset()
{
ElapsedHours = ElapsedMinutes = ElapsedSeconds = ElapsedMilliseconds = 0;
if (!Stopwatch.IsRunning) {
Stopwatch.Reset();
} else {
LapRecorder?.Mark(
Stopwatch.Elapsed.Hours,
Stopwatch.Elapsed.Minutes,
Stopwatch.Elapsed.Seconds,
Stopwatch.Elapsed.Milliseconds);
Stopwatch.Restart();
}
}

public void Adjust(int delta)
{
if (AdjustDayMode)
baseTime = baseTime.AddDays(delta);
else if (AdjustTimeMode)
baseTime = baseTime.AddSeconds(delta * 60);
Refresh();
}

public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

private void Refresh()
{
DateTime now = baseTime.Add(Time.Elapsed);
Day = now.Day;

TimeSpan time = now.TimeOfDay;
Hours = time.TotalHours;
Minutes = time.TotalMinutes
- (time.Hours * 60);
Seconds = time.TotalSeconds
- (time.Hours * 3600) - (time.Minutes * 60);

TimeSpan elapsed = Stopwatch.Elapsed;
ElapsedHours = elapsed.TotalHours;
ElapsedMinutes = elapsed.TotalMinutes
- (elapsed.Hours * 60);
ElapsedSeconds = elapsed.TotalSeconds
- (elapsed.Hours * 3600) - (elapsed.Minutes * 60);
ElapsedMilliseconds = elapsed.TotalMilliseconds
- (elapsed.Hours * 3600000) - (elapsed.Minutes * 60000) - (elapsed.Seconds * 1000);
}

private async Task MechanismLoopAsync()
{
while (!MechanismLoop.IsCancellationRequested) {
await Task.Delay(5);
Refresh();
}
}

private void SetProperty<T>(ref T currentValue, T newValue, string name)
{
if (newValue.Equals(currentValue))
return;
currentValue = newValue;
NotifyPropertyChanged(name);
}

private double hours;
private double minutes;
private double seconds;
private int day;
private double elapsedHours;
private double elapsedMinutes;
private double elapsedSeconds;
private double elapsedMilliseconds;
private bool adjustDayMode;
private bool adjustTimeMode;

private DateTime baseTime;
private Stopwatch Time { get; } = new();
private Stopwatch Stopwatch { get; } = new();

private CancellationTokenSource MechanismLoop { get; } = new();
private Task Mechanism { get; }
}
}
9 changes: 9 additions & 0 deletions examples/Chronometer/Chronometer/ChronometerModel.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>

</Project>
11 changes: 11 additions & 0 deletions examples/Chronometer/QmlChronometer/OutDir.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>bin\$(VisualStudioVersion)\$(Platform)\$(Configuration)\</OutDir>
<IntDir>obj\$(VisualStudioVersion)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />
</Project>
125 changes: 125 additions & 0 deletions examples/Chronometer/QmlChronometer/QChronometer/AdjustmentWheel.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/***************************************************************************************************
Copyright (C) 2023 The Qt Company Ltd.
SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
***************************************************************************************************/

import QtQml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Shapes

//////////////////////////////////////////////////////////////////////
// Adjustment wheel
Tumbler {
id: adjustmentWheel
model: 100
property int startX
property int startY

x: startX + ((chrono.adjustDayMode || chrono.adjustTimeMode) ? 8 : 0)
Behavior on x {
SpringAnimation { spring: 3; damping: 0.5 }
}
y: startY; width: 25; height: 70

enabled: chrono.adjustDayMode || chrono.adjustTimeMode
onEnabledChanged: {
if (enabled) {
chrono.reset();
if (!chrono.started) {
laps.reset();
showLap = currentLap;
}
}
}

property int lastIndex: 0
property var lastTime: Date.UTC(0)
property double turnSpeed: 0.0
onCurrentIndexChanged: {
if (currentIndex != lastIndex) {
var i1 = currentIndex;
var i0 = lastIndex;
if (Math.abs(i1 - i0) > 50) {
if (i1 < i0)
i1 += 100;
else
i0 += 100;
}
var deltaX = i1 - i0;
chrono.adjust(deltaX);
lastIndex = currentIndex;

var deltaT = Date.now() - lastTime;
lastTime += deltaT;
turnSpeed = Math.abs((deltaX * 1000) / deltaT);
}
}

MouseArea {
anchors.fill: parent
onWheel: function(wheel) {
turn(wheel.angleDelta.y > 0 ? 1 : -1);
}
}

function turn(delta) {
if (enabled) {
adjustmentWheel.currentIndex = (100 + adjustmentWheel.currentIndex + (delta)) % 100;
}
}

//////////////////////////////////////////////////////////////////////
// Wheel surface
background: Rectangle {
anchors.fill: adjustmentWheel
color: gray6
border.color: gray8
border.width: 2
radius: 2
}

//////////////////////////////////////////////////////////////////////
// Notches
delegate: Component {
Item {
Rectangle {
x: 4; y: 0; width: Tumbler.tumbler.width - 8; height: 2
color: gray3
}
}
}

//////////////////////////////////////////////////////////////////////
// Wheel shadow
Rectangle {
anchors.centerIn: parent
width: parent.width; height: parent.height
gradient: Gradient {
GradientStop { position: 0.0; color: gray3 }
GradientStop { position: 0.3; color: "transparent" }
GradientStop { position: 0.5; color: "transparent" }
GradientStop { position: 0.7; color: "transparent" }
GradientStop { position: 1.0; color: gray3 }
}
}

//////////////////////////////////////////////////////////////////////
// Wheel axis
Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: parent.startX - parent.x + 2
width: 20; height: 20
z: -1
gradient: Gradient {
GradientStop { position: 0.0; color: gray3 }
GradientStop { position: 0.3; color: gray6 }
GradientStop { position: 0.5; color: gray6 }
GradientStop { position: 0.7; color: gray6 }
GradientStop { position: 1.0; color: gray3 }
}
border.color: "transparent"
}
}
Loading

0 comments on commit 19c593f

Please sign in to comment.