mirror of
https://github.com/jwetzell/QControlKit.git
synced 2026-07-26 10:38:54 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ceb18307f6 | |||
| 2f5ce281d3 | |||
| 7b6ed09ced | |||
| 486af45d53 | |||
| e5d09538ab | |||
| 1a0ccc8763 | |||
| fce3eab8d7 | |||
| 2176ca4488 | |||
| 57ca80df77 | |||
| 974d14156f | |||
| 92a44d95d4 | |||
| 498d2a41f9 | |||
| 730e7bc554 | |||
| 1eb8e0c42b | |||
| 69b8210362 | |||
| 1deca3e7f3 | |||
| ff498f83d0 | |||
| 19794f40a7 | |||
| 6057105f44 | |||
| 66ae48cf33 | |||
| 9601d59d81 | |||
| 406bcc9e7f | |||
| 015913b2a1 | |||
| 6f20d7ba19 | |||
| 6dd0f766e8 | |||
| bd099a2162 | |||
| effd9d3f92 | |||
| e7f60ba782 | |||
| cd6115bfbc | |||
| e455b42b72 | |||
| 6f683ba6e8 | |||
| 3656a9f9b7 | |||
| c750297cf5 | |||
| b639dc401f | |||
| 96adbadbd7 |
@@ -18,7 +18,7 @@ jobs:
|
||||
- name: Publish NuGet
|
||||
# You may pin to the exact commit or the version.
|
||||
# uses: brandedoutcast/publish-nuget@c12b8546b67672ee38ac87bea491ac94a587f7cc
|
||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||
uses: alirezanet/publish-nuget@v3.0.4
|
||||
with:
|
||||
# Filepath of the project to be packaged, relative to root of repository
|
||||
PROJECT_FILE_PATH: QControlKit/QControlKit.csproj
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Joel Wetzell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -11,6 +11,7 @@
|
||||
public const string Cue = "Cue";
|
||||
public const string CueList = "Cue List";
|
||||
public const string Cart = "Cart";
|
||||
public const string CueCart = "Cue Cart";
|
||||
public const string Group = "Group";
|
||||
public const string Audio = "";
|
||||
public const string Mic = "Mic";
|
||||
@@ -46,73 +47,231 @@
|
||||
|
||||
public static class QOSCKey
|
||||
{
|
||||
public const string UID = "uniqueID";
|
||||
public const string Type = "type";
|
||||
public const string Parent = "parent";
|
||||
public const string Name = "name";
|
||||
public const string Number = "number";
|
||||
public const string Notes = "notes";
|
||||
public const string FileTarget = "fileTarget";
|
||||
public const string CueTargetNumber = "cueTargetNumber";
|
||||
public const string CurrentCueTarget = "currentCueTarget";
|
||||
public const string ColorName = "colorName";
|
||||
public const string Flagged = "flagged";
|
||||
public const string ActionElapsed = "actionElapsed";
|
||||
public const string AllowsEditingDuration = "allowsEditingDuration";
|
||||
public const string Armed = "armed";
|
||||
public const string AutoLoad = "autoLoad"; //implement on QCue
|
||||
|
||||
public const string CartPosition = "cartPosition";
|
||||
public const string ColorName = "colorName";
|
||||
public const string Cues = "cues";
|
||||
public const string CueTargetNumber = "cueTargetNumber";
|
||||
public const string CueTargetId = "cueTargetId"; //implement on QCue
|
||||
|
||||
public const string CurrentCueTarget = "currentCueTarget";
|
||||
public const string CurrentFileTime = "currentFileTime"; //implement on QCue
|
||||
public const string ContinueMode = "continueMode";
|
||||
public const string CurrentDuration = "currentDuration";
|
||||
|
||||
public const string DefaultName = "defaultName"; //implement on QCue
|
||||
public const string DisplayName = "displayName"; //implement on QCue
|
||||
public const string DuckLevel = "duckLevel"; //implement on QCue
|
||||
public const string DuckOthers = "duckOthers"; //implement on QCue
|
||||
public const string DuckTime = "duckTime"; //implement on QCue
|
||||
|
||||
|
||||
public const string FileTarget = "fileTarget";
|
||||
public const string Flagged = "flagged";
|
||||
public const string FadeAndStopOthers = "fadeAndStopOthers"; //implement on QCue
|
||||
public const string FadeAndStopOthersTime = "fadeAndStopOthersTime"; //implement on QCue
|
||||
|
||||
|
||||
public const string HasFileTargets = "hasFileTargets";
|
||||
public const string HasCueTargets = "hasCueTargets";
|
||||
|
||||
public const string IsActionRunning = "isActionRunning"; //implement on QCue
|
||||
public const string IsBroken = "isBroken";
|
||||
public const string IsLoaded = "isLoaded";
|
||||
public const string IsOverridden = "isOverridden";
|
||||
public const string IsPanicking = "isPanicking";
|
||||
public const string IsPaused = "isPaused";
|
||||
public const string IsRunning = "isRunning";
|
||||
public const string IsTailingOut = "isTailingOut";
|
||||
|
||||
public const string ListName = "listName";
|
||||
public const string LoadAt = "loadAt"; //implement on QCue
|
||||
public const string LoadActionAt = "loadActionAt"; //implement on QCue
|
||||
|
||||
public const string MaxTimeInCueSequence = "maxTimeInCueSequence"; //implement on QCue
|
||||
|
||||
|
||||
public const string Name = "name";
|
||||
public const string Notes = "notes";
|
||||
public const string Number = "number";
|
||||
|
||||
public const string PanicInTime = "panicInTime"; //implement on QCue
|
||||
public const string PreWait = "preWait";
|
||||
public const string PostWait = "postWait";
|
||||
public const string CurrentDuration = "currentDuration";
|
||||
public const string PercentPreWaitElapsed = "percentPreWaitElapsed";
|
||||
public const string PercentPostWaitElapsed = "percentPostWaitElapsed";
|
||||
public const string PercentActionElapsed = "percentActionElapsed";
|
||||
public const string PreWaitElapsed = "preWaitElapsed";
|
||||
public const string Parent = "parent";
|
||||
public const string PostWaitElapsed = "postWaitElapsed";
|
||||
public const string ActionElapsed = "actionElapsed";
|
||||
public const string GroupMode = "mode";
|
||||
public const string CartPosition = "cartPosition";
|
||||
public const string CartRows = "cartRows";
|
||||
public const string CartColumns = "cartColumns";
|
||||
public const string HasFileTargets = "hasFileTargets";
|
||||
public const string HasCueTargets = "hasCueTargets";
|
||||
public const string AllowsEditingDuration = "allowsEditingDuration";
|
||||
public const string IsPanicking = "isPanicking";
|
||||
public const string IsTailingOut = "isTailingOut";
|
||||
public const string IsRunning = "isRunning";
|
||||
public const string IsLoaded = "isLoaded";
|
||||
public const string IsPaused = "isPaused";
|
||||
public const string IsBroken = "isBroken";
|
||||
public const string IsOverridden = "isOverridden";
|
||||
public const string TranslationX = "translationX";
|
||||
public const string TranslationY = "translationY";
|
||||
public const string ScaleX = "scaleX";
|
||||
public const string ScaleY = "scaleY";
|
||||
public const string OriginX = "originX";
|
||||
public const string OriginY = "originY";
|
||||
public const string Quaternion = "quaternion";
|
||||
public const string SurfaceSize = "surfaceSize";
|
||||
public const string CueSize = "cueSize";
|
||||
public const string PreserveAspectRatio = "preserveAspectRatio";
|
||||
public const string Layer = "layer";
|
||||
public const string Patch = "patch";
|
||||
public const string PatchList = "patchList";
|
||||
public const string SurfaceList = "surfaceList";
|
||||
public const string Cues = "cues";
|
||||
public const string Children = "children";
|
||||
public const string ListName = "listName";
|
||||
public const string SurfaceID = "surfaceID";
|
||||
public const string FullSurface = "fullSurface";
|
||||
public const string Opacity = "opacity";
|
||||
public const string RotationZ = "rotationZ";
|
||||
public const string RotationY = "rotationY";
|
||||
public const string RotationX = "rotationX";
|
||||
public const string PlaybackPositionId = "playbackPositionId";
|
||||
|
||||
|
||||
public const string StartNextCueWhenSliceEnds = "startNextCueWhenSliceEnds";
|
||||
public const string StopTargetWhenSliceEnds = "stopTargetWhenSliceEnds";
|
||||
public const string SliderLevel = "sliderLevel";
|
||||
public const string SecondTriggerAction = "secondTriggerAction"; //implement on QCue
|
||||
public const string SecondTriggerOnRelease = "secondTriggerOnRelease"; //implement on QCue
|
||||
public const string SoloCueInTime = "soloCueInTime"; //implement on QCue
|
||||
|
||||
|
||||
public const string TempCueTargetNumber = "tempCueTargetNumber"; //implement on QCue
|
||||
public const string TempCueTargetId = "tempCueTargetId"; //implement on QCue
|
||||
public const string TempDuration = "tempDuration"; //implement on QCue
|
||||
public const string Type = "type";
|
||||
|
||||
public const string UID = "uniqueID";
|
||||
public const string UniqueID = "uniqueID";
|
||||
public const string ValuesForKeys = "valuesForKeys";
|
||||
public const string ValuesForKeysWithArguments = "valuesForKeysWithArguments";
|
||||
|
||||
//Group Cue Keys
|
||||
public const string CartColumns = "cartColumns";
|
||||
public const string CartRows = "cartRows";
|
||||
public const string Children = "children";
|
||||
public const string Go = "go";
|
||||
public const string Mode = "mode";
|
||||
public const string MoveCartCue = "moveCartCue";
|
||||
public const string PlaybackPositionId = "playbackPositionId";
|
||||
public const string PlaybackPosition = "playbackPosition"; //Implement on Group Cue
|
||||
public const string PlayheadId = "playheadId"; //Implement on Group Cue
|
||||
public const string Playhead = "playhead"; //Implement on Group Cue
|
||||
|
||||
//Audio Cue Keys
|
||||
public const string DoFade = "doFade"; //Implement on Audio Cue and Video Cue
|
||||
public const string DoPitchShift = "doPitchShift"; //Implement on Audio Cue and Video Cue
|
||||
public const string EndTime = "endTime"; //Implement on Audio Cue and Video Cue
|
||||
public const string Gang = "gang"; //Implement on Audio Cue and Video Cue
|
||||
public const string InfiniteLoop = "infiniteLoop"; //Implement on Audio Cue and Video Cue
|
||||
public const string Level = "level"; //Implement on Audio Cue and Video Cue
|
||||
public const string Levels = "levels"; //Implement on Audio Cue and Video Cue
|
||||
public const string LiveAverageLevel = "liveAverageLevel"; //Implement on Audio Cue and Video Cue
|
||||
public const string LockFadeToCue = "lockFadeToCue"; //Implement on Audio Cue and Video Cue
|
||||
public const string NumChannelsIn = "numChannelsIn"; //Implement on Audio Cue and Video Cue
|
||||
public const string PatchList = "patchList"; //Implement on Audio Cue and Video Cue
|
||||
public const string PlayCount = "playCount"; //Implement on Audio Cue and Video Cue
|
||||
public const string LiveRate = "liveRate"; //Implement on Audio Cue and Video Cue
|
||||
public const string SliceMarkers = "sliceMarkers"; //Implement on Audio Cue and Video Cue
|
||||
public const string SliceMarker = "sliceMarker"; //Implement on Audio Cue and Video Cue
|
||||
public const string Time = "time"; //Implement on Audio Cue related to slicemarker and Video Cue
|
||||
public const string LastSlicePlayCount = "lastSlicePlayCount"; //Implement on Audio Cue and Video Cue
|
||||
public const string LastSliceInfiniteLoop = "lastSliceInfiniteLoop"; //Implement on Audio Cue and Video Cue
|
||||
public const string SliderLevel = "sliderLevel"; // Implement on Video Cue
|
||||
public const string SliderLevels = "sliderLevels"; //Implement on Audio Cue and Video Cue
|
||||
public const string StartTime = "startTime"; // Implement on Audio Cue and Video Cue
|
||||
|
||||
//Mic Cue Keys
|
||||
public const string ChannelOffset = "channelOffset"; //Implement on Mic Cue
|
||||
public const string Channels = "channels"; //Implement on Mic Cue
|
||||
|
||||
//Video Cue Keys
|
||||
public const string CueSize = "cueSize"; //Implement on Video Cue
|
||||
public const string DoEffect = "doEffect"; //Implement on Video Cue
|
||||
public const string EffectIndex = "effectIndex"; //Implement on Video Cue
|
||||
public const string EffectSet = "effectSet"; //Implement on Video Cue
|
||||
public const string liveEffectSet = "liveEffectSet"; //Implement on Video Cue
|
||||
public const string FullSurface = "fullSurface"; //Implement on Video Cue
|
||||
public const string HoldLastFrame = "holdLastFrame"; //Implement on Video Cue
|
||||
public const string Layer = "layer"; //Implement on Video Cue
|
||||
public const string Opacity = "opacity"; //Implement on Video Cue
|
||||
public const string OriginX = "originX"; //Implement on Video Cue
|
||||
public const string OriginY = "originY"; //Implement on Video Cue
|
||||
public const string Origin = "origin"; //Implement on Video Cue
|
||||
public const string PreserveAspectRatio = "preserveAspectRatio"; //Implement on Video Cue
|
||||
public const string Quaternion = "quaternion"; //Implement on Video Cue
|
||||
public const string RotateZ = "rotateZ"; //Implement on Video Cue
|
||||
public const string RotateY = "rotateY"; //Implement on Video Cue
|
||||
public const string RotateX = "rotateX"; //Implement on Video Cue
|
||||
public const string LiveRotation = "liveRotation"; //Implement on Video Cue
|
||||
public const string XAxis = "Xaxis"; //Implement on Video Cue
|
||||
public const string YAxis = "Yaxis"; //Implement on Video Cue
|
||||
public const string ZAxis = "Zaxis"; //Implement on Video Cue
|
||||
public const string X = "x"; //Implement on Video Cue
|
||||
public const string Y = "y"; //Implement on Video Cue
|
||||
public const string Z = "z"; //Implement on Video Cue
|
||||
public const string ScaleX = "scaleX"; //Implement on Video Cue
|
||||
public const string LiveScaleX = "liveScaleX"; //Implement on Video Cue
|
||||
public const string ScaleY = "scaleY"; //Implement on Video Cue
|
||||
public const string LiveScaleY = "liveScaleY"; //Implement on Video Cue
|
||||
public const string Scale = "scale"; //Implement on Video Cue
|
||||
public const string LiveScale = "liveScale"; //Implement on Video Cue
|
||||
public const string SurfaceID = "surfaceID"; //Implement on Video Cue
|
||||
public const string SurfaceList = "surfaceList"; //Implement on Video Cue
|
||||
public const string SurfaceName = "surfaceName"; //Implement on Video Cue
|
||||
public const string SurfaceSize = "surfaceSize"; //Implement on Video Cue
|
||||
public const string TranslationX = "translationX";
|
||||
public const string LiveTranslationX = "liveTranslationX"; //Implement on Video Cue
|
||||
public const string TranslationY = "translationY";
|
||||
public const string LiveTranslationY = "liveTranslationY"; //Implement on Video Cue
|
||||
public const string Translation = "translation"; //Implement on Video Cue
|
||||
public const string LiveTranslation = "liveTranslation"; //Implement on Video Cue
|
||||
|
||||
//Camera Cue Keys (Extension of Video Cue
|
||||
public const string CameraPatch = "cameraPatch";
|
||||
|
||||
//Text Cue Keys
|
||||
public const string FixedWidth = "fixedWidth"; //Implement on Text Cue
|
||||
public const string Text = "text"; //Implement on Text Cue
|
||||
public const string LiveText = "liveText"; //Implement on Text Cue
|
||||
public const string Format = "format"; //Implement on Text Cue
|
||||
public const string Alignment = "alignment"; //Implement on Text Cue
|
||||
public const string FontFamily = "fontFamily"; //Implement on Text Cue
|
||||
public const string FontStyle = "fontStyle"; //Implement on Text Cue
|
||||
public const string FontFamilyAndStyle = "fontFamilyAndStyle"; //Implement on Text Cue
|
||||
public const string FontName = "fontName"; //Implement on Text Cue
|
||||
public const string FontSize = "fontSize"; //Implement on Text Cue
|
||||
public const string LineSpacing = "lineSpacing"; //Implement on Text Cue
|
||||
public const string Color = "color"; //Implement on Text Cue
|
||||
public const string BackgroundColor = "backgroundColor"; //Implement on Text Cue
|
||||
public const string StrikethroughColor = "strikethroughColor"; //Implement on Text Cue
|
||||
public const string UnderlineColor = "underlineColor"; //Implement on Text Cue
|
||||
public const string StrikethroughStyle = "strikethroughStyle"; //Implement on Text Cue
|
||||
public const string UnderlineStyle = "underlineStyle"; //Implement on Text Cue
|
||||
public const string OutputSize = "outputSize"; //Implement on Text Cue
|
||||
|
||||
//Light Cue Keys
|
||||
public const string AlwaysCollate = "alwaysCollate";
|
||||
public const string CollateAndStart = "collateAndStart";
|
||||
public const string LightCommandText = "lightCommandText";
|
||||
public const string Prune = "prune";
|
||||
public const string PruneCommands = "pruneCommands";
|
||||
public const string RemoveLightCommandsMatching = "removeLightCommandsMatching";
|
||||
public const string ReplaceLightCommand = "replaceLightCommand";
|
||||
public const string SafeSort = "safeSort";
|
||||
public const string SafeSortCommands = "safeSortCommands";
|
||||
public const string SetLight = "setLight";
|
||||
public const string UpdateLightCommand = "updateLightCommand";
|
||||
|
||||
//Fade Cue Keys
|
||||
//Network Cue Keys
|
||||
public const string CustomString = "customString";
|
||||
public const string MessageType = "messageType";
|
||||
public const string QLabCommand = "qlabCommand";
|
||||
public const string QLabCueNumber = "qlabCueNumber";
|
||||
public const string QLabCueParameters = "qlabCueParameters";
|
||||
public const string RawString = "rawString";
|
||||
public const string UdpString = "udpString";
|
||||
|
||||
//MIDI Cue Keys
|
||||
|
||||
//Midi File Cue Keys
|
||||
public const string Patch = "patch"; //Implement on Audio Cue and Video Cue and Network Cue
|
||||
public const string Rate = "rate"; //Implement on Audio Cue and Video Cue
|
||||
|
||||
//Devamp Cue Keys
|
||||
public const string startNextCueWhenSliceEnds = "startNextCueWhenSliceEnds";
|
||||
public const string stopTargetWhenSliceEnds = "stopTargetWhenSliceEnds";
|
||||
|
||||
//Script Cue Keys
|
||||
public const string ScriptSource = "scriptSource";
|
||||
|
||||
|
||||
// v3
|
||||
public const string Duration = "duration";
|
||||
public const string FullScreen = "fullScreen";
|
||||
public const string FullScreen = "fullScreen"; //Implement on Video Cue
|
||||
|
||||
}
|
||||
|
||||
public static class QIdentifiers
|
||||
@@ -130,6 +289,17 @@
|
||||
public const string Error = "error";
|
||||
}
|
||||
|
||||
public static class QConnectionRole
|
||||
{
|
||||
public const string View = "view";
|
||||
public const string ViewEdit = "view|edit";
|
||||
public const string ViewEditControl = "view|edit|control";
|
||||
public const string ViewControl = "view|control";
|
||||
public const string EditControl = "edit|control";
|
||||
public const string Edit = "edit";
|
||||
public const string Control = "control";
|
||||
}
|
||||
|
||||
public static class QColorName
|
||||
{
|
||||
public const string Red = "red";
|
||||
@@ -143,16 +313,191 @@
|
||||
public const string Default = "default"; //is this even an option?
|
||||
}
|
||||
|
||||
enum QFadeMode
|
||||
public enum QTriggerAction
|
||||
{
|
||||
Nothing = 0,
|
||||
Panics = 1,
|
||||
Stops = 2,
|
||||
Hard_Stops = 3,
|
||||
Hard_Stops_And_Restarts = 4
|
||||
}
|
||||
|
||||
public enum QFadeMode
|
||||
{
|
||||
Absolute = 0,
|
||||
Relative = 1
|
||||
}
|
||||
|
||||
enum QContinueMode
|
||||
public enum QContinueMode
|
||||
{
|
||||
NoContinue = 0,
|
||||
AutoContinue = 1,
|
||||
AutoFollow = 2
|
||||
}
|
||||
|
||||
public enum QMSCCommand
|
||||
{
|
||||
GO = 1,
|
||||
STOP = 2,
|
||||
RESUME = 3,
|
||||
TIMED_GO = 4,
|
||||
LOAD = 5,
|
||||
SET = 6,
|
||||
FIRE = 7,
|
||||
ALL_OFF =8,
|
||||
RESTORE = 9,
|
||||
RESET = 10,
|
||||
GO_OFF = 11,
|
||||
GO_OR_JAM_CLOCK = 16,
|
||||
STANDBY_PLUSS = 17,
|
||||
STANDBY_MINUS = 18,
|
||||
SEQUENCE_PLUS = 19,
|
||||
SEQUENCE_MINUS = 20,
|
||||
START_CLOCK = 21,
|
||||
STOP_CLOCK = 22,
|
||||
ZERO_CLOCK = 23,
|
||||
SET_CLOCK = 24,
|
||||
MTC_CHASE_ON = 25,
|
||||
MTC_CHASE_OFF = 26,
|
||||
OPEN_CUE_LIST = 27,
|
||||
CLOSE_CUE_LIST = 28,
|
||||
OPEN_CUE_PATH = 29,
|
||||
CLOSE_CUE_PATH = 30,
|
||||
}
|
||||
|
||||
public enum QMSCCommandFormat
|
||||
{
|
||||
All_Types = 127,
|
||||
Lighting_General = 1,
|
||||
Moving_Lights = 2,
|
||||
Color_Changers = 3,
|
||||
Strobes = 4,
|
||||
Lasers = 5,
|
||||
Chasers = 6,
|
||||
Sound_General = 16,
|
||||
Music = 17,
|
||||
CD_Players = 18,
|
||||
EPROM_Playback = 19,
|
||||
Audio_Tape_Machines = 20,
|
||||
Intercoms = 21,
|
||||
Amplifiers = 22,
|
||||
Audio_Effects_Devices = 23,
|
||||
Equalizers = 24,
|
||||
Machinery_General = 32,
|
||||
Rigging = 33,
|
||||
Flys = 34,
|
||||
Lifts = 35,
|
||||
Turntables = 36,
|
||||
Trusses = 37,
|
||||
Robots = 38,
|
||||
Animation = 39,
|
||||
Floats = 40,
|
||||
Breakaways = 41,
|
||||
Barges = 42,
|
||||
Video_General = 48,
|
||||
Video_Tape_Machines = 49,
|
||||
Video_Cassette_Machines = 50,
|
||||
Video_Disc_Players = 51,
|
||||
Video_Switchers = 52,
|
||||
Video_Effects = 53,
|
||||
Video_Character_Generators = 54,
|
||||
Video_Still_Stores = 55,
|
||||
Video_Monitors = 56,
|
||||
Projection_General = 64,
|
||||
Film_Projectors = 65,
|
||||
Slide_Projectors = 66,
|
||||
Video_Projectors = 67,
|
||||
Dissolvers = 68,
|
||||
Shutter_Controls = 69,
|
||||
Process_Control_General = 80,
|
||||
Hydraulic_Oil = 81,
|
||||
H2O = 82,
|
||||
CO2 = 83,
|
||||
Compressed_Air = 84,
|
||||
Natural_Gas = 85,
|
||||
Fog = 86,
|
||||
Smoke = 87,
|
||||
Cracked_Haze = 88,
|
||||
Pyrotechnics_General = 96,
|
||||
Fireworks = 97,
|
||||
Explosions = 98,
|
||||
Flame = 99,
|
||||
Smoke_Pots = 100
|
||||
}
|
||||
|
||||
public enum QNetworkMessageType
|
||||
{
|
||||
QLAB = 1,
|
||||
OSC = 2,
|
||||
UDP = 3
|
||||
}
|
||||
|
||||
public enum QNetworkQLabCommand
|
||||
{
|
||||
start = 1,
|
||||
stop = 2,
|
||||
hardStop = 3,
|
||||
pause = 4,
|
||||
resume = 5,
|
||||
togglePause = 6,
|
||||
load = 7,
|
||||
preview = 8,
|
||||
reset = 9,
|
||||
panic = 10,
|
||||
number = 11,
|
||||
name = 12,
|
||||
notes = 13,
|
||||
cueTargetNumber = 14,
|
||||
preWait = 15,
|
||||
duration = 16,
|
||||
postWait = 17,
|
||||
continueMode = 18,
|
||||
flagged = 19,
|
||||
armed = 20,
|
||||
colorName = 21
|
||||
}
|
||||
|
||||
public enum QRotationType
|
||||
{
|
||||
THREE_D = 0,
|
||||
X = 1,
|
||||
Y = 2,
|
||||
Z = 3
|
||||
}
|
||||
|
||||
public enum QVideoEffect
|
||||
{
|
||||
Color_Controls = 1,
|
||||
Exposure = 2,
|
||||
Gamma = 3,
|
||||
Sepia_Monochrome = 4,
|
||||
Min_Max_Invert = 5,
|
||||
White_point = 6,
|
||||
Box_Disc_Gaussian_Blurs = 7,
|
||||
Motion_Blur = 8,
|
||||
Sharpen_Luminance = 9,
|
||||
Unsharp_Mask = 10,
|
||||
Zoom_Blur = 11,
|
||||
Pixellation = 12,
|
||||
Screen = 13,
|
||||
Bloom_and_Gloom = 14,
|
||||
CMYK_Halftone = 15,
|
||||
Color_Posterize = 16,
|
||||
Crystallize_and_Pointillize = 17,
|
||||
Edge_Work = 18,
|
||||
Kaleidoscope = 1,
|
||||
Median_and_Comic_Effect = 19,
|
||||
Noise_Reduction = 20,
|
||||
Circle_Splash_Hole_Distortion = 21,
|
||||
Pinch_Bump_Distortion = 22,
|
||||
Torus_Lens_Distortion = 23,
|
||||
Twirl_Circular_Wrap_Vortex = 24,
|
||||
Glass_Lozenge = 25,
|
||||
Op_Tile = 26,
|
||||
Perspective_Tile = 27,
|
||||
Quad_Tiles = 28,
|
||||
Reflected_Tiles = 29,
|
||||
Rotated_Tiles = 30,
|
||||
Titles = 31
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using QControlKit.Constants;
|
||||
|
||||
namespace QControlKit.Cue
|
||||
{
|
||||
public class QDevampCue : QCue
|
||||
{
|
||||
public bool startNextCueWhenSliceEnds
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey(QOSCKey.startNextCueWhenSliceEnds);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.startNextCueWhenSliceEnds);
|
||||
}
|
||||
}
|
||||
|
||||
public bool stopTargetWhenSliceEnds
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey(QOSCKey.stopTargetWhenSliceEnds);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.stopTargetWhenSliceEnds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using QControlKit.Constants;
|
||||
|
||||
namespace QControlKit.Cue
|
||||
{
|
||||
public class QGroupCue : QCue
|
||||
{
|
||||
public int cartColumns
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)propertyForKey(QOSCKey.CartColumns);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.CartColumns);
|
||||
}
|
||||
}
|
||||
|
||||
public int cartRows
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)propertyForKey(QOSCKey.CartRows);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.CartRows);
|
||||
}
|
||||
}
|
||||
|
||||
public List<QCue> children
|
||||
{
|
||||
get
|
||||
{
|
||||
return cues;
|
||||
}
|
||||
}
|
||||
|
||||
public void go()
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.Go}");
|
||||
}
|
||||
|
||||
public int mode
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)propertyForKey(QOSCKey.Mode);
|
||||
}
|
||||
set
|
||||
{
|
||||
if(value > 0 && value < 5)
|
||||
{
|
||||
setProperty(value, QOSCKey.Mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void moveCartCue(QCue cart, int row, int column)
|
||||
{
|
||||
if(cart.type.Equals(QCueType.CueCart) || cart.type.Equals(QCueType.Cart))
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.MoveCartCue}/{cart.uid}", row, column);
|
||||
}
|
||||
}
|
||||
|
||||
public string playhead
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.Playhead).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.Playhead);
|
||||
}
|
||||
}
|
||||
|
||||
public string playheadId
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.PlayheadId).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.PlayheadId);
|
||||
}
|
||||
}
|
||||
|
||||
public string playbackPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.PlaybackPosition).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.PlaybackPosition);
|
||||
}
|
||||
}
|
||||
|
||||
public string playbackPositionId
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.PlaybackPositionId).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.PlaybackPositionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using QControlKit.Constants;
|
||||
|
||||
namespace QControlKit.Cue
|
||||
{
|
||||
public class QLightCue : QCue
|
||||
{
|
||||
public bool alwaysCollate
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey(QOSCKey.AlwaysCollate);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.AlwaysCollate);
|
||||
}
|
||||
}
|
||||
|
||||
public string lightCommandText
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.LightCommandText).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.LightCommandText);
|
||||
}
|
||||
}
|
||||
|
||||
public void collateAndStart()
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.CollateAndStart}");
|
||||
}
|
||||
|
||||
public void prune()
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.Prune}");
|
||||
}
|
||||
|
||||
public void pruneCommands()
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.PruneCommands}");
|
||||
}
|
||||
|
||||
public void removeLightCommandsMatching(string match)
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.RemoveLightCommandsMatching}", match);
|
||||
}
|
||||
|
||||
public void replaceLightCommand(string oldCommand, string newCommand)
|
||||
{
|
||||
if(this.workspace.versionParts[0] == "4" && int.Parse(this.workspace.versionParts[1]) >= 4)
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.ReplaceLightCommand}", oldCommand, newCommand);
|
||||
}
|
||||
else
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.UpdateLightCommand}", oldCommand, newCommand);
|
||||
}
|
||||
}
|
||||
|
||||
public void safeSort()
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.SafeSort}");
|
||||
}
|
||||
|
||||
public void safeSortCommands()
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.SafeSortCommands}");
|
||||
}
|
||||
|
||||
public void setLight(string light, object setting)
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.SetLight}", light, setting);
|
||||
}
|
||||
|
||||
public void updateLightCommand(string oldCommand, string newCommand)
|
||||
{
|
||||
if (int.Parse(this.workspace.versionParts[0]) >= 4 && int.Parse(this.workspace.versionParts[1]) >= 4)
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.ReplaceLightCommand}", oldCommand, newCommand);
|
||||
}
|
||||
else
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/{QOSCKey.UpdateLightCommand}", oldCommand, newCommand);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using QControlKit.Constants;
|
||||
|
||||
namespace QControlKit.Cue
|
||||
{
|
||||
public class QMicCue : QCue
|
||||
{
|
||||
public int channelOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)propertyForKey(QOSCKey.ChannelOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public int channels
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)propertyForKey(QOSCKey.Channels);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.Channels);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultLevels()
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/setDefaultLevels");
|
||||
}
|
||||
|
||||
public void setSilientLevels()
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/setSilentLevels");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using QControlKit.Constants;
|
||||
|
||||
namespace QControlKit.Cue
|
||||
{
|
||||
public class QMidiFileCue :QCue
|
||||
{
|
||||
public bool patch
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey(QOSCKey.Patch);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.Patch);
|
||||
}
|
||||
}
|
||||
|
||||
public bool rate
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey(QOSCKey.Rate);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.Rate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using QControlKit.Constants;
|
||||
|
||||
namespace QControlKit.Cue
|
||||
{
|
||||
public class QNetworkCue : QCue
|
||||
{
|
||||
public string customString
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.CustomString).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.CustomString);
|
||||
}
|
||||
}
|
||||
|
||||
public QNetworkMessageType messageType
|
||||
{
|
||||
get
|
||||
{
|
||||
return (QNetworkMessageType)propertyForKey(QOSCKey.MessageType);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.MessageType);
|
||||
}
|
||||
}
|
||||
|
||||
public QNetworkQLabCommand qlabCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return (QNetworkQLabCommand)propertyForKey(QOSCKey.QLabCommand);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.QLabCommand);
|
||||
}
|
||||
}
|
||||
|
||||
public int patch
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)propertyForKey(QOSCKey.Patch);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.Patch);
|
||||
}
|
||||
}
|
||||
|
||||
public string qlabCueNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.QLabCueNumber).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.QLabCueNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public string qlabCueParameters
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.QLabCueParameters).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.QLabCueParameters);
|
||||
}
|
||||
}
|
||||
|
||||
public string rawString
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.RawString).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.RawString);
|
||||
}
|
||||
}
|
||||
|
||||
public string udpString
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.UdpString).ToString();
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.UdpString);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using QControlKit.Constants;
|
||||
|
||||
namespace QControlKit.Cue
|
||||
{
|
||||
public class QScriptCue : QCue
|
||||
{
|
||||
public string scriptSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.ScriptSource).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public void compileSource()
|
||||
{
|
||||
workspace.sendMessage($"/cue_id/{this.uid}/compileSource");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using QControlKit.Constants;
|
||||
|
||||
namespace QControlKit.Cue
|
||||
{
|
||||
public class QTextCue : QCue
|
||||
{
|
||||
|
||||
public int fixedWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)propertyForKey(QOSCKey.FixedWidth);
|
||||
}
|
||||
set
|
||||
{
|
||||
if(fixedWidth > 0)
|
||||
{
|
||||
setProperty(value, QOSCKey.FixedWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
public string text
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.Text).ToString();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.Text);
|
||||
}
|
||||
}
|
||||
|
||||
public string liveText
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.LiveText).ToString();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.LiveText);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO:
|
||||
/* https://qlab.app/docs/v4/scripting/osc-dictionary-v4/#text-cue-methods
|
||||
* /cue/{cue_number}/text/format {json_string}
|
||||
* /cue/{cue_number}/text/format/alignment {alignment}
|
||||
* /cue/{cue_number}/text/format/fontFamily
|
||||
* /cue/{cue_number}/text/format/fontStyle
|
||||
* /cue/{cue_number}/text/format/fontFamilyAndStyle {family} {style}
|
||||
* /cue/{cue_number}/text/format/fontName {name}
|
||||
* /cue/{cue_number}/text/format/fontSize {number}
|
||||
* /cue/{cue_number}/text/format/lineSpacing {number}
|
||||
* /cue/{cue_number}/text/format/color {red} {green} {blue} {alpha}
|
||||
* /cue/{cue_number}/text/format/backgroundColor {red} {green} {blue} {alpha}
|
||||
* /cue/{cue_number}/text/format/strikethroughColor {red} {green} {blue} {alpha}
|
||||
* /cue/{cue_number}/text/format/underlineColor {red} {green} {blue} {alpha}
|
||||
* /cue/{cue_number}/text/format/strikethroughStyle {style}
|
||||
* /cue/{cue_number}/text/format/underlineStyle {style}
|
||||
* /cue/{cue_number}/text/outputSize
|
||||
* /cue/{cue_number}/liveText/outputSize
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,8 @@ namespace QControlKit.Events
|
||||
|
||||
public class QWorkspaceConnectedArgs : EventArgs
|
||||
{
|
||||
|
||||
public string status { get; set; }
|
||||
public string data { get; set; }
|
||||
}
|
||||
|
||||
public class QWorkspaceDisconnectedArgs : EventArgs
|
||||
@@ -59,6 +60,7 @@ namespace QControlKit.Events
|
||||
public class QWorkspaceConnectionErrorArgs : EventArgs
|
||||
{
|
||||
public string status { get; set; }
|
||||
public string data { get; set; }
|
||||
}
|
||||
public class QQLabPreferencesUpdatedArgs : EventArgs
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace QControlKit.Events
|
||||
using System;
|
||||
|
||||
namespace QControlKit.Events
|
||||
{
|
||||
public delegate void QServerFoundHandler(object source, QServerFoundArgs args);
|
||||
public delegate void QServerLostHandler(object source, QServerLostArgs args);
|
||||
@@ -16,7 +18,6 @@
|
||||
public delegate void QWorkspaceConnectionErrorHandler(object source, QWorkspaceConnectionErrorArgs args);
|
||||
public delegate void QQLabPreferencesUpdatedHandler(object source, QQLabPreferencesUpdatedArgs args);
|
||||
|
||||
|
||||
public delegate void QCueUpdatedHandler(object source, QCueUpdatedArgs args);
|
||||
public delegate void QCuePropertiesUpdatedHandler(object source, QCuePropertiesUpdatedArgs args);
|
||||
public delegate void QCueListsUpdatesHandler(object source, QCueListsUpdatedArgs args);
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||
<LastUsedPlatform>AnyCPU</LastUsedPlatform>
|
||||
<publishUrl>bin/Release/netstandard2.0/publish</publishUrl>
|
||||
<DeleteExistingFiles>false</DeleteExistingFiles>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<SelfContained>false</SelfContained>
|
||||
<_IsPortable>true</_IsPortable>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
+13
-12
@@ -13,6 +13,8 @@ namespace QControlKit
|
||||
{
|
||||
public class QBrowser
|
||||
{
|
||||
private ILogger _log = Log.Logger.ForContext<QBrowser>();
|
||||
|
||||
public ObservableCollection<QServer> servers = new ObservableCollection<QServer>();
|
||||
|
||||
public event QServerFoundHandler ServerFound;
|
||||
@@ -26,11 +28,14 @@ namespace QControlKit
|
||||
|
||||
public async void ProbeForQLabInstances()
|
||||
{
|
||||
_log.Debug("probing for instances");
|
||||
|
||||
IReadOnlyList<IZeroconfHost> results = await
|
||||
ZeroconfResolver.ResolveAsync(QBonjour.TCPService,TimeSpan.FromSeconds(3));
|
||||
|
||||
foreach (var zeroconfHost in results)
|
||||
{
|
||||
_log.Debug($"found host {zeroconfHost.IPAddress}:{zeroconfHost.DisplayName}");
|
||||
foreach (var service in zeroconfHost.Services)
|
||||
{
|
||||
if (service.Key.Equals(QBonjour.TCPService))
|
||||
@@ -40,7 +45,7 @@ namespace QControlKit
|
||||
|
||||
if (server == null)
|
||||
{
|
||||
Log.Information($"[qbrowser] Found {zeroconfHost.DisplayName} : {zeroconfHost.IPAddress} : {service.Value.Port}");
|
||||
_log.Information($"Found {zeroconfHost.DisplayName} : {zeroconfHost.IPAddress} : {service.Value.Port}");
|
||||
QServer serverToAdd = new QServer(zeroconfHost.IPAddress, service.Value.Port);
|
||||
serverToAdd.name = zeroconfHost.DisplayName;
|
||||
serverToAdd.zeroconfHost = zeroconfHost;
|
||||
@@ -62,19 +67,14 @@ namespace QControlKit
|
||||
|
||||
foreach(var server in qServers)
|
||||
{
|
||||
bool serverToBeRemoved = true;
|
||||
foreach(var zeroconfHost in results){
|
||||
QServer existingServer = serverForAddress(zeroconfHost.IPAddress);
|
||||
if(server != null)
|
||||
{
|
||||
serverToBeRemoved = false;
|
||||
}
|
||||
}
|
||||
if (serverToBeRemoved)
|
||||
IZeroconfHost found = results.ToList().Find(x => x.IPAddress.Equals(server.host));
|
||||
|
||||
if (found == null)
|
||||
{
|
||||
_log.Information($"Lost {server.name} : {server.host} : {server.port} disconnecting");
|
||||
server.disconnect();
|
||||
_log.Verbose($"after server disconnect()");
|
||||
servers.Remove(server);
|
||||
Log.Information($"[qbrowser] Lost {server.name} : {server.host} : {server.port}");
|
||||
OnServerLost(server);
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,8 @@ namespace QControlKit
|
||||
|
||||
public void Close()
|
||||
{
|
||||
foreach(var server in servers)
|
||||
_log.Information($"Close requested");
|
||||
foreach (var server in servers)
|
||||
{
|
||||
server.disconnect();
|
||||
}
|
||||
|
||||
+31
-32
@@ -12,6 +12,8 @@ namespace QControlKit
|
||||
{
|
||||
public class QClient
|
||||
{
|
||||
private ILogger _log = Log.Logger.ForContext<QClient>();
|
||||
|
||||
TCPClient tcpClient;
|
||||
|
||||
public event QWorkspacesUpdatedHandler WorkspacesUpdated;
|
||||
@@ -35,7 +37,7 @@ namespace QControlKit
|
||||
public QClient(string host, int port)
|
||||
{
|
||||
tcpClient = new TCPClient(host, port);
|
||||
Log.Debug($"[client] setup connection to: <{host}:{port}>");
|
||||
_log.Debug($"setup connection to: <{host}:{port}>");
|
||||
tcpClient.MessageReceived += ProcessMessage;
|
||||
}
|
||||
|
||||
@@ -52,7 +54,7 @@ namespace QControlKit
|
||||
|
||||
public void disconnect()
|
||||
{
|
||||
Log.Debug($"[client] disconnecting from {tcpClient.Address}");
|
||||
_log.Information($"disconnecting from {tcpClient.Address}");
|
||||
tcpClient.Close();
|
||||
}
|
||||
|
||||
@@ -60,7 +62,6 @@ namespace QControlKit
|
||||
public void sendMessage(string address, params object[] args)
|
||||
{
|
||||
tcpClient.Send(new OscMessage(address, args));
|
||||
Log.Debug($"[client] send message {address} : {args}");
|
||||
}
|
||||
|
||||
private void ProcessMessage(object source, MessageEventArgs args)
|
||||
@@ -70,7 +71,7 @@ namespace QControlKit
|
||||
|
||||
if (message.IsReply)
|
||||
{
|
||||
JToken data = message.response;
|
||||
JToken data = message.data;
|
||||
|
||||
//special case, want to update cue properties
|
||||
if (message.IsReplyFromCue)
|
||||
@@ -84,26 +85,25 @@ namespace QControlKit
|
||||
string property = message.AddressParts.Last();
|
||||
if (property == null)
|
||||
return;
|
||||
if (property == QOSCKey.PlaybackPositionId)
|
||||
{
|
||||
OnCueListChangedPlaybackPosition(message.cueID, data.ToString());
|
||||
return;
|
||||
}
|
||||
//create object manually since single value replies don't have dictionaries
|
||||
JObject properties = new JObject();
|
||||
properties.Add(property, data);
|
||||
|
||||
OnCueUpdated(message.cueID, properties);
|
||||
if (property == QOSCKey.PlaybackPositionId)
|
||||
{
|
||||
OnCueListChangedPlaybackPosition(message.cueID, data.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning($"[client] unhandled reply from cue: Type: {data.Type} value: {message.response}");
|
||||
_log.Error($"unhandled reply from cue: Type: {data.Type} value: {message.data}");
|
||||
}
|
||||
|
||||
}
|
||||
else if (message.IsReplyFromCueLists)
|
||||
{
|
||||
OnCueListsUpdated(message.response);
|
||||
OnCueListsUpdated(message.data);
|
||||
}
|
||||
else if (message.IsWorkspacesInfo)
|
||||
{
|
||||
@@ -111,14 +111,14 @@ namespace QControlKit
|
||||
}
|
||||
else if (message.IsConnect)
|
||||
{
|
||||
if (message.response.ToString() == "ok")
|
||||
OnWorkspaceConnected();
|
||||
if (message.status.ToString().Equals("ok"))
|
||||
OnWorkspaceConnected(message.status.ToString(),message.data.ToString());
|
||||
else
|
||||
OnWorkspaceConnectionError(message.response.ToString());
|
||||
OnWorkspaceConnectionError(message.status.ToString(), message.data.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning($"[client] unhandled reply message: {message.address}");
|
||||
_log.Error($"unhandled reply message: {message.address}");
|
||||
}
|
||||
}
|
||||
else if(message.IsUpdate) {
|
||||
@@ -150,7 +150,6 @@ namespace QControlKit
|
||||
else if ( message.IsPreferencesUpdate)
|
||||
{
|
||||
//need to do checks for 4.2 or newer
|
||||
|
||||
string key = message.AddressParts.Last();
|
||||
if (key == null)
|
||||
return;
|
||||
@@ -162,76 +161,76 @@ namespace QControlKit
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning($"[client] unhandled update message: {message.address}");
|
||||
_log.Error($"unhandled update message: {message.address}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning($"[client] unhandled message: {message.address}");
|
||||
_log.Error($"unhandled message: {message.address}");
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnCueUpdated(string cueID, JToken properties)
|
||||
{
|
||||
Log.Debug($"[client] cue updated: {cueID}");
|
||||
_log.Debug($"cue updated: {cueID}");
|
||||
CueUpdated?.Invoke(this, new QCueUpdatedArgs { cueID = cueID, data = properties });
|
||||
}
|
||||
protected virtual void OnCueNeedsUpdated(string cueID)
|
||||
{
|
||||
Log.Debug($"[client] cue needs updated: {cueID}");
|
||||
_log.Debug($"cue needs updated: {cueID}");
|
||||
CueNeedsUpdated?.Invoke(this, new QCueNeedsUpdatedArgs { cueID = cueID });
|
||||
}
|
||||
|
||||
protected virtual void OnCueListsUpdated(JToken response)
|
||||
{
|
||||
Log.Debug($"[client] Cue Lists Updated");
|
||||
_log.Debug("Cue Lists Updated");
|
||||
CueListsUpdated?.Invoke(this, new QCueListsUpdatedArgs { data = response });
|
||||
}
|
||||
|
||||
protected virtual void OnCueListChangedPlaybackPosition(string cueListID, string cueID)
|
||||
{
|
||||
Log.Debug($"[client] CueList <{cueListID}> Playback Position Changed to <{cueID}>");
|
||||
_log.Debug($"CueList <{cueListID}> Playback Position Changed to <{cueID}>");
|
||||
CueListChangedPlaybackPosition?.Invoke(this, new QCueListChangedPlaybackPositionArgs { cueListID = cueListID, cueID = cueID });
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceUpdated()
|
||||
{
|
||||
//Log.Debug($"[client] Workspace Updated");
|
||||
_log.Debug($"Workspace Updated");
|
||||
WorkspaceUpdated?.Invoke(this, new QWorkspaceUpdatedArgs());
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceSettingsUpdated(string settingsType)
|
||||
{
|
||||
Log.Debug($"[client] Workspace Settings Updated");
|
||||
_log.Debug($"Workspace Settings Updated");
|
||||
WorkspaceSettingsUpdated?.Invoke(this, new QWorkspaceSettingsUpdatedArgs { settingsType = settingsType });
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceLightDashboardUpdated()
|
||||
{
|
||||
Log.Debug($"[client] Workspace Light Dashboard Updated");
|
||||
_log.Debug("Workspace Light Dashboard Updated");
|
||||
WorkspaceLightDashboardUpdated?.Invoke(this, new QWorkspaceLightDashboardUpdatedArgs());
|
||||
}
|
||||
|
||||
protected virtual void OnQLabPreferencesUpdated(string key)
|
||||
{
|
||||
Log.Debug($"[client] QLab Preferences Updated");
|
||||
_log.Debug("QLab Preferences Updated");
|
||||
QLabPreferencesUpdated?.Invoke(this, new QQLabPreferencesUpdatedArgs { key = key });
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceDisconnected()
|
||||
{
|
||||
Log.Debug($"[client] Workspace Disconnected");
|
||||
_log.Debug("Workspace Disconnected");
|
||||
WorkspaceDisconnected?.Invoke(this, new QWorkspaceDisconnectedArgs());
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceConnected()
|
||||
protected virtual void OnWorkspaceConnected(string status, string data)
|
||||
{
|
||||
WorkspaceConnected?.Invoke(this, new QWorkspaceConnectedArgs());
|
||||
WorkspaceConnected?.Invoke(this, new QWorkspaceConnectedArgs { status = status, data = data });
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceConnectionError(string status)
|
||||
protected virtual void OnWorkspaceConnectionError(string status, string data)
|
||||
{
|
||||
WorkspaceConnectionError?.Invoke(this, new QWorkspaceConnectionErrorArgs { status = status });
|
||||
WorkspaceConnectionError?.Invoke(this, new QWorkspaceConnectionErrorArgs { status = status, data = data });
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspacesUpdated(QMessage message)
|
||||
@@ -239,7 +238,7 @@ namespace QControlKit
|
||||
if(WorkspacesUpdated != null)
|
||||
{
|
||||
List<QWorkspaceInfo> workspaces = new List<QWorkspaceInfo>();
|
||||
foreach (var item in message.response)
|
||||
foreach (var item in message.data)
|
||||
{
|
||||
QWorkspaceInfo workspacefound = JsonConvert.DeserializeObject<QWorkspaceInfo>(item.ToString());
|
||||
workspaces.Add(workspacefound);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<Authors>Joel Wetzell</Authors>
|
||||
<Version>1.0.0-devel</Version>
|
||||
<PackOnBuild>true</PackOnBuild>
|
||||
<PackageVersion>0.0.17</PackageVersion>
|
||||
<PackageVersion>0.0.33</PackageVersion>
|
||||
<PackageId>QControlKit</PackageId>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<Summary>Unofficial C# port of Figure53's QLabKit.objc</Summary>
|
||||
@@ -15,11 +15,23 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Zeroconf" Version="3.4.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="TcpSharp" Version="1.2.0" />
|
||||
<PackageReference Include="Zeroconf" Version="3.5.11" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Constants\" />
|
||||
<Folder Include="Cue\" />
|
||||
<Folder Include="SharpOSC\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Cue\" />
|
||||
<None Remove="SharpOSC" />
|
||||
<None Remove="Zeroconf" />
|
||||
<None Remove="SharpOSC\" />
|
||||
<None Remove="SimpleTCP" />
|
||||
<None Remove="SuperSimpleTcp" />
|
||||
<None Remove="WatsonTcp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
+145
-88
@@ -12,12 +12,14 @@ namespace QControlKit
|
||||
{
|
||||
public class QCue : IComparable
|
||||
{
|
||||
private ILogger _log = Log.Logger.ForContext<QCue>();
|
||||
|
||||
public QWorkspace workspace;
|
||||
public Dictionary<string, object> cueData;
|
||||
public List<QCue> childCues;
|
||||
public Dictionary<string, QCue> childCuesUIDMap;
|
||||
|
||||
|
||||
public int sortIndex;
|
||||
public int nestLevel;
|
||||
|
||||
@@ -43,31 +45,6 @@ namespace QControlKit
|
||||
{
|
||||
init();
|
||||
this.workspace = workspace;
|
||||
|
||||
//this breaks things???
|
||||
//it definitely is in the original but somehow the recursion is not working as I expect..
|
||||
//but cue population still works without this as child cues are populated later
|
||||
|
||||
/*JToken children = dict[QOSCKey.Cues];
|
||||
if(children != null && children.Type == JTokenType.Array)
|
||||
{
|
||||
Log.Debug($"[cue] new cue being created with {children.Count()} childCues");
|
||||
foreach (var aChildDict in children)
|
||||
{
|
||||
string uid = (string)aChildDict[QOSCKey.UID];
|
||||
//Log.Debug($"[cue] childDict with uid: {uid} being processed");
|
||||
if (uid == null)
|
||||
continue;
|
||||
string name = dict[QOSCKey.UID].ToString();
|
||||
Log.Debug($"[cue] calling new cue from {name}");
|
||||
|
||||
//QCue child = new QCue(aChildDict, workspace);
|
||||
|
||||
*//*childCues.Add(child);
|
||||
childCuesUIDMap.Add(uid, child);*//*
|
||||
}
|
||||
}*/
|
||||
|
||||
updatePropertiesWithDictionary(dict);
|
||||
}
|
||||
|
||||
@@ -76,30 +53,6 @@ namespace QControlKit
|
||||
init();
|
||||
this.workspace = workspace;
|
||||
this.nestLevel = nestLevel + 1;
|
||||
//this breaks things???
|
||||
//it definitely is in the original but somehow the recursion is not working as I expect..
|
||||
//but cue population still works without this as child cues are populated later
|
||||
|
||||
/*JToken children = dict[QOSCKey.Cues];
|
||||
if(children != null && children.Type == JTokenType.Array)
|
||||
{
|
||||
Log.Debug($"[cue] new cue being created with {children.Count()} childCues");
|
||||
foreach (var aChildDict in children)
|
||||
{
|
||||
string uid = (string)aChildDict[QOSCKey.UID];
|
||||
//Log.Debug($"[cue] childDict with uid: {uid} being processed");
|
||||
if (uid == null)
|
||||
continue;
|
||||
string name = dict[QOSCKey.UID].ToString();
|
||||
Log.Debug($"[cue] calling new cue from {name}");
|
||||
|
||||
//QCue child = new QCue(aChildDict, workspace);
|
||||
|
||||
*//*childCues.Add(child);
|
||||
childCuesUIDMap.Add(uid, child);*//*
|
||||
}
|
||||
}*/
|
||||
|
||||
updatePropertiesWithDictionary(dict);
|
||||
}
|
||||
|
||||
@@ -186,7 +139,7 @@ namespace QControlKit
|
||||
childCues.Add(cue);
|
||||
childCuesUIDMap.Add(uid, cue);
|
||||
//some sorting of the childCues needs to be done? //TODO
|
||||
//reset sorting index
|
||||
//reset sorting index?
|
||||
}
|
||||
|
||||
public void removeChildCue(QCue cue) {
|
||||
@@ -210,7 +163,6 @@ namespace QControlKit
|
||||
|
||||
QCue cue = childCuesUIDMap[aUid];
|
||||
|
||||
//Log.Debug($"Removing Child Cue From {listName} : {cue.uid} + {cue.listName}");
|
||||
childCues.Remove(cue);
|
||||
childCuesUIDMap.Remove(aUid);
|
||||
}
|
||||
@@ -244,7 +196,14 @@ namespace QControlKit
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.Parent).ToString();
|
||||
if(propertyForKey(QOSCKey.Parent) != null)
|
||||
{
|
||||
return propertyForKey(QOSCKey.Parent).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
public string playbackPositionID {
|
||||
@@ -301,7 +260,14 @@ namespace QControlKit
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.ListName).ToString();
|
||||
if(propertyForKey(QOSCKey.ListName) == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return propertyForKey(QOSCKey.ListName).ToString();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
@@ -353,46 +319,39 @@ namespace QControlKit
|
||||
if (workspace.connectedToQLab3 || workspace.isOlderThanVersion("4.2.0"))
|
||||
return false;
|
||||
|
||||
bool overridden = (bool)propertyForKey(QOSCKey.IsOverridden);
|
||||
|
||||
if (overridden)
|
||||
return true;
|
||||
foreach (var cue in cues)
|
||||
{
|
||||
if (cue.IsOverridden)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return getBoolForKey(QOSCKey.IsOverridden);
|
||||
}
|
||||
}
|
||||
public bool IsBroken
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((bool)propertyForKey(QOSCKey.IsBroken))
|
||||
return true;
|
||||
foreach(var cue in cues)
|
||||
foreach (var cue in cues)
|
||||
{
|
||||
if (cue.IsBroken)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return getBoolForKey(QOSCKey.IsBroken);
|
||||
}
|
||||
}
|
||||
public bool IsRunning
|
||||
{
|
||||
get
|
||||
{
|
||||
bool running = (bool)propertyForKey(QOSCKey.IsRunning);
|
||||
|
||||
if (running)
|
||||
return true;
|
||||
foreach(var cue in cues)
|
||||
foreach (var cue in cues)
|
||||
{
|
||||
if (cue.IsRunning)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return getBoolForKey(QOSCKey.IsRunning);
|
||||
}
|
||||
}
|
||||
public bool IsTailingOut
|
||||
@@ -402,16 +361,13 @@ namespace QControlKit
|
||||
if (workspace.connectedToQLab3)
|
||||
return false;
|
||||
|
||||
bool tailingOut = (bool)propertyForKey(QOSCKey.IsTailingOut);
|
||||
|
||||
if (tailingOut)
|
||||
return true;
|
||||
foreach(var cue in cues)
|
||||
foreach (var cue in cues)
|
||||
{
|
||||
if (cue.IsTailingOut)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return getBoolForKey(QOSCKey.IsTailingOut);
|
||||
}
|
||||
}
|
||||
public bool IsPanicking
|
||||
@@ -421,16 +377,13 @@ namespace QControlKit
|
||||
if (workspace.connectedToQLab3)
|
||||
return false;
|
||||
|
||||
bool panicking = (bool)propertyForKey(QOSCKey.IsPanicking);
|
||||
|
||||
if (panicking)
|
||||
return true;
|
||||
foreach (var cue in cues)
|
||||
{
|
||||
if (cue.IsPanicking)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return getBoolForKey(QOSCKey.IsPanicking);
|
||||
}
|
||||
}
|
||||
public bool IsGroup
|
||||
@@ -571,6 +524,62 @@ namespace QControlKit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public float actionElapsed
|
||||
{
|
||||
get
|
||||
{
|
||||
object secs = propertyForKey(QOSCKey.ActionElapsed);
|
||||
if (secs != null)
|
||||
{
|
||||
return float.Parse(secs.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0F;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public QTriggerAction secondTriggerAction
|
||||
{
|
||||
get
|
||||
{
|
||||
return (QTriggerAction)propertyForKey(QOSCKey.SecondTriggerAction);
|
||||
}
|
||||
set
|
||||
{
|
||||
setProperty(value, QOSCKey.SecondTriggerAction);
|
||||
}
|
||||
}
|
||||
|
||||
public bool secondTriggerOnRelease
|
||||
{
|
||||
get
|
||||
{
|
||||
var val = (int)propertyForKey(QOSCKey.SecondTriggerOnRelease);
|
||||
if (val == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
setProperty(0, QOSCKey.SecondTriggerOnRelease);
|
||||
}
|
||||
else
|
||||
{
|
||||
setProperty(1, QOSCKey.SecondTriggerOnRelease);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO add quaternion property and setter
|
||||
public Size surfaceSize() { throw new NotImplementedException(); }
|
||||
public Size cueSize() { throw new NotImplementedException(); }
|
||||
@@ -638,14 +647,12 @@ namespace QControlKit
|
||||
JToken value = obj.Value;
|
||||
if (obj.Key.Equals(QOSCKey.Cues))
|
||||
{
|
||||
//Log.Debug($"Cues OSC Key found in update message...updating child cues");
|
||||
if (value.Type != JTokenType.Array)
|
||||
continue;
|
||||
updateChildCuesWithPropertiesArray(value, false);
|
||||
}
|
||||
else if(obj.Key.Equals(QOSCKey.Children) && IsGroup)
|
||||
{
|
||||
//Log.Debug($"Children OSC Key found in update message for {uid} ...updating child and removing deleted ones.");
|
||||
if (value.Type != JTokenType.Array)
|
||||
continue;
|
||||
updateChildCuesWithPropertiesArray(value, true);
|
||||
@@ -659,7 +666,6 @@ namespace QControlKit
|
||||
{
|
||||
cueUpdated = true;
|
||||
propertiesUpdated.Add(obj.Key);
|
||||
//Log.Debug($"[cue] cue property {obj.Key} updated with {obj.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -730,7 +736,8 @@ namespace QControlKit
|
||||
|
||||
if (needsSortChildCues)
|
||||
{
|
||||
//something about cues needing to be sorted?
|
||||
childCues.Sort((q1, q2)=> q1.sortIndex.CompareTo(q2.sortIndex));
|
||||
needsSortChildCues = false;
|
||||
}
|
||||
|
||||
return needsNotifyCueUpdated;
|
||||
@@ -787,6 +794,32 @@ namespace QControlKit
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool getBoolForKey(string key)
|
||||
{
|
||||
if (propertyForKey(key) != null)
|
||||
{
|
||||
object prop = propertyForKey(key);
|
||||
//_log.Warning($"{listName} IsBroken: {propertyForKey(QOSCKey.IsBroken).ToString()} {prop.GetType().ToString()}");
|
||||
if(prop.GetType() == typeof(Boolean)){
|
||||
return (bool)prop;
|
||||
}
|
||||
else if (prop.GetType() == typeof(JValue))
|
||||
{
|
||||
JValue value = (JValue)prop;
|
||||
return (bool)value.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public object propertyForKey(string key)
|
||||
{
|
||||
//TODO: implerment special key checks color, surfaceName, patchDescription,
|
||||
@@ -857,7 +890,7 @@ namespace QControlKit
|
||||
}
|
||||
else if (key.Equals(QOSCKey.Children))
|
||||
{
|
||||
Log.Debug($"Children Cues property updated for: {this.displayName} : {this.uid}");
|
||||
_log.Debug($"Children Cues property updated for: {this.displayName} : {this.uid}");
|
||||
}
|
||||
else if(key.Equals(QOSCKey.PlaybackPositionId))
|
||||
{
|
||||
@@ -873,8 +906,6 @@ namespace QControlKit
|
||||
else
|
||||
cueData.Remove(key);
|
||||
|
||||
//TODO: Cuelistchangedplaybackpositionid?
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -937,6 +968,20 @@ namespace QControlKit
|
||||
public void togglePause() { workspace.togglePauseCue(this); }
|
||||
public void preview() { workspace.previewCue(this); }
|
||||
public void panic() { workspace.panicCue(this); }
|
||||
public void playheadNext()
|
||||
{
|
||||
if (this.type == QCueType.CueList)
|
||||
{
|
||||
workspace.sendMessageForCue(this, "playhead/next");
|
||||
}
|
||||
}
|
||||
public void playheadPrevious()
|
||||
{
|
||||
if (this.type == QCueType.CueList)
|
||||
{
|
||||
workspace.sendMessageForCue(this, "playhead/previous");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -944,7 +989,19 @@ namespace QControlKit
|
||||
#region Event Handling
|
||||
void OnCuePropertiesUpdated(List<string> properties)
|
||||
{
|
||||
Log.Debug($"[cue] <{nonEmptyName}> properties have been updated.");
|
||||
_log.Verbose("OnCuePropertiesUpdated");
|
||||
if(parentID != null && parentID != "")
|
||||
{
|
||||
QCue parentCue = workspace.cueWithID(parentID);
|
||||
if(parentCue != null)
|
||||
{
|
||||
workspace.fetchBasicPropertiesForCue(workspace.cueWithID(parentID));
|
||||
}
|
||||
else
|
||||
{
|
||||
_log.Error($"parent cue with id: {parentID} can't be found this could be a problem");
|
||||
}
|
||||
}
|
||||
CuePropertiesUpdated?.Invoke(this, new QCuePropertiesUpdatedArgs { properties = properties });
|
||||
}
|
||||
#endregion
|
||||
@@ -960,7 +1017,7 @@ namespace QControlKit
|
||||
{
|
||||
string indent = new string(' ', level*2);
|
||||
|
||||
Log.Information($"{indent}\u00b7{displayName} - {uid}");
|
||||
_log.Information($"{indent}\u00b7{displayName} - {uid}");
|
||||
if (IsGroup)
|
||||
{
|
||||
level++;
|
||||
|
||||
+71
-13
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SharpOSC;
|
||||
|
||||
@@ -28,7 +29,32 @@ namespace QControlKit
|
||||
public bool IsReply { get { return OSCMessage.Address.StartsWith("/reply"); } }
|
||||
|
||||
// /reply/cue_id/1/action
|
||||
public bool IsReplyFromCue { get{ return OSCMessage.Address.StartsWith("/reply/cue_id"); } }
|
||||
public bool IsReplyFromCue {
|
||||
get {
|
||||
if (!IsReply)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//return OSCMessage.Address.StartsWith("/reply/cue_id");
|
||||
if (AddressParts.Length > 5)
|
||||
{
|
||||
// /reply/workspace/*/cue_id/*/*
|
||||
if (AddressParts[1].Equals("workspace") && AddressParts[3].Equals("cue_id")){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(AddressParts.Length > 2)
|
||||
{
|
||||
// /reply/cue_id/*/*
|
||||
if (AddressParts[1].Equals("cue_id"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool IsReplyFromCueLists { get { return IsReply && OSCMessage.Address.EndsWith("cueLists"); } }
|
||||
|
||||
public bool IsUpdate { get{ return OSCMessage.Address.StartsWith("/update"); } }
|
||||
@@ -103,6 +129,7 @@ namespace QControlKit
|
||||
return (parts.Length == 4 && parts[3].Equals("connect"));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
//host method
|
||||
@@ -114,12 +141,25 @@ namespace QControlKit
|
||||
|
||||
public string[] AddressParts { get { return address.Split(new char[] { '/' },StringSplitOptions.RemoveEmptyEntries); } }
|
||||
|
||||
public JToken response
|
||||
public JToken data
|
||||
{
|
||||
get
|
||||
{
|
||||
JObject responseObj = JObject.Parse((string)arguments[0]);
|
||||
return responseObj["data"];
|
||||
JObject dataObj = JObject.Parse((string)arguments[0]);
|
||||
return dataObj["data"];
|
||||
}
|
||||
}
|
||||
|
||||
public JToken status
|
||||
{
|
||||
get
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0)
|
||||
{
|
||||
JObject statusObj = JObject.Parse((string)arguments[0]);
|
||||
return statusObj["status"];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,23 +169,41 @@ namespace QControlKit
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsCueUpdate)
|
||||
{
|
||||
if (IsCueUpdate) {
|
||||
return AddressParts[4];
|
||||
}else if (IsPlaybackPositionUpdate)
|
||||
{
|
||||
} else if (IsPlaybackPositionUpdate) {
|
||||
//TODO: check string cast
|
||||
return arguments.Count > 0 ? (string)arguments[0] : null;
|
||||
}else if (IsReplyFromCue)
|
||||
{
|
||||
} else if (IsReplyFromCue) {
|
||||
|
||||
// /reply/workspace/*/cue_id/*/*
|
||||
if (AddressParts.Length > 5)
|
||||
{
|
||||
return AddressParts[4];
|
||||
}
|
||||
// /reply/cue_id/*/*
|
||||
return AddressParts[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override
|
||||
public string ToString()
|
||||
{
|
||||
string stringified = "";
|
||||
|
||||
stringified += $"\nAddress: {this.address}\nArguments: \n";
|
||||
|
||||
|
||||
for(int i = 0; i<this.arguments.Count; i++)
|
||||
{
|
||||
object argument = this.arguments[i];
|
||||
stringified += $"\targ {i + 1}: {argument.ToString()}\n";
|
||||
}
|
||||
return stringified;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+11
-5
@@ -10,11 +10,13 @@ namespace QControlKit
|
||||
{
|
||||
public class QServer
|
||||
{
|
||||
private ILogger _log = Log.Logger.ForContext<QServer>();
|
||||
|
||||
public event QServerUpdatedHandler ServerUpdated;
|
||||
public event QServerWorkspaceAddedHandler WorkspaceAdded;
|
||||
public event QServerWorkspaceRemovedHandler WorkspaceRemoved;
|
||||
|
||||
private QClient client;
|
||||
private QClient _client;
|
||||
|
||||
public string host { get; set; }
|
||||
public int port { get; set; }
|
||||
@@ -28,18 +30,21 @@ namespace QControlKit
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
|
||||
client = new QClient(host, port);
|
||||
_client = new QClient(host, port);
|
||||
client.WorkspacesUpdated += OnServerWorkspacesUpdated;
|
||||
|
||||
if (!client.connect())
|
||||
{
|
||||
Log.Error($"[server] unable to connect to QLab Server: {host}:{port}");
|
||||
_log.Error($"unable to connect to QLab Server: {host}:{port}");
|
||||
}
|
||||
}
|
||||
|
||||
public string description { get { return $"{name} - {host} - {port}"; } }
|
||||
|
||||
|
||||
public QClient client {
|
||||
get { return _client; }
|
||||
}
|
||||
|
||||
public void refreshWorkspaces()
|
||||
{
|
||||
client.sendMessage("/workspaces");
|
||||
@@ -111,11 +116,12 @@ namespace QControlKit
|
||||
|
||||
public void disconnect()
|
||||
{
|
||||
_log.Information($"disconnect requested for server <{name}>");
|
||||
foreach (var workspace in workspaces)
|
||||
{
|
||||
if (workspace.connected)
|
||||
{
|
||||
Log.Debug($"[server] Closing workspace <{workspace.name}> still connected to {name}");
|
||||
_log.Debug($"Closing workspace <{workspace.name}> still connected to {name}");
|
||||
workspace.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
+82
-82
@@ -1,11 +1,8 @@
|
||||
//TODO: workspace connection error handlers
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Timers;
|
||||
|
||||
using QControlKit.Events;
|
||||
using QControlKit.Constants;
|
||||
|
||||
@@ -13,6 +10,7 @@ namespace QControlKit
|
||||
{
|
||||
public class QWorkspace: IEquatable<QWorkspace>
|
||||
{
|
||||
private ILogger _log = Log.Logger.ForContext<QWorkspace>();
|
||||
|
||||
private QServer server;
|
||||
private QClient client;
|
||||
@@ -25,9 +23,6 @@ namespace QControlKit
|
||||
|
||||
private QCue root;
|
||||
|
||||
private Timer heartbeatTimer;
|
||||
private int heartbeatAttempts;
|
||||
|
||||
public bool defaultSendUpdatesOSC;
|
||||
|
||||
public string version;
|
||||
@@ -36,6 +31,8 @@ namespace QControlKit
|
||||
public event QWorkspaceUpdatedHandler WorkspaceUpdated;
|
||||
public event QCueListChangedPlaybackPositionHandler CueListChangedPlaybackPosition;
|
||||
public event QWorkspaceConnectionErrorHandler WorkspaceConnectionError;
|
||||
public event QWorkspaceDisconnectedHandler WorkspaceDisconnected;
|
||||
public event QWorkspaceConnectedHandler WorkspaceConnected;
|
||||
|
||||
private void Init()
|
||||
{
|
||||
@@ -68,7 +65,7 @@ namespace QControlKit
|
||||
|
||||
updateWithWorkspaceInfo(workspaceInfo);
|
||||
|
||||
client = new QClient(server.host, server.port);
|
||||
client = server.client;
|
||||
|
||||
client.WorkspaceConnected += OnWorkspaceConnected;
|
||||
client.WorkspaceConnectionError += OnWorkspaceConnectionError;
|
||||
@@ -79,7 +76,7 @@ namespace QControlKit
|
||||
client.CueUpdated += OnCueUpdated;
|
||||
|
||||
this.server = server;
|
||||
Log.Debug($"[workspace] <{name}> on {server.name} initialized.");
|
||||
_log.Debug($"<{name}> on <{server.name}> initialized.");
|
||||
}
|
||||
|
||||
//updateWithDictionary
|
||||
@@ -160,26 +157,29 @@ namespace QControlKit
|
||||
|
||||
public List<QCue> cueLists { get { return root.cues; } }
|
||||
public string fullNameWithCueList(QCue cueList) { return ""; }
|
||||
//TODO other convenience methods
|
||||
|
||||
public string[] versionParts { get { return version.Split('.'); } }
|
||||
public bool connectedToQLab3 { get { return versionParts[0] == "3"; } }
|
||||
public bool connectedToQLab4 { get { return versionParts[0] == "4"; } }
|
||||
public bool connectedToQLab5 { get { return versionParts[0] == "5"; } }
|
||||
|
||||
#region Connection/reconnection
|
||||
|
||||
public void connect(string passcode = null)
|
||||
{
|
||||
Log.Information($"[workspace] connecting to <{name}> @ {this.server.host}:{this.server.port}");
|
||||
_log.Information($"connecting to <{name}> @ {this.server.host}:{this.server.port}");
|
||||
|
||||
if(hasPasscode && passcode == null)
|
||||
{
|
||||
Log.Error($"[workspace] *** workspace <{name}> requires a passcode but none was supplied.");
|
||||
OnWorkspaceConnectionError(this, new QWorkspaceConnectionErrorArgs { status = "badpass" });
|
||||
_log.Error($"*** workspace <{name}> requires a passcode but none was supplied.");
|
||||
OnWorkspaceConnectionError(this, new QWorkspaceConnectionErrorArgs { status = QConnectionStatus.BadPass, data = "badpass" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!client.connect())
|
||||
{
|
||||
Log.Error($"[workspace] *** couldn't connect to server client is not connected.");
|
||||
_log.Error($"*** couldn't connect to server client is not connected.");
|
||||
OnWorkspaceConnectionError(this, new QWorkspaceConnectionErrorArgs { status = QConnectionStatus.Error, data = "error" });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,10 +193,9 @@ namespace QControlKit
|
||||
|
||||
private void finishConnection()
|
||||
{
|
||||
//TODO
|
||||
connected = true;
|
||||
startReceivingUpdates();
|
||||
//fetchQLabVersion();
|
||||
//fetchQLabVersion(); //this is not needed since the version is loaded from the workspace info call
|
||||
fetchCueLists();
|
||||
|
||||
}
|
||||
@@ -210,30 +209,22 @@ namespace QControlKit
|
||||
else
|
||||
connect();
|
||||
|
||||
//todo
|
||||
}
|
||||
|
||||
public void disconnect()
|
||||
{
|
||||
Log.Information($"[workspace] disconnecting from <{name}>");
|
||||
_log.Information($"disconnecting from <{name}>");
|
||||
if (!connected)
|
||||
return;
|
||||
if (heartbeatTimer != null)
|
||||
stopHeartbeat();
|
||||
stopReceivingUpdates();
|
||||
disconnectFromWorkspace();
|
||||
|
||||
connected = false;
|
||||
client.disconnect();
|
||||
|
||||
//TODO
|
||||
//root.removeAllChildCues();
|
||||
|
||||
connected = false;
|
||||
}
|
||||
|
||||
public void temporarilyDisconnect()
|
||||
{
|
||||
//TODO
|
||||
//TODO what does this mean?
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -253,13 +244,15 @@ namespace QControlKit
|
||||
#region Workspace Methods
|
||||
public void disconnectFromWorkspace() { client.sendMessage($"{workspacePrefix}/disconnect"); }
|
||||
public void startReceivingUpdates() { client.sendMessage($"{workspacePrefix}/updates", 1); }
|
||||
public void getPropertyForActive(string prop) { client.sendMessage($"{workspacePrefix}/cue/active/{prop}"); }
|
||||
public void stopReceivingUpdates() { client.sendMessage($"{workspacePrefix}/updates", 0); }
|
||||
public void enableAlwaysReply() { client.sendMessage($"{workspacePrefix}/alwaysReply", 1); }
|
||||
public void disableAlwaysReply() { client.sendMessage($"{workspacePrefix}/alwaysReply", 0); }
|
||||
public void fetchQLabVersion() { client.sendMessage($"{workspacePrefix}/version"); } //TODO: EventHandler for this? Is this still needed?
|
||||
public void fetchCueLists() { client.sendMessage($"{workspacePrefix}/cueLists"); } //TODO: EventHandler for CueListUpdated
|
||||
public void fetchQLabVersion() { client.sendMessage($"{workspacePrefix}/version"); }
|
||||
public void fetchCueLists() { client.sendMessage($"{workspacePrefix}/cueLists"); }
|
||||
public void fetchPlaybackPositionForCue(QCue cue) { client.sendMessage(addressForCue(cue, QOSCKey.PlaybackPositionId)); } //EventHandler for this? can I use the CueListPlaybackPosition one?
|
||||
public void go() { client.sendMessage($"{workspacePrefix}/go"); }
|
||||
public void go(string cueNumber) { client.sendMessage($"{workspacePrefix}/go/{cueNumber}"); }
|
||||
public void save() { client.sendMessage($"{workspacePrefix}/save"); }
|
||||
public void undo() { client.sendMessage($"{workspacePrefix}/undo"); }
|
||||
public void redo() { client.sendMessage($"{workspacePrefix}/redo"); }
|
||||
@@ -271,39 +264,7 @@ namespace QControlKit
|
||||
#endregion
|
||||
|
||||
#region Heartbeat
|
||||
//TODO
|
||||
public void startHeartbeat()
|
||||
{
|
||||
clearHeartbeatTimeout();
|
||||
sendHeartbeat();
|
||||
}
|
||||
|
||||
public void stopHeartbeat()
|
||||
{
|
||||
clearHeartbeatTimeout();
|
||||
heartbeatAttempts = -1;
|
||||
}
|
||||
|
||||
public void clearHeartbeatTimeout()
|
||||
{
|
||||
heartbeatTimer.Stop();
|
||||
heartbeatTimer = null;
|
||||
heartbeatAttempts = 0;
|
||||
//TODO
|
||||
}
|
||||
|
||||
public void sendHeartbeat()
|
||||
{
|
||||
client.sendMessage("/thump");
|
||||
//TODO
|
||||
}
|
||||
|
||||
public void heartbeatTimeout(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
|
||||
//TODO? Do I even need this if I only allow TCP and just watch for a change in the state of the TCP connection
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -356,23 +317,46 @@ namespace QControlKit
|
||||
#endregion
|
||||
|
||||
#region Property Fetching
|
||||
//TODO
|
||||
|
||||
|
||||
public void fetchDefaultPropertiesForCue(QCue cue)
|
||||
{
|
||||
List<string> keys = new List<string> { QOSCKey.UID, QOSCKey.Number, QOSCKey.Name,
|
||||
QOSCKey.ListName, QOSCKey.Type, QOSCKey.ColorName,
|
||||
QOSCKey.Flagged, QOSCKey.Armed, QOSCKey.Notes };
|
||||
List<string> keys = new List<string> {
|
||||
QOSCKey.UID,
|
||||
QOSCKey.Flagged,
|
||||
QOSCKey.Armed,
|
||||
QOSCKey.IsRunning,
|
||||
QOSCKey.IsBroken,
|
||||
QOSCKey.IsLoaded,
|
||||
QOSCKey.Parent,
|
||||
};
|
||||
|
||||
fetchPropertiesForCue(cue, keys.ToArray(), false);
|
||||
}
|
||||
|
||||
public void fetchBasicPropertiesForCue(QCue cue)
|
||||
{
|
||||
List<string> keys = new List<string> { QOSCKey.Name, QOSCKey.ListName, QOSCKey.Number, QOSCKey.FileTarget, QOSCKey.CueTargetNumber,
|
||||
QOSCKey.HasFileTargets, QOSCKey.HasCueTargets, QOSCKey.Armed, QOSCKey.ColorName,
|
||||
QOSCKey.ContinueMode, QOSCKey.Flagged, QOSCKey.PreWait, QOSCKey.PostWait,
|
||||
QOSCKey.Duration, QOSCKey.AllowsEditingDuration, QOSCKey.Notes };
|
||||
List<string> keys = new List<string> {
|
||||
QOSCKey.Name,
|
||||
QOSCKey.ListName,
|
||||
QOSCKey.Number,
|
||||
QOSCKey.FileTarget,
|
||||
QOSCKey.CueTargetNumber,
|
||||
QOSCKey.HasFileTargets,
|
||||
QOSCKey.HasCueTargets,
|
||||
QOSCKey.Armed,
|
||||
QOSCKey.ColorName,
|
||||
QOSCKey.ContinueMode,
|
||||
QOSCKey.Flagged,
|
||||
QOSCKey.PreWait,
|
||||
QOSCKey.PostWait,
|
||||
QOSCKey.Duration,
|
||||
QOSCKey.AllowsEditingDuration,
|
||||
QOSCKey.IsBroken,
|
||||
QOSCKey.IsRunning,
|
||||
QOSCKey.IsLoaded,
|
||||
QOSCKey.Notes
|
||||
};
|
||||
|
||||
if (cue.IsGroup)
|
||||
keys.Add(QOSCKey.Children);
|
||||
fetchPropertiesForCue(cue, keys.ToArray(), false);
|
||||
@@ -400,6 +384,11 @@ namespace QControlKit
|
||||
client.sendMessage(address, args);
|
||||
}
|
||||
|
||||
public void sendMessageForCue(QCue cue, string action)
|
||||
{
|
||||
client.sendMessage(addressForCue(cue, action));
|
||||
}
|
||||
|
||||
private string addressForCue(QCue cue, string action)
|
||||
{
|
||||
return $"{workspacePrefix}/cue_id/{cue.propertyForKey(QOSCKey.UID)}/{action}";
|
||||
@@ -431,26 +420,28 @@ namespace QControlKit
|
||||
{
|
||||
//clear passcode if there was one set in the connect() method
|
||||
this.passcode = null;
|
||||
Log.Error($"[workspace] *** Password for workspace {name} was incorrect!");
|
||||
_log.Error($"*** Password for workspace <{name}> was incorrect!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"[workspace] *** Unable to connect to workspace: {name} on server: {server.name}");
|
||||
_log.Error($"*** Unable to connect to workspace: <{name}> on server: <{server.name}>");
|
||||
}
|
||||
|
||||
WorkspaceConnectionError?.Invoke(this, new QWorkspaceConnectionErrorArgs { status = args.status });
|
||||
WorkspaceConnectionError?.Invoke(this, args);
|
||||
}
|
||||
|
||||
private void OnWorkspaceConnected(object source, QWorkspaceConnectedArgs args)
|
||||
{
|
||||
Log.Information($"[workspace] Connection to <{name}> successful, finishing things up.");
|
||||
_log.Information($"Connection to <{name}> successful, finishing things up.");
|
||||
WorkspaceConnected?.Invoke(this, args);
|
||||
finishConnection();
|
||||
}
|
||||
|
||||
private void OnWorkspaceDisconnected(object source, QWorkspaceDisconnectedArgs args)
|
||||
{
|
||||
//this might not be called with TCP?
|
||||
Log.Warning($"[workspace] *** Workspace has indicated it is disconnecting");
|
||||
_log.Warning($"*** Workspace has indicated it is disconnecting");
|
||||
WorkspaceDisconnected?.Invoke(this, new QWorkspaceDisconnectedArgs());
|
||||
}
|
||||
|
||||
private void OnCueListsUpdated(object source, QCueListsUpdatedArgs args)
|
||||
@@ -518,7 +509,7 @@ namespace QControlKit
|
||||
//add Event handled? use CueUpdated one?
|
||||
}
|
||||
|
||||
Log.Debug($"[workspace] cueLists finished processing. root updated? {rootCueUpdated}");
|
||||
_log.Debug($"cueLists finished processing. root updated? {rootCueUpdated}");
|
||||
|
||||
|
||||
OnWorkspaceUpdated();
|
||||
@@ -536,8 +527,7 @@ namespace QControlKit
|
||||
cueList.setProperty(args.cueID, QOSCKey.PlaybackPositionId, false);
|
||||
}
|
||||
|
||||
//TODO: need to implement when playbackposition is "none"
|
||||
Log.Debug($"[workspace] cue list <{args.cueListID}> playback position changed to <{args.cueID}>");
|
||||
_log.Information($"cue list <{args.cueListID}> playback position changed to <{args.cueID}>");
|
||||
CueListChangedPlaybackPosition?.Invoke(this, new QCueListChangedPlaybackPositionArgs { cueListID = args.cueListID, cueID = args.cueID });
|
||||
|
||||
}
|
||||
@@ -551,7 +541,7 @@ namespace QControlKit
|
||||
{
|
||||
if (args.cueID.Equals(QIdentifiers.RootCueUpdate))
|
||||
{
|
||||
Log.Debug("[workspace] root cue update requested, updating all cue lists");
|
||||
_log.Debug("root cue update requested, updating all cue lists");
|
||||
foreach (var cuelist in this.cueLists)
|
||||
{
|
||||
if (!cuelist.uid.Equals(QIdentifiers.ActiveCues))
|
||||
@@ -573,10 +563,20 @@ namespace QControlKit
|
||||
|
||||
private void OnCueUpdated(object source, QCueUpdatedArgs args)
|
||||
{
|
||||
_log.Verbose($"OnCueUpdated: {args.cueID}");
|
||||
QCue cue = cueWithID(args.cueID);
|
||||
|
||||
if (cue == null || cue.ignoreUpdates)
|
||||
|
||||
if(cue == null)
|
||||
{
|
||||
_log.Error($"Could not find cue to update, this is likely a problem.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cue.ignoreUpdates)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cue.updatePropertiesWithDictionary(args.data);
|
||||
}
|
||||
@@ -591,7 +591,7 @@ namespace QControlKit
|
||||
#region Printing
|
||||
public void Print()
|
||||
{
|
||||
Log.Information($"[workspace] {name}");
|
||||
_log.Information($"{name}");
|
||||
foreach (var cueList in root.cues)
|
||||
{
|
||||
cueList.Print();
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace SharpOSC
|
||||
private static OscMessage parseMessage(byte[] msg)
|
||||
{
|
||||
int index = 0;
|
||||
//Log.Debug("Raw ASCII DATA: " + System.Text.Encoding.ASCII.GetString(msg));
|
||||
//Log.Debug("Raw UTF-8 DATA: " + System.Text.Encoding.UTF8.GetString(msg));
|
||||
string address = null;
|
||||
char[] types = new char[0];
|
||||
List<object> arguments = new List<object>();
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SharpOSC
|
||||
{
|
||||
public static class SlipFrame
|
||||
{
|
||||
public static readonly byte END = 0xc0;
|
||||
public static readonly byte ESC = 0xdb;
|
||||
public static readonly byte ESC_END = 0xDC;
|
||||
public static readonly byte ESC_ESC = 0xDD;
|
||||
|
||||
public static List<byte[]> Decode(byte[] data)
|
||||
{
|
||||
List<byte[]> messages = new List<byte[]>();
|
||||
|
||||
List<byte> buffer = new List<byte>();
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
if (data[i] == END && buffer.Count > 0)
|
||||
{
|
||||
messages.Add(buffer.ToArray());
|
||||
buffer.Clear();
|
||||
}
|
||||
else if (data[i] != END)
|
||||
{
|
||||
buffer.Add(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
public static byte[] Encode(byte[] data)
|
||||
{
|
||||
List<byte> slipData = new List<byte>();
|
||||
|
||||
byte[] esc_end = { ESC, ESC_END };
|
||||
byte[] esc_esc = { ESC, ESC_ESC };
|
||||
byte[] end = { END };
|
||||
|
||||
int length = data.Length;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (data[i] == END)
|
||||
{
|
||||
slipData.AddRange(esc_end);
|
||||
}
|
||||
else if (data[i] == ESC)
|
||||
{
|
||||
slipData.AddRange(esc_esc);
|
||||
}
|
||||
else
|
||||
{
|
||||
slipData.Add(data[i]);
|
||||
}
|
||||
}
|
||||
slipData.AddRange(end);
|
||||
return slipData.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using Serilog;
|
||||
using TcpSharp.Events;
|
||||
|
||||
namespace SharpOSC
|
||||
{
|
||||
@@ -19,6 +18,8 @@ namespace SharpOSC
|
||||
|
||||
public class TCPClient
|
||||
{
|
||||
private ILogger _log = Log.Logger.ForContext<TCPClient>();
|
||||
|
||||
public int Port
|
||||
{
|
||||
get { return _port; }
|
||||
@@ -31,15 +32,12 @@ namespace SharpOSC
|
||||
}
|
||||
public delegate void MessageReceivedHandler(object source, MessageEventArgs args);
|
||||
public event MessageReceivedHandler MessageReceived;
|
||||
private Thread receivingThread;
|
||||
|
||||
string _address;
|
||||
TcpClient client;
|
||||
|
||||
byte END = 0xc0;
|
||||
byte ESC = 0xdb;
|
||||
byte ESC_END = 0xDC;
|
||||
byte ESC_ESC = 0xDD;
|
||||
TcpSharp.TcpSharpSocketClient tcpClient;
|
||||
|
||||
private List<byte> frameStream = new List<byte>();
|
||||
|
||||
public TCPClient(string address, int port)
|
||||
{
|
||||
@@ -49,27 +47,82 @@ namespace SharpOSC
|
||||
|
||||
public bool Connect()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
client = new TcpClient(Address, Port);
|
||||
receivingThread = new Thread(ReceiveLoop);
|
||||
receivingThread.Start();
|
||||
Log.Debug($"[tcpclient] connected to <{Address}:{Port}>");
|
||||
tcpClient = new TcpSharp.TcpSharpSocketClient(Address, Port);
|
||||
tcpClient.OnConnected += ClientConnected;
|
||||
tcpClient.OnDataReceived += DataReceived;
|
||||
tcpClient.OnDisconnected += ClientDisconneted;
|
||||
tcpClient.OnError += ClientError;
|
||||
tcpClient.Connect();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e.Message);
|
||||
_log.Error(e.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
private void ClientError(object sender, OnClientErrorEventArgs e)
|
||||
{
|
||||
_log.Error("client error");
|
||||
_log.Error(e.Exception.ToString());
|
||||
}
|
||||
|
||||
private void ClientDisconneted(object sender, OnClientDisconnectedEventArgs e)
|
||||
{
|
||||
_log.Information($"client disconnected: {e.Reason}");
|
||||
Close();
|
||||
}
|
||||
|
||||
private void DataReceived(object sender, OnClientDataReceivedEventArgs e)
|
||||
{
|
||||
frameStream.AddRange(e.Data);
|
||||
|
||||
int i = 0;
|
||||
int frameEnd = frameStream.FindIndex(1, frameByte=>frameByte.Equals(SlipFrame.END));
|
||||
while(frameEnd > 0)
|
||||
{
|
||||
List<byte> frame = frameStream.GetRange(0, frameEnd+1);
|
||||
frameStream.RemoveRange(0, frameEnd + 1);
|
||||
List<byte[]> messages = SlipFrame.Decode(frame.ToArray());
|
||||
foreach (var message in messages)
|
||||
{
|
||||
try
|
||||
{
|
||||
OscPacket packet = OscPacket.GetPacket(message);
|
||||
OscMessage responseMessage = (OscMessage)packet;
|
||||
if (packet == null)
|
||||
{
|
||||
_log.Error("packet is null");
|
||||
}
|
||||
|
||||
if (responseMessage == null)
|
||||
{
|
||||
_log.Error("responeMessage is null");
|
||||
}
|
||||
OnMessageReceived(responseMessage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error($"Exception parsing OSC message: {ex.ToString()}");
|
||||
}
|
||||
}
|
||||
frameEnd = frameStream.FindIndex(0, frameByte => frameByte.Equals(SlipFrame.END));
|
||||
}
|
||||
}
|
||||
|
||||
private void ClientConnected(object sender, OnClientConnectedEventArgs e)
|
||||
{
|
||||
_log.Debug($"connected to <{Address}:{Port}>");
|
||||
}
|
||||
|
||||
public void Send(byte[] message)
|
||||
{
|
||||
byte[] slipData = SlipEncode(message);
|
||||
NetworkStream netStream = client.GetStream();
|
||||
netStream.Write(slipData.ToArray(), 0, slipData.ToArray().Length);
|
||||
byte[] slipData = SlipFrame.Encode(message);
|
||||
tcpClient.SendBytes(slipData.ToArray());
|
||||
}
|
||||
|
||||
public void Send(OscPacket packet)
|
||||
@@ -82,96 +135,24 @@ namespace SharpOSC
|
||||
{
|
||||
get
|
||||
{
|
||||
if (client == null)
|
||||
if (tcpClient == null)
|
||||
return false;
|
||||
else
|
||||
return client.Connected;
|
||||
return tcpClient.Connected;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReceiveLoop()
|
||||
{
|
||||
while (client.Connected)
|
||||
{
|
||||
Receive();
|
||||
}
|
||||
//Log.Debug("[tcpclient] - ReceiveLoop has exited");
|
||||
}
|
||||
|
||||
public void Receive()
|
||||
{
|
||||
Random random = new Random();
|
||||
int num = random.Next(1000);
|
||||
try
|
||||
{
|
||||
NetworkStream netStream = client.GetStream();
|
||||
netStream.ReadTimeout = 250;
|
||||
List<byte> responseData = new List<byte>();
|
||||
if (netStream.CanRead)
|
||||
{
|
||||
//var watch = System.Diagnostics.Stopwatch.StartNew();
|
||||
byte[] buffer = new byte[256];
|
||||
|
||||
int bytesRead = 0;
|
||||
int reads = 0;
|
||||
do
|
||||
{
|
||||
bytesRead = netStream.Read(buffer, 0, buffer.Length);
|
||||
responseData.AddRange(buffer);
|
||||
reads += 1;
|
||||
Thread.Sleep(1);
|
||||
//Log.Debug("Thread " + num + ": Bytes read: " + bytesRead + " - " + Encoding.UTF8.GetString(buffer));
|
||||
} while (netStream.DataAvailable);
|
||||
|
||||
//Console.WriteLine("Raw TCP In: " + System.Text.Encoding.UTF8.GetString(responseData.ToArray()));
|
||||
OscMessage response = (OscMessage)OscPacket.GetPacket(responseData.Skip(1).ToArray());
|
||||
//watch.Stop();
|
||||
//Console.WriteLine($"TCPCLient - message receive took {watch.ElapsedMilliseconds}ms and {reads} reads");
|
||||
OnMessageReceived(response);
|
||||
}
|
||||
} catch(Exception e)
|
||||
{
|
||||
//Console.WriteLine("TCPSENDER - Receive Exception: " + e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] SlipEncode(byte[] data)
|
||||
{
|
||||
List<byte> slipData = new List<byte>();
|
||||
|
||||
byte[] esc_end = { ESC, ESC_END };
|
||||
byte[] esc_esc = { ESC, ESC_ESC };
|
||||
byte[] end = { END };
|
||||
|
||||
int length = data.Length;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (data[i] == END)
|
||||
{
|
||||
slipData.AddRange(esc_end);
|
||||
}
|
||||
else if (data[i] == ESC)
|
||||
{
|
||||
slipData.AddRange(esc_esc);
|
||||
}
|
||||
else
|
||||
{
|
||||
slipData.Add(data[i]);
|
||||
}
|
||||
}
|
||||
slipData.AddRange(end);
|
||||
return slipData.ToArray();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (client != null)
|
||||
if (tcpClient != null)
|
||||
{
|
||||
if (client.Connected)
|
||||
tcpClient.OnConnected -= ClientConnected;
|
||||
tcpClient.OnDataReceived -= DataReceived;
|
||||
tcpClient.OnDisconnected -= ClientDisconneted;
|
||||
if (tcpClient.Connected)
|
||||
{
|
||||
Log.Debug($"[tcpClient] closing connection to {Address}");
|
||||
client.GetStream().Close();
|
||||
client.Close();
|
||||
_log.Debug($"closing connection to {Address}");
|
||||
tcpClient.Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,4 +162,4 @@ namespace SharpOSC
|
||||
MessageReceived?.Invoke(this, new MessageEventArgs() { Message = msg });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,6 @@ namespace SharpOSC
|
||||
Log.Error(e.ToString());
|
||||
// If there is an error reading the packet, null is sent to the callback
|
||||
}
|
||||
//Log.Debug("Raw UDP In: " + System.Text.Encoding.ASCII.GetString(bytes));
|
||||
OscPacketCallback(packet);
|
||||
}
|
||||
else
|
||||
@@ -151,7 +150,6 @@ namespace SharpOSC
|
||||
{
|
||||
byte[] bytes = queue.Dequeue();
|
||||
var packet = OscPacket.GetPacket(bytes);
|
||||
//Log.Debug("Raw UDP In: " + System.Text.Encoding.ASCII.GetString(bytes));
|
||||
return packet;
|
||||
}
|
||||
else
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.jwetzell.qcontrolkitxamdemo">
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
|
||||
<application android:label="QControlKitXamDemo.Android"></application>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
</manifest>
|
||||
@@ -1,109 +1,113 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{4F7F13C7-85EF-431F-AB03-B2494F0F4C7F}</ProjectGuid>
|
||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TemplateGuid>{c9e5eea5-ca05-42a1-839b-61506e0a37df}</TemplateGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>QControlKitXamDemo.Droid</RootNamespace>
|
||||
<AssemblyName>QControlKitXamDemo.Android</AssemblyName>
|
||||
<Deterministic>True</Deterministic>
|
||||
<AndroidApplication>True</AndroidApplication>
|
||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
||||
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
|
||||
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
|
||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidLinkMode>None</AndroidLinkMode>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Mono.Android" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog.Sinks.Xamarin">
|
||||
<Version>0.2.0.64</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2012" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="MainActivity.cs" />
|
||||
<Compile Include="Resources\Resource.designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\AboutResources.txt" />
|
||||
<None Include="Assets\AboutAssets.txt" />
|
||||
<None Include="Properties\AndroidManifest.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\Tabbar.xml" />
|
||||
<AndroidResource Include="Resources\layout\Toolbar.xml" />
|
||||
<AndroidResource Include="Resources\values\styles.xml" />
|
||||
<AndroidResource Include="Resources\values\colors.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon_round.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\launcher_foreground.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\drawable\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\QControlKit\QControlKit.csproj">
|
||||
<Project>{51cd2579-79c9-49a9-b68d-93cbe878baa1}</Project>
|
||||
<Name>QControlKit</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\QControlKitXamDemo\QControlKitXamDemo.csproj">
|
||||
<Project>{20D2D0D8-A518-42DC-BAB8-CF098CDF03C4}</Project>
|
||||
<Name>QControlKitXamDemo</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties XamarinHotReloadDebuggerTimeoutExceptionQControlKitXamDemoAndroidHideInfoBar="True" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{4F7F13C7-85EF-431F-AB03-B2494F0F4C7F}</ProjectGuid>
|
||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TemplateGuid>{c9e5eea5-ca05-42a1-839b-61506e0a37df}</TemplateGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>QControlKitXamDemo.Droid</RootNamespace>
|
||||
<AssemblyName>QControlKitXamDemo.Android</AssemblyName>
|
||||
<Deterministic>True</Deterministic>
|
||||
<AndroidApplication>True</AndroidApplication>
|
||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
||||
<TargetFrameworkVersion>v13.0</TargetFrameworkVersion>
|
||||
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
|
||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidLinkMode>None</AndroidLinkMode>
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Mono.Android" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog.Sinks.Xamarin">
|
||||
<Version>1.0.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2622" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.8.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="MainActivity.cs" />
|
||||
<Compile Include="Resources\Resource.designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\AboutResources.txt" />
|
||||
<None Include="Assets\AboutAssets.txt" />
|
||||
<None Include="Properties\AndroidManifest.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\Tabbar.xml" />
|
||||
<AndroidResource Include="Resources\layout\Toolbar.xml" />
|
||||
<AndroidResource Include="Resources\values\styles.xml" />
|
||||
<AndroidResource Include="Resources\values\colors.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon_round.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\launcher_foreground.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\drawable\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\QControlKit\QControlKit.csproj">
|
||||
<Project>{51cd2579-79c9-49a9-b68d-93cbe878baa1}</Project>
|
||||
<Name>QControlKit</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\QControlKitXamDemo\QControlKitXamDemo.csproj">
|
||||
<Project>{20D2D0D8-A518-42DC-BAB8-CF098CDF03C4}</Project>
|
||||
<Name>QControlKitXamDemo</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidAsset Include="Assets\materialdesignicons-webfont.ttf" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties XamarinHotReloadDebuggerTimeoutExceptionQControlKitXamDemoAndroidHideInfoBar="True" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
@@ -5,6 +5,8 @@ using System.Linq;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace QControlKitXamDemo.iOS
|
||||
{
|
||||
// The UIApplicationDelegate for the application. This class is responsible for launching the
|
||||
@@ -23,7 +25,7 @@ namespace QControlKitXamDemo.iOS
|
||||
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
|
||||
{
|
||||
global::Xamarin.Forms.Forms.Init();
|
||||
Log.Logger = new LoggerConfiguration().WriteTo.NSLog().MinimumLevel.Debug().CreateLogger();
|
||||
Log.Logger = new LoggerConfiguration().WriteTo.NSLog(outputTemplate: "[{Level}] ({SourceContext}) {Message}{NewLine}{Exception}").MinimumLevel.Verbose().CreateLogger();
|
||||
LoadApplication(new App());
|
||||
|
||||
return base.FinishedLaunching(app, options);
|
||||
|
||||
@@ -2,37 +2,47 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>8.0</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>QControlKitXamDemo</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.companyname.QControlKitXamDemo</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>QControlKitXamDemo</string>
|
||||
<key>XSAppIconAssets</key>
|
||||
<string>Assets.xcassets/AppIcon.appiconset</string>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>8.0</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>QControlKitXamDemo</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.companyname.QControlKitXamDemo</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>QControlKitXamDemo</string>
|
||||
<key>XSAppIconAssets</key>
|
||||
<string>Assets.xcassets/AppIcon.appiconset</string>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_qlab._tcp</string>
|
||||
</array>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Scan network for QLab instances</string>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>materialdesignicons-webfont.ttf</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
||||
<MtouchLink>None</MtouchLink>
|
||||
<MtouchInterpreter>-all</MtouchInterpreter>
|
||||
<CodesignProvision>Wildcard</CodesignProvision>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
|
||||
<DebugType>none</DebugType>
|
||||
@@ -125,13 +126,16 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog">
|
||||
<Version>2.10.0</Version>
|
||||
<Version>2.12.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.Xamarin">
|
||||
<Version>0.2.0.64</Version>
|
||||
<Version>1.0.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2515" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.3" />
|
||||
<PackageReference Include="SuperSimpleTcp">
|
||||
<Version>3.0.0.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2012" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
@@ -140,4 +144,7 @@
|
||||
<Name>QControlKitXamDemo</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\materialdesignicons-webfont.ttf" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
@@ -6,6 +6,52 @@
|
||||
mc:Ignorable="d"
|
||||
x:Class="QControlKitXamDemo.App">
|
||||
<Application.Resources>
|
||||
<OnPlatform x:Key="MaterialFontFamily" x:TypeArguments="x:String">
|
||||
<On Platform="iOS">Material Design Icons</On>
|
||||
<On Platform="Android">materialdesignicons-webfont.ttf#Material Design Icons</On>
|
||||
</OnPlatform>
|
||||
|
||||
<Style TargetType="Label"
|
||||
Class="PrimaryText"
|
||||
ApplyToDerivedTypes="true">
|
||||
<Setter Property="TextColor"
|
||||
Value="{DynamicResource PrimaryTextColor}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button"
|
||||
Class="PrimaryButton"
|
||||
ApplyToDerivedTypes="true">
|
||||
<Setter Property="TextColor"
|
||||
Value="{DynamicResource PrimaryTextColor}" />
|
||||
</Style>
|
||||
|
||||
<x:Double x:Key="SmallPadding">4</x:Double>
|
||||
<x:Double x:Key="MediumPadding">8</x:Double>
|
||||
<x:Double x:Key="StandardPadding">16</x:Double>
|
||||
|
||||
<Thickness x:Key="SmallTopThickness" Top="{StaticResource SmallPadding}" />
|
||||
|
||||
<Thickness x:Key="MediumTopThickness" Top="{StaticResource MediumPadding}" />
|
||||
|
||||
<Thickness x:Key="StandardTopThickness" Top="{StaticResource StandardPadding}" />
|
||||
|
||||
<Thickness x:Key="SmallThickness"
|
||||
Bottom="{StaticResource SmallPadding}"
|
||||
Left="{StaticResource SmallPadding}"
|
||||
Right="{StaticResource SmallPadding}"
|
||||
Top="{StaticResource SmallPadding}" />
|
||||
|
||||
<Thickness x:Key="MediumThickness"
|
||||
Bottom="{StaticResource MediumPadding}"
|
||||
Left="{StaticResource MediumPadding}"
|
||||
Right="{StaticResource MediumPadding}"
|
||||
Top="{StaticResource MediumPadding}" />
|
||||
|
||||
<Thickness x:Key="StandardThickness"
|
||||
Bottom="{StaticResource StandardPadding}"
|
||||
Left="{StaticResource StandardPadding}"
|
||||
Right="{StaticResource StandardPadding}"
|
||||
Top="{StaticResource StandardPadding}" />
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
@@ -9,6 +9,8 @@ namespace QControlKitXamDemo
|
||||
InitializeComponent();
|
||||
|
||||
MainPage = new NavigationPage(new MainPage());
|
||||
Current.RequestedThemeChanged += Current_RequestedThemeChanged;
|
||||
SetAppResources();
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
@@ -22,5 +24,80 @@ namespace QControlKitXamDemo
|
||||
protected override void OnResume()
|
||||
{
|
||||
}
|
||||
|
||||
private void Current_RequestedThemeChanged(object sender, AppThemeChangedEventArgs e)
|
||||
{
|
||||
SetAppResources();
|
||||
}
|
||||
|
||||
private void SetAppResources()
|
||||
{
|
||||
|
||||
switch (Current.RequestedTheme)
|
||||
{
|
||||
case OSAppTheme.Light:
|
||||
SetLightResources();
|
||||
break;
|
||||
case OSAppTheme.Dark:
|
||||
SetDarkResources();
|
||||
break;
|
||||
case OSAppTheme.Unspecified:
|
||||
//Default to Light
|
||||
SetLightResources();
|
||||
break;
|
||||
default:
|
||||
SetLightResources();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDarkResources()
|
||||
{
|
||||
|
||||
Resources["NavigationBarColor"] = Color.FromHex("#3f6dab");
|
||||
Resources["PageBackgroundColor"] = Color.FromHex("#525252");
|
||||
|
||||
|
||||
Resources["PrimaryColor"] = Color.WhiteSmoke;
|
||||
Resources["SecondaryColor"] = Color.White;
|
||||
Resources["PrimaryTextColor"] = Color.LightGray;
|
||||
Resources["SecondaryTextColor"] = Color.White;
|
||||
Resources["TertiaryTextColor"] = Color.Gray;
|
||||
Resources["TransparentColor"] = Color.Transparent;
|
||||
|
||||
Resources["IconTextColor"] = Color.WhiteSmoke;
|
||||
|
||||
Resources["ListViewBackgroundColor"] = Color.FromHex("#363636");
|
||||
|
||||
Resources["ServerCellBackgroundColor"] = Color.FromHex("#363636");
|
||||
Resources["WorkspaceCellBackgroundColor"] = Color.FromHex("#737373");
|
||||
|
||||
Resources["SelectedCueCellBackgroundColor"] = Color.FromHex("#737373");
|
||||
|
||||
}
|
||||
|
||||
private void SetLightResources()
|
||||
{
|
||||
Resources["NavigationBarColor"] = Color.FromHex("#3089ff");
|
||||
Resources["PageBackgroundColor"] = Color.LightGray;
|
||||
|
||||
|
||||
Resources["PrimaryColor"] = Color.WhiteSmoke;
|
||||
Resources["SecondaryColor"] = Color.White;
|
||||
Resources["PrimaryTextColor"] = Color.Black;
|
||||
Resources["SecondaryTextColor"] = Color.White;
|
||||
Resources["TertiaryTextColor"] = Color.Gray;
|
||||
Resources["TransparentColor"] = Color.Transparent;
|
||||
|
||||
Resources["IconTextColor"] = Color.Black;
|
||||
|
||||
Resources["ListViewBackgroundColor"] = Color.White;
|
||||
|
||||
Resources["ServerCellBackgroundColor"] = Color.White;
|
||||
Resources["WorkspaceCellBackgroundColor"] = Color.FromHex("#D8D8D8");
|
||||
|
||||
Resources["SelectedCueCellBackgroundColor"] = Color.FromHex("#D8D8D8");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Xamarin.Forms;
|
||||
|
||||
using QControlKit.Events;
|
||||
using QControlKit.Constants;
|
||||
using Serilog;
|
||||
|
||||
namespace QControlKitXamDemo
|
||||
{
|
||||
@@ -20,25 +21,44 @@ namespace QControlKitXamDemo
|
||||
connectedWorkspace = workspace;
|
||||
connectedWorkspace.WorkspaceUpdated += Workspace_WorkspaceUpdated;
|
||||
connectedWorkspace.WorkspaceConnectionError += ConnectedWorkspace_WorkspaceConnectionError;
|
||||
connectedWorkspace.WorkspaceConnected += ConnectedWorkspace_WorkspaceConnected; ;
|
||||
connectedWorkspace.connect(passcode);
|
||||
connectedWorkspace.defaultSendUpdatesOSC = true;
|
||||
connectedWorkspace.CueListChangedPlaybackPosition += ConnectedWorkspace_CueListChangedPlaybackPosition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected override void OnDisappearing()
|
||||
{
|
||||
base.OnDisappearing();
|
||||
connectedWorkspace.disconnect();
|
||||
connectedWorkspace.WorkspaceUpdated -= Workspace_WorkspaceUpdated;
|
||||
connectedWorkspace.WorkspaceConnectionError -= ConnectedWorkspace_WorkspaceConnectionError;
|
||||
connectedWorkspace.WorkspaceConnected -= ConnectedWorkspace_WorkspaceConnected;
|
||||
connectedWorkspace.CueListChangedPlaybackPosition -= ConnectedWorkspace_CueListChangedPlaybackPosition;
|
||||
}
|
||||
|
||||
private async void ConnectedWorkspace_WorkspaceConnected(object source, QWorkspaceConnectedArgs args)
|
||||
{
|
||||
if (args.status.Equals("ok") && connectedWorkspace.connectedToQLab5)
|
||||
{
|
||||
if (!args.data.Contains(QConnectionRole.View))
|
||||
{
|
||||
string passcode = await DisplayPromptAsync("PIN does not have view permissions.", "Try Again", maxLength: 4, keyboard: Keyboard.Numeric);
|
||||
if (passcode != null)
|
||||
{
|
||||
connectedWorkspace.connect(passcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void ConnectedWorkspace_WorkspaceConnectionError(object source, QWorkspaceConnectionErrorArgs args)
|
||||
{
|
||||
if (args.status.Equals("badpass"))
|
||||
{
|
||||
string passcode = await DisplayPromptAsync("Passcode was incorrect.", "Try Again", maxLength: 4, keyboard: Keyboard.Numeric);
|
||||
string passcode = await DisplayPromptAsync("PIN is incorrect.", "Try Again", maxLength: 4, keyboard: Keyboard.Numeric);
|
||||
if (passcode != null)
|
||||
{
|
||||
connectedWorkspace.connect(passcode);
|
||||
@@ -51,16 +71,31 @@ namespace QControlKitXamDemo
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
QCue selectedCue = connectedWorkspace.cueWithID(args.cueID);
|
||||
connectedWorkspace.fetchDefaultPropertiesForCue(selectedCue);
|
||||
selectedCueGrid.BindingContext = new QCueViewModel(selectedCue, false);
|
||||
if (cueGridDict.ContainsKey(args.cueID))
|
||||
if(selectedCue != null) //TODO: I think this being null is the result of a race condition?
|
||||
{
|
||||
var cueGrid = cueGridDict[args.cueID]; //element to scroll to
|
||||
cueListScrollView.ScrollToAsync(cueGrid, ScrollToPosition.Center, true);
|
||||
connectedWorkspace.fetchBasicPropertiesForCue(selectedCue);
|
||||
selectedCueGrid.BindingContext = new QCueViewModel(selectedCue, false);
|
||||
if (cueGridDict.ContainsKey(args.cueID))
|
||||
{
|
||||
var cueGrid = cueGridDict[args.cueID]; //element to scroll to
|
||||
cueListScrollView.ScrollToAsync(cueGrid, ScrollToPosition.Center, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void updateCuePropertes(QCue cue)
|
||||
{
|
||||
cue.workspace.fetchDefaultPropertiesForCue(cue);
|
||||
if (cue.cues.Count > 0)
|
||||
{
|
||||
foreach (QCue childCue in cue.cues)
|
||||
{
|
||||
childCue.workspace.fetchDefaultPropertiesForCue(childCue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace_WorkspaceUpdated(object source, QWorkspaceUpdatedArgs args)
|
||||
{
|
||||
if(connectedWorkspace.cueLists.Count > 0)
|
||||
@@ -68,6 +103,7 @@ namespace QControlKitXamDemo
|
||||
List<Task> cueAddTasks = new List<Task>();
|
||||
foreach(var aCue in connectedWorkspace.cueLists)
|
||||
{
|
||||
updateCuePropertes(aCue);
|
||||
Grid cueGrid = cueToGrid(aCue);
|
||||
cueGridDict.Add(aCue.uid, cueGrid);
|
||||
MainThread.InvokeOnMainThreadAsync(() =>
|
||||
|
||||
@@ -3,14 +3,121 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:Class="QControlKitXamDemo.MainPage">
|
||||
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
|
||||
mc:Ignorable="d"
|
||||
x:Class="QControlKitXamDemo.MainPage"
|
||||
ios:Page.UseSafeArea="true"
|
||||
BackgroundColor="{DynamicResource PageBackgroundColor}">
|
||||
<ContentPage.Content>
|
||||
|
||||
<ListView x:Name="serverListView" GroupDisplayBinding="{Binding name}" IsGroupingEnabled="True">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextCell Text="{Binding name}"/>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
</ContentPage>
|
||||
<StackLayout>
|
||||
<Frame BackgroundColor="{DynamicResource PageBackgroundColor}"
|
||||
CornerRadius="0"
|
||||
Margin="0"
|
||||
Padding="0"
|
||||
HasShadow="False">
|
||||
<StackLayout Spacing="0" BackgroundColor="Transparent">
|
||||
<Label Margin="0,10,0,10"
|
||||
Padding="0"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="FillAndExpand"
|
||||
HorizontalTextAlignment="Center"
|
||||
FontSize="Title"
|
||||
Text="Discovered QLab Instances" />
|
||||
<!--Need to try and remove the group spacing caused by ios:GroupHeaderStyle-->
|
||||
<ListView x:Name="serverListView"
|
||||
ios:ListView.GroupHeaderStyle="Grouped"
|
||||
GroupDisplayBinding="{Binding name}"
|
||||
IsGroupingEnabled="True"
|
||||
d:IsGroupingEnabled="False"
|
||||
BackgroundColor="Transparent"
|
||||
SeparatorVisibility="None"
|
||||
ItemsSource="{Binding ServersGrouped}"
|
||||
Margin="0">
|
||||
<ListView.GroupHeaderTemplate>
|
||||
<DataTemplate>
|
||||
<ViewCell>
|
||||
<Frame BackgroundColor="{DynamicResource ServerCellBackgroundColor}"
|
||||
Margin="0,0,0,0"
|
||||
Padding="10,0,10,0"
|
||||
CornerRadius="0">
|
||||
<Grid BackgroundColor="Transparent" VerticalOptions="FillAndExpand"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Column="0"
|
||||
Text="{Binding GroupName}"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="FillAndExpand"
|
||||
VerticalTextAlignment="Center"
|
||||
HorizontalTextAlignment="Start"
|
||||
StyleClass="PrimaryText"/>
|
||||
<Label Grid.Column="1"
|
||||
Text="{Binding version}"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="FillAndExpand"
|
||||
VerticalTextAlignment="Center"
|
||||
HorizontalTextAlignment="End"
|
||||
StyleClass="PrimaryText"/>
|
||||
</Grid>
|
||||
</Frame>
|
||||
</ViewCell>
|
||||
</DataTemplate>
|
||||
</ListView.GroupHeaderTemplate>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ViewCell>
|
||||
<Frame BackgroundColor="{DynamicResource WorkspaceCellBackgroundColor}"
|
||||
BorderColor="Black"
|
||||
Margin="5,0,5,0"
|
||||
Padding="10,0,10,0"
|
||||
CornerRadius="0"
|
||||
HasShadow="False">
|
||||
<Grid Margin="0"
|
||||
BackgroundColor="Transparent"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
||||
<Label Grid.Column="0" Text="{Binding Name}"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="FillAndExpand"
|
||||
VerticalTextAlignment="Center"
|
||||
HorizontalTextAlignment="Start"
|
||||
StyleClass="PrimaryText"/>
|
||||
|
||||
<Label Grid.Column="1" Text="󱆄"
|
||||
FontFamily="{StaticResource MaterialFontFamily}"
|
||||
FontSize="Large"
|
||||
IsVisible="{Binding HasPasscode}"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="FillAndExpand"
|
||||
VerticalTextAlignment="Center"
|
||||
HorizontalTextAlignment="End"
|
||||
StyleClass="PrimaryText"/>
|
||||
</Grid>
|
||||
</Frame>
|
||||
</ViewCell>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</StackLayout>
|
||||
</Frame>
|
||||
|
||||
</StackLayout>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
@@ -2,146 +2,71 @@
|
||||
using System.ComponentModel;
|
||||
using Xamarin.Forms;
|
||||
using QControlKit;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QControlKit.Events;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
using QControlKitXamDemo.ViewModels;
|
||||
using Acr.UserDialogs;
|
||||
|
||||
namespace QControlKitXamDemo
|
||||
{
|
||||
// Learn more about making custom code visible in the Xamarin.Forms previewer
|
||||
// by visiting https://aka.ms/xamarinforms-previewer
|
||||
[DesignTimeVisible(false)]
|
||||
public partial class MainPage : ContentPage
|
||||
{
|
||||
public ObservableCollection<ServerGroup> servers = new ObservableCollection<ServerGroup>();
|
||||
private QBrowserViewModel qBrowserViewModel;
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
serverListView.ItemsSource = servers;
|
||||
QBrowser browser = new QBrowser();
|
||||
browser.ServerLost += Browser_ServerLost;
|
||||
browser.ServerFound += Browser_ServerFound;
|
||||
serverListView.ItemSelected += ServerListView_ItemSelected;
|
||||
|
||||
Device.StartTimer(TimeSpan.FromSeconds(5), () =>
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
browser.ProbeForQLabInstances();
|
||||
});
|
||||
return true;
|
||||
});
|
||||
qBrowserViewModel = new QBrowserViewModel(new QBrowser());
|
||||
serverListView.BindingContext = qBrowserViewModel;
|
||||
serverListView.ItemSelected += QWorkspaceSelected;
|
||||
|
||||
}
|
||||
|
||||
private void Browser_ServerFound(object source, QServerFoundArgs args)
|
||||
async void QWorkspaceSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
{
|
||||
List<ServerGroup> serverGroups = servers.ToList();
|
||||
|
||||
bool serverFound = false;
|
||||
foreach (var serverGroup in serverGroups)
|
||||
if (e.SelectedItem == null)
|
||||
{
|
||||
|
||||
if (serverGroup.host == args.server.host)
|
||||
{
|
||||
serverFound = true;
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!serverFound)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
ServerGroup serverGroup = new ServerGroup(args.server.name);
|
||||
args.server.WorkspaceAdded += Server_WorkspaceAdded;
|
||||
args.server.WorkspaceRemoved += Server_WorkspaceRemoved;
|
||||
serverGroup.host = args.server.host;
|
||||
servers.Add(serverGroup);
|
||||
});
|
||||
}
|
||||
}
|
||||
qBrowserViewModel.autoUpdate = false;
|
||||
QWorkspace selectedWorkspace = (e.SelectedItem as QWorkspaceViewModel).workspace;
|
||||
Log.Debug($"workspace: {selectedWorkspace.nameWithoutPathExtension} has been selected");
|
||||
((ListView)sender).SelectedItem = null;
|
||||
|
||||
private void Server_WorkspaceRemoved(object source, QServerWorkspaceChangedArgs args)
|
||||
{
|
||||
foreach (var server in servers)
|
||||
if (selectedWorkspace.hasPasscode)
|
||||
{
|
||||
if (server.host == args.server.host)
|
||||
UserDialogs.Instance.Prompt(new PromptConfig
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
InputType = InputType.Number,
|
||||
MaxLength = 4,
|
||||
Title = "Workspace Requires Passcode",
|
||||
OkText = "Connect",
|
||||
IsCancellable = true,
|
||||
OnTextChanged = args =>
|
||||
{
|
||||
server.Remove(args.workspace);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Server_WorkspaceAdded(object source, QServerWorkspaceChangedArgs args)
|
||||
{
|
||||
foreach(var server in servers)
|
||||
{
|
||||
if(server.host == args.server.host)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
args.IsValid = args.Value != null && !args.Value.Equals("") && args.Value.Length == 4;
|
||||
},
|
||||
OnAction = async (resp) =>
|
||||
{
|
||||
server.Add(args.workspace);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Browser_ServerLost(object source, QServerLostArgs args)
|
||||
{
|
||||
|
||||
List<ServerGroup> serverGroups = servers.ToList();
|
||||
foreach(var serverGroup in serverGroups)
|
||||
{
|
||||
if(serverGroup.host == args.server.host)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
servers.Remove(serverGroup);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async void ServerListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
{
|
||||
if(e.SelectedItem != null)
|
||||
{
|
||||
QWorkspace selectedWorkspace = e.SelectedItem as QWorkspace;
|
||||
Log.Debug($"[demo] Workspace <{selectedWorkspace.nameWithoutPathExtension}> has been selected");
|
||||
if (selectedWorkspace.hasPasscode)
|
||||
{
|
||||
string passcode = await DisplayPromptAsync("Workspace has passcode", "Enter Passcode", maxLength: 4, keyboard: Keyboard.Numeric);
|
||||
if (passcode != null)
|
||||
{
|
||||
|
||||
await Navigation.PushAsync(new CueListPage(selectedWorkspace, passcode));
|
||||
if (resp.Ok)
|
||||
{
|
||||
await Navigation.PushAsync(new CueListPage(selectedWorkspace, resp.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await Navigation.PushAsync(new CueListPage(selectedWorkspace));
|
||||
|
||||
}
|
||||
serverListView.SelectedItem = null;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
await Navigation.PushAsync(new CueListPage(selectedWorkspace));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerGroup : ObservableCollection<QWorkspace>{
|
||||
public string name { get; set; }
|
||||
public string host { get; set; }
|
||||
public ServerGroup(string name)
|
||||
|
||||
protected override void OnAppearing()
|
||||
{
|
||||
this.name = name;
|
||||
base.OnAppearing();
|
||||
qBrowserViewModel.autoUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
@@ -11,9 +11,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2012" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2622" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.8.0" />
|
||||
<PackageReference Include="Acr.UserDialogs" Version="7.2.0.564" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -28,4 +29,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\QControlKit\QControlKit.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Acr.UserDialogs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xamarin.Forms;
|
||||
|
||||
using QControlKit;
|
||||
using QControlKit.Events;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Serilog;
|
||||
|
||||
namespace QControlKitXamDemo.ViewModels
|
||||
{
|
||||
public class QBrowserViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private ILogger _log = Log.Logger.ForContext<QBrowserViewModel>();
|
||||
|
||||
QBrowser browser;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public bool autoUpdate = false;
|
||||
public ObservableCollection<QServerViewModel> ServersGrouped { get; set; }
|
||||
|
||||
bool connected = false;
|
||||
public QBrowserViewModel(QBrowser browser)
|
||||
{
|
||||
this.browser = browser;
|
||||
ServersGrouped = new ObservableCollection<QServerViewModel>();
|
||||
|
||||
this.browser.ServerFound += OnServerFound;
|
||||
this.browser.ServerLost += OnServerLost;
|
||||
Device.StartTimer(TimeSpan.FromSeconds(4), () =>
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (autoUpdate)
|
||||
{
|
||||
_log.Verbose($"Auto Update is enabled running probe");
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
_log.Debug("QBrowser probe triggered");
|
||||
this.browser.ProbeForQLabInstances();
|
||||
});
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void OnServerFound(object source, QServerFoundArgs args)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
_log.Debug($"adding server: {args.server.description}");
|
||||
ServersGrouped.Add(new QServerViewModel(args.server));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void OnServerLost(object source, QServerLostArgs args)
|
||||
{
|
||||
QServerViewModel serverToRemove = null;
|
||||
|
||||
foreach (QServerViewModel serverGroup in ServersGrouped)
|
||||
{
|
||||
if (serverGroup.host.Equals(args.server.host))
|
||||
{
|
||||
serverToRemove = serverGroup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (serverToRemove != null)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
_log.Debug($"removing server: {args.server.description}");
|
||||
ServersGrouped.Remove(serverToRemove);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void OnPropertyChanged([CallerMemberName] string name = "")
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
}
|
||||
|
||||
public void InitiateScan()
|
||||
{
|
||||
if (!autoUpdate)
|
||||
{
|
||||
_log.Debug("Manual Scan Initiated");
|
||||
browser.ProbeForQLabInstances();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,14 @@ using Xamarin.Forms;
|
||||
using Serilog;
|
||||
using QControlKit.Events;
|
||||
using QControlKit.Constants;
|
||||
using System;
|
||||
|
||||
namespace QControlKitXamDemo.ViewModels
|
||||
{
|
||||
public class QCueViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private ILogger _log = Log.Logger.ForContext<QCueViewModel>();
|
||||
|
||||
QCue cue;
|
||||
bool isSelected = false;
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
@@ -17,22 +20,32 @@ namespace QControlKitXamDemo.ViewModels
|
||||
public QCueViewModel(QCue cue, bool checkPlayback)
|
||||
{
|
||||
this.cue = cue;
|
||||
if(checkPlayback)
|
||||
if (checkPlayback)
|
||||
{
|
||||
this.cue.workspace.CueListChangedPlaybackPosition += Workspace_CueListChangedPlaybackPosition;
|
||||
}
|
||||
this.cue.CuePropertiesUpdated += OnCuePropertiesUpdated;
|
||||
}
|
||||
|
||||
private void OnCuePropertiesUpdated(object source, QCuePropertiesUpdatedArgs args)
|
||||
{
|
||||
foreach(var property in args.properties)
|
||||
_log.Debug($"properties updated from cue");
|
||||
|
||||
foreach (var property in args.properties)
|
||||
{
|
||||
Log.Debug($"[cueviewmodel] property <{property}> has been updated.");
|
||||
_log.Debug($"property <{property}> has been updated for cue {name}.");
|
||||
if (property.Equals(QOSCKey.Name) || property.Equals(QOSCKey.ListName))
|
||||
{
|
||||
OnPropertyChanged("name");
|
||||
}else if (property.Equals(QOSCKey.ColorName))
|
||||
{
|
||||
OnPropertyChanged("color");
|
||||
}else if (property.Equals(QOSCKey.ActionElapsed))
|
||||
{
|
||||
OnPropertyChanged("actionElapsed");
|
||||
}else if (property.Equals(QOSCKey.IsBroken) || property.Equals(QOSCKey.IsRunning))
|
||||
{
|
||||
OnPropertyChanged("status");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,6 +97,34 @@ namespace QControlKitXamDemo.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public string actionElapsed
|
||||
{
|
||||
get
|
||||
{
|
||||
TimeSpan time = TimeSpan.FromSeconds(cue.actionElapsed);
|
||||
|
||||
return time.ToString(@"mm\:ss\:ff");
|
||||
}
|
||||
}
|
||||
|
||||
public string status
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cue.IsRunning)
|
||||
{
|
||||
return "running";
|
||||
}else if (cue.IsBroken)
|
||||
{
|
||||
return "broken";
|
||||
}
|
||||
else
|
||||
{
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSelected {
|
||||
get
|
||||
{
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xamarin.Forms;
|
||||
|
||||
using QControlKit;
|
||||
using QControlKit.Events;
|
||||
using Serilog;
|
||||
|
||||
namespace QControlKitXamDemo.ViewModels
|
||||
{
|
||||
public class QServerViewModel : ObservableCollection<QWorkspaceViewModel>, INotifyPropertyChanged
|
||||
{
|
||||
private ILogger _log = Log.Logger.ForContext<QServerViewModel>();
|
||||
|
||||
QServer server;
|
||||
public new event PropertyChangedEventHandler PropertyChanged;
|
||||
public string name
|
||||
{
|
||||
get => server.name;
|
||||
set => server.name = value;
|
||||
}
|
||||
|
||||
public string host => server.host;
|
||||
|
||||
public string version => server.version == null ? "" : $"v{server.version}";
|
||||
|
||||
public string GroupName => $"{name} ({host})";
|
||||
|
||||
public QServerViewModel(QServer server)
|
||||
{
|
||||
this.server = server;
|
||||
name = this.server.name;
|
||||
foreach (QWorkspace workspace in this.server.workspaces)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Add(new QWorkspaceViewModel(workspace));
|
||||
});
|
||||
}
|
||||
this.server.WorkspaceAdded += Server_WorkspaceAdded;
|
||||
this.server.WorkspaceRemoved += Server_WorkspaceRemoved;
|
||||
this.server.ServerUpdated += OnServerUpdated;
|
||||
}
|
||||
|
||||
private void Server_WorkspaceRemoved(object source, QServerWorkspaceChangedArgs args)
|
||||
{
|
||||
QWorkspaceViewModel workspaceToRemove = null;
|
||||
|
||||
foreach (QWorkspaceViewModel workspaceViewModel in this)
|
||||
{
|
||||
if (workspaceViewModel.workspace.uniqueID == args.workspace.uniqueID)
|
||||
{
|
||||
workspaceToRemove = workspaceViewModel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (workspaceToRemove != null)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Remove(workspaceToRemove);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void Server_WorkspaceAdded(object source, QServerWorkspaceChangedArgs args)
|
||||
{
|
||||
QWorkspaceViewModel workspaceViewModel = new QWorkspaceViewModel(args.workspace);
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Add(workspaceViewModel);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void OnServerUpdated(object source, QServerUpdatedArgs args)
|
||||
{
|
||||
OnPropertyChanged("GroupName");
|
||||
OnPropertyChanged("version");
|
||||
}
|
||||
|
||||
void OnPropertyChanged([CallerMemberName] string name = "")
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using QControlKit;
|
||||
|
||||
namespace QControlKitXamDemo.ViewModels
|
||||
{
|
||||
public class QWorkspaceViewModel
|
||||
{
|
||||
public QWorkspace workspace;
|
||||
public QWorkspaceViewModel(QWorkspace workspace)
|
||||
{
|
||||
this.workspace = workspace;
|
||||
}
|
||||
|
||||
public string Name => workspace.name;
|
||||
|
||||
public bool HasPasscode => workspace.hasPasscode;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,15 @@
|
||||
This is an unofficial .NET library port of Figure53's [QLabKit](https://github.com/Figure53/QLabKit.objc).
|
||||
|
||||
|
||||
## Components
|
||||
- **QBrowser**: Searches for an maintains a list of QLab "instances" using bonjour
|
||||
- **QClient**: Wrapper over underlying TCP/UDP connection as well as providing event handlers for common QLab replies (i.e. cue needs updated, workspace need updated, etc.)
|
||||
- **QCue**: The most basic object in QLab, contains shared properties and methods for a cue in a cuelist (cuelists are also a cue) is extended for other cue types (Text, Midi, etc.)
|
||||
- **QMessage**: Wrapper over underlying OSC Message, has methods to quickly determine the message type and parts (Workspace info, address, arguments, etc.)
|
||||
- **QServer**: This class represents a computer that is running QLab, it has host information (IP, Port) as well as discovered workspaces on that computer.
|
||||
- **QWorkspace**: This class represents a workspace on a QServer, it contains methods and properties to interact with a workspace as well as access the underlying QCues and QClient that is facilitating communication
|
||||
|
||||
|
||||
## Todo: give a basic example of the workflow
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user