mirror of
https://github.com/Ryujinx/GtkSharp.git
synced 2025-01-03 17:05:47 +00:00
Merge pull request #156 from lytico/lytico_cellrenderer_getsize
Gtk.CellRenderer: implement OnGetSize
This commit is contained in:
commit
40773f3c88
167
Source/Libs/GtkSharp/CellRenderer.GetSize.cs
Normal file
167
Source/Libs/GtkSharp/CellRenderer.GetSize.cs
Normal file
|
@ -0,0 +1,167 @@
|
|||
using GtkSharp;
|
||||
|
||||
namespace Gtk
|
||||
{
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public partial class CellRenderer
|
||||
{
|
||||
static GetSizeNativeDelegate GetSize_cb_delegate;
|
||||
|
||||
static GetSizeNativeDelegate GetSizeVMCallback {
|
||||
get {
|
||||
if (GetSize_cb_delegate == null)
|
||||
GetSize_cb_delegate = new GetSizeNativeDelegate (GetSize_cb);
|
||||
return GetSize_cb_delegate;
|
||||
}
|
||||
}
|
||||
|
||||
static void OverrideGetSize (GLib.GType gtype)
|
||||
{
|
||||
OverrideGetSize (gtype, GetSizeVMCallback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sets callback GetSize in GtkCellRendererClass-Struct
|
||||
/// </summary>
|
||||
/// <param name="gtype"></param>
|
||||
/// <param name="callback"></param>
|
||||
static void OverrideGetSize (GLib.GType gtype, GetSizeNativeDelegate callback)
|
||||
{
|
||||
unsafe {
|
||||
IntPtr* raw_ptr = (IntPtr*) (((long) gtype.GetClassPtr ()) + (long) class_abi.GetFieldOffset ("get_size"));
|
||||
*raw_ptr = Marshal.GetFunctionPointerForDelegate ((Delegate) callback);
|
||||
}
|
||||
}
|
||||
|
||||
// We have to implement this VM manually because x_offset, y_offset, width and height params may be NULL and therefore cannot be treated as "out int"
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate void GetSizeNativeDelegate (IntPtr item, IntPtr widget, IntPtr cell_area_ptr, IntPtr x_offset, IntPtr y_offset, IntPtr width, IntPtr height);
|
||||
|
||||
static void GetSize_cb (IntPtr item, IntPtr widget, IntPtr cell_area_ptr, IntPtr x_offset, IntPtr y_offset, IntPtr width, IntPtr height)
|
||||
{
|
||||
try {
|
||||
CellRenderer obj = GLib.Object.GetObject (item, false) as CellRenderer;
|
||||
Gtk.Widget widg = GLib.Object.GetObject (widget, false) as Gtk.Widget;
|
||||
Gdk.Rectangle cell_area = Gdk.Rectangle.Zero;
|
||||
if (cell_area_ptr != IntPtr.Zero)
|
||||
cell_area = Gdk.Rectangle.New (cell_area_ptr);
|
||||
int a, b, c, d;
|
||||
|
||||
obj.OnGetSize (widg, ref cell_area, out a, out b, out c, out d);
|
||||
if (x_offset != IntPtr.Zero)
|
||||
Marshal.WriteInt32 (x_offset, a);
|
||||
if (y_offset != IntPtr.Zero)
|
||||
Marshal.WriteInt32 (y_offset, b);
|
||||
if (width != IntPtr.Zero)
|
||||
Marshal.WriteInt32 (width, c);
|
||||
if (height != IntPtr.Zero)
|
||||
Marshal.WriteInt32 (height, d);
|
||||
} catch (Exception e) {
|
||||
GLib.ExceptionManager.RaiseUnhandledException (e, false);
|
||||
}
|
||||
}
|
||||
|
||||
[GLib.DefaultSignalHandler (Type = typeof(Gtk.CellRenderer), ConnectionMethod = nameof(OverrideGetSize))]
|
||||
protected virtual void OnGetSize (Gtk.Widget widget, ref Gdk.Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height)
|
||||
{
|
||||
InternalOnGetSize (widget, ref cell_area, out x_offset, out y_offset, out width, out height);
|
||||
}
|
||||
|
||||
private void InternalOnGetSize (Gtk.Widget widget, ref Gdk.Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height)
|
||||
{
|
||||
IntPtr native_cell_area = GLib.Marshaller.StructureToPtrAlloc (cell_area);
|
||||
gtksharp_cellrenderer_base_get_size (Handle, widget?.Handle ?? IntPtr.Zero, native_cell_area, out x_offset, out y_offset, out width, out height);
|
||||
cell_area = Gdk.Rectangle.New (native_cell_area);
|
||||
Marshal.FreeHGlobal (native_cell_area);
|
||||
}
|
||||
|
||||
static GetSizeNativeDelegate InternalGetSizeNativeDelegate (GLib.GType gtype)
|
||||
{
|
||||
GetSizeNativeDelegate unmanaged = null;
|
||||
unsafe {
|
||||
IntPtr* raw_ptr = (IntPtr*) (((long) gtype.GetClassPtr ()) + (long) class_abi.GetFieldOffset ("get_size"));
|
||||
if (*raw_ptr == IntPtr.Zero)
|
||||
return default;
|
||||
|
||||
unmanaged = Marshal.GetDelegateForFunctionPointer<GetSizeNativeDelegate> (*raw_ptr);
|
||||
}
|
||||
|
||||
return unmanaged;
|
||||
}
|
||||
|
||||
static void gtksharp_cellrenderer_base_get_size (IntPtr cell, IntPtr widget, IntPtr cell_area, out int x_offset, out int y_offset, out int width, out int height)
|
||||
{
|
||||
/*
|
||||
const gchar *__gtype_prefix = "__gtksharp_";
|
||||
#define HAS_PREFIX(a) (*((guint64 *)(a)) == *((guint64 *) __gtype_prefix))
|
||||
|
||||
static GObjectClass *
|
||||
get_threshold_class (GObject *obj)
|
||||
{
|
||||
GType gtype = G_TYPE_FROM_INSTANCE (obj);
|
||||
while (HAS_PREFIX (g_type_name (gtype)))
|
||||
gtype = g_type_parent (gtype);
|
||||
GObjectClass *klass = g_type_class_peek (gtype);
|
||||
if (klass == NULL) klass = g_type_class_ref (gtype);
|
||||
return klass;
|
||||
}
|
||||
|
||||
void gtksharp_cellrenderer_base_get_size (GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height)
|
||||
{
|
||||
GtkCellRendererClass *klass = (GtkCellRendererClass *) get_threshold_class (G_OBJECT (cell));
|
||||
if (klass->get_size)
|
||||
(* klass->get_size) (cell, widget, cell_area, x_offset, y_offset, width, height);
|
||||
}
|
||||
*/
|
||||
|
||||
x_offset = 0;
|
||||
y_offset = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
if (cell == IntPtr.Zero) {
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = TryGetObject (cell);
|
||||
var parent = obj.NativeType;
|
||||
while ((parent = parent.GetBaseType ()) != GLib.GType.None) {
|
||||
|
||||
if (parent.ToString ().StartsWith ("__gtksharp_")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var GetSize = InternalGetSizeNativeDelegate (parent);
|
||||
if (GetSize != default) {
|
||||
var a = Marshal.AllocHGlobal (sizeof(int));
|
||||
var b = Marshal.AllocHGlobal (sizeof(int));
|
||||
var c = Marshal.AllocHGlobal (sizeof(int));
|
||||
var d = Marshal.AllocHGlobal (sizeof(int));
|
||||
try {
|
||||
GetSize (cell, widget, cell_area, a, b, c, d);
|
||||
if (a != IntPtr.Zero)
|
||||
Marshal.WriteInt32 (a, x_offset);
|
||||
if (b != IntPtr.Zero)
|
||||
Marshal.WriteInt32 (b, y_offset);
|
||||
if (c != IntPtr.Zero)
|
||||
Marshal.WriteInt32 (c, width);
|
||||
if (d != IntPtr.Zero)
|
||||
Marshal.WriteInt32 (d, height);
|
||||
} finally {
|
||||
Marshal.FreeHGlobal (a);
|
||||
Marshal.FreeHGlobal (b);
|
||||
Marshal.FreeHGlobal (c);
|
||||
Marshal.FreeHGlobal (d);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -48,10 +48,6 @@ namespace Gtk {
|
|||
gtk_cell_renderer_render2 (Handle, context == null ? IntPtr.Zero : context.Handle, widget == null ? IntPtr.Zero : widget.Handle, ref background_area, ref cell_area, ref expose_area, (int) flags);
|
||||
}
|
||||
|
||||
// We have to implement this VM manually because x_offset, y_offset, width and height params may be NULL and therefore cannot be treated as "out int"
|
||||
// TODO: Implement "nullable" attribute for value type parameters in GAPI
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
delegate void OnGetSizeDelegate (IntPtr item, IntPtr widget, IntPtr cell_area_ptr, IntPtr x_offset, IntPtr y_offset, IntPtr width, IntPtr height);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
53
Source/Samples/Sections/Widgets/CellRendererSection.cs
Normal file
53
Source/Samples/Sections/Widgets/CellRendererSection.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using Gtk;
|
||||
using System;
|
||||
namespace Samples
|
||||
{
|
||||
|
||||
[Section (ContentType = typeof(CustomCellRenderer), Category = Category.Widgets)]
|
||||
class CellRendererSection : ListSection
|
||||
{
|
||||
public CellRendererSection ()
|
||||
{
|
||||
AddItem (CreateCellRenderer ());
|
||||
|
||||
}
|
||||
ListStore liststore;
|
||||
|
||||
public (string, Widget) CreateCellRenderer ()
|
||||
{
|
||||
liststore = new ListStore (typeof (float), typeof (string));
|
||||
liststore.AppendValues (0.5f, "50%");
|
||||
|
||||
TreeView view = new TreeView (liststore);
|
||||
|
||||
view.AppendColumn ("Progress", new CellRendererText (), "text", 1);
|
||||
view.AppendColumn ("Progress", new CustomCellRenderer (), "percent", 0);
|
||||
GLib.Timeout.Add (50, new GLib.TimeoutHandler (update_percent));
|
||||
|
||||
return (nameof(CustomCellRenderer), view);
|
||||
}
|
||||
|
||||
bool increasing = true;
|
||||
bool update_percent ()
|
||||
{
|
||||
TreeIter iter;
|
||||
liststore.GetIterFirst (out iter);
|
||||
float perc = (float) liststore.GetValue (iter, 0);
|
||||
|
||||
if ((perc > 0.99) || (perc < 0.01 && perc > 0)) {
|
||||
increasing = !increasing;
|
||||
}
|
||||
|
||||
if (increasing)
|
||||
perc += 0.01f;
|
||||
else
|
||||
perc -= 0.01f;
|
||||
|
||||
liststore.SetValue (iter, 0, perc);
|
||||
liststore.SetValue (iter, 1, Convert.ToInt32 (perc * 100) + "%");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
// CustomCellRenderer.cs : C# implementation of an example custom cellrenderer
|
||||
// from http://scentric.net/tutorial/sec-custom-cell-renderers.html
|
||||
//
|
||||
// Author: Todd Berman <tberman@sevenl.net>
|
||||
//
|
||||
// (c) 2004 Todd Berman
|
||||
|
||||
// adopted from: https://github.com/mono/gtk-sharp/commits/2.99.3/sample/CustomCellRenderer.cs
|
||||
|
||||
using System;
|
||||
using Gtk;
|
||||
using Gdk;
|
||||
using GLib;
|
||||
|
||||
namespace Samples
|
||||
{
|
||||
|
||||
public class CustomCellRenderer : CellRenderer
|
||||
{
|
||||
|
||||
private float percent;
|
||||
|
||||
[GLib.Property ("percent")]
|
||||
public float Percentage {
|
||||
get { return percent; }
|
||||
set { percent = value; }
|
||||
}
|
||||
|
||||
protected override void OnGetSize (Widget widget, ref Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height)
|
||||
{
|
||||
base.OnGetSize (widget, ref cell_area, out x_offset, out y_offset, out width, out height);
|
||||
|
||||
int calc_width = (int) this.Xpad * 2 + 100;
|
||||
int calc_height = (int) this.Ypad * 2 + 10;
|
||||
|
||||
width = calc_width;
|
||||
height = calc_height;
|
||||
|
||||
x_offset = 0;
|
||||
y_offset = 0;
|
||||
if (!cell_area.Equals (Rectangle.Zero)) {
|
||||
x_offset = (int) (this.Xalign * (cell_area.Width - calc_width));
|
||||
x_offset = Math.Max (x_offset, 0);
|
||||
|
||||
y_offset = (int) (this.Yalign * (cell_area.Height - calc_height));
|
||||
y_offset = Math.Max (y_offset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRender (Cairo.Context cr, Widget widget, Rectangle background_area, Rectangle cell_area, CellRendererState flags)
|
||||
{
|
||||
int x = (int) (cell_area.X + this.Xpad);
|
||||
int y = (int) (cell_area.Y + this.Ypad);
|
||||
int width = (int) (cell_area.Width - this.Xpad * 2);
|
||||
int height = (int) (cell_area.Height - this.Ypad * 2);
|
||||
|
||||
widget.StyleContext.Save ();
|
||||
widget.StyleContext.AddClass ("trough");
|
||||
widget.StyleContext.RenderBackground (cr, x, y, width, height);
|
||||
widget.StyleContext.RenderFrame (cr, x, y, width, height);
|
||||
|
||||
Border padding = widget.StyleContext.GetPadding (StateFlags.Normal);
|
||||
x += padding.Left;
|
||||
y += padding.Top;
|
||||
width -= padding.Left + padding.Right;
|
||||
height -= padding.Top + padding.Bottom;
|
||||
|
||||
widget.StyleContext.Restore ();
|
||||
|
||||
widget.StyleContext.Save ();
|
||||
widget.StyleContext.AddClass ("progressbar");
|
||||
widget.StyleContext.RenderActivity (cr, x, y, (int) (width * Percentage), height);
|
||||
widget.StyleContext.Restore ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue