Samples: add PolarFixed-Sample

This commit is contained in:
lytico 2020-04-06 22:01:49 +02:00
parent 10f9819446
commit 926062eb69
2 changed files with 260 additions and 0 deletions

View File

@ -0,0 +1,196 @@
// adopted from: https://github.com/mono/gtk-sharp/commits/2.99.3/sample/PolarFixed.cs
// This is a completely pointless widget, but it shows how to subclass container...
using System;
using System.Collections.Generic;
using Gtk;
using Gdk;
namespace Samples
{
class PolarFixed : Container
{
IList<PolarFixedChild> children;
public PolarFixed()
{
children = new List<PolarFixedChild>();
HasWindow = false;
}
// The child properties object
public class PolarFixedChild : Container.ContainerChild
{
double theta;
uint r;
public PolarFixedChild(PolarFixed parent, Widget child, double theta, uint r) : base(parent, child)
{
this.theta = theta;
this.r = r;
}
// We call parent.QueueResize() from the property setters here so that you
// can move the widget around just by changing its child properties (just
// like with a native container class).
public double Theta {
get { return theta; }
set {
theta = value;
parent.QueueResize();
}
}
public uint R {
get { return r; }
set {
r = value;
parent.QueueResize();
}
}
}
// Override the child properties accessor to return the right object from
// "children".
public override ContainerChild this[Widget w] {
get {
foreach (PolarFixedChild pfc in children) {
if (pfc.Child == w)
return pfc;
}
return null;
}
}
// Indicate the kind of children the container will accept. Most containers
// will accept any kind of child, so they should return Gtk.Widget.GType.
// The default is "GLib.GType.None", which technically means that no (new)
// children can be added to the container, though Container.Add does not
// enforce this.
protected override GLib.GType OnChildType()
{
return Gtk.Widget.GType;
}
// Implement gtk_container_forall(), which is also used by
// Gtk.Container.Children and Gtk.Container.AllChildren.
protected override void ForAll(bool include_internals, Callback callback)
{
base.ForAll(include_internals, callback);
foreach (PolarFixedChild pfc in children)
callback(pfc.Child);
}
// Invoked by Container.Add (w). It's good practice to have this do *something*,
// even if it's not something terribly useful.
protected override void OnAdded(Widget w)
{
Put(w, 0.0, 0);
}
// our own adder method
public void Put(Widget w, double theta, uint r)
{
children.Add(new PolarFixedChild(this, w, theta, r));
w.Parent = this;
QueueResize();
}
public void Move(Widget w, double theta, uint r)
{
PolarFixedChild pfc = (PolarFixedChild) this[w];
if (pfc != null) {
pfc.Theta = theta;
pfc.R = r;
}
}
// invoked by Container.Remove (w)
protected override void OnRemoved(Widget w)
{
PolarFixedChild pfc = (PolarFixedChild) this[w];
if (pfc != null) {
pfc.Child.Unparent();
children.Remove(pfc);
QueueResize();
}
}
// Handle size request
protected override void OnGetPreferredHeight(out int minimal_height, out int natural_height)
{
Requisition req = new Requisition();
OnSizeRequested(ref req);
minimal_height = natural_height = req.Height;
}
protected override void OnGetPreferredWidth(out int minimal_width, out int natural_width)
{
Requisition req = new Requisition();
OnSizeRequested(ref req);
minimal_width = natural_width = req.Width;
}
void OnSizeRequested(ref Requisition req)
{
int child_width, child_minwidth, child_height, child_minheight;
int x, y;
req.Width = req.Height = 0;
foreach (PolarFixedChild pfc in children) {
// Recursively request the size of each child
pfc.Child.GetPreferredWidth(out child_minwidth, out child_width);
pfc.Child.GetPreferredHeight(out child_minheight, out child_height);
// Figure out where we're going to put it
x = (int) (Math.Cos(pfc.Theta) * pfc.R) + child_width / 2;
y = (int) (Math.Sin(pfc.Theta) * pfc.R) + child_height / 2;
// Update our own size request to fit it
if (req.Width < 2 * x)
req.Width = 2 * x;
if (req.Height < 2 * y)
req.Height = 2 * y;
}
// Take Container.BorderWidth into account
req.Width += (int) (2 * BorderWidth);
req.Height += (int) (2 * BorderWidth);
}
// Size allocation. Note that the allocation received may be smaller than what we
// requested. Some containers will take that into account by giving some or all
// of their children a smaller allocation than they requested. Other containers
// (like this one) just let their children get placed partly out-of-bounds if they
// aren't allocated enough room.
protected override void OnSizeAllocated(Rectangle allocation)
{
Requisition childReq, childMinReq;
int cx, cy, x, y;
// This sets the "Allocation" property. For widgets that
// have a GdkWindow, it also calls GdkWindow.MoveResize()
base.OnSizeAllocated(allocation);
// Figure out where the center of the grid will be
cx = allocation.X + (allocation.Width / 2);
cy = allocation.Y + (allocation.Height / 2);
foreach (PolarFixedChild pfc in children) {
pfc.Child.GetPreferredSize(out childMinReq, out childReq);
x = (int) (Math.Cos(pfc.Theta) * pfc.R) - childReq.Width / 2;
y = (int) (Math.Sin(pfc.Theta) * pfc.R) + childReq.Height / 2;
allocation.X = cx + x;
allocation.Width = childReq.Width;
allocation.Y = cy - y;
allocation.Height = childReq.Height;
pfc.Child.SizeAllocate(allocation);
}
}
}
}

View File

@ -0,0 +1,64 @@
using System;
using Gtk;
namespace Samples
{
[Section(ContentType = typeof(PolarFixed), Category = Category.Widgets)]
class PolarFixedSection : ListSection
{
public PolarFixedSection()
{
AddItem(CreateClock());
AddItem(CreateSpiral());
}
public (string, Widget) CreateClock()
{
uint r;
double theta;
// Clock
PolarFixed pf = new PolarFixed();
for (int hour = 1; hour <= 12; hour++) {
theta = (Math.PI / 2) - hour * (Math.PI / 6);
if (theta < 0)
theta += 2 * Math.PI;
Label l = new Label("<big><b>" + hour.ToString() + "</b></big>");
l.UseMarkup = true;
pf.Put(l, theta, 50);
}
return ("Clock", pf);
}
public (string, Widget) CreateSpiral()
{
uint r;
double theta;
var pf = new PolarFixed();
r = 0;
theta = 0.0;
foreach (string id in Gtk.Stock.ListIds()) {
StockItem item = Gtk.Stock.Lookup(id);
if (item.Label == null)
continue;
var icon = Gtk.Image.NewFromIconName(item.StockId, IconSize.SmallToolbar);
pf.Put(icon, theta, r);
// Logarithmic spiral: r = a*e^(b*theta)
r += 1;
theta = 10 * Math.Log(10 * r);
}
return ("Spiral", pf);
}
}
}