diff options
| author | jpbruyere <jp_bruyere@hotmail.com> | 2013-11-16 09:16:43 +0100 |
|---|---|---|
| committer | jpbruyere <jp_bruyere@hotmail.com> | 2013-11-16 09:16:43 +0100 |
| commit | dab0f2befeda33bd1c8e59ec41a2e1768712086b (patch) | |
| tree | e1dc606a3d8eeccd221e8adc03edc8639c3daa17 | |
first commit
| -rw-r--r-- | .gitignore | 7 | ||||
| -rw-r--r-- | GOLib.csproj | 187 | ||||
| -rw-r--r-- | lib/OpenTK.Compatibility.dll | bin | 0 -> 3223552 bytes | |||
| -rw-r--r-- | lib/OpenTK.GLControl.dll | bin | 0 -> 24576 bytes | |||
| -rw-r--r-- | lib/OpenTK.dll | bin | 0 -> 2719744 bytes | |||
| -rw-r--r-- | lib/freetype6.dll | bin | 0 -> 551096 bytes | |||
| -rw-r--r-- | lib/intl.dll | bin | 0 -> 152489 bytes | |||
| -rw-r--r-- | lib/libcairo-2.dll | bin | 0 -> 1294335 bytes | |||
| -rw-r--r-- | lib/libcairo-gobject-2.dll | bin | 0 -> 44049 bytes | |||
| -rw-r--r-- | lib/libcairo-script-interpreter-2.dll | bin | 0 -> 182789 bytes | |||
| -rw-r--r-- | lib/libexpat-1.dll | bin | 0 -> 143096 bytes | |||
| -rw-r--r-- | lib/libfontconfig-1.dll | bin | 0 -> 279059 bytes | |||
| -rw-r--r-- | lib/libpng14-14.dll | bin | 0 -> 230529 bytes | |||
| -rw-r--r-- | lib/zlib1.dll | bin | 0 -> 100352 bytes | |||
| -rw-r--r-- | src/AssemblyInfo.cs | 36 | ||||
| -rw-r--r-- | src/Button.cs | 460 | ||||
| -rw-r--r-- | src/Colors.cs | 58 | ||||
| -rw-r--r-- | src/Container.cs | 139 | ||||
| -rw-r--r-- | src/GenericStack.cs | 101 | ||||
| -rw-r--r-- | src/GraphicObject.cs | 733 | ||||
| -rw-r--r-- | src/Group.cs | 429 | ||||
| -rw-r--r-- | src/GroupBox.cs | 213 | ||||
| -rw-r--r-- | src/HorizontalStack.cs | 16 | ||||
| -rw-r--r-- | src/HorizontalWrappingWidget.cs | 38 | ||||
| -rw-r--r-- | src/Image.cs | 138 | ||||
| -rw-r--r-- | src/Interface.cs | 567 | ||||
| -rw-r--r-- | src/Label.cs | 302 | ||||
| -rw-r--r-- | src/Mouse.cs | 24 | ||||
| -rw-r--r-- | src/Mouse3d.cs | 182 | ||||
| -rw-r--r-- | src/Panel.cs | 324 | ||||
| -rw-r--r-- | src/PanelWithTitle.cs | 160 | ||||
| -rw-r--r-- | src/Point.cs | 124 | ||||
| -rw-r--r-- | src/Rectangle.cs | 240 | ||||
| -rw-r--r-- | src/Rectangles.cs | 164 | ||||
| -rw-r--r-- | src/ScrollingWidget.cs | 138 | ||||
| -rw-r--r-- | src/Size.cs | 107 | ||||
| -rw-r--r-- | src/Slider.cs | 143 | ||||
| -rw-r--r-- | src/Spinner.cs | 137 | ||||
| -rw-r--r-- | src/TextBox.cs | 528 | ||||
| -rw-r--r-- | src/VerticalStack.cs | 16 | ||||
| -rw-r--r-- | src/VerticalWrappingWidget.cs | 38 | ||||
| -rw-r--r-- | src/Win32.cs | 60 | ||||
| -rw-r--r-- | src/WrappedWidgetGroup.cs | 154 | ||||
| -rw-r--r-- | src/directories.cs | 15 | ||||
| -rw-r--r-- | src/enums.cs | 72 |
45 files changed, 6050 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3b3b05fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +Win_x86 + +Debug + +/*.sln + +/GOLib.suo diff --git a/GOLib.csproj b/GOLib.csproj new file mode 100644 index 00000000..e32dd8f9 --- /dev/null +++ b/GOLib.csproj @@ -0,0 +1,187 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">Linux_x86</Platform> + <ProductVersion>8.0.30703</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{C2980F9B-4798-4C05-99E2-E174810F7C7B}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>go</RootNamespace> + <AssemblyName>Interface</AssemblyName> + <FileAlignment>512</FileAlignment> + <AllowUnsafeBlocks>True</AllowUnsafeBlocks> + <NoStdLib>False</NoStdLib> + <TreatWarningsAsErrors>False</TreatWarningsAsErrors> + <OutputPath>bin\$(configuration)\$(Platform)</OutputPath> + <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath> + <WarningLevel>4</WarningLevel> + <NoWin32Manifest>False</NoWin32Manifest> + <SignAssembly>false</SignAssembly> + <DelaySign>False</DelaySign> + <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> + <Optimize>False</Optimize> + <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> + <BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath> + <DebugType>Full</DebugType> + </PropertyGroup> + <PropertyGroup Condition=" '$(Platform)' == 'Win_x86' "> + <BaseAddress>4194304</BaseAddress> + <PlatformTarget>x86</PlatformTarget> + <Prefer32Bit>False</Prefer32Bit> + <RegisterForComInterop>False</RegisterForComInterop> + <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> + </PropertyGroup> + <PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <BaseAddress>4194304</BaseAddress> + <RegisterForComInterop>False</RegisterForComInterop> + <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> + </PropertyGroup> + <PropertyGroup Condition=" '$(Platform)' == 'Linux_x86' "> + <PlatformTarget>x86</PlatformTarget> + <BaseAddress>4194304</BaseAddress> + <RegisterForComInterop>False</RegisterForComInterop> + <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> + <Optimize>True</Optimize> + <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> + <BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath> + <DebugType>None</DebugType> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Linux_x86' "> + <DefineConstants>TRACE;DEBUG;__linux__</DefineConstants> + <OutputPath>..\bin\Debug\Linux_x86</OutputPath> + <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Win_x86' "> + <DefineConstants>TRACE;DEBUG;_WIN32</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Linux_x86' "> + <DefineConstants>__linux__</DefineConstants> + <OutputPath>..\bin\Release\Linux_x86</OutputPath> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Win_x86' "> + <DefineConstants>_WIN32</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugType>none</DebugType> + </PropertyGroup> + <ItemGroup> + <Compile Include="src\Button.cs" /> + <Compile Include="src\Colors.cs" /> + <Compile Include="src\directories.cs" /> + <Compile Include="src\enums.cs" /> + <Compile Include="src\GroupBox.cs" /> + <Compile Include="src\HorizontalStack.cs" /> + <Compile Include="src\HorizontalWrappingWidget.cs" /> + <Compile Include="src\Image.cs" /> + <Compile Include="src\Label.cs" /> + <Compile Include="src\Mouse.cs" /> + <Compile Include="src\Panel.cs" /> + <Compile Include="src\PanelWithTitle.cs" /> + <Compile Include="src\Point.cs" /> + <Compile Include="src\AssemblyInfo.cs" /> + <Compile Include="src\Rectangle.cs" /> + <Compile Include="src\Rectangles.cs" /> + <Compile Include="src\ScrollingWidget.cs" /> + <Compile Include="src\Size.cs" /> + <Compile Include="src\Slider.cs" /> + <Compile Include="src\Spinner.cs" /> + <Compile Include="src\TextBox.cs" /> + <Compile Include="src\GenericStack.cs" /> + <Compile Include="src\VerticalStack.cs" /> + <Compile Include="src\VerticalWrappingWidget.cs" /> + <Compile Include="src\GraphicObject.cs" /> + <Compile Include="src\Group.cs" /> + <Compile Include="src\Container.cs" /> + <Compile Include="src\Win32.cs" /> + <Compile Include="src\WrappedWidgetGroup.cs" /> + <Compile Include="src\Interface.cs" /> + </ItemGroup> + <ItemGroup> + <Content Include="lib\freetype6.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="lib\intl.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="lib\libcairo-2.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="lib\libcairo-gobject-2.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="lib\libcairo-script-interpreter-2.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="lib\libexpat-1.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="lib\libfontconfig-1.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="lib\libpng14-14.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="lib\zlib1.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + </ItemGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Drawing" /> + <Reference Include="System.Windows.Forms" /> + <Reference Include="Mono.Cairo" /> + <Reference Condition="'$(Platform)'=='Win_x86'" Include="OpenTK, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>lib\OpenTK.dll</HintPath> + </Reference> + <Reference Condition="'$(Platform)'=='Win_x86'" Include="OpenTK.Compatibility, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>lib\OpenTK.Compatibility.dll</HintPath> + </Reference> + <Reference Condition="'$(Platform)'=='Win_x86'" Include="OpenTK.GLControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>lib\OpenTK.GLControl.dll</HintPath> + </Reference> + <Reference Condition="'$(Platform)'=='Linux_x86'" Include="OpenTK.Compatibility"> + <HintPath>..\..\..\OpenTK\1.0\Binaries\OpenTK\Debug\OpenTK.Compatibility.dll</HintPath> + </Reference> + <Reference Condition="'$(Platform)'=='Linux_x86'" Include="OpenTK"> + <HintPath>..\..\..\OpenTK\1.0\Binaries\OpenTK\Debug\OpenTK.dll</HintPath> + </Reference> + <Reference Condition="'$(Platform)'=='Linux_x86'" Include="OpenTK.GLControl"> + <HintPath>..\..\..\OpenTK\1.0\Binaries\OpenTK\Debug\OpenTK.GLControl.dll</HintPath> + </Reference> + <Reference Condition="'$(Platform)'=='Linux_x86'" Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"> + <Private>False</Private> + <Package>gtk-sharp-2.0</Package> + </Reference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> + <ItemGroup Condition="'$(Platform)'=='Linux_x86'"> + <None Include="lib\libfb.so"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="lib\libgo.so"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="Pointeurs\left_ptr.png"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + </ItemGroup> + <ItemGroup /> +</Project>
\ No newline at end of file diff --git a/lib/OpenTK.Compatibility.dll b/lib/OpenTK.Compatibility.dll Binary files differnew file mode 100644 index 00000000..d6d8149e --- /dev/null +++ b/lib/OpenTK.Compatibility.dll diff --git a/lib/OpenTK.GLControl.dll b/lib/OpenTK.GLControl.dll Binary files differnew file mode 100644 index 00000000..e31628d5 --- /dev/null +++ b/lib/OpenTK.GLControl.dll diff --git a/lib/OpenTK.dll b/lib/OpenTK.dll Binary files differnew file mode 100644 index 00000000..afff0dd1 --- /dev/null +++ b/lib/OpenTK.dll diff --git a/lib/freetype6.dll b/lib/freetype6.dll Binary files differnew file mode 100644 index 00000000..ead809b6 --- /dev/null +++ b/lib/freetype6.dll diff --git a/lib/intl.dll b/lib/intl.dll Binary files differnew file mode 100644 index 00000000..d2612081 --- /dev/null +++ b/lib/intl.dll diff --git a/lib/libcairo-2.dll b/lib/libcairo-2.dll Binary files differnew file mode 100644 index 00000000..34f84afd --- /dev/null +++ b/lib/libcairo-2.dll diff --git a/lib/libcairo-gobject-2.dll b/lib/libcairo-gobject-2.dll Binary files differnew file mode 100644 index 00000000..f4bbf6fa --- /dev/null +++ b/lib/libcairo-gobject-2.dll diff --git a/lib/libcairo-script-interpreter-2.dll b/lib/libcairo-script-interpreter-2.dll Binary files differnew file mode 100644 index 00000000..74acaf60 --- /dev/null +++ b/lib/libcairo-script-interpreter-2.dll diff --git a/lib/libexpat-1.dll b/lib/libexpat-1.dll Binary files differnew file mode 100644 index 00000000..b3cf4100 --- /dev/null +++ b/lib/libexpat-1.dll diff --git a/lib/libfontconfig-1.dll b/lib/libfontconfig-1.dll Binary files differnew file mode 100644 index 00000000..7ad870bb --- /dev/null +++ b/lib/libfontconfig-1.dll diff --git a/lib/libpng14-14.dll b/lib/libpng14-14.dll Binary files differnew file mode 100644 index 00000000..8b93b06a --- /dev/null +++ b/lib/libpng14-14.dll diff --git a/lib/zlib1.dll b/lib/zlib1.dll Binary files differnew file mode 100644 index 00000000..869b00d4 --- /dev/null +++ b/lib/zlib1.dll diff --git a/src/AssemblyInfo.cs b/src/AssemblyInfo.cs new file mode 100644 index 00000000..29cf4b58 --- /dev/null +++ b/src/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GOLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GOLib")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("150376dc-e648-46a2-b692-6429d0a62362")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Button.cs b/src/Button.cs new file mode 100644 index 00000000..d29cfbc0 --- /dev/null +++ b/src/Button.cs @@ -0,0 +1,460 @@ +using System; + + +using System.Collections.Generic; +using System.Linq; +using System.Text; +//using OpenTK.Graphics.OpenGL; + +using Cairo; + +using winColors = System.Drawing.Color; +using System.Diagnostics; + +namespace go +{ + public class Button : Group + { + public static class Theme + { + public static Color background = Color.Gray; + public static Color borderColor = Color.Black; + public static int margin = 1; + public static int borderWidth = 1; + public static VerticalAlignment verticalAlignment = VerticalAlignment.None; + public static HorizontalAlignment horizontalAlignment = HorizontalAlignment.None; + public static bool sizeToContent = false; + } + + public Button(ButtonWidgetClick _clickEvent, string _text, bool _checkable = false, int width = 0, int height = 0) + : base(width, height) + { + initButtonWidget(_clickEvent, _checkable); + label = new Label(_text); + sizeToContent = true; + label.fontColor = Color.Black; + label.fontSize = 14; + label.horizontalAlignment = HorizontalAlignment.Stretch; + label.verticalAlignment = VerticalAlignment.Stretch; + label.textAlignment = Alignment.Center; + + } + public Button(System.Drawing.Bitmap iconBitmap, ButtonWidgetClick _clickEvent, bool _checkable, int width, int height) + : base(width, height) + { + icon = new Image(iconBitmap); + initButtonWidget(_clickEvent, _checkable); + } + public Button(string iconFile, ButtonWidgetClick _clickEvent = null, bool _checkable = false, bool _affectMultiSelectState = true) + : base() + { + affectMultiSelectState = _affectMultiSelectState; + icon = new Image(iconFile); + initButtonWidget(_clickEvent, _checkable); + sizeToContent = true; + } + public Button(string iconFile, ButtonWidgetClick _clickEvent, bool _checkable, int width, int height, bool _affectMultiSelectState = true) + : base(width, height) + { + affectMultiSelectState = _affectMultiSelectState; + icon = new Image(iconFile); + initButtonWidget(_clickEvent, _checkable); + } + public Button(string iconFile, string checkedIconFile, ButtonWidgetClick _clickEvent, bool _checkable = false, int width = 30, int height = 30, bool _affectMultiSelectState = true) + : base(width, height) + { + affectMultiSelectState = _affectMultiSelectState; + icon = new Image(iconFile); + checkedIcon = new Image(checkedIconFile); + checkedIcon.isVisible = false; + + initButtonWidget(_clickEvent, _checkable); + } + + void initButtonWidget(ButtonWidgetClick _clickEvent = null, bool _checkable = false) + { + focusable = true; + IsCheckable = _checkable; + clickEvent = _clickEvent; + + background = Theme.background; + borderColor = Theme.borderColor; + borderWidth = Theme.borderWidth; + margin = Theme.margin; + horizontalAlignment = Theme.horizontalAlignment; + verticalAlignment = Theme.verticalAlignment; + sizeToContent = Theme.sizeToContent; + } + + public enum ButtonStates + { + normal, + mouseOver, + mouseDown, + Disable + } + + public static int maxIconSize = 22; + + ButtonStates _CurrentState = ButtonStates.normal; + public ButtonStates CurrentState + { + get { return _CurrentState; } + set + { + if (value == _CurrentState) + return; + _CurrentState = value; + registerForRedraw(); + //registerForGraphicUpdate(); + //needGraphicalUpdate = true; + } + } + + public ButtonWidgetClick clickEvent; + + bool _isChecked = false; + public bool IsChecked + { + get { return _isChecked; } + set + { + if (value == _isChecked) + return; + + _isChecked = value; + + if (clickEvent != null) + clickEvent(this); + + registerForGraphicUpdate(); + } + } + + public bool IsCheckable = false; + public bool affectMultiSelectState = true; + public bool border3D = false; + + Image _icon; + Image _checkedIcon; + Label _label; + + public Image icon + { + get { return _icon; } + set + { + if (_icon != null) + removeChild(_icon); + + if (value == null) + _icon = null; + else + { + _icon = addChild(value) as Image; + _icon.horizontalAlignment = go.HorizontalAlignment.Stretch; + _icon.verticalAlignment = go.VerticalAlignment.Stretch; + _icon.background = Color.Transparent; + putWidgetOnBottom(_icon); + //_icon.borderWidth = 5; + } + } + } + public Image checkedIcon + { + get { return _checkedIcon; } + set + { + if (_checkedIcon != null) + removeChild(_checkedIcon); + + if (value == null) + _checkedIcon = null; + else + { + _checkedIcon = addChild(value) as Image; + _checkedIcon.horizontalAlignment = go.HorizontalAlignment.Stretch; + _checkedIcon.verticalAlignment = go.VerticalAlignment.Stretch; + _checkedIcon.background = Color.Transparent; + + putWidgetOnBottom(_checkedIcon); + } + } + } + public Label label + { + get { return _label; } + set + { + if (_label != null) + removeChild(_label); + + if (value == null) + _label = null; + else + { + _label = addChild(value) as Label; + _label.horizontalAlignment = go.HorizontalAlignment.Stretch; + _label.verticalAlignment = go.VerticalAlignment.Stretch; + _label.textAlignment = Alignment.VerticalStretch; + putWidgetOnTop(_label); + } + } + } + + public string text + { + get { return label.text; } + set + { + label = new Label(value); + } + } + + //public ButtonWidget(string iconFile, int _x, int _y, bool _checkable = false):base() + //{ + // IsCheckable = _checkable; + // x = _x; + // y = _y; + + // icon = new ImageWidget(iconFile); + // icon.Parent = this; + //} + + + + public override bool ProcessMousePosition(Point mousePos) + { + if (CurrentState == ButtonStates.Disable) + return false; + + bool result = base.ProcessMousePosition(mousePos); + + if (result && CurrentState != ButtonStates.mouseDown) + CurrentState = ButtonStates.mouseOver; + else + CurrentState = ButtonStates.normal; + + return result; + + } + public override void ProcessMouseDown(Point mousePos) + { + //base.ProcessMouseDown(mousePos); + + + if (CurrentState != Button.ButtonStates.Disable) + { + Interface.activeWidget = this; + + if (IsCheckable) + { + if (IsChecked) + IsChecked = false; + else + { + Group wg = Parent as Group; + if (wg != null) + { + if (affectMultiSelectState && !multiSelect) + { + foreach (Button but in wg.Children.OfType<Button>()) + { + if (but.IsCheckable) + { + if (but.IsChecked && but.affectMultiSelectState) + { + but.IsChecked = false; + break; + } + } + } + } + } + IsChecked = true; + } + } + else if (clickEvent != null) + clickEvent(this); + + CurrentState = Button.ButtonStates.mouseDown; + } + + + } + public override void ProcessMouseUp(Point mousePos) + { + if (CurrentState != Button.ButtonStates.Disable) + { + CurrentState = ButtonStates.normal; + ProcessMousePosition(mousePos); + } + + //base.ProcessMouseUp(mousePos); + } + + internal override void updateGraphic() + { + if (IsChecked) + { + if (checkedIcon != null) + { + icon.isVisible = false; + checkedIcon.isVisible = true; + } + } + else + { + if (checkedIcon != null) + { + icon.isVisible = true; + checkedIcon.isVisible = false; + } + + } + + base.updateGraphic(); + } + public override void registerForRedraw() + { + base.registerForRedraw(); + } + public override void cairoDraw(ref Context ctx, Rectangles clip = null) + { + base.cairoDraw(ref ctx, clip); + + //int stride = 4 * renderBounds.Width; + //int bmpSize = Math.Abs(stride) * renderBounds.Height; + //bmp = new byte[bmpSize]; + + //using (ImageSurface draw = + // new ImageSurface(bmp, Format.Argb32, renderBounds.Width, renderBounds.Height, stride)) + //{ + + Rectangle r = renderBoundsInContextCoordonate.Clone; + + ctx.Save(); + ctx.ResetClip(); + ctx.Antialias = Antialias.Subpixel; + if (IsCheckable) + { + if (IsChecked) + { + if (border3D) + Interface.StrokeLoweredRectangle(ctx, r); + + } + else + { + if (checkedIcon == null) + { + ctx.Color = new Color(0.3, 0.3, 0.3, 0.4); + ctx.Rectangle(r); + ctx.Fill(); + } + if (border3D) + Interface.StrokeRaisedRectangle(ctx, r); + } + } + switch (CurrentState) + { + case ButtonStates.normal: + break; + case ButtonStates.mouseOver: + ctx.Operator = Operator.Add; + ctx.Rectangle(r); + ctx.Color = new Color(0.2, 0.2, 0.2, 1.0); + ctx.Fill(); + ctx.Operator = Operator.Over; + break; + case ButtonStates.mouseDown: + //ctx.Scale(0.7, 0.7); + ctx.Operator = Operator.Add; + ctx.Rectangle(r); + ctx.Color = Color.Red1; + ctx.Fill(); + ctx.Operator = Operator.Over; + break; + case ButtonStates.Disable: + ctx.Color = new Color(0.2, 0.2, 0.2, 0.7); + ctx.Rectangle(r); + ctx.Fill(); + break; + + } + ctx.Restore(); + + } + //ctx.Target.WriteToPng(directories.rootDir + @"test.png"); + + //public override void Render() + //{ + // if (!isVisible) + // return; + + // switch (CurrentState) + // { + // case ButtonStates.normal: + // if (IsCheckable) + // { + // if (IsChecked) + // Interface.setTeint(1.0f); + // else + // Interface.setTeint(0.6f); + // } + // else + // Interface.setTeint(1.0f); + // break; + // case ButtonStates.mouseOver: + // //GL.PixelZoom(1.2f, 1.2f); + // Interface.setTeint(1.1f); + // GL.Color3(winColors.Red); + // break; + // case ButtonStates.mouseDown: + // GL.PixelZoom(0.9f, 0.9f); + // break; + // case ButtonStates.Disable: + // Interface.setTeint(0.3f); + // break; + // } + + // ImageWidget img = icon; + + // if (icon != null) + // { + // if (IsCheckable) + // { + // if (checkedIcon != null && IsChecked) + // { + // img = checkedIcon; + // } + // } + // } + + // if (invalidateLayout) + // updateLayout(); + + + // if (label != null) + // label.Render(); + + // if (img != null) + // img.Render(); + + + // GL.PixelZoom(1.0f, 1.0f); + // Interface.setTeint(1.0f); + + // //if (CurrentState == ButtonStates.mouseOver) + // //{ + // // GL.PixelTransfer(PixelTransferParameter.BlueScale, 5.0f); + // // GL.PixelTransfer(PixelTransferParameter.RedScale, 2.5f); + // // GL.PixelTransfer(PixelTransferParameter.GreenScale, 2.5f); + // //} + + // base.renderBaseWidgetOnly(); + + // Interface.setTeint(1.0f); + //} + } +} diff --git a/src/Colors.cs b/src/Colors.cs new file mode 100644 index 00000000..02bf81fb --- /dev/null +++ b/src/Colors.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + + +namespace go +{ + public struct Color + { + public double A; + public double R; + public double G; + public double B; + + public Color(double _R, double _G, double _B, double _A) + { + A = _A; + R = _R; + G = _G; + B = _B; + } + public static implicit operator System.Drawing.Color(Color c) + { + return System.Drawing.Color.FromArgb((int)(c.A * 255), (int)(c.R * 255), (int)(c.G * 255), (int)(c.B * 255)); + } + public static implicit operator Cairo.Color(Color c) + { + return new Cairo.Color(c.R, c.G, c.B, c.A); + } + public static readonly Color White = new Color(1, 1, 1, 1); + public static readonly Color Black = new Color(0, 0, 0, 1); + public static readonly Color LightGray = new Color(0.8, 0.8, 0.8, 1); + public static readonly Color DarkGray = new Color(0.2, 0.2, 0.2, 1); + public static readonly Color Gray = new Color(0.5, 0.5, 0.5, 1); + public static readonly Color DimGray = new Color(0.2, 0.2, 0.2, 0.8); + public static readonly Color Transparent = new Color(0.0, 0.0, 0.0, 0.0); + public static readonly Color Red1 = new Color(0.9, 0.4, 0.4, 0.9); + public static readonly Color DimWhite = new Color(0.9, 0.9, 0.9, 0.8); + public static readonly Color ElectricBlue = new Color(0.3, 0.3, 0.6, 1); + public static readonly Color SkyBlue = new Color(0.7, 0.8, 1, 1); + public static readonly Color Lavande = new Color(0.8, 0.8, 1, 1); + public static readonly Color YellowGreen = new Color(0.8, 0.8, 0.1, 1); + public static readonly Color blue1 = new Color(0.3, 0.3, 0.4, 1); + public static readonly Color Green = new Color(0, 1, 0, 1); + public static readonly Color Blue = new Color(0, 0, 1, 1); + public static readonly Color Red = new Color(1, 0, 0, 1); + public static readonly Color LightGoldenrodYellow = new Color(0.5, 0.5, 0, 0.5); + public static readonly Color DarkOrange = new Color(1, 0.2, 0, 1); + public static readonly Color MediumBlue = new Color(0, 0, 1, 1); + public static readonly Color LightBlue = new Color(0.7, 0.7, 1, 1); + public static readonly Color Navy = new Color(0, 0, 1, 1); + public static readonly Color MediumTurquoise = new Color(0, 0, 1, 1); + public static readonly Color Goldenrod = new Color(0, 0, 1, 1); + public static readonly Color Yellow = new Color(1, 1, 0, 1); + } +} diff --git a/src/Container.cs b/src/Container.cs new file mode 100644 index 00000000..76e81c29 --- /dev/null +++ b/src/Container.cs @@ -0,0 +1,139 @@ +using System; + +namespace go +{ + public class Container : GraphicObject + { + public Container() + : base() + { + } + public Container(Rectangle _bounds) + : base(_bounds) + { + } + + public GraphicObject child; + public T setChild<T>(T _child) + { + + if (child != null) + child.Parent = null; + + child = _child as GraphicObject; + + if (child != null) + child.Parent = this; + + return (T)_child; + } + public override void invalidateLayout() + { + base.invalidateLayout(); + + if (child != null) + child.invalidateLayout(); + } + public override bool layoutIsValid + { + get + { + if (!isVisible) + return true; + + if (!base.layoutIsValid) + return false; + else if (child != null) + if (!child.layoutIsValid) + return false; + + return true; + } + set + { + base.layoutIsValid = value; + } + } + + public override void updateLayout() + { + if (!isVisible) + return; + + if (!(sizeIsValid && positionIsValid)) + base.updateLayout(); + + if (child != null) + { + child.updateLayout(); + if (sizeToContent && child.sizeIsValid) + { + renderBounds.Size = child.renderBounds.Size + 2 * margin + 2 * borderWidth; + child.renderBounds.TopLeft = clientBounds.TopLeft; + sizeIsValid = true; + } + } + + if (layoutIsValid) + registerForRedraw(); + } + + public override bool ProcessMousePosition(Point mousePos) + { + if (!isVisible) + return false; + + bool result = base.ProcessMousePosition(mousePos); + + //if (this is Panel) + // return result; + //else + + if (result) + if (child != null) + child.ProcessMousePosition(mousePos); + + return result; + } + public override void ProcessMouseWeel(int delta) + { + if (!isVisible) + return; + + if (child != null) + child.ProcessMouseWeel(delta); + } + + public override void cairoDraw(ref Cairo.Context ctx, Rectangles clip = null) + { + if (!isVisible)//check if necessary?? + return; + + ctx.Save(); + + ctx.Rectangle(renderBoundsInContextCoordonate); + ctx.Clip(); + + if (clip != null) + clip.clip(ctx); + + base.cairoDraw(ref ctx, clip); + + //clip to client zone + + ctx.Rectangle(ClientBoundsInContextCoordonate); + ctx.Clip(); + + if (clip != null) + clip.Rebase(this); + + if (child != null) + child.cairoDraw(ref ctx, clip); + + ctx.Restore(); + //ctx.Target.WriteToPng(@"/home/jp/test.png"); + + } + } +} + diff --git a/src/GenericStack.cs b/src/GenericStack.cs new file mode 100644 index 00000000..aa5ceeaa --- /dev/null +++ b/src/GenericStack.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace go +{ + public class GenericStack : Group + { + public int widgetSpacing = 5; + public Orientation Orientation = Orientation.Horizontal; + + public GenericStack() + : base() + { + borderWidth = 0; + sizeToContent = true; + + } + + int currentXForWidget = 0; + int currentYForWidget = 0; + + public override void updateLayout() + { + //if (!(sizeIsValid && positionIsValid)) + base.updateLayout(); + + currentXForWidget = clientBounds.X; + currentYForWidget = clientBounds.Y; + + + Rectangle contentBounds = Rectangle.Zero; + + GraphicObject[] widgets = new GraphicObject[Children.Count]; + Children.CopyTo(widgets); + foreach (GraphicObject w in widgets) + { + if (!enoughtSpaceForWidget(w)) + advance(w); + + if (enoughtSpaceForWidget(w)) + { + w.renderBounds.X = currentXForWidget; + w.renderBounds.Y = currentYForWidget; + + w.positionIsValid = true; + + contentBounds += w.renderBounds; + + advance(w); + } + else + break; + } + + contentBounds.Width += borderWidth + margin; + contentBounds.Height += borderWidth + margin; + + if (sizeToContent) + renderBounds.Size = contentBounds.Size; + else if (VerticalScrolling) + renderBounds.Size = new Size(renderBounds.Size.Width, contentBounds.Size.Height); + else if (HorizontalScrolling) + renderBounds.Size = new Size(contentBounds.Size.Width, renderBounds.Size.Height); + + if (layoutIsValid) + registerForRedraw(); + } + + + bool enoughtSpaceForWidget(GraphicObject w) + { + if (!sizeToContent) + { + int nextXForWidget = 0; + int nextYForWidget = 0; + + if (Orientation == Orientation.Horizontal) + nextXForWidget = currentXForWidget + w.renderBounds.Width; + else + nextYForWidget = nextYForWidget + w.renderBounds.Height; + + + if (nextXForWidget > clientBounds.Right && !HorizontalScrolling) + return false; + if (currentYForWidget > clientBounds.Bottom && !VerticalScrolling) + return false; + } + return true; + } + void advance(GraphicObject w) + { + if (Orientation == Orientation.Horizontal) + currentXForWidget = currentXForWidget + widgetSpacing + w.renderBounds.Width; + else + currentYForWidget = currentYForWidget + widgetSpacing + w.renderBounds.Height; + + } + } +} diff --git a/src/GraphicObject.cs b/src/GraphicObject.cs new file mode 100644 index 00000000..afab5a20 --- /dev/null +++ b/src/GraphicObject.cs @@ -0,0 +1,733 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +//using OpenTK.Graphics.OpenGL; +using System.Drawing.Imaging; +using System.Diagnostics; +using OpenTK.Input; + +using Cairo; + + +namespace go +{ + public class GraphicObject + { + public GraphicObject() + { + init(); + registerForGraphicUpdate(); + } + public GraphicObject(Rectangle _bounds) + { + bounds = _bounds; + init(); + registerForGraphicUpdate(); + } + + void init() + { + background = Theme.background; + foreground = Theme.foreground; + borderColor = Theme.borderColor; + borderWidth = Theme.borderWidth; + margin = Theme.margin; + horizontalAlignment = Theme.horizontalAlignment; + verticalAlignment = Theme.verticalAlignment; + sizeToContent = Theme.sizeToContent; + } + + public virtual int x + { + get { return bounds.X; } + set + { + if (bounds.X == value) + return; + + bounds.X = value; + + layoutIsValid = false; + registerForGraphicUpdate(); + } + } + public virtual int y + { + get { return bounds.Y; } + set + { + if (bounds.Y == value) + return; + + bounds.Y = value; + + layoutIsValid = false; + registerForGraphicUpdate(); + } + } + public int width + { + get { return bounds.Width; } + set + { + if (bounds.Width == value) + return; + + bounds.Width = value; + + invalidateLayout(); + } + } + public int height + { + get { return bounds.Height; } + set + { + if (bounds.Height == value) + return; + + bounds.Height = value; + + invalidateLayout(); + } + } + + public virtual Rectangle renderBoundsInContextCoordonate + { + get + { + if (Parent == null) + return renderBounds.Clone; + //if (Parent.isCached) + // return renderBounds.Clone; + + Rectangle tmp = Parent.renderBoundsInContextCoordonate; + + return new Rectangle( + tmp.X + renderBounds.X, + tmp.Y + renderBounds.Y, + renderBounds.Width, + renderBounds.Height); + } + } + public virtual Rectangle ClientBoundsInContextCoordonate + { + get + { + if (Parent == null) + return new Rectangle( + renderBounds.X + clientBounds.X, + renderBounds.Y + clientBounds.Y, + clientBounds.Width, + clientBounds.Height); + + //if (Parent is Panel && !(this is ScrollingWidget)) + // return Parent.clientBounds; + + Rectangle tmp = Parent.renderBoundsInContextCoordonate; + + return new Rectangle( + tmp.X + renderBounds.X + clientBounds.X, + tmp.Y + renderBounds.Y + clientBounds.Y, + clientBounds.Width, + clientBounds.Height); + } + + } + + //public virtual Rectangle rectangleInContextCoordonate(Rectangle r) + //{ + // if (Parent == null) + // return r; + + // Rectangle tmp = Parent.rectangleInContextCoordonate(r); + + // return new Rectangle( + // tmp.X + r.X, + // tmp.Y + r.Y, + // r.Width, + // r.Height); + //} + public virtual Rectangle renderBoundsInBackendSurfaceCoordonate + { + get + { + Rectangle tmp = Parent.renderBoundsInBackendSurfaceCoordonate; + + return new Rectangle( + tmp.X + renderBounds.X, + tmp.Y + renderBounds.Y, + renderBounds.Width, + renderBounds.Height); + } + } + public virtual Rectangle ClientBoundsInBackendSurfaceCoordonate + { + get + { + if (Parent == null) + return new Rectangle( + renderBounds.X + clientBounds.X, + renderBounds.Y + clientBounds.Y, + clientBounds.Width, + clientBounds.Height); ; + + //if (Parent is Panel && !(this is ScrollingWidget)) + // return Parent.clientBounds; + + Rectangle tmp = Parent.ClientBoundsInBackendSurfaceCoordonate; + + return new Rectangle( + tmp.X + renderBounds.X + clientBounds.X, + tmp.Y + renderBounds.Y + clientBounds.Y, + clientBounds.Width, + clientBounds.Height); + } + + } + public virtual Rectangle rectInScreenCoord(Rectangle r) + { + return + new Rectangle( + ScreenCoordBounds.X + r.X, + ScreenCoordBounds.Y + r.Y, + r.Width, + r.Height); + } + public virtual Rectangle ScreenCoordBounds + { + get + { + return Parent == null ? bounds : + new Rectangle( + Parent.ScreenCoordBounds.X + renderBounds.X, + Parent.ScreenCoordBounds.Y + renderBounds.Y, + renderBounds.Width, + renderBounds.Height); + } + } + public virtual Rectangle ScreenCoordClientBounds + { + get + { + return Parent == null ? + new Rectangle( + renderBounds.X + clientBounds.X, + renderBounds.Y + clientBounds.Y, + clientBounds.Width, + clientBounds.Height) : + new Rectangle( + Parent.ScreenCoordClientBounds.X + clientBounds.X, + Parent.ScreenCoordClientBounds.Y + clientBounds.Y, + clientBounds.Width, + clientBounds.Height); + } + } + + public Rectangle bounds = new Rectangle(); + public Rectangle renderBounds = new Rectangle(); + + public virtual Rectangle clientBounds + { + get + { + //if (renderBounds == Rectangle.Empty) + // Debugger.Break(); + Rectangle cb = renderBounds.Clone; + cb.X = 0; + cb.Y = 0; + cb.Inflate(-(borderWidth + margin), -(borderWidth + margin)); + return cb; + } + } + + //static copy of themable proporties, + //set default value for all newly created item + public static class Theme + { + public static Color background = Color.DimGray; + public static Color foreground = Color.White; + public static Color borderColor = Color.Gray; + public static int margin = 0; + public static int borderWidth = 0; + public static VerticalAlignment verticalAlignment = VerticalAlignment.Stretch; + public static HorizontalAlignment horizontalAlignment = HorizontalAlignment.Stretch; + public static bool sizeToContent = false; + } + + Color _background; + Color _foreground; + Color _borderColor; + int _borderWidth; + int _margin; + + public VerticalAlignment verticalAlignment; + public HorizontalAlignment horizontalAlignment; + public bool sizeToContent; + + public Color background + { + get { return _background; } + set + { + _background = value; + registerForGraphicUpdate(); + } + } + public Color foreground + { + get { return _foreground; } + set + { + _foreground = value; + registerForGraphicUpdate(); + } + } + public Color borderColor + { + get { return _borderColor; } + set + { + _borderColor = value; + registerForGraphicUpdate(); + } + } + public int borderWidth + { + get { return _borderWidth; } + set + { + _borderWidth = value; + registerForGraphicUpdate(); + } + } + public int margin + { + get { return _margin; } + set + { + _margin = value; + registerForGraphicUpdate(); + } + } + + public object Tag; + + public GraphicObject Parent; + + public bool focusable = false; + + private bool _hasFocus = false; + protected bool _isVisible = true; + + public virtual bool hasFocus + { + get { return _hasFocus; } + set + { + _hasFocus = value; + } + } + public virtual bool isVisible + { + get { return _isVisible; } + set + { + if (value == _isVisible) + return; + + _isVisible = value; + if (Parent != null) + Parent.invalidateLayout(); + //else + // registerForRedraw(); + } + } + + + internal bool sizeIsValid = false; + internal bool positionIsValid = false; + + public virtual void invalidateLayout() + { + bmp = null; + layoutIsValid = false; + } + public virtual bool layoutIsValid + { + get { return sizeIsValid & positionIsValid; } + set + { + if (value == sizeIsValid && value == positionIsValid) + return; + + //_layoutIsValid = value; + + sizeIsValid = value; + positionIsValid = value; + + //if (!layoutIsValid && Parent != null) + // Parent.layoutIsValid = false; + } + } + + public virtual bool isCached + { + get { return false; } + } + public virtual bool cachingInProgress + { + get { return false; } + set { return; } + } + + + public byte[] bmp; + + + + Panel _panel; + public Panel panel + { + get + { + if (_panel == null) + { + GraphicObject w = Parent; + + while (w != null) + { + Panel p = w as Panel; + if (p != null) + { + _panel = p; + break; + } + w = w.Parent; + } + } + + return _panel; + } + } + + public virtual void registerForGraphicUpdate() + { + bmp = null; + registerForRedraw(); + //Interface.registerForGraphicUpdate(this); + } + public virtual void registerForRedraw() + { + if (layoutIsValid && isVisible) + Interface.redrawClip.AddRectangle(this.renderBoundsInBackendSurfaceCoordonate); + } + public virtual void updatePosition() + { + renderBounds.X = bounds.X; + renderBounds.Y = bounds.Y; + } + public virtual Size measureRawSize() + { + return bounds.Size; + } + + public virtual void computeSize() + { + Size rawSize = measureRawSize(); + + float vRatio = 1f; + float hRatio = 1f; + + sizeIsValid = true; + + if (bounds.Width == 0) + if (rawSize.Width == 0) + { + if (horizontalAlignment != go.HorizontalAlignment.Stretch) + { + Debug.WriteLine("Not able to find width for item"); + sizeIsValid = false; + } + } + else + renderBounds.Width = rawSize.Width; + else + renderBounds.Width = bounds.Width; + + if (bounds.Height == 0) + if (rawSize.Height == 0) + { + if (verticalAlignment != go.VerticalAlignment.Stretch) + { + Debug.WriteLine("Not able to find height for item"); + sizeIsValid = false; + } + } + else + renderBounds.Height = (int)rawSize.Height; + else + renderBounds.Height = bounds.Height; + + if (verticalAlignment == VerticalAlignment.Stretch) + { + if (Parent != null) + { + if (Parent.sizeIsValid) + { + Rectangle pcb = Parent.clientBounds; + //vRatio = (float)pcb.Height / renderBounds.Height; + renderBounds.Height = pcb.Height; + //renderBounds.Width = (int)(vRatio * renderBounds.Width); + } + } + else + { + Debug.WriteLine("parent can't be null for streched item"); + sizeIsValid = false; + } + } + + if (horizontalAlignment == HorizontalAlignment.Stretch) + { + if (Parent != null) + { + if (Parent.sizeIsValid) + { + Rectangle pcb = Parent.clientBounds; + //hRatio = (float)pcb.Width / renderBounds.Width; + renderBounds.Width = pcb.Width; + //renderBounds.Height = (int)(hRatio * renderBounds.Height); + } + } + else + { + Debug.WriteLine("parent can't be null for streched item"); + sizeIsValid = false; + } + } + + } + public virtual void updateLayout() + { + if (layoutIsValid) + return; + + Rectangle oldRenderBounds = renderBounds.Clone; + + + + if (!sizeIsValid) + computeSize(); + + if (!positionIsValid) + { + //on aligne par rapport aux parent que si le parent contient une taille + if (Parent != null) + { + //if (Parent is WrappedWidgetGroup) + // positionIsValid = false; + //else + { + if (Parent.sizeIsValid) + { + positionIsValid = true; + + Rectangle pcb = Parent.clientBounds; + + switch (horizontalAlignment) + { + case HorizontalAlignment.Stretch: + case HorizontalAlignment.Left: + renderBounds.X = pcb.Left; + break; + case HorizontalAlignment.Right: + if (sizeIsValid) + renderBounds.X = pcb.Right - renderBounds.Width; + else + positionIsValid = false; + break; + case HorizontalAlignment.Center: + if (sizeIsValid) + renderBounds.X = pcb.X + pcb.Width / 2 - renderBounds.Width / 2; + else + positionIsValid = false; + break; + case HorizontalAlignment.None: + //if (bounds.X == 0) + //{ + // Debug.WriteLine("Not able to set X position for item"); + // positionIsValid = false; + //} + //else + renderBounds.X = bounds.X; + break; + } + + switch (verticalAlignment) + { + case VerticalAlignment.Stretch: + case VerticalAlignment.Top: + renderBounds.Y = pcb.Top; + break; + case VerticalAlignment.Bottom: + if (sizeIsValid) + renderBounds.Y = pcb.Bottom - renderBounds.Height; + else + positionIsValid = false; + break; + case VerticalAlignment.Center: + if (sizeIsValid) + renderBounds.Y = pcb.Y + pcb.Height / 2 - renderBounds.Height / 2; + else + positionIsValid = false; + break; + case VerticalAlignment.None: + //if (bounds.Y == 0) + //{ + // Debug.WriteLine("Not able to set Y position for item"); + // positionIsValid = false; + //} + //else + renderBounds.Y = bounds.Y; + break; + } + } + } + } + else + { + positionIsValid = true; + renderBounds.TopLeft = bounds.TopLeft; + } + } + + if (layoutIsValid) + registerForRedraw(); + } + internal virtual void updateGraphic() + { + int stride = 4 * renderBounds.Width; + + int bmpSize = Math.Abs(stride) * renderBounds.Height; + bmp = new byte[bmpSize]; + + using (ImageSurface draw = + new ImageSurface(bmp, Format.Argb32, renderBounds.Width, renderBounds.Height, stride)) + { + using (Context gr = new Context(draw)) + { + gr.Antialias = Antialias.Subpixel; + Rectangle rBack = new Rectangle(renderBounds.Size);// renderBoundsInContextCoordonate.Clone; + gr.Color = background; + gr.Rectangle(rBack); + gr.Fill(); + + if (borderWidth > 0) + { + rBack.Inflate(-borderWidth / 2, -borderWidth / 2); + gr.LineWidth = borderWidth; + gr.Color = borderColor; + gr.Rectangle(rBack); + gr.Stroke(); + } + } + draw.Flush(); + //draw.WriteToPng(directories.rootDir + @"test.png"); + } + + //if (layoutIsValid) + // registerForRedraw(); + } + public virtual void cairoDraw(ref Context ctx, Rectangles clip = null) + { + if (!isVisible) + return; + + if (bmp == null) + updateGraphic(); + + Rectangle tmp; + + tmp = renderBoundsInContextCoordonate;//.Clone; + + int stride = 4 * renderBounds.Width; + using (ImageSurface source = new ImageSurface(bmp, Format.Argb32, tmp.Width, tmp.Height, stride)) + { + + //ctx.Save(); + //if (Parent != null) + //{ + //ctx.ResetClip(); + // //ctx.Rectangle(Parent.clientBounds); + // ctx.Rectangle(tmp); + // ctx.Clip(); + //} + ctx.SetSourceSurface(source, tmp.X, tmp.Y); + ctx.Paint(); + //ctx.Restore(); + //source.WriteToPng(directories.rootDir + @"test.png"); + } + //ctx.Target.WriteToPng(directories.rootDir + @"test.png"); + + } + + #region Keyboard handling + public virtual void ProcessKeyboard(Key key) + { } + #endregion + + #region Mouse handling + public virtual bool ProcessMousePosition(Point mousePos) + { + if (!isVisible) + return false; + + if (ScreenCoordBounds.Contains(mousePos)) + { + if (focusable) + Interface.hoverWidget = this; + return true; + } + else + { + //if (focusable) + // Interface.hoverWidget = null; + return false; + } + } + public virtual void ProcessMouseDown(Point mousePos) + { + if (!isVisible) + return; + Panel.activeWidget = this; + } + public virtual void ProcessMouseUp(Point mousePos) + { + //Interface.activeWidget = null; + + if (!isVisible) + return; + } + + public virtual void ProcessMouseWeel(int delta) + { + if (!isVisible) + return; + } + #endregion + + public override string ToString() + { + string tmp = this.GetType().ToString().Split(new char[] { '.' }).Last() + ":-"; + if (!layoutIsValid) + tmp += "L-"; + //if (Interface.graphicUpdateList.Contains(this)) + // tmp += "GU-"; + if (Interface.redrawClip.intersect(this.renderBoundsInBackendSurfaceCoordonate)) + tmp += "D-"; + return tmp + string.Format("rb:{0}", renderBounds); + } + } +} diff --git a/src/Group.cs b/src/Group.cs new file mode 100644 index 00000000..95fc0df7 --- /dev/null +++ b/src/Group.cs @@ -0,0 +1,429 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using System.Diagnostics; +using Cairo; + +namespace go +{ + public class Group : ScrollingWidget + { + public List<GraphicObject> Children = new List<GraphicObject>(); + + public ImageSurface cairoCache; + + bool _cachingInProgress = false; + public override bool cachingInProgress + { + get { return _cachingInProgress; } + set { _cachingInProgress = value; } + } + + public Group(int _width = 30, int _height = 30) + : base(_width, _height) + { + init(); + } + + public Group() + : base() + { + init(); + } + void init() + { + focusable = true; + borderWidth = 0; + background = Color.Transparent; + } + + //public Widget addChild(Widget child) + //{ + // Children.Add(child); + // child.Parent = this; + // layoutIsValid = false; + // return child; + //} + public T addChild<T>(T child) + { + Children.Add(child as GraphicObject); + (child as GraphicObject).Parent = this as GraphicObject; + layoutIsValid = false; + return (T)child; + } + public void removeChild(GraphicObject child) + { + Children.Remove(child); + child.Parent = null; + layoutIsValid = false; + } + + public GraphicObject activeWidget; + public bool multiSelect = false; + public override void invalidateLayout() + { + base.invalidateLayout(); + foreach (GraphicObject w in Children) + w.invalidateLayout(); + } + public override bool layoutIsValid + { + get + { + if (!isVisible) + return true; + + if (!base.layoutIsValid) + return false; + else//le layout n'est valide que si tous les enfents sont validés aussi + { + + foreach (GraphicObject w in Children) + if (!w.layoutIsValid) + return false; + + } + + return true; + } + set + { + base.layoutIsValid = value; + } + } + + ////limit to clientbounds of wg for drawing on cached imagesurface + ////if called by wg itself, call base.BoundsInPanelCoordonate + //public override Rectangle renderBoundsInContextCoordonate + //{ + // get + // { + // if (Parent == null) + // return new Rectangle(renderBounds.Size); + + // //if (Parent is Panel && !(this is ScrollingWidget)) + // // return Parent.clientBounds; + + // Rectangle tmp = Parent.renderBoundsInContextCoordonate; + + // return new Rectangle( + // tmp.X + renderBounds.X, + // tmp.Y + renderBounds.Y, + // renderBounds.Width, + // renderBounds.Height); + + // return cachingInProgress ? new Rectangle( + // clientBounds.X + scrollX, + // clientBounds.Y + scrollY, + // clientBounds.Width, + // clientBounds.Height) + // : base.renderBoundsInContextCoordonate; + // } + //} + //public override bool needGraphicalUpdate + //{ + // get { return _needGraphicalUpdate; } + // set + // { + // if (value == _needGraphicalUpdate) + // return; + + // base.needGraphicalUpdate = value; + + // if (_needGraphicalUpdate) + // { + + // Widget[] widgets = new Widget[Children.Count]; + // Children.CopyTo(widgets); + // foreach (Widget w in widgets) + // { + // //if (w.isCached) + // // w.needGraphicalUpdate = true; + // //else + // w.needRedraw = true; + // } + // } + // } + //} + //nécessaire becose no cached of widgetgroup...TODO + //public override bool needRedraw + //{ + // get + // { + // return base.needRedraw; + // } + // set + // { + // if (value == _needRedraw) + // return; + + // base.needRedraw = value; + // if (_needRedraw && !isCached) + // { + // Widget[] widgets = new Widget[Children.Count]; + // Children.CopyTo(widgets); + // foreach (Widget w in widgets) + // w.needRedraw = true; + // } + // } + //} + + public override void ProcessMouseDown(Point mousePos) + { + if (!isVisible) + return; + + if (activeWidget == null) + return; + + //if (activeWidget.ScreenCoordBounds.Contains(mousePos)) + //{ + // activeWidget.ProcessMouseDown(mousePos); + + // //WrappedWidgetGroup wg = activeWidget as WrappedWidgetGroup; + // //if (wg != null) + // //{ + // // wg.ProcessMouseDown(mousePos); + // //} + //} + } + public override bool ProcessMousePosition(Point mousePos) + { + if (!isVisible) + return false; + + bool baseResult = base.ProcessMousePosition(mousePos); + + if (activeWidget != null) + { + if (activeWidget.ProcessMousePosition(mousePos)) + return true; + else + activeWidget = null; + } + + foreach (GraphicObject w in Children) + { + if (w.isVisible) + { + if (w.ProcessMousePosition(mousePos)) + { + activeWidget = w; + return true; + } + } + } + + activeWidget = null; + return baseResult; + } + public override bool isCached + { + get + { + return cairoCache == null ? false : true; + } + } + public void putWidgetOnTop(GraphicObject w) + { + if (Children.Contains(w)) + { + Children.Remove(w); + Children.Add(w); + } + } + public void putWidgetOnBottom(GraphicObject w) + { + if (Children.Contains(w)) + { + Children.Remove(w); + Children.Insert(0, w); + } + } + + #region widget overrides + public override void updateLayout() + { + //while (!layoutIsValid) + //{ + //le layout ne se fait à la base que si _LayoutIsValid = false + if (!(sizeIsValid && positionIsValid)) + base.updateLayout(); + + Rectangle contentBounds = Rectangle.Zero; + + GraphicObject[] widgets = new GraphicObject[Children.Count]; + Children.CopyTo(widgets); + foreach (GraphicObject w in widgets) + { + if (!w.layoutIsValid) + w.updateLayout(); + + contentBounds = contentBounds + w.renderBounds; + } + + contentBounds.Width += borderWidth + margin; + contentBounds.Height += borderWidth + margin; + + if (sizeToContent || VerticalScrolling || HorizontalScrolling) + { + sizeIsValid = true; + + foreach (GraphicObject w in widgets) + { + if (!w.sizeIsValid && w.isVisible) + { + sizeIsValid = false; + break; + } + } + + // contentBounds.Width += borderWidth + margin; + //contentBounds.Height += borderWidth + margin; + if (sizeIsValid) + { + if (sizeToContent) + renderBounds.Size = contentBounds.Size; + else if (VerticalScrolling) + renderBounds.Size = new Size(renderBounds.Size.Width, contentBounds.Size.Height); + else if (HorizontalScrolling) + renderBounds.Size = new Size(contentBounds.Size.Width, renderBounds.Size.Height); + } + } + //if (sizeToContent) + // renderBounds.Size = contentBounds.Size; + //else if (VerticalScrolling) + // renderBounds.Size = new Size(renderBounds.Size.Width, contentBounds.Size.Height); + //else if (HorizontalScrolling) + // renderBounds.Size = new Size(contentBounds.Size.Width, renderBounds.Size.Height); + + //} + if (layoutIsValid) + registerForRedraw(); + } + internal override void updateGraphic() + { + if (cairoCache != null) + cairoCache.Dispose(); + + cairoCache = null; + + base.updateGraphic(); + } + public override void cairoDraw(ref Context ctx, Rectangles clip = null) + { + if (!isVisible)//check if necessary?? + return; + + if (bmp == null) //update graphic before caching because UG reset cache + updateGraphic(); + + Rectangle rBoundsInContext = null; + Rectangles containedRects = null; + Rectangles smallerContainedRect = null; + + //if (isCached) + // rBoundsInContext = new Rectangle(rBoundsInContext.Size); + + bool rectsInBounds = false; + bool rebuildCache = false; + + if (cairoCache == null) + { + cairoCache = + new ImageSurface(Format.Argb32, renderBounds.Width, renderBounds.Height); + + rebuildCache = true; + } + + cachingInProgress = true; + + if (clip != null) + { + clip.Rebase(this); + + + if (!rebuildCache) + { + rBoundsInContext = this.renderBoundsInContextCoordonate; + + containedRects = clip.containedRects(rBoundsInContext); + smallerContainedRect = containedRects.SmallerRects(rBoundsInContext); + + if (smallerContainedRect.count > 0) + rectsInBounds = true; + } + } + + if (rectsInBounds || rebuildCache) + { + Context gr = new Context(cairoCache); + + if (rectsInBounds) + smallerContainedRect.clearAndClip(gr); + + //gr.Target.WriteToPng(directories.rootDir + @"test.png"); + + base.cairoDraw(ref gr); + + //gr.Target.WriteToPng(directories.rootDir + @"test.png"); + + GraphicObject[] widgets = new GraphicObject[Children.Count]; + Children.CopyTo(widgets); + foreach (GraphicObject w in widgets) + { + if (rebuildCache) + w.cairoDraw(ref gr); + else + { + Rectangle r = w.renderBoundsInContextCoordonate; + Rectangles clipRects = smallerContainedRect.intersectingRects(r); + //gr.Rectangle(r); + //gr.LineWidth = 1; + //gr.Color = new Cairo.Color(1, 0, 1, 1); + //gr.Stroke(); + + if (clipRects.count > 0) + w.cairoDraw(ref gr, clipRects); + //gr.Target.WriteToPng(directories.rootDir + @"test.png"); + } + } + + cairoCache.Flush(); + + //cairoCache.WriteToPng(directories.rootDir + @"test.png"); + } + + cachingInProgress = false; + + //draw cache + //Rectangle rCBPC = Parent.ClientBoundsInPanelCoordonate; + //cachingInProgress change context coordonate system + rBoundsInContext = this.renderBoundsInContextCoordonate; + //ctx.ResetClip(); + ctx.SetSourceSurface(cairoCache, rBoundsInContext.X, rBoundsInContext.Y); + //ctx.Rectangle(r); + ctx.Paint(); + + //ctx.ResetClip(); + //ctx.Rectangle(rBoundsInContext); + //ctx.Color = Color.Red; + //ctx.Fill(); + //ctx.Target.WriteToPng(directories.rootDir + @"test.png"); + + } + #endregion + + public override string ToString() + { + string tmp = base.ToString(); + foreach (GraphicObject w in Children) + { + tmp += "\n" + w.ToString(); + } + return tmp; + } + } +} diff --git a/src/GroupBox.cs b/src/GroupBox.cs new file mode 100644 index 00000000..749053cc --- /dev/null +++ b/src/GroupBox.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Cairo; + +namespace go +{ + public class GroupBox : Container + { + public GroupBox(Rectangle _bounds, string _title = "GroupBox") + : base(_bounds) + { + title = _title; + init(); + } + public GroupBox(string _title = "GroupBox") + : base() + { + title = _title; + sizeToContent = true; + init(); + } + void init() + { + horizontalAlignment = go.HorizontalAlignment.None; + verticalAlignment = go.VerticalAlignment.None; + borderColor = Color.White; + borderWidth = 1; + margin = 5; + } + string _title; + public string title + { + get { return _title; } + set + { + _title = value; + registerForGraphicUpdate(); + } + } + + int _fontSize = 10; + public int fontSize + { + get { return _fontSize; } + set + { + _fontSize = value; + registerForGraphicUpdate(); + } + } + public override Rectangle ClientBoundsInContextCoordonate + { + get + { + return base.ClientBoundsInContextCoordonate; + } + } + public override Rectangle clientBounds + { + get + { + Size ts = titleSize(); + + Rectangle cb = renderBounds.Clone; + cb.X = 0; + cb.Y = ts.Height; + cb.Height -= ts.Height; + cb.Inflate(-borderWidth - margin, -borderWidth - margin); + + return cb; + } + } + public Size titleSize() + { +#if _WIN32 || _WIN64 + byte[] txt = System.Text.UTF8Encoding.UTF8.GetBytes(_title); +#endif + + Size s; + + using (Context gr = new Context(new ImageSurface(Format.Argb32, 1, 1))) + { + gr.SetFontSize(fontSize); + TextExtents te; +#if _WIN32 || _WIN64 + te = gr.TextExtents(txt); +#elif __linux__ + te = gr.TextExtents(title); +#endif + FontExtents fe = gr.FontExtents; + s = new Size((int)Math.Ceiling(te.XAdvance), (int)Math.Ceiling(fe.Height)); + } + return s;// +borderWidth; + } + + public override void updateLayout() + { + if (!layoutIsValid) + { + base.updateLayout(); + + if (layoutIsValid) + renderBounds.Height += titleSize().Height;//?????????? + } + } + internal override void updateGraphic() + { + int stride = 4 * renderBounds.Width; + + int bmpSize = Math.Abs(stride) * renderBounds.Height; + bmp = new byte[bmpSize]; + + byte[] txt = System.Text.UTF8Encoding.UTF8.GetBytes(title);// utf = new System.Text.Decoder(); + + using (ImageSurface draw = new ImageSurface(bmp, Format.Argb32, renderBounds.Width, renderBounds.Height, stride)) + { + using (Context gr = new Context(draw)) + { + + + Rectangle r = new Rectangle(renderBounds.Size); + //gr.Rotate(Math.PI); + gr.SetFontSize(fontSize); + FontExtents fe = gr.FontExtents; + TextExtents te = gr.TextExtents(title); + // double a = Math.PI; + //gr.Transform(new c.Matrix(Math.Cos(a),-Math.Sin(a),Math.Sin(a),Math.Cos(a),renderBounds.Width,renderBounds.Height)); + gr.Antialias = Antialias.Subpixel; + gr.LineWidth = borderWidth; + gr.Color = background; + //gr.MoveTo(renderBounds.X+1,renderBounds.Y+1); + + + gr.Rectangle(r); + gr.Fill(); + + Rectangle rTitle = r.Clone; + + int th = (int)Math.Ceiling(fe.Height / 2); + r.Y += th; + r.Height -= th; + + const int titleGap = 5; + + if (borderWidth > 0) + { + gr.Color = borderColor; + gr.LineWidth = borderWidth; + + r.Inflate(-borderWidth / 2, -borderWidth / 2); + + + rTitle.X = r.X + titleGap; + rTitle.Width = (int)Math.Ceiling(te.XAdvance) + 2 * titleGap; + rTitle.Height = (int)Math.Ceiling(fe.Height); + gr.Save(); + gr.FillRule = FillRule.EvenOdd; + gr.Rectangle(new Rectangle(renderBounds.Size)); + gr.Rectangle(rTitle); + gr.Clip(); + + + gr.Rectangle(r); + gr.Stroke(); + gr.Restore(); + } + + gr.MoveTo(rTitle.X + titleGap, rTitle.Y + (int)Math.Ceiling(fe.Height - fe.Descent)); + +#if _WIN32 || _WIN64 + gr.ShowText(txt); +#elif __linux__ + gr.ShowText(title); +#endif + gr.Color = borderColor; + gr.FillExtents(); + + } + //draw.Flush(); + //draw.WriteToPng(directories.rootDir + @"test.png"); + } + + //registerForRedraw(); + } + public override void cairoDraw(ref Context ctx, Rectangles clip = null) + { + base.cairoDraw(ref ctx, clip); + } + //public override void cairoDraw(ref Context ctx, Rectangles clip = null) + //{ + // if (!isVisible)//check if necessary?? + // return; + + // base.cairoDraw(ref ctx, clip); + + // if (clip != null) + // clip.Rebase(this); + + // if (child != null) + // child.cairoDraw(ref ctx, clip); + + // //ctx.Target.WriteToPng(@"/home/jp/test.png"); + //} + + public override string ToString() + { + return this.title + ":" + base.ToString(); + } + } +} + diff --git a/src/HorizontalStack.cs b/src/HorizontalStack.cs new file mode 100644 index 00000000..f68d1bce --- /dev/null +++ b/src/HorizontalStack.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace go +{ + public class HorizontalStack : GenericStack + { + public HorizontalStack() + : base() + { + Orientation = go.Orientation.Horizontal; + } + } +} diff --git a/src/HorizontalWrappingWidget.cs b/src/HorizontalWrappingWidget.cs new file mode 100644 index 00000000..f16ccf34 --- /dev/null +++ b/src/HorizontalWrappingWidget.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Cairo; + +namespace go +{ + public class HorizontalWrappingWidget : WrappedWidgetGroup + { + public HorizontalWrappingWidget(int _borderWidth = 0) : + base() + { + Orientation = Orientation.Horizontal; + borderWidth = _borderWidth; + sizeToContent = true; + background = Color.Transparent; + } + public HorizontalWrappingWidget(Color _borderColor, int _borderWidth = 1) : + base() + { + Orientation = Orientation.Horizontal; + borderWidth = _borderWidth; + borderColor = _borderColor; + background = Color.Transparent; + sizeToContent = true; + } + public HorizontalWrappingWidget(Color _borderColor, Color _background, int _borderWidth = 1) : + base() + { + Orientation = Orientation.Horizontal; + borderWidth = _borderWidth; + borderColor = _borderColor; + background = _background; + sizeToContent = true; + } + } +} diff --git a/src/Image.cs b/src/Image.cs new file mode 100644 index 00000000..04640247 --- /dev/null +++ b/src/Image.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +//using OpenTK.Graphics.OpenGL; +using Cairo; +using System.IO; + +namespace go +{ + public class Image : GraphicObject + { + + byte[] image; + Size imgSize; + + public System.Drawing.Bitmap imgBitmap { + set { + loadImage (value); + } + } + + string _imgPath; + + public string imgPath { + get { return _imgPath; } + set { + _imgPath = value; + loadImage (_imgPath); + } + } + + public Image () : base() + { + } + + public Image (string ImagePath, Rectangle _bounds) + : base(_bounds) + { + imgPath = ImagePath; + } + + public Image (string ImagePath) + : base() + { + imgPath = ImagePath; + } + + public Image (System.Drawing.Bitmap _bitmap) + : base() + { + imgBitmap = _bitmap; + } + + public override Size measureRawSize () + { + if (image == null) + loadImage (directories.rootDir + @"Images/Icons/icon_alert.gif"); + + return new Size (imgSize.Width + borderWidth + margin, imgSize.Height + borderWidth + margin); + } + + //load image via System.Drawing.Bitmap, cairo load png only + public void loadImage (string path) + { + if (File.Exists (path)) + loadImage (new System.Drawing.Bitmap (path)); + } + + public void loadImage (System.Drawing.Bitmap bitmap) + { + if (bitmap == null) + return; + + System.Drawing.Imaging.BitmapData data = bitmap.LockBits + (new System.Drawing.Rectangle (0, 0, bitmap.Width, bitmap.Height), + System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + + imgSize = new Size (bitmap.Width, bitmap.Height); + + int stride = data.Stride; + int bitmapSize = Math.Abs (data.Stride) * bitmap.Height; + + image = new byte[bitmapSize]; + System.Runtime.InteropServices.Marshal.Copy (data.Scan0, image, 0, bitmapSize); + + bitmap.UnlockBits (data); + //bitmap.Dispose(); + } + + internal override void updateGraphic () + { + //int maxUV = 0; + float ratio = 1f; + + + //Image.WriteToPng(directories.rootDir + @"test.png"); + //maxUV = Math.Max(Image.Width, Image.Height); + + float widthRatio = (float)clientBounds.Width / imgSize.Width; + float heightRatio = (float)clientBounds.Height / imgSize.Height; + + ratio = Math.Min (widthRatio, heightRatio); + + int stride = 4 * renderBounds.Width; + + //init bmp with widget background and border + base.updateGraphic (); + + using (ImageSurface draw = + new ImageSurface(bmp, Format.Argb32, renderBounds.Width, renderBounds.Height, stride)) { + using (Context gr = new Context(draw)) { + //Rectangle r = new Rectangle(0, 0, renderBounds.Width, renderBounds.Height); + gr.Antialias = Antialias.Subpixel; + + Rectangle rImg = clientBounds.Clone; + + gr.Scale (widthRatio, heightRatio); + using (ImageSurface imgSurf = new ImageSurface(image, Format.Argb32, imgSize.Width, imgSize.Height, 4 * imgSize.Width)) { + gr.SetSourceSurface (imgSurf, (int)(rImg.X / widthRatio), (int)(rImg.Y / heightRatio)); + + gr.Paint (); + } + draw.Flush (); + } + //draw.WriteToPng(directories.rootDir + @"test.png"); + } + + //Image.Dispose(); + + //registerForRedraw(); + } + + + + } +} diff --git a/src/Interface.cs b/src/Interface.cs new file mode 100644 index 00000000..1abef72d --- /dev/null +++ b/src/Interface.cs @@ -0,0 +1,567 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenTK.Graphics.OpenGL; + +using GLU = OpenTK.Graphics.Glu; +using OpenTK.Input; +using OpenTK; +using Cairo; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; + +namespace go +{ + public delegate void WidgetEvent (GraphicObject sender); + + public delegate void ButtonWidgetClick (Button sender); + //public delegate object ValueGetter(Widget sender); + + + public static class Interface + { + + [DllImport ("libgo.so")] + private static extern void TTY_init (); + + [DllImport ("libgo.so")] + private static extern void TTY_attend (); + + [DllImport ("libgo.so")] + private static extern void FB_init (out Framebuffer fb); + + [DllImport ("libgo.so")] + public static extern void DEV_init (int largeur, int hauteur); + + [DllImport ("libgo.so")] + public static extern void DEV_lectureEvenement (out Evenement e); + + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public struct Framebuffer + { + public IntPtr ptr; + public int hauteur; + public int largeur; + public int linelength; + } + + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public struct Evenement + { + public int type; + public int data1; + public int data2; + public int data3; + public IntPtr emetteur; + public const int MOUSE_DOWN = 0x21; + public const int MOUSE_UP = 0x22; + public const int MOUSE_MVT = 0x23; + } + + public static List<Panel> panels = new List<Panel> (); + public static Panel activePanel; + + #region cairo contexte + public static Context ctx; + public static Surface surf; + public static byte[] buffer; //opengl byte buffer for rastering + + public static Surface mouseGraphic; + + public static void createFrameBufferSurface () + { + + + Framebuffer fb; + FB_init (out fb); + surf = new Cairo.ImageSurface (fb.ptr, Format.ARGB32, fb.largeur, fb.hauteur, fb.linelength); + ctx = new Context (surf); + + DEV_init (fb.largeur, fb.hauteur); + TTY_init(); + + initMouseGraphic (); + + } + + public static void createWin32Surface () + { + IntPtr hdc = Win32.GetDC (IntPtr.Zero); + surf = new Win32Surface (hdc); + ctx = new Context (surf); + } + public static void createOpenGLSurface() + { + int stride = 4 * renderBounds.Width; + + int bmpSize = Math.Abs(stride) * renderBounds.Height; + buffer = new byte[bmpSize]; + surf = new ImageSurface(buffer, Format.Argb32, renderBounds.Width, renderBounds.Height, stride); + ctx = new Context(surf); + } + public static void createOpenGLSurface (Rectangle bounds) + { + renderBounds = bounds; + + createOpenGLSurface(); + } + + public static void initMouseGraphic () + { + mouseGraphic = new ImageSurface (@"Pointeurs/left_ptr.png"); + //mouseGraphic = new ImageSurface(@"test.png"); + Thread t = new Thread (deviceThread); + t.Start (); + } + + public static void deviceThread () + { + while (true) + { + TTY_attend(); + + Interface.Evenement e; + Interface.DEV_lectureEvenement (out e); + + switch (e.type) { + case Evenement.MOUSE_MVT: + //erase previouse mouse +// ctx.Operator = Operator.Clear; +// ctx.SetSourceSurface(mouseGraphic,mouseX,mouseY); +// ctx.Paint(); +// ctx.Operator = Operator.Over; + lock(redrawClip) + { + redrawClip.AddRectangle (new Rectangle (mouseX, mouseY, 48, 48)); + } + mouseX = e.data1; + mouseY = e.data2; + + break; + default: + break; + } + } + } + #endregion + + //for panel only + public static Rectangles redrawClip = new Rectangles (); + public static char decimalSeparator = '.'; + + #region Mouse Handling" + public static bool MouseIsInInterface = false; + //used only for pannel mouse grabbing, should extend it to other go + public static bool grabMouse = false; + public static MouseDevice Mouse; + + public static bool ProcessMousePosition (Point mousePos, Vector2 Delta) + { + if (checkMouse (mousePos)) { + if (Delta != Vector2.Zero) { + if (Interface.activePanel != null) { + Interface.activePanel.updateMouseCursor (); + } + + + if (Mouse [MouseButton.Left]) { + if (Interface.activePanel != null) { + if (Interface.grabMouse) { + go.Panel p = Interface.activePanel; + p.registerForRedraw (); //add previous clip rect + switch (Interface.activePanel.mouseBorderPosition) { + case PanelBorderPosition.Top: + p.y -= (int)Delta.Y; + p.height += (int)Delta.Y; + break; + case PanelBorderPosition.Left: + p.x -= (int)Delta.X; + p.width += (int)Delta.X; + break; + case PanelBorderPosition.Right: + p.width -= (int)Delta.X; + break; + case PanelBorderPosition.Bottom: + p.height -= (int)Delta.Y; + break; + case PanelBorderPosition.TopLeft: + p.y -= (int)Delta.Y; + p.height += (int)Delta.Y; + p.x -= (int)Delta.X; + p.width += (int)Delta.X; + break; + case PanelBorderPosition.TopRight: + p.y -= (int)Delta.Y; + p.height += (int)Delta.Y; + p.width -= (int)Delta.X; + break; + case PanelBorderPosition.BottomLeft: + p.height -= (int)Delta.Y; + p.x -= (int)Delta.X; + p.width += (int)Delta.X; + break; + case PanelBorderPosition.BottomRight: + p.height -= (int)Delta.Y; + p.width -= (int)Delta.X; + break; + case PanelBorderPosition.Moving: + p.x -= (int)Delta.X; + p.y -= (int)Delta.Y; + p.updatePosition (); + break; + case PanelBorderPosition.ClientArea: + break; + default: + break; + } + p.invalidateLayout (); + } + } + } + } + return true; + } else + return false; + } + + public static void ProcessMouseWheel (int delta) + { + int step = 15; + if (activePanel != null) + activePanel.ProcessMouseWeel (delta * step); + } + + static bool checkMouse (Point mousePos) + { + if (grabMouse) + return true; + else if (activePanel != null) { + if (activePanel.ProcessMousePosition (mousePos)) + return true; + else + activePanel = null; + } + + foreach (Panel p in panels) { + if (p.isVisible) { + if (p.ProcessMousePosition (mousePos)) { + activePanel = p; + activePanel.putOnTop (); + Interface.MouseIsInInterface = true; + return true; + } + } + } + activePanel = null; + + Interface.MouseIsInInterface = false; + return false; + } + + public static void Mouse_ButtonDown (object sender, MouseButtonEventArgs e) + { + if (!MouseIsInInterface) + return; + + Point m = e.Position; + + if (activePanel != null) { + activePanel.putOnTop (); + + Rectangle r = Interface.activePanel.ScreenCoordClientBounds; + + if (r.Contains (m)) { + grabMouse = false; + } else { + grabMouse = true; + } + activePanel.ProcessMouseDown (e.Position); + activePanel.updateMouseCursor (); + } + + if (hoverWidget != null) + hoverWidget.ProcessMouseDown (e.Position); + } + + public static void Mouse_ButtonUp (object sender, MouseButtonEventArgs e) + { + + grabMouse = false; + + if (activeWidget != null) { + activeWidget.ProcessMouseUp (e.Position); + } + } + + #endregion + + #region keyboard handling + public static KeyboardDevice Keyboard; + private static bool _capitalOn = false; + + public static bool capitalOn { + get { + return + Keyboard [Key.ShiftLeft] || Keyboard [Key.ShiftRight] ? + !_capitalOn : _capitalOn; + } + set { _capitalOn = value; } + } + + public static void ProcessKeyboard (Key k) + { + switch (k) { + case Key.CapsLock: + capitalOn = !capitalOn; + break; + } + + if (activeWidget != null) + activeWidget.ProcessKeyboard (k); + } + #endregion + + + + + //used to manage focusable widget like textboxes or buttons + private static GraphicObject _activeWidget; + + public static GraphicObject activeWidget { + get { return _activeWidget; } + set { _activeWidget = value; } + } + + static GraphicObject _hoverWidget; + + public static GraphicObject hoverWidget { + get { return _hoverWidget; } + set { + if (value == _hoverWidget) + return; + + _hoverWidget = value; + } + } + + static Rectangle _renderBounds = new Rectangle(0, 0, 800, 600); + public static Rectangle renderBounds + { + get { return _renderBounds; } + set + { + _renderBounds = value; + ctx = null; + if (surf != null) + surf.Dispose(); + createOpenGLSurface(); + foreach (Panel p in panels) + { + p.invalidateLayout(); + } + } + } + + public static Panel addPanel (Rectangle _bounds) + { + Panel p = new Panel (_bounds); + panels.Add (p); + return p; + } + + public static PanelWithTitle addPanel (Rectangle _bounds, string _title) + { + PanelWithTitle p = new PanelWithTitle (_bounds); + p.title = _title; + panels.Add (p); + return p; + } + + public static int mouseX = 0; + public static int mouseY = 0; + + public static void update () + { + + + + Stopwatch layoutTime = new Stopwatch (); + Stopwatch guTime = new Stopwatch (); + Stopwatch drawingTime = new Stopwatch (); + + + Panel[] inversedPanels = new Panel[panels.Count]; + panels.CopyTo (inversedPanels); + inversedPanels = inversedPanels.Reverse ().ToArray (); + + foreach (Panel p in inversedPanels) { + if (p.isVisible) { + layoutTime.Start (); + p.processkLayouting (); + layoutTime.Stop (); + + + } + } + lock(redrawClip) + { + if (redrawClip.count > 0) { + redrawClip.clearAndClip (ctx); + + + foreach (Panel p in inversedPanels) { + if (p.isVisible) { + drawingTime.Start (); + + ctx.Save (); + + if (redrawClip.count > 0) { + + + Rectangle r = p.renderBounds; + Rectangles clip = redrawClip.intersectingRects (r); + + if (clip.count > 0) + p.cairoDraw (ref ctx, clip); + //p.processDrawing(ctx); + } + drawingTime.Stop (); + + ctx.Restore (); + } + } + //ctx.SetSourceSurface (mouseGraphic, mouseX, mouseY); + //ctx.Paint (); + ctx.ResetClip (); + redrawClip.Reset (); + } + + } + + //Debug.WriteLine("INTERFACE: layouting: {0} ticks \t graphical update {1} ticks \t drawing {2} ticks", + // layoutTime.ElapsedTicks, + // guTime.ElapsedTicks, + // drawingTime.ElapsedTicks); + Debug.WriteLine ("INTERFACE: layouting: {0} ms \t graphical update {1} ms \t drawing {2} ms", + layoutTime.ElapsedMilliseconds, + guTime.ElapsedMilliseconds, + drawingTime.ElapsedMilliseconds); + + } + + public static void setTeint (float colorScale) + { + GL.PixelTransfer (PixelTransferParameter.RedScale, colorScale); + GL.PixelTransfer (PixelTransferParameter.BlueScale, colorScale); + GL.PixelTransfer (PixelTransferParameter.GreenScale, colorScale); + } + + public static byte[] flitY (byte[] source, int stride, int height) + { + byte[] bmp = new byte[source.Length]; + source.CopyTo (bmp, 0); + + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < stride; x++) { + byte tmp = bmp [y * stride + x]; + bmp [y * stride + x] = bmp [(height - 1 - y) * stride + x]; + bmp [(height - y - 1) * stride + x] = tmp; + } + } + return bmp; + } + + public static double min (params double[] arr) + { + int minp = 0; + for (int i = 1; i < arr.Length; i++) + if (arr [i] < arr [minp]) + minp = i; + + return arr [minp]; + } + + public static void DrawRoundedRectangle (Cairo.Context gr, Rectangle r, double radius) + { + DrawRoundedRectangle (gr, r.X, r.Y, r.Width, r.Height, radius); + } + + public static void DrawCurvedRectangle (Cairo.Context gr, Rectangle r) + { + DrawCurvedRectangle (gr, r.X, r.Y, r.Width, r.Height); + } + + public static void DrawRoundedRectangle (Cairo.Context gr, double x, double y, double width, double height, double radius) + { + gr.Save (); + + if ((radius > height / 2) || (radius > width / 2)) + radius = min (height / 2, width / 2); + + gr.MoveTo (x, y + radius); + gr.Arc (x + radius, y + radius, radius, Math.PI, -Math.PI / 2); + gr.LineTo (x + width - radius, y); + gr.Arc (x + width - radius, y + radius, radius, -Math.PI / 2, 0); + gr.LineTo (x + width, y + height - radius); + gr.Arc (x + width - radius, y + height - radius, radius, 0, Math.PI / 2); + gr.LineTo (x + radius, y + height); + gr.Arc (x + radius, y + height - radius, radius, Math.PI / 2, Math.PI); + gr.ClosePath (); + gr.Restore (); + } + + public static void DrawCurvedRectangle (Cairo.Context gr, double x, double y, double width, double height) + { + gr.Save (); + gr.MoveTo (x, y + height / 2); + gr.CurveTo (x, y, x, y, x + width / 2, y); + gr.CurveTo (x + width, y, x + width, y, x + width, y + height / 2); + gr.CurveTo (x + width, y + height, x + width, y + height, x + width / 2, y + height); + gr.CurveTo (x, y + height, x, y + height, x, y + height / 2); + gr.Restore (); + } + + public static void StrokeRaisedRectangle (Cairo.Context gr, Rectangle r, double width = 1) + { + gr.Save (); + r.Inflate ((int)-width / 2, (int)-width / 2); + gr.LineWidth = width; + gr.Color = Color.White; + gr.MoveTo (r.BottomLeft); + gr.LineTo (r.TopLeft); + gr.LineTo (r.TopRight); + gr.Stroke (); + + gr.Color = Color.DarkGray; + gr.MoveTo (r.TopRight); + gr.LineTo (r.BottomRight); + gr.LineTo (r.BottomLeft); + gr.Stroke (); + + gr.Restore (); + } + + public static void StrokeLoweredRectangle (Cairo.Context gr, Rectangle r, double width = 1) + { + gr.Save (); + r.Inflate ((int)-width / 2, (int)-width / 2); + gr.LineWidth = width; + gr.Color = Color.DarkGray; + gr.MoveTo (r.BottomLeft); + gr.LineTo (r.TopLeft); + gr.LineTo (r.TopRight); + gr.Stroke (); + gr.Color = Color.White; + gr.MoveTo (r.TopRight); + gr.LineTo (r.BottomRight); + gr.LineTo (r.BottomLeft); + gr.Stroke (); + + gr.Restore (); + } + } + + +} diff --git a/src/Label.cs b/src/Label.cs new file mode 100644 index 00000000..699c2e88 --- /dev/null +++ b/src/Label.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; +using Cairo; + +namespace go +{ + public class Label : GraphicObject + { + //static constructor to init label specific theme value + public static class Theme + { + public static Color background = Color.Transparent; + public static Color borderColor = Color.White; + public static int margin = 0; + public static int borderWidth = 0; + public static VerticalAlignment verticalAlignment = VerticalAlignment.None; + public static HorizontalAlignment horizontalAlignment = HorizontalAlignment.None; + public static bool sizeToContent = false; + //label specific + public static int fontSize = 10; + public static Color fontColor = Color.White; + } + + public Label(string _text) + : base() + { + init(); + updateFont(); + text = _text; + + } + + void init() + { + background = Theme.background; + borderColor = Theme.borderColor; + borderWidth = Theme.borderWidth; + margin = Theme.margin; + horizontalAlignment = Theme.horizontalAlignment; + verticalAlignment = Theme.verticalAlignment; + sizeToContent = Theme.sizeToContent; + fontSize = Theme.fontSize; + fontColor = Theme.fontColor; + } + + + + protected string _text = "label"; + int _fontSize; + Color _fontColor; + + public string text + { + get { return _text; } + set + { + if (_text == value) + return; + + registerForGraphicUpdate(); + + //if (value.Length != _text.Length) + // layoutIsValid = false; + + _text = value; + } + } + public int fontSize + { + get { return _fontSize; } + set + { + _fontSize = value; + registerForGraphicUpdate(); + } + } + public Color fontColor + { + get { return _fontColor; } + set + { + _fontColor = value; + registerForGraphicUpdate(); + } + } + + public byte[] utf8Text + { + get { return System.Text.UTF8Encoding.UTF8.GetBytes(text); } + } + + protected Rectangle rText; + + //public FontStyle fontStyle + //{ + // get { return _fontStyle; } + // set + // { + // _fontStyle = value; + // updateFont(); + // } + //} + //public FontFamily fontFamily + //{ + // get { return _fontFamily; } + // set + // { + // _fontFamily = value; + // updateFont(); + // } + //} + + + + //Font TextFont; + + public Alignment textAlignment = Alignment.LeftCenter; + + + + void updateFont() + { + //TextFont = new Font(fontFamily, fontSize, fontStyle, GraphicsUnit.Pixel); + bmp = null; + } + + public override Size measureRawSize() + { + byte[] txt = utf8Text; + + Size s; + + using (Context gr = new Context(new ImageSurface(Format.Argb32,1,1))) + { + gr.SetFontSize(fontSize); + TextExtents te; +#if _WIN32 || _WIN64 + te = gr.TextExtents(utf8Text); +#elif __linux__ + te = gr.TextExtents(text); +#endif + FontExtents fe = gr.FontExtents; + s = new Size((int)Math.Ceiling(te.XAdvance),(int)Math.Ceiling(fe.Height)); + } + return s;// +borderWidth; + } + + internal override void updateGraphic() + { + byte[] txt = utf8Text; + int stride = 4 * renderBounds.Width; + + + //init bmp with widget background and border + base.updateGraphic(); + + using (ImageSurface bitmap = + new ImageSurface(bmp, Format.Argb32, renderBounds.Width, renderBounds.Height, stride)) + { + using (Context gr = new Context(bitmap)) + { + gr.FontOptions.Antialias = Antialias.Subpixel; + gr.FontOptions.HintMetrics = HintMetrics.On; + gr.SetFontSize(fontSize); + FontExtents fe = gr.FontExtents; + rText = new Rectangle(new Point(0,0), measureRawSize()); + //gr.Rotate(Math.PI); + + // double a = Math.PI; + //gr.Transform(new c.Matrix(Math.Cos(a),-Math.Sin(a),Math.Sin(a),Math.Cos(a),renderBounds.Width,renderBounds.Height)); + gr.Antialias = Antialias.Subpixel; + gr.LineWidth = borderWidth; + + float widthRatio = 1f; + float heightRatio = 1f; + + Rectangle cb = clientBounds; + + //ignore text alignment if size to content = true + if (!sizeToContent) + { + switch (textAlignment) + { + case Alignment.None: + break; + case Alignment.TopLeft: //ok + rText.X = cb.X; + rText.Y = cb.Y; + break; + case Alignment.TopCenter: //ok + rText.Y = cb.Y; + rText.X = cb.X + cb.Width / 2 - rText.Width / 2; + break; + case Alignment.TopRight: //ok + rText.X = cb.Right - rText.Width; + rText.Y = cb.Y; + break; + case Alignment.TopStretch://ok + heightRatio = widthRatio = (float)cb.Width / rText.Width; + rText.X = cb.X; + rText.Y = cb.Y; + rText.Width = cb.Width; + rText.Height = (int)(rText.Height * heightRatio); + break; + case Alignment.LeftCenter://ok + rText.X = cb.X; + rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2; + break; + case Alignment.LeftStretch://ok + heightRatio = widthRatio = (float)cb.Height / rText.Height; + rText.X = cb.X; + rText.Y = cb.Y; + rText.Height = cb.Height; + rText.Width = (int)(widthRatio * cb.Width); + break; + case Alignment.RightCenter://ok + rText.X = cb.X + cb.Width - rText.Width; + rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2; + break; + case Alignment.RightStretch://ok + heightRatio = widthRatio = (float)cb.Height / rText.Height; + rText.Height = cb.Height; + rText.Width = (int)(widthRatio * cb.Width); + rText.X = cb.X; + rText.Y = cb.Y; + break; + case Alignment.BottomCenter://ok + rText.X = cb.Width / 2 - rText.Width / 2; + rText.Y = cb.Height - rText.Height; + break; + case Alignment.BottomStretch://ok + heightRatio = widthRatio = (float)cb.Width / rText.Width; + rText.Width = cb.Width; + rText.Height = (int)(rText.Height * heightRatio); + rText.Y = cb.Bottom - rText.Height; + rText.X = cb.X; + break; + case Alignment.BottomLeft://ok + rText.X = cb.X; + rText.Y = cb.Bottom - rText.Height; + break; + case Alignment.BottomRight://ok + rText.Y = cb.Bottom - rText.Height; + rText.X = cb.Right - rText.Width; + break; + case Alignment.Center://ok + rText.X = cb.X + cb.Width / 2 - rText.Width / 2; + rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2; + break; + case Alignment.Fit://ok, peut être mieu aligné + widthRatio = (float)cb.Width / rText.Width; + heightRatio = (float)cb.Height / rText.Height; + rText = cb.Clone; + break; + case Alignment.HorizontalStretch://ok + heightRatio = widthRatio = (float)cb.Width / rText.Width; + rText.Width = cb.Width; + rText.Height = (int)(heightRatio * rText.Height); + rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2; + rText.X = cb.X; + break; + case Alignment.VerticalStretch://ok + heightRatio = widthRatio = (float)cb.Height / rText.Height; + rText.Height = cb.Height; + rText.Width = (int)(widthRatio * rText.Width); + rText.X = cb.X + cb.Width / 2 - rText.Width / 2; + rText.Y = cb.Y; + break; + default: + break; + } + } + + + gr.Color = fontColor; + + gr.FontMatrix = new Matrix(widthRatio * fontSize, 0, 0, heightRatio * fontSize, 0, 0); + + fe = gr.FontExtents; + + gr.MoveTo(rText.X, rText.Y + fe.Ascent); +#if _WIN32 || _WIN64 + gr.ShowText(txt); +#elif __linux__ + gr.ShowText(text); +#endif + + gr.Fill(); + + } + bitmap.Flush(); + //bitmap.WriteToPng(directories.rootDir + @"test.png"); + } + + //registerForRedraw(); + } + + } +} diff --git a/src/Mouse.cs b/src/Mouse.cs new file mode 100644 index 00000000..cc4e0933 --- /dev/null +++ b/src/Mouse.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace go +{ + public static class Mouse2d + { + public static Point position; + + public static int X + { + get { return position.X; } + set { position.X = value; } + } + public static int Y + { + get { return position.Y; } + set { position.Y = value; } + } + + } +} diff --git a/src/Mouse3d.cs b/src/Mouse3d.cs new file mode 100644 index 00000000..c4da2a98 --- /dev/null +++ b/src/Mouse3d.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenTK; +using OpenTK.Graphics.OpenGL; +using System.Drawing; +using System.Diagnostics; +using OTKGL; +using OpenTK.Input; + +namespace OTKGL +{ + + + + public static class Mouse3d + { + #region winApi + + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public struct Point + { + + /// LONG->int + public int x; + + /// LONG->int + public int y; + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public struct HICON__ + { + + /// int + public int unused; + } + +#if _WIN32 || _WIN64 + /// Return Type: HCURSOR->HICON->HICON__* + ///hCursor: HCURSOR->HICON->HICON__* + [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SetCursor")] + public static extern System.IntPtr SetCursor([System.Runtime.InteropServices.InAttribute()] System.IntPtr hCursor); +#elif __linux__ + public static System.IntPtr SetCursor(System.IntPtr hCursor) + { + return (IntPtr)0; + } +#endif + + /// Return Type: BOOL->int + ///lpPoint: LPPOINT->tagPOINT* + [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetCursorPos")] + [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] + public static extern bool GetCursorPos([System.Runtime.InteropServices.OutAttribute()] out Point lpPoint); + + /// Return Type: BOOL->int + ///X: int + ///Y: int + [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SetCursorPos")] + [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] + public static extern bool SetCursorPos(int X, int Y); + + #endregion + + public static float RotationSpeed = 0.005f; + + public static Vector3 Position; + public static bool MouseLeftIsDown = false; + public static bool MouseRightIsDown = false; + public static bool MouseMiddleIsDown = false; + + + static int oldMouseX; + static int oldMouseY; + + public static void setPosition(Vector3 newPos) + { + Position = newPos; + Point pt; + GetCursorPos(out pt); + oldMouseX = pt.x; + oldMouseY = pt.y; + } + + public static void update() + { + //SetCursor((IntPtr)0); + + Point pt; + GetCursorPos(out pt); + + //mise a jour mouse 3d + + int mDiffX = oldMouseX - pt.x; + int mDiffY = oldMouseY - pt.y; + + + + GetCursorPos(out pt); + + oldMouseX = pt.x; + oldMouseY = pt.y; + + Delta = new Vector2(mDiffX, mDiffY); + + + //if (Delta != Vector2.Zero) + //{ + // if (MouseRightIsDown ) + // { + // //camera rotation + // Matrix4 m = Matrix4.CreateRotationZ(Delta.X * RotationSpeed); + // vLook = Vector3.Transform(vLook, m); + + // //vecteur perpendiculaire sur le plan x,y + // Vector3 vLookPerpendicularOnXYPlane = new Vector3(new Vector2(vLook).PerpendicularLeft); + // vLookPerpendicularOnXYPlane.Normalize(); + + // Matrix4 m2 = Matrix4.Rotate(vLookPerpendicularOnXYPlane, -Delta.Y * RotationSpeed); + + // vLook = Vector3.Transform(vLook, m2); + // } + + //} + //return vLook; + } + + public static Vector2 Delta = Vector2.Zero; + + + public static float X + { get { return Position.X; } } + public static float Y + { get { return Position.Y; } } + + + public static void init() + { + float initpos = 40f; + Position = new Vector3(initpos,initpos,World.CurrentWorld.getHeight(initpos,initpos)); + } + public static void render() + { + GL.PushAttrib(AttribMask.EnableBit); + GL.Disable(EnableCap.Texture2D); + GL.Disable(EnableCap.Lighting); + GL.Disable(EnableCap.DepthTest); + + GL.PointSize(5.0f); + GL.Color3(Color.Aqua); + + GL.Begin(BeginMode.Points); + GL.Vertex3(Position); + GL.End(); + + GL.Color3(Color.White); + GL.PopAttrib(); + } + + public static void Mouse_ButtonDown(object sender, MouseButtonEventArgs e) + { + if (e.Button == MouseButton.Left) + MouseLeftIsDown = true; + if (e.Button == MouseButton.Right) + MouseRightIsDown = true; + if (e.Button == MouseButton.Middle) + MouseMiddleIsDown = true; + } + public static void Mouse_ButtonUp(object sender, MouseButtonEventArgs e) + { + if (e.Button == MouseButton.Left) + MouseLeftIsDown = false; + if (e.Button == MouseButton.Right) + MouseRightIsDown = false; + if (e.Button == MouseButton.Middle) + MouseMiddleIsDown = false; + + } + + } +} diff --git a/src/Panel.cs b/src/Panel.cs new file mode 100644 index 00000000..24206775 --- /dev/null +++ b/src/Panel.cs @@ -0,0 +1,324 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenTK.Graphics.OpenGL; +using System.Windows.Forms; + +using Cairo; +using OpenTK; + +namespace go +{ + public class Panel : Container + { + private static GraphicObject _activeWidget; + + public static GraphicObject activeWidget + { + get { return _activeWidget; } + set + { + if (_activeWidget != null) + _activeWidget.hasFocus = false; + _activeWidget = value; + if (_activeWidget != null) + _activeWidget.hasFocus = true; + } + } + + public override int x + { + get { return bounds.X; } + set + { + if (value < 0) + bounds.X = 0; + else if (value > Interface.renderBounds.Right) + value = (int)Interface.renderBounds.Right - bounds.Width; + else + bounds.X = value; + } + } + public override int y + { + get { return bounds.Y; } + set + { + if (value < 0) + bounds.Y = 0; + else if (value > Interface.renderBounds.Bottom - bounds.Height) + bounds.Y = (int)Interface.renderBounds.Bottom - bounds.Height; + else + bounds.Y = value; + } + } + public override bool isVisible + { + get { return _isVisible; } + set + { + if (value == _isVisible) + return; + + if (!value)//register old clip while visible for backend clearing + registerForRedraw(); + + _isVisible = value; + + invalidateLayout(); + + //callForRedraw(); + } + } + bool _cachingInProgress = false; + public override bool cachingInProgress + { + get { return _cachingInProgress; } + set { _cachingInProgress = value; } + } + + public override void registerForRedraw() + { + base.registerForRedraw(); + } + //smart array of clipping rectangles + //public Rectangles redrawClip = new Rectangles(); + + + public PanelBorderPosition mouseBorderPosition = PanelBorderPosition.ClientArea; + + public override Rectangle renderBoundsInBackendSurfaceCoordonate + { get { return renderBounds.Clone; } } + + public Panel(Rectangle _bounds) + : base(_bounds) + { + borderWidth = 1; + margin = 5; + verticalAlignment = go.VerticalAlignment.None; + horizontalAlignment = go.HorizontalAlignment.None; + } + + + public void processkLayouting() + { + if (!isVisible) + return; + + while (!this.layoutIsValid) + { + + this.updateLayout(); + + } + } + + public void processDrawing(Context ctx) + { + //if (bmp == null) + //{ + // updateGraphic(); + // cachingInProgress = true; + //} + //if (redrawClip.count > 0) + //{ + // if (!cachingInProgress) //not full redraw of cache + // { + // //clip to panel client zone; + // ctx.Rectangle(renderBoundsInBackSurfaceCoordonate); + // ctx.Clip(); + // redrawClip.clearAndClip(ctx); + // } + + // cairoDraw(ref ctx); + + // //clip to panel client zone; + // ctx.Rectangle(renderBoundsInBackSurfaceCoordonate); + // ctx.Clip(); + // //ctx.Target.WriteToPng(directories.rootDir + @"test.png"); + + + // if (child != null) + // { + // Rectangle r = child.renderBoundsInBackSurfaceCoordonate; + + // Rectangles clip = redrawClip.intersectingRects(r); + + // if (clip.count > 0 || cachingInProgress) + // child.cairoDraw(ref ctx, clip); + // } + + // cachingInProgress = false; + + // ctx.ResetClip(); + // redrawClip.Reset(); + //} + } + + #region widget overides + + //public override void registerForRedraw() + //{ + // Interface.redrawClip.AddRectangle(this.renderBoundsInContextCoordonate); + //} + + + #region Mouse handling + public override void ProcessMouseDown(Point mousePos) + { + if (!isVisible) + return; + + if (mouseBorderPosition == PanelBorderPosition.Closing) + isVisible = false; + + //base.ProcessMouseDown(mousePos); + + //if (child != null) + // child.ProcessMouseDown(mousePos); + + + } + public override bool ProcessMousePosition(Point mousePos) + { + if (!isVisible) + return false; + + if (base.ProcessMousePosition(mousePos)) + { + if (ScreenCoordClientBounds.Contains(mousePos)) + { + mouseBorderPosition = PanelBorderPosition.ClientArea; + + if (child != null) + child.ProcessMousePosition(mousePos); + } + else + { + Point m = mousePos; + + if (this is PanelWithTitle) + { + if (rectInScreenCoord((this as PanelWithTitle).rClose).Contains(m)) + { + mouseBorderPosition = PanelBorderPosition.Closing; + return true; + } + } + + Rectangle r = ScreenCoordClientBounds.Clone; + + if (m.X <= r.X) + { + if (m.Y <= r.Y) + mouseBorderPosition = PanelBorderPosition.TopLeft; + else if (m.Y >= r.Bottom) + mouseBorderPosition = PanelBorderPosition.BottomLeft; + else + mouseBorderPosition = PanelBorderPosition.Left; + } + else if (m.X >= r.Right) + { + if (m.Y <= r.Y) + mouseBorderPosition = PanelBorderPosition.TopRight; + else if (m.Y >= r.Bottom) + mouseBorderPosition = PanelBorderPosition.BottomRight; + else + mouseBorderPosition = PanelBorderPosition.Right; + } + else + { + if (m.Y <= r.Y) + { + if (this is PanelWithTitle) + { + if (m.Y <= r.Y - ((this as PanelWithTitle).titleSize().Height + 2 * borderWidth)) + mouseBorderPosition = PanelBorderPosition.Top; + else + mouseBorderPosition = PanelBorderPosition.Moving; + + + return true; + } + else + mouseBorderPosition = PanelBorderPosition.Top; + } + else if (m.Y >= r.Bottom) + mouseBorderPosition = PanelBorderPosition.Bottom; + else + mouseBorderPosition = PanelBorderPosition.ClientArea; + } + } + + return true; + } + else + return false; + } + + #endregion + + #endregion + + public void updateMouseCursor() + { + switch (mouseBorderPosition) + { + case PanelBorderPosition.Top: + Win32.SetCursor(Cursors.SizeNS.Handle); + break; + case PanelBorderPosition.Left: + Win32.SetCursor(Cursors.SizeWE.Handle); + break; + case PanelBorderPosition.Right: + Win32.SetCursor(Cursors.SizeWE.Handle); + break; + case PanelBorderPosition.Bottom: + Win32.SetCursor(Cursors.SizeNS.Handle); + break; + case PanelBorderPosition.TopLeft: + Win32.SetCursor(Cursors.SizeNWSE.Handle); + break; + case PanelBorderPosition.TopRight: + Win32.SetCursor(Cursors.SizeNESW.Handle); + break; + case PanelBorderPosition.BottomLeft: + Win32.SetCursor(Cursors.SizeNESW.Handle); + break; + case PanelBorderPosition.BottomRight: + Win32.SetCursor(Cursors.SizeNWSE.Handle); + break; + case PanelBorderPosition.Moving: + Win32.SetCursor(Cursors.SizeAll.Handle); + break; + case PanelBorderPosition.Closing: + Win32.SetCursor(Cursors.Default.Handle); + break; + case PanelBorderPosition.ClientArea: + //Interface.SetCursor(Cursors.Hand.Handle); + break; + default: + break; + } + } + public void putOnTop() + { + if (Interface.panels.IndexOf(this) > 0) + { + Interface.panels.Remove(this); + Interface.panels.Insert(0, this); + this.registerForRedraw(); + } + } + + + + public override string ToString() + { + string tmp = this.GetType().ToString().Split(new char[] { '.' }).Last() + ":-"; + return tmp + string.Format("rb:{0}", renderBounds); + } + } +} + diff --git a/src/PanelWithTitle.cs b/src/PanelWithTitle.cs new file mode 100644 index 00000000..3208821f --- /dev/null +++ b/src/PanelWithTitle.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Cairo; + +namespace go +{ + public class PanelWithTitle : Panel + { + public PanelWithTitle(Rectangle _bounds) + : base(_bounds) + { + background = Color.DimGray; + } + + string _title = "Panel"; + public string title + { + get { return _title; } + set + { + _title = value; + registerForGraphicUpdate(); + } + } + + int _fontSize = 10; + public int fontSize + { + get { return _fontSize; } + set + { + _fontSize = value; + registerForGraphicUpdate(); + } + } + public Color titleBackground = new Color(0.5, 0.5, 0.7, 0.8); + public Color titleTextColor = new Color(0.9, 0.9, 0.9, 1); + public Size titleSize () + { +#if _WIN32 || _WIN64 + byte[] txt = System.Text.UTF8Encoding.UTF8.GetBytes(_title); +#endif + + Size s; + + using (Context gr = new Context(new ImageSurface(Format.Argb32,1,1))) + { + gr.SetFontSize(fontSize); + TextExtents te; +#if _WIN32 || _WIN64 + te = gr.TextExtents(txt); +#elif __linux__ + te = gr.TextExtents(title); +#endif + FontExtents fe = gr.FontExtents; + s = new Size((int)Math.Ceiling(te.XAdvance),(int)Math.Ceiling(fe.Height)); + } + return s;// +borderWidth; + } + public override Rectangle clientBounds + { + get + { + Size st = titleSize() + borderWidth*2; + Rectangle cb = bounds.Clone; + cb.X = 0; + cb.Y = st.Height; + cb.Height -= st.Height; + cb.Inflate(-borderWidth-margin, -borderWidth-margin); + + //cb.Y += titleHeight; + return cb; + } + } + + internal Rectangle rClose = new Rectangle();//close button + internal override void updateGraphic() + { + + int stride = 4 * renderBounds.Width; + + int bmpSize = Math.Abs(stride) * renderBounds.Height; + bmp = new byte[bmpSize]; + + byte[] txt = System.Text.UTF8Encoding.UTF8.GetBytes(title);// utf = new System.Text.Decoder(); + + using (ImageSurface draw = new ImageSurface(bmp, Format.Argb32, renderBounds.Width, renderBounds.Height, stride)) + { + using (Context gr = new Context(draw)) + { + + + Rectangle r = new Rectangle(0, 0, renderBounds.Width, renderBounds.Height); + //gr.Rotate(Math.PI); + gr.SetFontSize(fontSize); + FontExtents fe = gr.FontExtents; + // double a = Math.PI; + //gr.Transform(new c.Matrix(Math.Cos(a),-Math.Sin(a),Math.Sin(a),Math.Cos(a),renderBounds.Width,renderBounds.Height)); + gr.Antialias = Antialias.Subpixel; + gr.LineWidth = borderWidth; + gr.Color = background; + //gr.MoveTo(renderBounds.X+1,renderBounds.Y+1); + gr.Rectangle(r); + gr.Fill(); + draw.Flush(); + + Rectangle rTitle = r.Clone; + rTitle.Height = titleSize().Height + borderWidth * 2; + gr.Color = Color.blue1; + gr.Rectangle(rTitle); + gr.Fill(); + rTitle.Inflate(-borderWidth / 2, -borderWidth / 2); + gr.Rectangle(rTitle); + gr.Color = borderColor; + gr.Stroke(); + + r.Inflate(-borderWidth / 2, -borderWidth / 2); + gr.Rectangle(r); + gr.Color = borderColor; + gr.Stroke(); + //gr.TextExtents(txt); + + + gr.MoveTo(borderWidth + 1, fe.Height - fe.Descent + borderWidth); +#if _WIN32 || _WIN64 + gr.ShowText(txt); +#elif __linux__ + gr.ShowText(title); +#endif + gr.Fill(); + //gr.Stroke(); + gr.LineWidth = 1; + + rClose = rTitle.Clone; + rClose.Width = rClose.Height; + rClose.Left = rTitle.Right - rClose.Width; + rClose.Inflate(-6, -6); + gr.MoveTo(rClose.X, rClose.Y); + gr.LineTo(rClose.Right, rClose.Bottom); + gr.MoveTo(rClose.X, rClose.Bottom); + gr.LineTo(rClose.Right, rClose.Top); + gr.Stroke(); + rClose.Inflate(3, 3); + gr.Rectangle(rClose); + gr.Stroke(); + } + draw.Flush(); + //draw.WriteToPng(directories.rootDir + @"test.png"); + } + + //registerForRedraw(); + } + public override string ToString() + { + return this.title + ":" + base.ToString(); + } + } +} diff --git a/src/Point.cs b/src/Point.cs new file mode 100644 index 00000000..7f0fd865 --- /dev/null +++ b/src/Point.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace go +{ + public struct Point + { + int _x; + int _y; + + public int X + { + get { return _x; } + set { _x = value; } + } + public int Y + { + get { return _y; } + set { _y = value; } + } + public Point(int x, int y) + { + _x = x; + _y = y; + } + + public static implicit operator Cairo.Point(Point p) + { + return new Cairo.Point(p.X, p.Y); + } + public static implicit operator Cairo.PointD(Point p) + { + return new Cairo.PointD(p.X, p.Y); + } + public static implicit operator System.Drawing.Point(Point p) + { + return new System.Drawing.Point(p.X, p.Y); + } + public static implicit operator Point(System.Drawing.Point p) + { + return new Point(p.X, p.Y); + } + public static implicit operator Point(int i) + { + return new Point(i, i); + } + + public static Point operator +(Point p1, Point p2) + { + return new Point(p1.X + p2.X, p1.Y + p2.Y); + } + public static Point operator -(Point p1, Point p2) + { + return new Point(p1.X - p2.X, p1.Y - p2.Y); + } + public static bool operator >=(Point p1, Point p2) + { + return p1.X >= p2.X && p1.Y >= p2.Y ? true : false; + } + public static bool operator <=(Point p1, Point p2) + { + return p1.X <= p2.X && p1.Y <= p2.Y ? true : false; + } + public static bool operator ==(Point s, int i) + { + if (s.X == i && s.Y == i) + return true; + else + return false; + } + public static bool operator !=(Point s, int i) + { + if (s.X == i && s.Y == i) + return false; + else + return true; + } + public static bool operator >(Point s, int i) + { + if (s.X > i && s.Y > i) + return true; + else + return false; + } + public static bool operator <(Point s, int i) + { + if (s.X < i && s.Y < i) + return true; + else + return false; + } + public static bool operator ==(Point s1, Point s2) + { + if (s1.X == s2.X && s1.Y == s2.Y) + return true; + else + return false; + } + public static bool operator !=(Point s1, Point s2) + { + if (s1.X == s2.X && s1.Y == s2.Y) + return false; + else + return true; + } + + public override string ToString() + { + return string.Format("({0},{1})", X, Y); + } + + public override bool Equals(object obj) + { + return base.Equals(obj); + } + public override int GetHashCode() + { + return base.GetHashCode(); + } + } + +} diff --git a/src/Rectangle.cs b/src/Rectangle.cs new file mode 100644 index 00000000..9a5cbcbe --- /dev/null +++ b/src/Rectangle.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace go +{ + //should try to change it to struct + public class Rectangle + { + int _x = 0; + int _y = 0; + int _width = 0; + int _height = 0; + + public Rectangle() + { } + public Rectangle(Point p, Size s) + { + _x = p.X; + _y = p.Y; + _width = s.Width; + _height = s.Height; + } + public Rectangle(Size s) + { + _x = 0; + _y = 0; + _width = s.Width; + _height = s.Height; + } + public Rectangle(int x, int y, int width, int height) + { + _x = x; + _y = y; + _width = width; + _height = height; + } + + public int X + { + get { return _x; } + set { _x = value; } + } + public int Y + { + get { return _y; } + set { _y = value; } + } + public int Left + { + get { return _x; } + set { _x = value; } + } + public int Top + { + get { return _y; } + set { _y = value; } + } + public int Right + { + get { return _x + _width; } + } + public int Bottom + { + get { return _y + _height; } + } + + public int Width + { + get { return _width; } + set { _width = value; } + } + public int Height + { + get { return _height; } + set { _height = value; } + } + public Size Size + { + get { return new Size(Width, Height); } + set + { + Width = value.Width; + Height = value.Height; + } + } + public Point TopLeft + { + set + { + X = value.X; + Y = value.Y; + } + get { return new Point(X, Y); } + } + public Point TopRight + { + get { return new Point(Right, Y); } + } + public Point BottomLeft + { + get { return new Point(X, Bottom); } + } + public Point BottomRight + { + get { return new Point(Right, Bottom); } + } + public void Inflate(int xDelta, int yDelta) + { + this.X -= xDelta; + this.Width += 2 * xDelta; + this.Y -= yDelta; + this.Height += 2 * yDelta; + } + public bool Contains(Point p) + { + return (p.X >= X && p.X <= X + Width && p.Y >= Y && p.Y <= Y + Height) ? + true : false; + } + public bool Contains(Rectangle r) + { + return r.TopLeft >= this.TopLeft && r.BottomRight <= this.BottomRight ? true : false; + } + public bool Intersect(Rectangle r) + { + int maxLeft = Math.Max(this.Left, r.Left); + int minRight = Math.Min(this.Right, r.Right); + int maxTop = Math.Max(this.Top, r.Top); + int minBottom = Math.Min(this.Bottom, r.Bottom); + + if (maxLeft < minRight && maxTop < minBottom) + return true; + + return false; + + } + public Rectangle Intersection(Rectangle r) + { + Rectangle result = new Rectangle(); + + if (r.Left >= this.Left) + result.Left = r.Left; + else + result.TopLeft = this.TopLeft; + + if (r.Right >= this.Right) + result.Width = this.Right - result.Left; + else + result.Width = r.Right - result.Left; + + if (r.Top >= this.Top) + result.Top = r.Top; + else + result.Top = this.Top; + + if (r.Bottom >= this.Bottom) + result.Height = this.Bottom - result.Top; + else + result.Height = r.Bottom - result.Top; + + return result; + } + public static implicit operator Rectangle(System.Drawing.Rectangle r) + { + return new Rectangle(r.X, r.Y, r.Width, r.Height); + } + public static implicit operator System.Drawing.Rectangle(Rectangle r) + { + return new System.Drawing.Rectangle(r.X, r.Y, r.Width, r.Height); + } + public static implicit operator Cairo.Rectangle(Rectangle r) + { + return new Cairo.Rectangle((double)r.X, (double)r.Y, (double)r.Width, (double)r.Height); + } + public static Rectangle operator +(Rectangle r1, Rectangle r2) + { + int x = Math.Min(r1.X, r2.X); + int y = Math.Min(r1.Y, r2.Y); + int x2 = Math.Max(r1.Right, r2.Right); + int y2 = Math.Max(r1.Bottom, r2.Bottom); + return new Rectangle(x, y, x2 - x, y2 - y); + } + public static bool operator ==(Rectangle r1, Rectangle r2) + { + return r1.TopLeft == r2.TopLeft && r1.Size == r2.Size ? true : false; + } + public static bool operator !=(Rectangle r1, Rectangle r2) + { + return r1.TopLeft == r2.TopLeft && r1.Size == r2.Size ? false : true; + } + + public RectanglesRelations test(Rectangle r) + { + if (r == this) + return RectanglesRelations.Equal; + + int nbrPtIncluded = 0; + + if (this.Contains(r.TopLeft)) + nbrPtIncluded++; + if (this.Contains(r.TopRight)) + nbrPtIncluded++; + if (this.Contains(r.BottomLeft)) + nbrPtIncluded++; + if (this.Contains(r.BottomRight)) + nbrPtIncluded++; + + switch (nbrPtIncluded) + { + case 0: + return RectanglesRelations.NoRelation; + case 4: + return RectanglesRelations.Contains; + default: + return RectanglesRelations.Intersect; + } + } + public Rectangle Clone + { + get + { + return new Rectangle(X, Y, Width, Height); + } + } + public static Rectangle Zero + { + get { return new Rectangle(0, 0, 0, 0); } + } + public static Rectangle Empty + { + get { return Zero; } + } + public override string ToString() + { + return string.Format("({0},{1},{2},{3})", X, Y, Width, Height); + } + } + +} diff --git a/src/Rectangles.cs b/src/Rectangles.cs new file mode 100644 index 00000000..8129fc83 --- /dev/null +++ b/src/Rectangles.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Cairo; +using System.Diagnostics; + +namespace go +{ + public class Rectangles + { + public List<Rectangle> list = new List<Rectangle>(); + public int count + { + get { return list.Count; } + } + + public void AddRectangle(Rectangle r) + { + //if (r.Left == 0) + // Debugger.Break(); + if (addRect(r)) + list.Add(r); + } + public void Reset() + { + list = new List<Rectangle>(); + } + bool addRect(Rectangle r) + { + foreach (Rectangle rInList in list) + if (rInList.Contains(r)) + return false; + return true; + } + + public bool intersect(Rectangle r) + { + foreach (Rectangle rInList in list) + if (rInList.Intersect(r)) + return true; + return false; + } + + public Rectangles intersectingRects(Rectangle r) + { + Rectangles tmp = new Rectangles(); + + foreach (Rectangle rInList in list) + if (rInList.Intersect(r)) + tmp.list.Add(rInList.Clone);//on bypass le test déjà fait a l'ajout intial du rect dans la liste + + return tmp; + } + public Rectangles SmallerContainedRects(Rectangle r) + { + Rectangles tmp = new Rectangles(); + + foreach (Rectangle rInList in list) + if (r.Contains(rInList) && rInList.Size < r.Size) + tmp.list.Add(rInList.Clone); + + return tmp; + } + public Rectangles SmallerRects(Rectangle r) + { + Rectangles tmp = new Rectangles(); + + foreach (Rectangle rInList in list) + if (rInList.Size < r.Size) + tmp.list.Add(rInList.Clone); + + return tmp; + } + public Rectangles containedRects(Rectangle r) + { + Rectangles tmp = new Rectangles(); + + foreach (Rectangle rInList in list) + if (r.Contains(rInList) && rInList.Size <= r.Size) + tmp.list.Add(rInList.Clone); + + return tmp; + } + public void Rebase(GraphicObject w) + { + Rectangle r = w.renderBounds; + List<Rectangle> newList = new List<Rectangle>(); + + foreach (Rectangle rInList in list) + { + Rectangle rebasedR = rInList.Clone; + rebasedR.TopLeft-= r.TopLeft; + + ScrollingWidget sw = w as ScrollingWidget; + if (sw != null) + { + if (sw.VerticalScrolling) + rebasedR.Top -= sw.scrollY; + if (sw.HorizontalScrolling) + rebasedR.Left -= sw.scrollX; + } + newList.Add(rebasedR); + } + list = newList; + } + public void clearAndClip(Context ctx) + { + //ctx.Save(); + + foreach (Rectangle r in list) + { + ctx.Rectangle(r); + } + + ctx.ClipPreserve(); + ctx.Operator = Operator.Clear; + ctx.Fill(); + ctx.Operator = Operator.Over; + //ctx.Restore(); + } + public void clip(Context ctx) + { + foreach (Rectangle r in list) + { + ctx.Rectangle(r); + } + + ctx.Clip(); + } + public void clear(Context ctx) + { + //ctx.Save(); + + foreach (Rectangle r in list) + { + ctx.Rectangle(r); + } + ctx.Operator = Operator.Clear; + ctx.Fill(); + ctx.Operator = Operator.Over; + //ctx.Restore(); + } + //public RectanglesRelations test(Rectangle r) + //{ + // foreach (Rectangle rInList in list) + // { + // switch (rInList.test(r)) + // { + // case RectanglesRelations.NoRelation: + // break; + // case RectanglesRelations.Intersect: + // break; + // case RectanglesRelations.Contains: + // break; + // case RectanglesRelations.Equal: + // break; + // default: + // break; + // } + // } + //} + } +} diff --git a/src/ScrollingWidget.cs b/src/ScrollingWidget.cs new file mode 100644 index 00000000..5a541bcf --- /dev/null +++ b/src/ScrollingWidget.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using Cairo; + +namespace go +{ + public class ScrollingWidget : GraphicObject + { + public ScrollingWidget(int _width = 30, int _height = 30) + : base(new Rectangle(0, 0, _width, _height)) + { + + } + + public ScrollingWidget() + : base() + { + + } + public bool VerticalScrolling = false; + public bool HorizontalScrolling = false; + + public int scrollX = 0; + public int scrollY = 0; + + + public override Rectangle ScreenCoordBounds + { + get + { + return Parent == null ? bounds : + new Rectangle( + Parent.ScreenCoordBounds.X + renderBounds.X + scrollX, + Parent.ScreenCoordBounds.Y + renderBounds.Y + scrollY, + renderBounds.Width, + renderBounds.Height); + } + } + + public override Rectangle renderBoundsInContextCoordonate + { + get + { + //should be in go with cache, scrolling widget have no cache + if (cachingInProgress) + return new Rectangle(renderBounds.Size); + //if (Parent.isCached) + // return renderBounds.Clone; + + Rectangle tmp = Parent.renderBoundsInContextCoordonate; + + return new Rectangle( + tmp.X + renderBounds.X + scrollX, + tmp.Y + renderBounds.Y + scrollY, + renderBounds.Width, + renderBounds.Height); + + } + } + + public override Rectangle ClientBoundsInContextCoordonate + { + get + { + if (cachingInProgress) + return new Rectangle( + clientBounds.X, + clientBounds.Y, + clientBounds.Width, + clientBounds.Height); + + //if (Parent is Panel && !(this is ScrollingWidget)) + // return Parent.clientBounds; + + Rectangle tmp = Parent.renderBoundsInContextCoordonate; + + return new Rectangle( + tmp.X + renderBounds.X + clientBounds.X + scrollX, + tmp.Y + renderBounds.Y + clientBounds.Y + scrollY, + clientBounds.Width, + clientBounds.Height); + } + } + public override Rectangle renderBoundsInBackendSurfaceCoordonate + { + get + { + Rectangle tmp = Parent.renderBoundsInBackendSurfaceCoordonate; + + return new Rectangle( + tmp.X + renderBounds.X + scrollX, + tmp.Y + renderBounds.Y + scrollY, + renderBounds.Width, + renderBounds.Height); + } + } + + public override bool ProcessMousePosition(Point mousePos) + { + return base.ProcessMousePosition(mousePos); + } + public override void ProcessMouseWeel(int delta) + { + if (!isVisible) + return; + + + if (VerticalScrolling && renderBounds.Height > Parent.clientBounds.Height) + { + //add redraw call with old bounds to errase old position + registerForRedraw(); + + scrollY += delta; + + if (scrollY > 0) + scrollY = 0; + else if (scrollY < -renderBounds.Height + Parent.clientBounds.Height) + scrollY = -renderBounds.Height + Parent.clientBounds.Height; + + } + if (HorizontalScrolling && renderBounds.Width > Parent.clientBounds.Width) + { + //add redraw call with old bounds to errase old position + registerForRedraw(); + + scrollX += delta; + } + + + //renderBounds.Y = -scrollY; + registerForRedraw(); + } + + } +} diff --git a/src/Size.cs b/src/Size.cs new file mode 100644 index 00000000..5dadfc33 --- /dev/null +++ b/src/Size.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace go +{ + public struct Size + { + public static Size Zero + { get { return new Size(0, 0); } } + int _width; + int _height; + + //public Size() + //{ } + public Size(int width, int height) + { + _width = width; + _height = height; + } + public int Width + { + get { return _width; } + set { _width = value; } + } + public int Height + { + get { return _height; } + set { _height = value; } + } + public override string ToString() + { + return string.Format("({0},{1})", Width, Height); + } + public static implicit operator Size(int i) + { + return new Size(i, i); + } + public static bool operator ==(Size s1, Size s2) + { + if (s1.Width == s2.Width && s1.Height == s2.Height) + return true; + else + return false; + } + public static bool operator !=(Size s1, Size s2) + { + if (s1.Width == s2.Width && s1.Height == s2.Height) + return false; + else + return true; + } + public static bool operator >(Size s1, Size s2) + { + if (s1.Width > s2.Width && s1.Height > s2.Height) + return true; + else + return false; + } + public static bool operator >=(Size s1, Size s2) + { + if (s1.Width >= s2.Width && s1.Height >= s2.Height) + return true; + else + return false; + } + public static bool operator <(Size s1, Size s2) + { + if (s1.Width < s2.Width) + if (s1.Height <= s2.Height) + return true; + else + return false; + else if (s1.Width == s2.Width && s1.Height < s2.Height) + return true; + + return false; + } + public static bool operator <=(Size s1, Size s2) + { + if (s1.Width <= s2.Width && s1.Height <= s2.Height) + return true; + else + return false; + } + public static bool operator ==(Size s, int i) + { + if (s.Width == i && s.Height == i) + return true; + else + return false; + } + public static bool operator !=(Size s, int i) + { + if (s.Width == i && s.Height == i) + return false; + else + return true; + } + public static Size operator +(Size s, int i) + { + return new Size(s.Width + i, s.Height + i); + } + } + +} diff --git a/src/Slider.cs b/src/Slider.cs new file mode 100644 index 00000000..5c4d9f0d --- /dev/null +++ b/src/Slider.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Cairo; + +namespace go +{ + public class Slider : GraphicObject + { + double _actualValue, _minValue, _maxValue, _smallStep, _bigStep, unity; + Rectangle cursor; + bool holdCursor = false; + + public double value + { + get { return _actualValue; } + set + { + if (value < _minValue) + _actualValue = _minValue; + else if (value > _maxValue) + _actualValue = _maxValue; + else + _actualValue = value; + + registerForGraphicUpdate(); + } + } + public Slider(double minimum, double maximum, double step) + : base() + { + _minValue = minimum; + _maxValue = maximum; + _smallStep = step; + _bigStep = step * 5; + horizontalAlignment = HorizontalAlignment.None; + verticalAlignment = VerticalAlignment.None; + focusable = true; + } + + void computeCursorPosition() + { + cursor = new Rectangle(new Size(4, 10)); + Rectangle r = clientBounds; + PointD p1 = r.TopLeft + new Point(0, r.Height / 2); + + unity = (double)r.Width / (_maxValue - _minValue); + + cursor.TopLeft = new Point((int)(_actualValue * unity - cursor.Width / 2), + (int)(p1.Y - cursor.Height / 2)); + + } + public override void ProcessMouseDown(Point mousePos) + { + Interface.activeWidget = this; + + base.ProcessMouseDown(mousePos); + + + Rectangle cursInScreenCoord = rectInScreenCoord(cursor); + if (cursInScreenCoord.Contains(mousePos)) + { + holdCursor = true; + } + else if (mousePos.X < cursInScreenCoord.Left) + { + value -= _bigStep; + } + else + { + value += _bigStep; + } + + } + public override void ProcessMouseUp(Point mousePos) + { + holdCursor = false; + base.ProcessMouseUp(mousePos); + } + public override bool ProcessMousePosition(Point mousePos) + { + return base.ProcessMousePosition(mousePos); + } + internal override void updateGraphic() + { + int stride = 4 * renderBounds.Width; + + + //init bmp with widget background and border + base.updateGraphic(); + computeCursorPosition(); + + using (ImageSurface bitmap = + new ImageSurface(bmp, Format.Argb32, renderBounds.Width, renderBounds.Height, stride)) + { + using (Context gr = new Context(bitmap)) + { + gr.FontOptions.Antialias = Antialias.Subpixel; + + gr.Color = foreground; + + Rectangle r = clientBounds.Clone; + PointD p1 = r.TopLeft + new Point(0, r.Height / 2); + PointD p2 = r.TopRight + new Point(0, r.Height / 2); + + gr.LineWidth = 1; + gr.MoveTo(p1); + gr.LineTo(p2); + + gr.Stroke(); + gr.LineWidth = 0.5; + + double sst = unity * _smallStep; + double bst = unity * _bigStep; + + + PointD vBar = new PointD(0, sst); + for (double x = _minValue; x <= _maxValue - _minValue; x += _smallStep) + { + double lineLength = 2.5; + if (x % _bigStep == 0) + lineLength *= 2; + PointD p = new PointD(p1.X + x * unity, p1.Y); + gr.MoveTo(p); + gr.LineTo(new PointD(p.X, p.Y + lineLength)); + } + + gr.Stroke(); + + + gr.Rectangle(cursor); + gr.Fill(); + + + } + + bitmap.Flush(); + //bitmap.WriteToPng(@"d:\test.png"); + } + } + } +} diff --git a/src/Spinner.cs b/src/Spinner.cs new file mode 100644 index 00000000..e829c57c --- /dev/null +++ b/src/Spinner.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using System.Diagnostics; + +namespace go +{ + public class Spinner : HorizontalStack + { + Label Label; + Button up; + Button down; + + float _actualValue, _minValue, _maxValue, _increment; + WidgetEvent _onValueChange; + + + public float Value + { + get { return _actualValue; } + set + { + _actualValue = value; + Label.text = _actualValue.ToString(); + } + } + + public void Init(float _initialValue, float _min, float _max, float _step, WidgetEvent onValueChange, string _label = "") + { + sizeToContent = true; + + if (!string.IsNullOrEmpty(_label)) + { + Label = addChild(new Label(_label)); + Label.verticalAlignment = go.VerticalAlignment.None; + Label.horizontalAlignment = go.HorizontalAlignment.None; + + Label.width = 100; + Label.textAlignment = Alignment.LeftCenter; + } + + Label = addChild(new TextBoxWidget(_initialValue.ToString())); + Label.borderColor = Color.LightGray; + Label.background = Color.DimWhite; + Label.fontColor = Color.Black; + Label.borderWidth = 1; + Label.width = 50; + Label.verticalAlignment = go.VerticalAlignment.None; + Label.horizontalAlignment = go.HorizontalAlignment.None; + Label.textAlignment = Alignment.RightCenter; + + + + VerticalStack arrows = new VerticalStack(); + arrows.widgetSpacing = 0; + arrows.horizontalAlignment = go.HorizontalAlignment.Center; + arrows.verticalAlignment = go.VerticalAlignment.Stretch; + arrows.width = 15; + arrows.borderWidth = 0; + arrows.sizeToContent = true; + + up = arrows.addChild(new Button(directories.rootDir + @"Images/Icons/spin_up.png", spinUp, false, 15, 10)); + up.borderWidth = 0; + up.margin = 0; + + //up.alignment = Alignment.HorizontalStretch; + + + down = arrows.addChild(new Button(directories.rootDir + @"Images/Icons/spin_down.png", spinDown, false, 15, 10)); + down.borderWidth = 0; + down.margin = 0; + //down.alignment = Alignment.HorizontalStretch; + + addChild(arrows); + + _actualValue = _initialValue; + _minValue = _min; + _maxValue = _max; + _increment = Math.Abs(_step); + _onValueChange = onValueChange; + } + + public Spinner(float _initialValue, float _min, float _max, float _step, WidgetEvent onValueChange) + : base() + { + Init(_initialValue, _min, _max, _step, onValueChange); + } + public Spinner(string _label, float _initialValue, float _min, float _max, float _step, WidgetEvent onValueChange) + : base() + { + Init(_initialValue, _min, _max, _step, onValueChange,_label); + } + public void spinUp(Button sender) + { + _actualValue += _increment; + if (_actualValue > _maxValue) + _actualValue = _maxValue; + + Label.text = _actualValue.ToString(); + + _onValueChange(this); + } + public void spinDown(Button sender) + { + _actualValue -= _increment; + if (_actualValue < _minValue) + _actualValue = _minValue; + + Label.text = _actualValue.ToString(); + + _onValueChange(this); + } + + public override void updateLayout() + { + base.updateLayout(); + up.height = Label.renderBounds.Height / 2; + down.height = Label.renderBounds.Height / 2; + down.y = Label.renderBounds.Top + Label.renderBounds.Height / 2; + } + + public override bool ProcessMousePosition(Point mousePos) + { + //if (base.ProcessMousePosition(mousePos)) + // Debugger.Break(); + + return base.ProcessMousePosition(mousePos); + } + public override void cairoDraw(ref Cairo.Context ctx, Rectangles clip = null) + { + base.cairoDraw(ref ctx, clip); + } + } + +} diff --git a/src/TextBox.cs b/src/TextBox.cs new file mode 100644 index 00000000..d2742b16 --- /dev/null +++ b/src/TextBox.cs @@ -0,0 +1,528 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenTK.Input; +using Cairo; +using System.Diagnostics; + +namespace go +{ + public class TextBoxWidget : Label + { + public TextBoxWidget(string _initialValue, WidgetEvent _onTextChanged = null) + : base(_initialValue) + { + onTextChanged = _onTextChanged; + focusable = true; + selColor = Color.SkyBlue; + selFontColor = Color.Black; + fontColor = Color.Black; + background = Color.White; + textAlignment = Alignment.LeftCenter; + } + + //trigger update when lost focus to errase text beam + public override bool hasFocus + { + get + { + return base.hasFocus; + } + set + { + base.hasFocus = value; + registerForGraphicUpdate(); + } + } + public WidgetEvent onTextChanged; + + Color selColor; + Color selFontColor; + + //mouse coord in widget space, filled only when clicked + Point mouseLocalPos; + + //0 based cursor position in string + private int _currentPos; + public int currentPos + { + get { return _currentPos; } + set { _currentPos = value; } + } + public int selStartPos; + public int selEndPos; + //ordered selection start and end positions + public int selectionStart + { + get { return selEndPos < 0 ? selStartPos : Math.Min(selStartPos, selEndPos); } + } + public int selectionEnd + { get { return selEndPos < 0 ? selEndPos : Math.Max(selStartPos, selEndPos); } } + + + //cursor position in cairo units in widget client coord. + double textCursorPos; + double SelStartCursorPos = -1; + double SelEndCursorPos = -1; + + bool SelectionInProgress = false; + + public string selectedText + { get { return selectionEnd < 0 ? null : text.Substring(selectionStart, selectionEnd - selectionStart); } } + public bool selectionIsEmpty + { get { return string.IsNullOrEmpty(selectedText); } } + + #region Keyboard handling + public override void ProcessKeyboard(Key key) + { + switch (key) + { + case Key.Back: + if (!selectionIsEmpty) + { + text = text.Remove(selectionStart, selectionEnd - selectionStart); + selEndPos = -1; + currentPos = selStartPos; + } + else if (currentPos > 0) + { + currentPos--; + text = text.Remove(currentPos, 1); + } + break; + case Key.Clear: + break; + case Key.Delete: + if (!selectionIsEmpty) + { + text = text.Remove(selectionStart, selectionEnd - selectionStart); + selEndPos = -1; + currentPos = selStartPos; + } + else if (currentPos < text.Length) + text = text.Remove(currentPos, 1); + break; + case Key.Down: + break; + case Key.End: + currentPos = text.Length; + break; + case Key.Enter: + case Key.KeypadEnter: + if (onTextChanged != null) + onTextChanged(this); + break; + case Key.Escape: + text = ""; + currentPos = 0; + selEndPos = -1; + break; + case Key.Home: + currentPos = 0; + break; + case Key.Insert: + break; + case Key.Left: + if (currentPos > 0) + currentPos--; + break; + case Key.Menu: + break; + case Key.NumLock: + break; + case Key.PageDown: + break; + case Key.PageUp: + break; + case Key.RWin: + break; + case Key.Right: + if (currentPos < text.Length) + currentPos++; + break; + case Key.Tab: + text = text.Insert(currentPos, "\t"); + currentPos++; + break; + case Key.Up: + break; + case Key.KeypadDecimal: + text = text.Insert(currentPos, new string(new char[] { Interface.decimalSeparator })); + currentPos++; + break; + case Key.Space: + text = text.Insert(currentPos, " "); + currentPos++; + break; + case Key.KeypadDivide: + case Key.Slash: + text = text.Insert(currentPos, "/"); + currentPos++; + break; + case Key.KeypadMultiply: + text = text.Insert(currentPos, "*"); + currentPos++; + break; + case Key.KeypadMinus: + case Key.Minus: + text = text.Insert(currentPos, "-"); + currentPos++; + break; + case Key.KeypadPlus: + case Key.Plus: + text = text.Insert(currentPos, "+"); + currentPos++; + break; + default: + if (!selectionIsEmpty) + { + text = text.Remove(selectionStart, selectionEnd - selectionStart); + currentPos = selStartPos; + } + + string k = "?"; + if ((char)key >= 67 && (char)key <= 76) + k = ((int)key - 67).ToString(); + else if ((char)key >= 109 && (char)key <= 118) + k = ((int)key - 109).ToString(); + else if (Interface.capitalOn) + k = key.ToString(); + else + k = key.ToString().ToLower(); + + text = text.Insert(currentPos, k); + currentPos++; + + selEndPos = -1; + selStartPos = currentPos; + + break; + } + registerForGraphicUpdate(); + + } + #endregion + + #region Mouse handling + public override bool ProcessMousePosition(Point mousePos) + { + Rectangle scb = ScreenCoordBounds; + + if (scb.Contains(mousePos)) + { + Interface.hoverWidget = this; + + //Interface.SetCursor(System.Windows.Forms.Cursors.IBeam.Handle); + + if (Interface.Mouse[MouseButton.Left]) + { + SelectionInProgress = true; + Debug.WriteLine("selection in progress"); + mouseLocalPos = mousePos - ScreenCoordBounds.TopLeft - rText.TopLeft; + registerForGraphicUpdate(); + } + + return true; + } + else + { + Interface.hoverWidget = null; + return false; + } + } + public override void ProcessMouseDown(Point mousePos) + { + Interface.activeWidget = this; + + if (!this.hasFocus) + { + selStartPos = 0; + selEndPos = text.Length; + } + else + { + mouseLocalPos = mousePos - ScreenCoordBounds.TopLeft - rText.TopLeft; + selStartPos = -1; + selEndPos = -1; + } + base.ProcessMouseDown(mousePos); + + registerForGraphicUpdate(); + } + public override void ProcessMouseUp(Point mousePos) + { + SelectionInProgress = false; + } + #endregion + + void computeTextCursor(Context gr) + { + FontExtents fe = gr.FontExtents; + TextExtents te; + + double cPos = 0f; + for (int i = 0; i < _text.Length; i++) + { +#if _WIN32 || _WIN64 + byte[] c = System.Text.UTF8Encoding.UTF8.GetBytes(text.Substring(i, 1)); + te = gr.TextExtents(c); +#elif __linux__ + te = gr.TextExtents(text.Substring(i, 1)); +#endif + double halfWidth = te.XAdvance / 2; + + if (mouseLocalPos.X <= cPos + halfWidth) + { + currentPos = i; + textCursorPos = cPos; + mouseLocalPos = -1; + return; + } + + cPos += te.XAdvance; + } + currentPos = _text.Length; + textCursorPos = cPos; + + //reset mouseLocalPos + mouseLocalPos = -1; + } + void computeTextCursorPosition(Context gr) + { + FontExtents fe = gr.FontExtents; + TextExtents te; + + double cPos = 0f; + + int limit = currentPos; + + if (selectionEnd > 0) + limit = Math.Max(currentPos, selectionEnd); + + for (int i = 0; i <= limit; i++) + { + if (i == currentPos) + textCursorPos = cPos; + if (i == selectionStart) + SelStartCursorPos = cPos; + if (i == selectionEnd) + SelEndCursorPos = cPos; + + if (i < text.Length) + { +#if _WIN32 || _WIN64 + byte[] c = System.Text.UTF8Encoding.UTF8.GetBytes(text.Substring(i, 1)); + te = gr.TextExtents(c); +#elif __linux__ + te = gr.TextExtents(text.Substring(i,1)); +#endif + cPos += te.XAdvance; + } + } + + } + + internal override void updateGraphic() + { + byte[] txt = utf8Text; + int stride = 4 * renderBounds.Width; + + + //init bmp with widget background and border + base.updateGraphic(); + + using (ImageSurface bitmap = + new ImageSurface(bmp, Format.Argb32, renderBounds.Width, renderBounds.Height, stride)) + { + using (Context gr = new Context(bitmap)) + { + gr.FontOptions.Antialias = Antialias.Subpixel; + gr.FontOptions.HintMetrics = HintMetrics.On; + gr.SetFontSize(fontSize); + FontExtents fe = gr.FontExtents; + rText = new Rectangle(new Point(0, 0), measureRawSize()); + //gr.Rotate(Math.PI); + + // double a = Math.PI; + //gr.Transform(new c.Matrix(Math.Cos(a),-Math.Sin(a),Math.Sin(a),Math.Cos(a),renderBounds.Width,renderBounds.Height)); + gr.Antialias = Antialias.Subpixel; + gr.LineWidth = borderWidth; + + float widthRatio = 1f; + float heightRatio = 1f; + + Rectangle cb = clientBounds; + Interface.StrokeLoweredRectangle(gr, cb, 1); + //ignore text alignment if size to content = true + if (!sizeToContent) + { + switch (textAlignment) + { + case Alignment.None: + break; + case Alignment.TopLeft: //ok + rText.X = cb.X; + rText.Y = cb.Y; + break; + case Alignment.TopCenter: //ok + rText.Y = cb.Y; + rText.X = cb.X + cb.Width / 2 - rText.Width / 2; + break; + case Alignment.TopRight: //ok + rText.X = cb.Right - rText.Width; + rText.Y = cb.Y; + break; + case Alignment.TopStretch://ok + heightRatio = widthRatio = (float)cb.Width / rText.Width; + rText.X = cb.X; + rText.Y = cb.Y; + rText.Width = cb.Width; + rText.Height = (int)(rText.Height * heightRatio); + break; + case Alignment.LeftCenter://ok + rText.X = cb.X; + rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2; + break; + case Alignment.LeftStretch://ok + heightRatio = widthRatio = (float)cb.Height / rText.Height; + rText.X = cb.X; + rText.Y = cb.Y; + rText.Height = cb.Height; + rText.Width = (int)(widthRatio * cb.Width); + break; + case Alignment.RightCenter://ok + rText.X = cb.X + cb.Width - rText.Width; + rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2; + break; + case Alignment.RightStretch://ok + heightRatio = widthRatio = (float)cb.Height / rText.Height; + rText.Height = cb.Height; + rText.Width = (int)(widthRatio * cb.Width); + rText.X = cb.X; + rText.Y = cb.Y; + break; + case Alignment.BottomCenter://ok + rText.X = cb.Width / 2 - rText.Width / 2; + rText.Y = cb.Height - rText.Height; + break; + case Alignment.BottomStretch://ok + heightRatio = widthRatio = (float)cb.Width / rText.Width; + rText.Width = cb.Width; + rText.Height = (int)(rText.Height * heightRatio); + rText.Y = cb.Bottom - rText.Height; + rText.X = cb.X; + break; + case Alignment.BottomLeft://ok + rText.X = cb.X; + rText.Y = cb.Bottom - rText.Height; + break; + case Alignment.BottomRight://ok + rText.Y = cb.Bottom - rText.Height; + rText.X = cb.Right - rText.Width; + break; + case Alignment.Center://ok + rText.X = cb.X + cb.Width / 2 - rText.Width / 2; + rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2; + break; + case Alignment.Fit://ok, peut être mieu aligné + widthRatio = (float)cb.Width / rText.Width; + heightRatio = (float)cb.Height / rText.Height; + rText = cb.Clone; + break; + case Alignment.HorizontalStretch://ok + heightRatio = widthRatio = (float)cb.Width / rText.Width; + rText.Width = cb.Width; + rText.Height = (int)(heightRatio * rText.Height); + rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2; + rText.X = cb.X; + break; + case Alignment.VerticalStretch://ok + heightRatio = widthRatio = (float)cb.Height / rText.Height; + rText.Height = cb.Height; + rText.Width = (int)(widthRatio * rText.Width); + rText.X = cb.X + cb.Width / 2 - rText.Width / 2; + rText.Y = cb.Y; + break; + default: + break; + } + } + + + + gr.FontMatrix = new Matrix(widthRatio * fontSize, 0, 0, heightRatio * fontSize, 0, 0); + + fe = gr.FontExtents; + + #region draw text cursor + if (mouseLocalPos > 0) + { + computeTextCursor(gr); + + if (SelectionInProgress) + { + selEndPos = currentPos; + SelEndCursorPos = textCursorPos; + } + else if (selStartPos < 0) + { + selStartPos = currentPos; + SelStartCursorPos = textCursorPos; + selEndPos = -1; + } + else + computeTextCursorPosition(gr); + + } + else + computeTextCursorPosition(gr); + if (hasFocus) + { + gr.LineWidth = 1; + gr.MoveTo(new PointD(textCursorPos + rText.TopLeft.X, rText.Y + rText.TopLeft.Y)); + gr.LineTo(new PointD(textCursorPos + rText.TopLeft.X, rText.Y + fe.Height + rText.TopLeft.Y)); + gr.Stroke(); + } + + #endregion + + if (selEndPos >= 0) + { + gr.Color = selColor; + Rectangle selRect = + new Rectangle((int)SelStartCursorPos + rText.TopLeft.X, (int)(rText.Y) + rText.TopLeft.Y, (int)(SelEndCursorPos - SelStartCursorPos), (int)fe.Height); + gr.Rectangle(selRect); + gr.Fill(); + + gr.Color = selFontColor; + } + else + gr.Color = fontColor; + + gr.MoveTo(rText.X, rText.Y + fe.Ascent); +#if _WIN32 || _WIN64 + gr.ShowText(txt); +#elif __linux__ + gr.ShowText(text); +#endif + gr.Fill(); + + + + + //gr.LineWidth = 1; + //gr.MoveTo(new PointD(rText.TopLeft.X, rText.Y)); + //gr.LineTo(new PointD(rText.TopLeft.X, rText.Y + fe.Ascent)); + //gr.Stroke(); + + } + bitmap.Flush(); + //bitmap.WriteToPng(directories.rootDir + @"test.png"); + } + + //registerForRedraw(); + } + + } +} diff --git a/src/VerticalStack.cs b/src/VerticalStack.cs new file mode 100644 index 00000000..e730200b --- /dev/null +++ b/src/VerticalStack.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace go +{ + public class VerticalStack : GenericStack + { + public VerticalStack() + : base() + { + Orientation = go.Orientation.Vertical; + } + } +} diff --git a/src/VerticalWrappingWidget.cs b/src/VerticalWrappingWidget.cs new file mode 100644 index 00000000..dbebcad0 --- /dev/null +++ b/src/VerticalWrappingWidget.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Cairo; + +namespace go +{ + public class VerticalWrappingWidget : WrappedWidgetGroup + { + public VerticalWrappingWidget(int _borderWidth = 0) : + base() + { + Orientation = Orientation.Vertical; + borderWidth = _borderWidth; + sizeToContent = true; + background = Color.Transparent; + } + public VerticalWrappingWidget(Color _borderColor, int _borderWidth = 1) : + base() + { + Orientation = Orientation.Vertical; + borderWidth = _borderWidth; + borderColor = _borderColor; + background = Color.Transparent; + sizeToContent = true; + } + public VerticalWrappingWidget(Color _borderColor, Color _background, int _borderWidth = 1) : + base() + { + Orientation = Orientation.Vertical; + borderWidth = _borderWidth; + borderColor = _borderColor; + background = _background; + sizeToContent = true; + } + + } +} diff --git a/src/Win32.cs b/src/Win32.cs new file mode 100644 index 00000000..292ea778 --- /dev/null +++ b/src/Win32.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace go +{ + public static class Win32 + { + [DllImport("user32.dll")] + public static extern IntPtr GetDC(IntPtr hWnd); + #region mouse winApi + + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public struct Point + { + + /// LONG->int + public int x; + + /// LONG->int + public int y; + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public struct HICON__ + { + + /// int + public int unused; + } + +#if _WIN32 || _WIN64 + /// Return Type: HCURSOR->HICON->HICON__* + ///hCursor: HCURSOR->HICON->HICON__* + [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SetCursor")] + public static extern System.IntPtr SetCursor([System.Runtime.InteropServices.InAttribute()] System.IntPtr hCursor); +#elif __linux__ + public static System.IntPtr SetCursor(System.IntPtr hCursor) + { + return (IntPtr)0; + } +#endif + + /// Return Type: BOOL->int + ///lpPoint: LPPOINT->tagPOINT* + [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "GetCursorPos")] + [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] + public static extern bool GetCursorPos([System.Runtime.InteropServices.OutAttribute()] out Point lpPoint); + + /// Return Type: BOOL->int + ///X: int + ///Y: int + [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SetCursorPos")] + [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] + public static extern bool SetCursorPos(int X, int Y); + + #endregion + } +} diff --git a/src/WrappedWidgetGroup.cs b/src/WrappedWidgetGroup.cs new file mode 100644 index 00000000..fd886cb9 --- /dev/null +++ b/src/WrappedWidgetGroup.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using OpenTK.Graphics.OpenGL; +using System.Diagnostics; + +namespace go +{ + public class WrappedWidgetGroup : Group + { + + public int widgetSpacing = 2; + + public Orientation Orientation = Orientation.Horizontal; + + + public WrappedWidgetGroup() + : base() + { + borderWidth = 0; + } + + int currentXForWidget = 0; + int currentYForWidget = 0; + + int highestWidget = 0; + int largestWidget = 0; + + + public override void updateLayout() + { + //while (!layoutIsValid) + //{ + //if (!(sizeIsValid && positionIsValid)) + base.updateLayout(); + + //if (!base.layoutIsValid) + // return; + + currentXForWidget = clientBounds.X; + currentYForWidget = clientBounds.Y; + + highestWidget = 0; + largestWidget = 0; + + Rectangle contentBounds = Rectangle.Zero; + + GraphicObject[] widgets = new GraphicObject[Children.Count]; + Children.CopyTo(widgets); + foreach (GraphicObject w in widgets) + { + if (w.renderBounds.Width > largestWidget) + largestWidget = w.renderBounds.Width; + if (w.renderBounds.Height > highestWidget) + highestWidget = w.renderBounds.Height; + + if (!enoughtSpaceForWidget(w)) + advance(w); + + if (enoughtSpaceForWidget(w)) + { + w.renderBounds.X = currentXForWidget; + w.renderBounds.Y = currentYForWidget; + + w.positionIsValid = true; + + contentBounds += w.renderBounds; + + advance(w); + } + else + break; + } + + contentBounds.Width += borderWidth + margin; + contentBounds.Height += borderWidth + margin; + + if (sizeToContent) + renderBounds.Size = contentBounds.Size; + else if (VerticalScrolling) + renderBounds.Size = new Size(renderBounds.Size.Width, contentBounds.Size.Height); + else if (HorizontalScrolling) + renderBounds.Size = new Size(contentBounds.Size.Width, renderBounds.Size.Height); + + if (layoutIsValid) + registerForRedraw(); + } + + + bool enoughtSpaceForWidget(GraphicObject w) + { + int nextXForWidget = 0; + int nextYForWidget = 0; + + if (Orientation == Orientation.Horizontal) + nextXForWidget = currentXForWidget + w.renderBounds.Width; + else + nextYForWidget = nextYForWidget + w.renderBounds.Height; + + if (!sizeToContent) + { + if (nextXForWidget > clientBounds.Right && !HorizontalScrolling) + return false; + if (currentYForWidget > clientBounds.Bottom && !VerticalScrolling) + return false; + } + return true; + } + void advance(GraphicObject w) + { + if (Orientation == Orientation.Horizontal) + { + //if (w is LabelWidget) + // Debugger.Break(); + currentXForWidget = currentXForWidget + widgetSpacing + w.renderBounds.Width; + } + else + currentYForWidget = currentYForWidget + widgetSpacing + w.renderBounds.Height; + + if (!sizeToContent) + { + if (currentXForWidget > clientBounds.Right && !HorizontalScrolling) + { + if (Orientation == Orientation.Vertical) + { + //not scrolling + } + else + { + currentXForWidget = clientBounds.X; + currentYForWidget += widgetSpacing + highestWidget; + highestWidget = 0; + } + } + if (currentYForWidget > clientBounds.Bottom && !VerticalScrolling) + { + if (Orientation == Orientation.Horizontal) + { + //not scrolling + } + else + { + currentXForWidget += widgetSpacing + largestWidget; + currentYForWidget = clientBounds.Y; + largestWidget = 0; + } + + } + } + } + } +} diff --git a/src/directories.cs b/src/directories.cs new file mode 100644 index 00000000..5e9428a9 --- /dev/null +++ b/src/directories.cs @@ -0,0 +1,15 @@ +using System; + +namespace go +{ + public static class directories + { +#if _WIN32 || _WIN64 + public const string rootDir = @"d:/"; +#elif __linux__ + public const string rootDir = @"/mnt/data/"; +#endif + + } +} + diff --git a/src/enums.cs b/src/enums.cs new file mode 100644 index 00000000..976ac24d --- /dev/null +++ b/src/enums.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace go +{ + public enum Orientation + { + Horizontal, + Vertical + } + public enum Alignment + { + None, + TopCenter, + TopStretch, + LeftCenter, + LeftStretch, + RightCenter, + RightStretch, + BottomCenter, + BottomStretch, + TopLeft, + TopRight, + BottomLeft, + BottomRight, + Center, + Fit, + HorizontalStretch, + VerticalStretch + } + + public enum PanelBorderPosition + { + Top, + Left, + Right, + Bottom, + TopLeft, + TopRight, + BottomLeft, + BottomRight, + Moving, + Closing, + ClientArea + } + public enum HorizontalAlignment + { + Stretch, + Left, + Right, + Center, + None + } + public enum VerticalAlignment + { + Stretch, + Top, + Bottom, + Center, + None + } + + public enum RectanglesRelations + { + NoRelation, //nothing to do + Intersect, //clipped clear & repaint, no test + Contains, //clipped clear & repaint, test children + Equal //repaint, no test + } +} |