EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicTests", "Samples\BasicTests\BasicTests.csproj", "{7AEB6DD5-916E-4415-84E1-78EC6E5881CE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "glfw-sharp", "..\..\glfw-sharp\glfw-sharp.csproj", "{A07754EB-1CAF-4D2D-8247-A3B6A46FB943}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
{7AEB6DD5-916E-4415-84E1-78EC6E5881CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7AEB6DD5-916E-4415-84E1-78EC6E5881CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7AEB6DD5-916E-4415-84E1-78EC6E5881CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A07754EB-1CAF-4D2D-8247-A3B6A46FB943}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A07754EB-1CAF-4D2D-8247-A3B6A46FB943}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A07754EB-1CAF-4D2D-8247-A3B6A46FB943}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A07754EB-1CAF-4D2D-8247-A3B6A46FB943}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
<PackageReference Include="System.Reflection.Emit.ILGeneration" Version="4.6.0" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.6.0" />
<!--<PackageReference Include="glfw-sharp" Version="0.2.0" />-->
- <PackageReference Include="glfw-sharp" Version="0.2.4" />
+<!-- <PackageReference Include="glfw-sharp" Version="0.2.5" />-->
</ItemGroup>
<PropertyGroup Condition=" '$(CrowStbSharp)' == 'true'">
<DefineConstants>$(DefineConstants);STB_SHARP</DefineConstants>
</EmbeddedResource>
<EmbeddedResource Include="Default.style" />
<EmbeddedResource Include="Icons\*.*" />
+ <EmbeddedResource Include="Cursors\*.*">
+ <LogicalName>Crow.Cursors.%(Filename)</LogicalName>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\glfw-sharp\glfw-sharp.csproj" />
</ItemGroup>
</Project>
/// <summary>
/// Universal Color structure
/// </summary>
- public struct Color
+ public struct Color : IEquatable<Color>
{
#region CTOR
public Color(double _R, double _G, double _B, double _A)
double.Parse(c[3]));
}
- public static bool operator ==(Color left, Color right)
- {
- if (left.predefinied & right.predefinied)
- return left.htmlCode == right.htmlCode;
- return left.A != right.A ? false :
- left.R != right.R ? false :
- left.G != right.G ? false :
- left.B != right.B ? false : true;
- }
- public static bool operator !=(Color left, Color right)
- {
- if (left.predefinied & right.predefinied)
- return left.htmlCode != right.htmlCode;
- return left.A == right.A ? false :
- left.R == right.R ? false :
- left.G == right.G ? false :
- left.B == right.B ? false : true;
-
- }
public static bool operator ==(Color c, string n)
{
return n.StartsWith("#", StringComparison.Ordinal) ?
#endregion
+ public override bool Equals (object obj)
+ => obj is Color c && Equals(c);
+ public bool Equals (Color other)
+ {
+ if (predefinied & other.predefinied)
+ return htmlCode == other.htmlCode;
+ return A == other.A && R == other.R && G == other.G && B == other.B;
+ }
+
public override int GetHashCode ()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
- hash = hash * 23 + A.GetHashCode();
- hash = hash * 23 + R.GetHashCode();
- hash = hash * 23 + G.GetHashCode();
- hash = hash * 23 + B.GetHashCode();
+ hash = hash * 23 + A.GetHashCode ();
+ hash = hash * 23 + R.GetHashCode ();
+ hash = hash * 23 + G.GetHashCode ();
+ hash = hash * 23 + B.GetHashCode ();
return hash;
}
}
- public override bool Equals (object obj)
- {
- return (obj == null || obj.GetType() != typeof(Color)) ?
- false :
- this == (Color)obj;
- }
+
public override string ToString()
{
if (!string.IsNullOrEmpty(Name))
{
return (Color)s;
}
- //public static Color FromHSV(double _h, double _v = 1.0, double _s = 1.0, double _alpha = 1.0){
- // Color c = Color.Black;
- // c.ResetName ();
- // c.A = _alpha;
- // if (_s == 0) {//HSV from 0 to 1
- // c.R = _v;
- // c.G = _v;
- // c.B = _v;
- // }else{
- // double var_h = _h * 6.0;
-
- // if (var_h == 6.0)
- // var_h = 0; //H must be < 1
- // double var_i = Math.Floor( var_h ); //Or ... var_i = floor( var_h )
- // double var_1 = _v * ( 1.0 - _s );
- // double var_2 = _v * (1.0 - _s * (var_h - var_i));
- // double var_3 = _v * (1.0 - _s * (1.0 - (var_h - var_i)));
-
- // if (var_i == 0.0) {
- // c.R = _v;
- // c.G = var_3;
- // c.B = var_1;
- // }else if ( var_i == 1.0 ) { c.R = var_2 ; c.G = _v ; c.B = var_1; }
- // else if ( var_i == 2 ) { c.R = var_1 ; c.G = _v ; c.B = var_3; }
- // else if ( var_i == 3 ) { c.R = var_1 ; c.G = var_2 ; c.B = _v; }
- // else if ( var_i == 4 ) { c.R = var_3 ; c.G = var_1 ; c.B = _v; }
- // else { c.R = _v ; c.G = var_1 ; c.B = var_2; }
- // }
- // return c;
- //}
public static Color FromHSV (double _h, double _v = 1.0, double _s = 1.0, double _alpha = 1.0) {
double H = _h * 360;
double C = _v * _s;
return new Color (C + m, X + m, m, _alpha);
}
+
}
}
}
public enum MouseCursor
{
- Arrow,
- IBeam,
- Crosshair,
- Circle,
- Hand,
- Move,
- Wait,
- H,
- V,
- Top,
- TopLeft,
- TopRight,
- Left,
- Right,
- BottomLeft,
- Bottom,
- BottomRight,
- NW,
- NE,
- SW,
- SE,
+ arrow,
+ base_arrow_down,
+ base_arrow_up,
+ boat,
+ bottom_left_corner,
+ bottom_right_corner,
+ bottom_side,
+ bottom_tee,
+ center_ptr,
+ circle,
+ cross,
+ cross_reverse,
+ crosshair,
+ dot,
+ dot_box_mask,
+ double_arrow,
+ draft_large,
+ draft_small,
+ draped_box,
+ exchange,
+ fleur,
+ gumby,
+ hand,
+ hand1,
+ hand2,
+ help,
+ ibeam,
+ left_ptr,
+ left_ptr_watch,
+ left_side,
+ left_tee,
+ ll_angle,
+ lr_angle,
+ move,
+ pencil,
+ pirate,
+ plus,
+ question_arrow,
+ right_ptr,
+ right_side,
+ right_tee,
+ sailboat,
+ sb_down_arrow,
+ sb_h_double_arrow,
+ sb_left_arrow,
+ sb_right_arrow,
+ sb_up_arrow,
+ sb_v_double_arrow,
+ shuttle,
+ sizing,
+ target,
+ tcross,
+ top_left_arrow,
+ top_left_corner,
+ top_right_corner,
+ top_side,
+ top_tee,
+ trek,
+ ul_angle,
+ ur_angle,
+ watch,
+ X_cursor,
+ xterm,
}
/// <summary>
/// Cursor shape use in Sliders
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Runtime.InteropServices;
using System.Threading;
using Crow.Cairo;
using Crow.IML;
}
#endregion
+ #region CTOR
+ static Interface ()
+ {
+ /*if (Type.GetType ("Mono.Runtime") == null) {
+ throw new Exception (@"C.R.O.W. run only on Mono, download latest version at: http://www.mono-project.com/download/stable/");
+ }*/
+
+ CROW_CONFIG_ROOT =
+ System.IO.Path.Combine (
+ Environment.GetFolderPath (Environment.SpecialFolder.UserProfile),
+ ".config");
+ CROW_CONFIG_ROOT = System.IO.Path.Combine (CROW_CONFIG_ROOT, "crow");
+ if (!Directory.Exists (CROW_CONFIG_ROOT))
+ Directory.CreateDirectory (CROW_CONFIG_ROOT);
+
+ //ensure all assemblies are loaded, because IML could contains classes not instanciated in source
+ foreach (string af in Directory.GetFiles (AppDomain.CurrentDomain.BaseDirectory, "*.dll")) {
+ try {
+ Assembly.LoadFrom (af);
+ } catch {
+ Console.WriteLine ("{0} not loaded as assembly.", af);
+ }
+ }
+
+ FontRenderingOptions = new FontOptions ();
+ FontRenderingOptions.Antialias = Antialias.Subpixel;
+ FontRenderingOptions.HintMetrics = HintMetrics.On;
+ FontRenderingOptions.HintStyle = HintStyle.Full;
+ FontRenderingOptions.SubpixelOrder = SubpixelOrder.Default;
+
+ loadCursors ();
+ }
+ public Interface (int width, int height, IntPtr glfwWindowHandle) : this (width, height, false, false)
+ {
+ hWin = glfwWindowHandle;
+ }
+ public Interface (int width = 800, int height = 600, bool startUIThread = true, bool createSurface = true)
+ {
+ CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
+ CurrentInterface = this;
+ clientRectangle = new Rectangle (0, 0, width, height);
+
+ if (createSurface)
+ initSurface ();
+
+ if (startUIThread) {
+ Thread t = new Thread (InterfaceThread) {
+ IsBackground = true
+ };
+ t.Start ();
+ }
+
+#if MEASURE_TIME
+ PerfMeasures.Add (updateMeasure);
+ PerfMeasures.Add (drawingMeasure);
+ PerfMeasures.Add (layoutingMeasure);
+ PerfMeasures.Add (clippingMeasure);
+#endif
+ }
+ #endregion
+
/** GLFW callback may return a custom pointer, this list makes the link between the GLFW window pointer and the
manage VkWindow instance. */
static Dictionary<IntPtr, Interface> windows = new Dictionary<IntPtr, Interface> ();
/** GLFW window native pointer and current native handle for mouse cursor */
- IntPtr hWin, currentCursor;
+ IntPtr hWin;
+ Cursor currentCursor;
+ bool ownWindow;
void initSurface ()
{
Glfw3.WindowHint (WindowAttribute.ClientApi, 0);
Glfw3.WindowHint (WindowAttribute.Resizable, 1);
+ Glfw3.WindowHint (WindowAttribute.Decorated, 1);
hWin = Glfw3.CreateWindow (clientRectangle.Width, clientRectangle.Height, "win name", MonitorHandle.Zero, IntPtr.Zero);
-
if (hWin == IntPtr.Zero)
throw new Exception ("[GLFW3] Unable to create vulkan Window");
+ ownWindow = true;
Glfw3.SetKeyCallback (hWin, HandleKeyDelegate);
Glfw3.SetMouseButtonPosCallback (hWin, HandleMouseButtonDelegate);
#endregion
- #region CTOR
- static Interface () {
- /*if (Type.GetType ("Mono.Runtime") == null) {
- throw new Exception (@"C.R.O.W. run only on Mono, download latest version at: http://www.mono-project.com/download/stable/");
- }*/
-
- CROW_CONFIG_ROOT =
- System.IO.Path.Combine (
- Environment.GetFolderPath (Environment.SpecialFolder.UserProfile),
- ".config");
- CROW_CONFIG_ROOT = System.IO.Path.Combine (CROW_CONFIG_ROOT, "crow");
- if (!Directory.Exists (CROW_CONFIG_ROOT))
- Directory.CreateDirectory (CROW_CONFIG_ROOT);
- //ensure all assemblies are loaded, because IML could contains classes not instanciated in source
- foreach (string af in Directory.GetFiles (AppDomain.CurrentDomain.BaseDirectory, "*.dll")) {
- try {
- Assembly.LoadFrom (af);
- } catch {
- Console.WriteLine ("{0} not loaded as assembly.", af);
- }
- }
-
- FontRenderingOptions = new FontOptions ();
- FontRenderingOptions.Antialias = Antialias.Subpixel;
- FontRenderingOptions.HintMetrics = HintMetrics.On;
- FontRenderingOptions.HintStyle = HintStyle.Full;
- FontRenderingOptions.SubpixelOrder = SubpixelOrder.Default;
- }
- public Interface (int width, int height, IntPtr glfwWindowHandle) : this(width, height, false, false)
- {
- hWin = glfwWindowHandle;
- }
- public Interface(int width=800, int height=600, bool startUIThread = true, bool createSurface = true) {
- CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
- CurrentInterface = this;
- clientRectangle = new Rectangle (0, 0, width, height);
-
- if (createSurface)
- initSurface ();
-
- if (startUIThread) {
- Thread t = new Thread (InterfaceThread) {
- IsBackground = true
- };
- t.Start ();
- }
-
-#if MEASURE_TIME
- PerfMeasures.Add (updateMeasure);
- PerfMeasures.Add (drawingMeasure);
- PerfMeasures.Add (layoutingMeasure);
- PerfMeasures.Add (clippingMeasure);
-#endif
- }
- #endregion
public bool Running {
get => !Glfw3.WindowShouldClose (hWin);
- set => Glfw3.SetWindowShouldClose (hWin, 1);
+ set => Glfw3.SetWindowShouldClose (hWin, value == true ? 0 : 1);
}
public virtual void InterfaceThread ()
{
#endif
}
}
- protected virtual void Startup ()
+ protected virtual void OnInitialized ()
{
try {
Load ("#main.crow").DataSource = this;
} catch { }
+ Initialized.Raise (this, null);
}
/// <summary>
/// load styling, init default tooltips and context menus, load main.crow resource if exists.
loadStyling ();
initTooltip ();
initContextMenus ();
- Startup ();
+ OnInitialized ();
}
/// <summary>
/// call Init() then enter the running loop performing ProcessEvents until running==false.
// TODO: dispose managed state (managed objects).
}
- if (currentCursor != IntPtr.Zero)
- Glfw3.DestroyCursor (currentCursor);
-
- Glfw3.DestroyWindow (hWin);
- Glfw3.Terminate ();
+ currentCursor?.Dispose ();
+ if (ownWindow) {
+ Glfw3.DestroyWindow (hWin);
+ Glfw3.Terminate ();
+ }
disposedValue = true;
}
/// <summary> delay before tooltip appears </summary>
public static int TOOLTIP_DELAY = 500;
/// <summary>Double click threshold in milisecond</summary>
- public static int DOUBLECLICK_TRESHOLD = 240;//max duration between two mouse_down evt for a dbl clk in milisec.
+ public static int DOUBLECLICK_TRESHOLD = 320;//max duration between two mouse_down evt for a dbl clk in milisec.
/// <summary> Time to wait in millisecond before starting repeat loop</summary>
public static int DEVICE_REPEAT_DELAY = 700;
/// <summary> Time interval in millisecond between device event repeat</summary>
#region Events
//public event EventHandler<MouseCursorChangedEventArgs> MouseCursorChanged;
////public event EventHandler Quit;
-
+ public event EventHandler Initialized;
//public event EventHandler<MouseWheelEventArgs> MouseWheelChanged;
//public event EventHandler<MouseButtonEventArgs> MouseButtonUp;
//public event EventHandler<MouseButtonEventArgs> MouseButtonDown;
}
#region Mouse and Keyboard Handling
- MouseCursor cursor = MouseCursor.Arrow;
+ MouseCursor cursor = MouseCursor.top_left_arrow;
+ static void loadCursors ()
+ {
+ const int minimumSize = 32;
+ //Load cursors
+ XCursor.Cursors [MouseCursor.arrow] = XCursorFile.Load ("#Crow.Cursors.arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.base_arrow_down] = XCursorFile.Load ("#Crow.Cursors.base_arrow_down").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.base_arrow_up] = XCursorFile.Load ("#Crow.Cursors.base_arrow_up").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.boat] = XCursorFile.Load ("#Crow.Cursors.boat").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.bottom_left_corner] = XCursorFile.Load ("#Crow.Cursors.bottom_left_corner").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.bottom_right_corner] = XCursorFile.Load ("#Crow.Cursors.bottom_right_corner").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.bottom_side] = XCursorFile.Load ("#Crow.Cursors.bottom_side").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.bottom_tee] = XCursorFile.Load ("#Crow.Cursors.bottom_tee").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.center_ptr] = XCursorFile.Load ("#Crow.Cursors.center_ptr").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.circle] = XCursorFile.Load ("#Crow.Cursors.circle").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.cross] = XCursorFile.Load ("#Crow.Cursors.cross").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.cross_reverse] = XCursorFile.Load ("#Crow.Cursors.cross_reverse").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.crosshair] = XCursorFile.Load ("#Crow.Cursors.crosshair").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.dot] = XCursorFile.Load ("#Crow.Cursors.dot").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.dot_box_mask] = XCursorFile.Load ("#Crow.Cursors.dot_box_mask").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.double_arrow] = XCursorFile.Load ("#Crow.Cursors.double_arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.draft_large] = XCursorFile.Load ("#Crow.Cursors.draft_large").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.draft_small] = XCursorFile.Load ("#Crow.Cursors.draft_small").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.draped_box] = XCursorFile.Load ("#Crow.Cursors.draped_box").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.exchange] = XCursorFile.Load ("#Crow.Cursors.exchange").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.fleur] = XCursorFile.Load ("#Crow.Cursors.fleur").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.gumby] = XCursorFile.Load ("#Crow.Cursors.gumby").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.hand] = XCursorFile.Load ("#Crow.Cursors.hand").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.hand1] = XCursorFile.Load ("#Crow.Cursors.hand1").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.hand2] = XCursorFile.Load ("#Crow.Cursors.hand2").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.help] = XCursorFile.Load ("#Crow.Cursors.help").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.ibeam] = XCursorFile.Load ("#Crow.Cursors.ibeam").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.left_ptr] = XCursorFile.Load ("#Crow.Cursors.left_ptr").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.left_ptr_watch] = XCursorFile.Load ("#Crow.Cursors.left_ptr_watch").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.left_side] = XCursorFile.Load ("#Crow.Cursors.left_side").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.left_tee] = XCursorFile.Load ("#Crow.Cursors.left_tee").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.ll_angle] = XCursorFile.Load ("#Crow.Cursors.ll_angle").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.lr_angle] = XCursorFile.Load ("#Crow.Cursors.lr_angle").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.move] = XCursorFile.Load ("#Crow.Cursors.move").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.pencil] = XCursorFile.Load ("#Crow.Cursors.pencil").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.pirate] = XCursorFile.Load ("#Crow.Cursors.pirate").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.plus] = XCursorFile.Load ("#Crow.Cursors.plus").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.question_arrow] = XCursorFile.Load ("#Crow.Cursors.question_arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.right_ptr] = XCursorFile.Load ("#Crow.Cursors.right_ptr").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.right_side] = XCursorFile.Load ("#Crow.Cursors.right_side").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.right_tee] = XCursorFile.Load ("#Crow.Cursors.right_tee").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.sailboat] = XCursorFile.Load ("#Crow.Cursors.sailboat").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.sb_down_arrow] = XCursorFile.Load ("#Crow.Cursors.sb_down_arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.sb_h_double_arrow] = XCursorFile.Load ("#Crow.Cursors.sb_h_double_arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.sb_left_arrow] = XCursorFile.Load ("#Crow.Cursors.sb_left_arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.sb_right_arrow] = XCursorFile.Load ("#Crow.Cursors.sb_right_arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.sb_up_arrow] = XCursorFile.Load ("#Crow.Cursors.sb_up_arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.sb_v_double_arrow] = XCursorFile.Load ("#Crow.Cursors.sb_v_double_arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.shuttle] = XCursorFile.Load ("#Crow.Cursors.shuttle").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.sizing] = XCursorFile.Load ("#Crow.Cursors.sizing").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.target] = XCursorFile.Load ("#Crow.Cursors.target").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.tcross] = XCursorFile.Load ("#Crow.Cursors.tcross").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.top_left_arrow] = XCursorFile.Load ("#Crow.Cursors.top_left_arrow").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.top_left_corner] = XCursorFile.Load ("#Crow.Cursors.top_left_corner").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.top_right_corner] = XCursorFile.Load ("#Crow.Cursors.top_right_corner").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.top_side] = XCursorFile.Load ("#Crow.Cursors.top_side").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.top_tee] = XCursorFile.Load ("#Crow.Cursors.top_tee").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.trek] = XCursorFile.Load ("#Crow.Cursors.trek").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.ul_angle] = XCursorFile.Load ("#Crow.Cursors.ul_angle").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.ur_angle] = XCursorFile.Load ("#Crow.Cursors.ur_angle").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.watch] = XCursorFile.Load ("#Crow.Cursors.watch").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.X_cursor] = XCursorFile.Load ("#Crow.Cursors.X_cursor").Cursors.First (c => c.Width >= minimumSize);
+ XCursor.Cursors [MouseCursor.xterm] = XCursorFile.Load ("#Crow.Cursors.xterm").Cursors.First (c => c.Width >= minimumSize);
+ }
+
Stopwatch lastMouseDown = Stopwatch.StartNew (), mouseRepeatTimer = new Stopwatch ();
bool doubleClickTriggered; //next mouse up will trigger a double click
public Point MousePosition { get; set; } = default;
public bool IsDown (MouseButton button) => Glfw3.GetMouseButton (hWin, button) != InputAction.Release;
+ Cursor createCursor (MouseCursor mc)
+ {
+ XCursor c = XCursor.Cursors [mc];
+ return new CustomCursor (c.Width, c.Height, c.data, c.Xhot, c.Yhot);
+ }
+
+
public MouseCursor MouseCursor {
get => cursor;
set {
-
+
if (value == cursor)
return;
cursor = value;
- if (currentCursor != IntPtr.Zero)
- Glfw3.DestroyCursor (currentCursor);
- switch (MouseCursor) {
- case MouseCursor.Arrow:
- currentCursor = Glfw3.CreateStandardCursor (CursorShape.Arrow);
- break;
- case MouseCursor.IBeam:
- currentCursor = Glfw3.CreateStandardCursor (CursorShape.IBeam);
- break;
- case MouseCursor.Crosshair:
- currentCursor = Glfw3.CreateStandardCursor (CursorShape.Crosshair);
- break;
- case MouseCursor.Circle:
- break;
- case MouseCursor.Hand:
- currentCursor = Glfw3.CreateStandardCursor (CursorShape.Hand);
- break;
- case MouseCursor.Wait:
- break;
- case MouseCursor.H:
- currentCursor = Glfw3.CreateStandardCursor (CursorShape.HResize);
- break;
- case MouseCursor.V:
- currentCursor = Glfw3.CreateStandardCursor (CursorShape.VResize);
- break;
- case MouseCursor.Move:
- case MouseCursor.Top:
- case MouseCursor.TopLeft:
- case MouseCursor.TopRight:
- case MouseCursor.Left:
- case MouseCursor.Right:
- case MouseCursor.BottomLeft:
- case MouseCursor.Bottom:
- case MouseCursor.BottomRight:
- case MouseCursor.NW:
- case MouseCursor.NE:
- case MouseCursor.SW:
- case MouseCursor.SE:
- default:
- currentCursor = Glfw3.CreateStandardCursor (CursorShape.Arrow);
- break;
- }
- Glfw3.SetCursor (hWin, currentCursor);
+ currentCursor?.Dispose ();
+ currentCursor = createCursor (cursor);
+ Console.WriteLine ($"cursor=>{cursor}");
+ currentCursor.Set (hWin);
//MouseCursorChanged.Raise (this,new MouseCursorChangedEventArgs(cursor));
}
}
{
base.onMouseEnter (sender, e);
if ((Parent as GenericStack).Orientation == Orientation.Horizontal)
- IFace.MouseCursor = MouseCursor.H;
+ IFace.MouseCursor = MouseCursor.sb_h_double_arrow;
else
- IFace.MouseCursor = MouseCursor.V;
+ IFace.MouseCursor = MouseCursor.sb_v_double_arrow;
}
public override void onMouseDown (object sender, MouseButtonEventArgs e)
{
#region GraphicObject overrides
[XmlIgnore]public override bool HasFocus //trigger update when lost focus to errase text beam
{
- get
- {
- return base.HasFocus;
- }
- set
- {
+ get => base.HasFocus;
+ set {
base.HasFocus = value;
RegisterForRedraw();
}
bool isActive;
bool isHover;
bool mouseRepeat;
- MouseCursor mouseCursor = MouseCursor.Arrow;
+ MouseCursor mouseCursor = MouseCursor.top_left_arrow;
protected bool isVisible = true;
bool isEnabled = true;
VerticalAlignment verticalAlignment = VerticalAlignment.Center;
/// Determine Cursor when mouse is Hover.
/// </summary>
[DesignCategory ("Behaviour")]
- [DefaultValue (MouseCursor.Arrow)]
+ [DefaultValue (MouseCursor.top_left_arrow)]
public virtual MouseCursor MouseCursor {
get { return mouseCursor; }
set {
Debug.WriteLine("MouseEnter => " + this.ToString());
#endif
- IFace.MouseCursor = mouseCursor;
+ IFace.MouseCursor = MouseCursor;
if (IFace.DragAndDropOperation != null) {
Widget g = this;
//if (currentDirection != lastDir) {
switch (currentDirection) {
case Direction.None:
- otkgw.MouseCursor = MouseCursor.Move;
+ otkgw.MouseCursor = MouseCursor.move;
break;
case Direction.N:
- otkgw.MouseCursor = MouseCursor.Top;
+ otkgw.MouseCursor = MouseCursor.top_side;
break;
case Direction.S:
- otkgw.MouseCursor = MouseCursor.Bottom;
+ otkgw.MouseCursor = MouseCursor.bottom_side;
break;
case Direction.E:
- otkgw.MouseCursor = MouseCursor.Right;
+ otkgw.MouseCursor = MouseCursor.right_side;
break;
case Direction.W:
- otkgw.MouseCursor = MouseCursor.Left;
+ otkgw.MouseCursor = MouseCursor.left_side;
break;
case Direction.NW:
- otkgw.MouseCursor = MouseCursor.TopLeft;
+ otkgw.MouseCursor = MouseCursor.top_left_corner;
break;
case Direction.NE:
- otkgw.MouseCursor = MouseCursor.TopRight;
+ otkgw.MouseCursor = MouseCursor.top_right_corner;
break;
case Direction.SW:
- otkgw.MouseCursor = MouseCursor.BottomLeft;
+ otkgw.MouseCursor = MouseCursor.bottom_left_corner;
break;
case Direction.SE:
- otkgw.MouseCursor = MouseCursor.BottomRight;
+ otkgw.MouseCursor = MouseCursor.bottom_right_corner;
break;
}
//}
{
base.onMouseLeave (sender, e);
currentDirection = Direction.None;
- IFace.MouseCursor = MouseCursor.Arrow;
+ IFace.MouseCursor = MouseCursor.top_left_arrow;
}
public override void onMouseDown (object sender, MouseButtonEventArgs e)
{
protected void butQuitPress (object sender, MouseButtonEventArgs e)
{
- IFace.MouseCursor = MouseCursor.Arrow;
+ IFace.MouseCursor = MouseCursor.top_left_arrow;
close ();
}
return tmp;
}
- public static XCursorFile Load(Interface iface, string path)
+ public static XCursorFile Load(string path)
{
- return loadFromStream (iface.GetStreamFromPath (path));
+ return loadFromStream (Interface.StaticGetStreamFromPath (path));
}
- static XCursor imageLoad(BinaryReader sr)
+ static XCursor imageLoad (BinaryReader sr)
{
- XCursor tmp = new XCursor();
+ XCursor tmp = new XCursor ();
// header: 36 Image headers are 36 bytes
- uint header = sr.ReadUInt32();
+ uint header = sr.ReadUInt32 ();
// type: 0xfffd0002 Image type is 0xfffd0002
- uint type = sr.ReadUInt32();
+ uint type = sr.ReadUInt32 ();
// subtype: CARD32 Image subtype is the nominal size
- uint subtype = sr.ReadUInt32();
+ uint subtype = sr.ReadUInt32 ();
// version: 1
- uint version = sr.ReadUInt32();
+ uint version = sr.ReadUInt32 ();
// width: CARD32 Must be less than or equal to 0x7fff
- tmp.Width = sr.ReadUInt32();
+ tmp.Width = sr.ReadUInt32 ();
// height: CARD32 Must be less than or equal to 0x7fff
- tmp.Height = sr.ReadUInt32();
+ tmp.Height = sr.ReadUInt32 ();
// xhot: CARD32 Must be less than or equal to width
- tmp.Xhot = sr.ReadUInt32();
+ tmp.Xhot = sr.ReadUInt32 ();
// yhot: CARD32 Must be less than or equal to height
- tmp.Yhot = sr.ReadUInt32();
+ tmp.Yhot = sr.ReadUInt32 ();
// delay: CARD32 Delay between animation frames in milliseconds
- tmp.Delay = sr.ReadUInt32();
+ tmp.Delay = sr.ReadUInt32 ();
// pixels: LISTofCARD32 Packed ARGB format pixels
- tmp.data = sr.ReadBytes((int)(tmp.Width * tmp.Height * 4));
+ tmp.data = new byte [tmp.Width * tmp.Height * 4];
+ for (int i = 0; i < tmp.Width * tmp.Height; i++) {
+ //unchecked { tmp.data [i * 4 + 3] = (byte)(2 * (int)sr.ReadByte ()); }
+ tmp.data [i * 4 + 0] = sr.ReadByte ();
+ tmp.data [i * 4 + 1] = sr.ReadByte ();
+ tmp.data [i * 4 + 2] = sr.ReadByte ();
+ tmp.data [i * 4 + 3] = sr.ReadByte ();
+
+ //Console.WriteLine ($"{tmp.data [i * 4 + 3],2:X} {tmp.data [i * 4 + 0],2:X} {tmp.data [i * 4 + 1],2:X} {tmp.data [i * 4 + 2],2:X}");
+ }
+ //tmp.data = sr.ReadBytes((int)(tmp.Width * tmp.Height * 4));
+ /*using(Stream fs = new FileStream($"/tmp/test.bin_{tmp.Width}", FileMode.Create))
+ using (BinaryWriter sr2 = new BinaryWriter(fs)) {
+ sr2.Write (tmp.data, 0, tmp.data.Length);
+ }*/
return tmp;
}
}
public class XCursor
{
- public static XCursor Default;
- public static XCursor Cross;
- public static XCursor Arrow;
- public static XCursor Text;
- public static XCursor SW;
- public static XCursor SE;
- public static XCursor NW;
- public static XCursor NE;
- public static XCursor N;
- public static XCursor S;
- public static XCursor V;
- public static XCursor H;
-
+ public static readonly Dictionary<MouseCursor, XCursor> Cursors = new Dictionary<MouseCursor, XCursor>();
public uint Width;
public uint Height;
public uint Xhot;
<Authors>Jean-Philippe Bruyère</Authors>
<LangVersion>7.2</LangVersion>
- <CrowVersion>0.8.12</CrowVersion>
+ <CrowVersion>0.9.1</CrowVersion>
<CrowPackageVersion>$(CrowVersion)-beta</CrowPackageVersion>
<CrowStbSharp>true</CrowStbSharp>
</PropertyGroup>
C# Rapid Open Widgets
<br>
<p align="center">
+ <a href="https://www.nuget.org/packages/Crow"><img src="https://buildstats.info/nuget/Crow"></a>
<a href="https://travis-ci.org/jpbruyere/Crow">
<img src="https://img.shields.io/travis/jpbruyere/Crow.svg?&logo=travis&logoColor=white">
</a>
</p>
</h1>
-**C.R.O.W.** is an open source [application framework](https://en.wikipedia.org/wiki/Application_framework) for building portable graphical interfaces in **C#**. It provides a declarative interface language with **styling** and **templates** called [IML](interface-markup-language) for **Interface Markup Language** similar to [XAML](https://en.wikipedia.org/wiki/Extensible_Application_Markup_Language) and a binding system for easy code linking.
+### Introduction
-C.R.O.W. is in **beta** development state, api could change.
-
-There's currently **3 main versions**, diverging on the way they handle OS integration. The last one replace [Cairo](https://www.cairographics.org/) with [vkvg](https://github.com/jpbruyere/vkvg).
+Open source [application framework](https://en.wikipedia.org/wiki/Application_framework) for building portable graphical interfaces in **C#**, featuring a ***declarative language*** for ui with ***styling*** and ***templates*** called [IML](interface-markup-language) similar to [XAML](https://en.wikipedia.org/wiki/Extensible_Application_Markup_Language) and a ***binding system*** for easy code linking.
-| Package | Description | Link |
-|-------------------|--------------------|------------------------------|
-| Crow.OpenTK |OS layer handle with [OpenTK](https://github.com/opentk/opentk), fast implementation of 3D gui in OTK scenes |[](https://www.nuget.org/packages/Crow.OpenTK) |
-| Crow | `IBackend` interface for **xcb** and **win32** |[](https://www.nuget.org/packages/Crow) |
-| Crow.Vk | OS layer with [GLFW](https://www.glfw.org/), [vkvg](https://github.com/jpbruyere/vkvg) for accelerated 2d vectors and text.| [](https://www.nuget.org/packages/Crow.Vk) |
+C.R.O.W. is in **beta** development state, api could change.
-#### Features
+### Features
- [Declarative interface definition](https://github.com/jpbruyere/Crow/wiki/interface-markup-language).
- [Templates](https://github.com/jpbruyere/Crow/wiki/Templates)
- [Styling](https://github.com/jpbruyere/Crow/wiki/Styling)
- [Dynamic binding system](https://github.com/jpbruyere/Crow/wiki/The-binding-system)
- SVG rendering (with [rsvg library](https://developer.gnome.org/rsvg/))
+### Requirements
+- [GLFW3](https://www.glfw.org/) for platform dependant integration.
+- [Cairo Graphic Library](https://cairographics.org/) >= 1.20, for 2d graphic rendering.
+- [rsvg library](https://developer.gnome.org/rsvg/) for svg rendering
+
+
<p align="center">
<a href="https://github.com/jpbruyere/Crow/blob/master/Images/screenshot.png">
<kbd><img src="https://github.com/jpbruyere/Crow/blob/master/Images/screenshot.png" height="200"></kbd>
</a>
</p>
-#### Documentation
+### Documentation
Due to the early state of this project and the frequent changes, some part of the docs may be outdated.
Please report bugs and issues on [GitHub](https://github.com/jpbruyere/Crow/issues)
-### Requirements
-- [Cairo Graphic Library](https://cairographics.org/) >= 1.20
-- [rsvg library](https://developer.gnome.org/rsvg/) for svg rendering
-
}
}
- protected override void Startup ()
+ protected override void OnInitialized ()
{
Commands = new List<Crow.Command> (new Crow.Command [] {
new Crow.Command(new Action(() => command1())) { Caption = "command1"},
namespace HelloWorld
{
- class Program : Interface {
- Command CMDQuit;
+ class Program {
static void Main (string[] args) {
- using (Program vke = new Program ()) {
- vke.Run ();
+ using (Interface app = new Interface ()) {
+ app.Initialized += (sender, e) => (sender as Interface).Load ("#HelloWorld.helloworld.crow");
+ app.Run ();
}
}
- protected override void Startup ()
- {
- CMDQuit = new Command (new Action (Quit)) { Caption = "Quit", Icon = new SvgPicture ("#Crow.Icons.exit-symbol.svg") };
-
- Widget w = Load ("#HelloWorld.helloworld.crow");
- w.KeyPress += W_KeyPress;
- w.DataSource = this;
- }
-
- Color [] colors = { Color.Blue, Color.DarkGoldenRod, Color.Red, Color.Azure, Color.Brown, Color.Black, Color.White, Color.Pink };
- int ptr = 0;
-
- void W_KeyPress (object sender, KeyPressEventArgs e)
- {
- switch (e.KeyChar) {
- case 'w':
- LoadIMLFragment ($"<DockWindow Name='win{ptr}' Left='450' Top='450' Width='150' Height='150' Background='{colors [ptr]}'/>");
- break;
- case 'x':
- LoadIMLFragment ($"<Window Name='win{ptr}' Left='450' Top='450' Width='150' Height='150' Background='{colors [ptr]}'/>");
- break;
- }
-
- ptr++;
- if (ptr == colors.Length)
- ptr = 0;
- }
-
}
}
<?xml version="1.0"?>
-<Window>
- <Label Text="Hello World"/>
+<Window Width="200" Height="200">
+ <TextBox Text="Hello World" Background="Blue"/>
</Window>
}
}
- protected override void Startup ()
+ protected override void OnInitialized ()
{
Widget g = Load ("#ShowCase.showcase.crow");
g.DataSource = this;
void showError (Exception ex)
{
- NotifyValueChanged ("ErrorMessage", ex.ToString());
+ NotifyValueChanged ("ErrorMessage", ex.Message);
NotifyValueChanged ("ShowError", true);
}
void hideError ()