]> O.S.I.I.S - jp/crow.git/commitdiff
first commit
authorjpbruyere <jp_bruyere@hotmail.com>
Sat, 16 Nov 2013 08:16:43 +0000 (09:16 +0100)
committerjpbruyere <jp_bruyere@hotmail.com>
Sat, 16 Nov 2013 08:16:43 +0000 (09:16 +0100)
45 files changed:
.gitignore [new file with mode: 0644]
GOLib.csproj [new file with mode: 0644]
lib/OpenTK.Compatibility.dll [new file with mode: 0644]
lib/OpenTK.GLControl.dll [new file with mode: 0644]
lib/OpenTK.dll [new file with mode: 0644]
lib/freetype6.dll [new file with mode: 0644]
lib/intl.dll [new file with mode: 0644]
lib/libcairo-2.dll [new file with mode: 0644]
lib/libcairo-gobject-2.dll [new file with mode: 0644]
lib/libcairo-script-interpreter-2.dll [new file with mode: 0644]
lib/libexpat-1.dll [new file with mode: 0644]
lib/libfontconfig-1.dll [new file with mode: 0644]
lib/libpng14-14.dll [new file with mode: 0644]
lib/zlib1.dll [new file with mode: 0644]
src/AssemblyInfo.cs [new file with mode: 0644]
src/Button.cs [new file with mode: 0644]
src/Colors.cs [new file with mode: 0644]
src/Container.cs [new file with mode: 0644]
src/GenericStack.cs [new file with mode: 0644]
src/GraphicObject.cs [new file with mode: 0644]
src/Group.cs [new file with mode: 0644]
src/GroupBox.cs [new file with mode: 0644]
src/HorizontalStack.cs [new file with mode: 0644]
src/HorizontalWrappingWidget.cs [new file with mode: 0644]
src/Image.cs [new file with mode: 0644]
src/Interface.cs [new file with mode: 0644]
src/Label.cs [new file with mode: 0644]
src/Mouse.cs [new file with mode: 0644]
src/Mouse3d.cs [new file with mode: 0644]
src/Panel.cs [new file with mode: 0644]
src/PanelWithTitle.cs [new file with mode: 0644]
src/Point.cs [new file with mode: 0644]
src/Rectangle.cs [new file with mode: 0644]
src/Rectangles.cs [new file with mode: 0644]
src/ScrollingWidget.cs [new file with mode: 0644]
src/Size.cs [new file with mode: 0644]
src/Slider.cs [new file with mode: 0644]
src/Spinner.cs [new file with mode: 0644]
src/TextBox.cs [new file with mode: 0644]
src/VerticalStack.cs [new file with mode: 0644]
src/VerticalWrappingWidget.cs [new file with mode: 0644]
src/Win32.cs [new file with mode: 0644]
src/WrappedWidgetGroup.cs [new file with mode: 0644]
src/directories.cs [new file with mode: 0644]
src/enums.cs [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..3b3b05f
--- /dev/null
@@ -0,0 +1,7 @@
+Win_x86
+
+Debug
+
+/*.sln
+
+/GOLib.suo
diff --git a/GOLib.csproj b/GOLib.csproj
new file mode 100644 (file)
index 0000000..e32dd8f
--- /dev/null
@@ -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
new file mode 100644 (file)
index 0000000..d6d8149
Binary files /dev/null and b/lib/OpenTK.Compatibility.dll differ
diff --git a/lib/OpenTK.GLControl.dll b/lib/OpenTK.GLControl.dll
new file mode 100644 (file)
index 0000000..e31628d
Binary files /dev/null and b/lib/OpenTK.GLControl.dll differ
diff --git a/lib/OpenTK.dll b/lib/OpenTK.dll
new file mode 100644 (file)
index 0000000..afff0dd
Binary files /dev/null and b/lib/OpenTK.dll differ
diff --git a/lib/freetype6.dll b/lib/freetype6.dll
new file mode 100644 (file)
index 0000000..ead809b
Binary files /dev/null and b/lib/freetype6.dll differ
diff --git a/lib/intl.dll b/lib/intl.dll
new file mode 100644 (file)
index 0000000..d261208
Binary files /dev/null and b/lib/intl.dll differ
diff --git a/lib/libcairo-2.dll b/lib/libcairo-2.dll
new file mode 100644 (file)
index 0000000..34f84af
Binary files /dev/null and b/lib/libcairo-2.dll differ
diff --git a/lib/libcairo-gobject-2.dll b/lib/libcairo-gobject-2.dll
new file mode 100644 (file)
index 0000000..f4bbf6f
Binary files /dev/null and b/lib/libcairo-gobject-2.dll differ
diff --git a/lib/libcairo-script-interpreter-2.dll b/lib/libcairo-script-interpreter-2.dll
new file mode 100644 (file)
index 0000000..74acaf6
Binary files /dev/null and b/lib/libcairo-script-interpreter-2.dll differ
diff --git a/lib/libexpat-1.dll b/lib/libexpat-1.dll
new file mode 100644 (file)
index 0000000..b3cf410
Binary files /dev/null and b/lib/libexpat-1.dll differ
diff --git a/lib/libfontconfig-1.dll b/lib/libfontconfig-1.dll
new file mode 100644 (file)
index 0000000..7ad870b
Binary files /dev/null and b/lib/libfontconfig-1.dll differ
diff --git a/lib/libpng14-14.dll b/lib/libpng14-14.dll
new file mode 100644 (file)
index 0000000..8b93b06
Binary files /dev/null and b/lib/libpng14-14.dll differ
diff --git a/lib/zlib1.dll b/lib/zlib1.dll
new file mode 100644 (file)
index 0000000..869b00d
Binary files /dev/null and b/lib/zlib1.dll differ
diff --git a/src/AssemblyInfo.cs b/src/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..29cf4b5
--- /dev/null
@@ -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 (file)
index 0000000..d29cfbc
--- /dev/null
@@ -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 (file)
index 0000000..02bf81f
--- /dev/null
@@ -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 (file)
index 0000000..76e81c2
--- /dev/null
@@ -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 (file)
index 0000000..aa5ceea
--- /dev/null
@@ -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 (file)
index 0000000..afab5a2
--- /dev/null
@@ -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 (file)
index 0000000..95fc0df
--- /dev/null
@@ -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 (file)
index 0000000..749053c
--- /dev/null
@@ -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 (file)
index 0000000..f68d1bc
--- /dev/null
@@ -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 (file)
index 0000000..f16ccf3
--- /dev/null
@@ -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 (file)
index 0000000..0464024
--- /dev/null
@@ -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 (file)
index 0000000..1abef72
--- /dev/null
@@ -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 (file)
index 0000000..699c2e8
--- /dev/null
@@ -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 (file)
index 0000000..cc4e093
--- /dev/null
@@ -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 (file)
index 0000000..c4da2a9
--- /dev/null
@@ -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 (file)
index 0000000..2420677
--- /dev/null
@@ -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 (file)
index 0000000..3208821
--- /dev/null
@@ -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 (file)
index 0000000..7f0fd86
--- /dev/null
@@ -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 (file)
index 0000000..9a5cbcb
--- /dev/null
@@ -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 (file)
index 0000000..8129fc8
--- /dev/null
@@ -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 (file)
index 0000000..5a541bc
--- /dev/null
@@ -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 (file)
index 0000000..5dadfc3
--- /dev/null
@@ -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 (file)
index 0000000..5c4d9f0
--- /dev/null
@@ -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 (file)
index 0000000..e829c57
--- /dev/null
@@ -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 (file)
index 0000000..d2742b1
--- /dev/null
@@ -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 (file)
index 0000000..e730200
--- /dev/null
@@ -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 (file)
index 0000000..dbebcad
--- /dev/null
@@ -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 (file)
index 0000000..292ea77
--- /dev/null
@@ -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 (file)
index 0000000..fd886cb
--- /dev/null
@@ -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 (file)
index 0000000..5e9428a
--- /dev/null
@@ -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 (file)
index 0000000..976ac24
--- /dev/null
@@ -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
+    }
+}