diff --git a/Maigre.sln b/Maigre.sln index 26c68a1..9b1bd36 100644 --- a/Maigre.sln +++ b/Maigre.sln @@ -16,6 +16,6 @@ Global {3C4985A8-E1D7-4633-8D79-B2816289F777}.Debug|x86.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = Maigre\Maigre.csproj + StartupItem = libmaigre\libmaigre.cproj EndGlobalSection EndGlobal diff --git a/Maigre/Cairo/ColorExtensions.cs b/Maigre/Cairo/ColorExtensions.cs new file mode 100644 index 0000000..c7b5802 --- /dev/null +++ b/Maigre/Cairo/ColorExtensions.cs @@ -0,0 +1,208 @@ +// +// ColorExtensions.cs +// +// Author: +// Aaron Bockover +// +// Copyright 2010 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; + +namespace Cairo +{ + public static class ColorExtensions + { + public static Cairo.Color ToCairoColor (this Gdk.Color color) + { + return ToCairoColor (color, 1.0); + } + + public static Cairo.Color ToCairoColor (this Gdk.Color color, double alpha) + { + return new Cairo.Color ( + (double)(color.Red >> 8) / 255.0, + (double)(color.Green >> 8) / 255.0, + (double)(color.Blue >> 8) / 255.0, + alpha); + } + + public static Cairo.Color AlphaBlend (this Cairo.Color ca, Cairo.Color cb, double alpha) + { + return new Cairo.Color ( + (1.0 - alpha) * ca.R + alpha * cb.R, + (1.0 - alpha) * ca.G + alpha * cb.G, + (1.0 - alpha) * ca.B + alpha * cb.B); + } + + public static Cairo.Color FromRgb (uint rgbColor) + { + return FromRgba ((rgbColor << 8) | 0x000000ff); + } + + public static Cairo.Color FromRgba (uint rgbaColor) + { + return new Cairo.Color ( + (byte)(rgbaColor >> 24) / 255.0, + (byte)(rgbaColor >> 16) / 255.0, + (byte)(rgbaColor >> 8) / 255.0, + (byte)(rgbaColor & 0x000000ff) / 255.0); + } + + public static bool ColorIsDark (this Cairo.Color color) + { + double h, s, b; + ToHsb (color, out h, out s, out b); + return b < 0.5; + } + + public static void ToHsb (this Cairo.Color color, out double hue, + out double saturation, out double brightness) + { + double min, max, delta; + double red = color.R; + double green = color.G; + double blue = color.B; + + hue = 0; + saturation = 0; + brightness = 0; + + if (red > green) { + max = Math.Max (red, blue); + min = Math.Min (green, blue); + } else { + max = Math.Max (green, blue); + min = Math.Min (red, blue); + } + + brightness = (max + min) / 2; + + if (Math.Abs (max - min) < 0.0001) { + hue = 0; + saturation = 0; + } else { + saturation = brightness <= 0.5 + ? (max - min) / (max + min) + : (max - min) / (2 - max - min); + + delta = max - min; + + if (red == max) { + hue = (green - blue) / delta; + } else if (green == max) { + hue = 2 + (blue - red) / delta; + } else if (blue == max) { + hue = 4 + (red - green) / delta; + } + + hue *= 60; + if (hue < 0) { + hue += 360; + } + } + } + + private static double Modula (double number, double divisor) + { + return ((int)number % divisor) + (number - (int)number); + } + + public static Cairo.Color FromHsb (double hue, double saturation, double brightness) + { + int i; + double [] hue_shift = { 0, 0, 0 }; + double [] color_shift = { 0, 0, 0 }; + double m1, m2, m3; + + m2 = brightness <= 0.5 + ? brightness * (1 + saturation) + : brightness + saturation - brightness * saturation; + + m1 = 2 * brightness - m2; + + hue_shift[0] = hue + 120; + hue_shift[1] = hue; + hue_shift[2] = hue - 120; + + color_shift[0] = color_shift[1] = color_shift[2] = brightness; + + i = saturation == 0 ? 3 : 0; + + for (; i < 3; i++) { + m3 = hue_shift[i]; + + if (m3 > 360) { + m3 = Modula (m3, 360); + } else if(m3 < 0) { + m3 = 360 - Modula (Math.Abs (m3), 360); + } + + if (m3 < 60) { + color_shift[i] = m1 + (m2 - m1) * m3 / 60; + } else if (m3 < 180) { + color_shift[i] = m2; + } else if (m3 < 240) { + color_shift[i] = m1 + (m2 - m1) * (240 - m3) / 60; + } else { + color_shift[i] = m1; + } + } + + return new Cairo.Color (color_shift[0], color_shift[1], color_shift[2]); + } + + public static Cairo.Color Shade (this Cairo.Color @base, double ratio) + { + double h, s, b; + + ToHsb (@base, out h, out s, out b); + + b = Math.Max (Math.Min (b * ratio, 1), 0); + s = Math.Max (Math.Min (s * ratio, 1), 0); + + var color = FromHsb (h, s, b); + color.A = @base.A; + return color; + } + + public static Cairo.Color AdjustBrightness (this Cairo.Color @base, double br) + { + double h, s, b; + ToHsb (@base, out h, out s, out b); + b = Math.Max (Math.Min (br, 1), 0); + return FromHsb (h, s, b); + } + + public static string GetHexString (this Cairo.Color color, bool withAlpha) + { + return withAlpha + ? String.Format ("#{0:x2}{1:x2}{2:x2}{3:x2}", + (byte)(color.R * 255), + (byte)(color.G * 255), + (byte)(color.B * 255), + (byte)(color.A * 255)) + : String.Format ("#{0:x2}{1:x2}{2:x2}", + (byte)(color.R * 255), + (byte)(color.G * 255), + (byte)(color.B * 255)); + } + } +} diff --git a/Maigre/Cairo/ContextExtensions.cs b/Maigre/Cairo/ContextExtensions.cs new file mode 100644 index 0000000..09e6a60 --- /dev/null +++ b/Maigre/Cairo/ContextExtensions.cs @@ -0,0 +1,142 @@ +// +// Style.cs +// +// Author: +// Aaron Bockover +// +// Copyright 2007-2010 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; + +namespace Cairo +{ + public static class ContextExtensions + { + /*public static Pango.Layout CreateCairoLayout (Gtk.Widget widget, Cairo.Context cairo_context) + { + var layout = PangoCairoHelper.CreateLayout (cairo_context); + layout.FontDescription = widget.PangoContext.FontDescription; + + double resolution = widget.Screen.Resolution; + if (resolution != -1) { + using (var context = PangoCairoHelper.LayoutGetContext (layout)) { + PangoCairoHelper.ContextSetResolution (context, resolution); + } + } + + return layout; + }*/ + + public static Surface CreateSurfaceForPixbuf (this Cairo.Context cr, Gdk.Pixbuf pixbuf) + { + var surface = cr.Target.CreateSimilar (cr.Target.Content, pixbuf.Width, pixbuf.Height); + using (var surface_cr = new Context (surface)) { + Gdk.CairoHelper.SetSourcePixbuf (surface_cr, pixbuf, 0, 0); + surface_cr.Paint (); + return surface; + } + } + + public static void RoundedRectangle (this Cairo.Context cr, + double x, double y, double w, double h, double r) + { + RoundedRectangle (cr, x, y, w, h, r, Corner.All, false); + } + + public static void RoundedRectangle (this Cairo.Context cr, + double x, double y, double w, double h, + double r, Corner corners) + { + RoundedRectangle (cr, x, y, w, h, r, corners, false); + } + + public static void RoundedRectangle (this Cairo.Context cr, + double x, double y, double w, double h, + double r, Corner corners, bool topBottomFallsThrough) + { + if (topBottomFallsThrough && corners == Corner.None) { + cr.MoveTo (x, y - r); + cr.LineTo (x, y + h + r); + cr.MoveTo (x + w, y - r); + cr.LineTo (x + w, y + h + r); + return; + } else if (r < 0.0001 || corners == Corner.None) { + cr.Rectangle (x, y, w, h); + return; + } + + if ((corners & (Corner.TopLeft | Corner.TopRight)) == 0 && topBottomFallsThrough) { + y -= r; + h += r; + cr.MoveTo (x + w, y); + } else { + if ((corners & Corner.TopLeft) != 0) { + cr.MoveTo (x + r, y); + } else { + cr.MoveTo (x, y); + } + + if ((corners & Corner.TopRight) != 0) { + cr.Arc (x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2); + } else { + cr.LineTo (x + w, y); + } + } + + if ((corners & (Corner.BottomLeft | Corner.BottomRight)) == 0 && topBottomFallsThrough) { + h += r; + cr.LineTo (x + w, y + h); + cr.MoveTo (x, y + h); + cr.LineTo (x, y + r); + cr.Arc (x + r, y + r, r, Math.PI, Math.PI * 1.5); + } else { + if ((corners & Corner.BottomRight) != 0) { + cr.Arc (x + w - r, y + h - r, r, 0, Math.PI * 0.5); + } else { + cr.LineTo (x + w, y + h); + } + + if ((corners & Corner.BottomLeft) != 0) { + cr .Arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI); + } else { + cr.LineTo (x, y + h); + } + + if ((corners & Corner.TopLeft) != 0) { + cr.Arc (x + r, y + r, r, Math.PI, Math.PI * 1.5); + } else { + cr.LineTo (x, y); + } + } + } + + public static void DisposeSelfAndTarget (this Cairo.Context cr) + { + ((IDisposable)cr.Target).Dispose (); + ((IDisposable)cr).Dispose (); + } + + public static void SetColor (this Cairo.Context cr, Gdk.Color color) + { + cr.Color = color.ToCairoColor (); + } + } +} diff --git a/Maigre/Cairo/Corner.cs b/Maigre/Cairo/Corner.cs new file mode 100644 index 0000000..f4095f9 --- /dev/null +++ b/Maigre/Cairo/Corner.cs @@ -0,0 +1,41 @@ +// +// Corner.cs +// +// Author: +// Aaron Bockover +// +// Copyright 2010 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; + +namespace Cairo +{ + [Flags] + public enum Corner + { + None = 0, + TopLeft = 1, + TopRight = 2, + BottomLeft = 4, + BottomRight = 8, + All = 15 + } +} \ No newline at end of file diff --git a/Maigre/Maigre.csproj b/Maigre/Maigre.csproj index 9b62f2e..a4b9085 100644 --- a/Maigre/Maigre.csproj +++ b/Maigre/Maigre.csproj @@ -15,7 +15,7 @@ true full false - ..\engines + . DEBUG prompt 4 @@ -33,13 +33,37 @@ - + + + + + + + + + + + + + + + + + + + + + + - + + + + \ No newline at end of file diff --git a/Maigre/Theme.cs b/Maigre/Maigre/DrawContext.cs similarity index 76% rename from Maigre/Theme.cs rename to Maigre/Maigre/DrawContext.cs index b876089..68f168f 100644 --- a/Maigre/Theme.cs +++ b/Maigre/Maigre/DrawContext.cs @@ -1,5 +1,5 @@ // -// Style.cs +// DrawContext.cs // // Author: // Aaron Bockover @@ -25,9 +25,6 @@ // THE SOFTWARE. using System; -using Gtk; -using Gdk; -using Cairo; namespace Maigre { @@ -36,8 +33,8 @@ namespace Maigre public string Method { get; private set; } public Gtk.Style Style { get; private set; } public Gdk.Window Window { get; private set; } - public Gtk.StateType StateType { get; private set; } - public Gtk.ShadowType ShadowType { get; private set; } + public Gtk.StateType State { get; private set; } + public Gtk.ShadowType Shadow { get; private set; } public Gdk.Rectangle Area { get; private set; } public Gtk.Widget Widget { get; private set; } public string Detail { get; private set; } @@ -56,19 +53,6 @@ namespace Maigre public int Y1 { get; private set; } public int Y2 { get; private set; } public bool Fill { get; private set; } - public Gtk.ArrowType ArrowType { get; private set; } - } - - public static class Theme - { - public static void DrawBox (DrawContext context) - { - Console.WriteLine ("{0}:{1} ({2})", context.Method, context.Detail, context.Area); - using (var cr = Gdk.CairoHelper.Create (context.Window)) { - cr.Color = new Cairo.Color (0, 1, 1); - cr.Rectangle (context.X, context.Y, context.Width, context.Height); - cr.Fill (); - } - } + public Gtk.ArrowType Arrow { get; private set; } } } diff --git a/Maigre/Maigre/Theme.cs b/Maigre/Maigre/Theme.cs new file mode 100644 index 0000000..878ee30 --- /dev/null +++ b/Maigre/Maigre/Theme.cs @@ -0,0 +1,47 @@ +// +// Style.cs +// +// Author: +// Aaron Bockover +// +// Copyright 2010 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using Cairo; + +namespace Maigre +{ + public static class Theme + { + public static void DrawBox (DrawContext ctx) + { + using (var cr = Gdk.CairoHelper.Create (ctx.Window)) { + switch (ctx.Detail) { + case "button": + cr.RoundedRectangle (ctx.X, ctx.Y, ctx.Width, ctx.Height, 3); + cr.SetColor (ctx.Widget.Style.Background (ctx.State)); + cr.Fill (); + break; + } + } + } + } +} diff --git a/Maigre/Makefile b/Maigre/Makefile new file mode 100644 index 0000000..98456de --- /dev/null +++ b/Maigre/Makefile @@ -0,0 +1,24 @@ +MAIGRE_SOURCES = \ + Cairo/ColorExtensions.cs \ + Cairo/ContextExtensions.cs \ + Cairo/Corner.cs \ + Maigre/DrawContext.cs \ + Maigre/Theme.cs + +MAIGRE_OTHER = gtkrc + +REFERENCES = \ + Mono.Cairo \ + -pkg:gtk-sharp-2.0 \ + System \ + System.Core + +REFERENCES_BUILD = \ + $(filter -pkg:%, $(REFERENCES)) \ + $(foreach r, $(filter-out -pkg:%, $(REFERENCES)), -r:$(r)) + +Maigre.dll: $(MAIGRE_SOURCES) + gmcs -out:$@ -target:library -debug $(REFERENCES_BUILD) $(MAIGRE_SOURCES) + +clean: + rm -rf Maigre.dll* obj/ diff --git a/maigre.gtkrc b/Maigre/gtkrc similarity index 100% rename from maigre.gtkrc rename to Maigre/gtkrc diff --git a/Makefile b/Makefile index 5e2eeeb..681f3e8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,15 @@ +all: + $(MAKE) -C libmaigre + $(MAKE) -C Maigre + clean: - rm -rf engines - rm -rf Maigre.dll* + $(MAKE) -C libmaigre clean + $(MAKE) -C Maigre clean + rm -rf lib test: - cp engines/Maigre.dll* . - GTK_PATH=$$PWD GTK2_RC_FILES=maigre.gtkrc gtk-demo + rm -rf lib + mkdir -p lib/engines + cp Maigre/gtkrc lib + cp libmaigre/libmaigre.so Maigre/Maigre.dll lib/engines + GTK_PATH=$$PWD/lib GTK2_RC_FILES=lib/gtkrc gtk-demo diff --git a/libmaigre/Makefile b/libmaigre/Makefile new file mode 100644 index 0000000..66fac48 --- /dev/null +++ b/libmaigre/Makefile @@ -0,0 +1,46 @@ +LIBMAIGRE_SOURCES = \ + maigre-mono-bridge.c \ + maigre-rc-style.c \ + maigre-style.c \ + maigre-theme-module.c + +LIBMAIGRE_OTHER = \ + maigre-gtk-style-generator \ + maigre-mono-bridge.h \ + maigre-rc-style.h \ + maigre-style.h + +PC_DEPS = \ + mono \ + gtk+-2.0 + +CC = gcc + +LIBMAIGRE_CFLAGS = \ + -Wall -O2 -ggdb3 \ + $(shell pkg-config --cflags $(PC_DEPS)) \ + $(CFLAGS) + +LIBMAIGRE_LDFLAGS = \ + -shared \ + $(shell pkg-config --libs $(PC_DEPS)) \ + $(LDFLAGS) + +LIBMAIGRE_OBJECTS = $(LIBMAIGRE_SOURCES:.c=.o) + +all: libmaigre.so + +libmaigre.so: maigre-style-overrides.c $(LIBMAIGRE_OBJECTS) + $(CC) $(LIBMAIGRE_LDFLAGS) $(LIBMAIGRE_OBJECTS) -o $@ + +.c.o: + $(CC) -c $(LIBMAIGRE_CFLAGS) $< -o $@ + +maigre-style-overrides.c: maigre-gtk-style-generator + ./$< + +clean: + rm -rf $(LIBMAIGRE_OBJECTS) libmaigre.so maigre-style-overrides.c + +test: + $(MAKE) -C .. test diff --git a/libmaigre/libmaigre.cproj b/libmaigre/libmaigre.cproj index 2a1a8bb..caf24e1 100644 --- a/libmaigre/libmaigre.cproj +++ b/libmaigre/libmaigre.cproj @@ -11,12 +11,6 @@ - - - - - - true @@ -55,4 +49,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libmaigre/maigre-mono-bridge.c b/libmaigre/maigre-mono-bridge.c index 3edfcbd..a7fbcd1 100644 --- a/libmaigre/maigre-mono-bridge.c +++ b/libmaigre/maigre-mono-bridge.c @@ -80,8 +80,8 @@ maigre_mono_bridge_load_draw_context (MaigreMonoBridge *bridge) "k__BackingField", "