mirror of
https://github.com/Ryujinx/GtkSharp.git
synced 2024-12-26 00:35:34 +00:00
f2343fbb71
* sample/CustomNotebook.cs: * sample/CustomWidget.cs: use Widget.WidgetFlags prop to avoid obsolete warning svn path=/trunk/gtk-sharp/; revision=39528
643 lines
15 KiB
C#
643 lines
15 KiB
C#
using GLib;
|
|
using Gtk;
|
|
using System;
|
|
using System.Collections;
|
|
|
|
class CustomNotebookTest {
|
|
static CustomNotebook cn;
|
|
static Notebook nb;
|
|
static int tabCount;
|
|
|
|
public static int Main (string[] args)
|
|
{
|
|
Application.Init ();
|
|
Window win = new Window ("Custom Notebook Test");
|
|
win.DeleteEvent += new DeleteEventHandler (OnQuit);
|
|
|
|
VBox box = new VBox (false, 5);
|
|
Button addButton = new Button ("Add Tab");
|
|
//addButton.Clicked += OnAddTab;
|
|
Button rmButton = new Button ("Remove Tab");
|
|
rmButton.Clicked += OnRemoveTab;
|
|
box.PackStart (addButton, false, false, 0);
|
|
box.PackStart (rmButton, false, false, 0);
|
|
HPaned paned = new HPaned ();
|
|
|
|
cn = new CustomNotebook ();
|
|
cn.BorderWidth = 5;
|
|
cn.Scrollable = false;
|
|
Gdk.Pixbuf icon = cn.RenderIcon (Stock.Execute, IconSize.Menu, "");
|
|
//for (tabCount = 0; tabCount < 3; tabCount++)
|
|
cn.AppendPage (new Label ("Custom Notebook"), Stock.Execute, "extended tab" + tabCount);
|
|
cn.AppendPage (new Label ("Custom Notebook"), Stock.Execute, "tab" + (tabCount + 1));
|
|
cn.AppendPage (new Label ("Custom Notebook"), Stock.Execute, "extended tab" + (tabCount + 2));
|
|
paned.Pack1 (cn, true, false);
|
|
|
|
nb = new Notebook ();
|
|
nb.BorderWidth = 5;
|
|
nb.Scrollable = false;
|
|
for (tabCount = 0; tabCount < 3; tabCount++)
|
|
nb.AppendPage (new Label ("Regular Notebook"), new Label ("tab" + tabCount));
|
|
paned.Pack2 (nb, true, false);
|
|
box.PackEnd (paned, true, true, 0);
|
|
|
|
win.Add (box);
|
|
win.ShowAll ();
|
|
Application.Run ();
|
|
return 0;
|
|
}
|
|
|
|
/*static void OnAddTab (object sender, EventArgs args)
|
|
{
|
|
cn.AppendPage (new Label ("Custom Notebook"), Stock.Execute, "tab" + tabCount + 1);
|
|
cn.ShowAll ();
|
|
nb.AppendPage (new Label ("Regular Notebook"), new Label ("tab" + tabCount + 1));
|
|
nb.ShowAll ();
|
|
tabCount++;
|
|
}*/
|
|
|
|
static void OnRemoveTab (object sender, EventArgs args)
|
|
{
|
|
}
|
|
|
|
static void OnQuit (object sender, DeleteEventArgs args)
|
|
{
|
|
Application.Quit ();
|
|
}
|
|
}
|
|
|
|
class CustomNotebookPage {
|
|
private Gdk.Rectangle allocation;
|
|
private Widget child = null;
|
|
private Gdk.Pixbuf icon = null;
|
|
private bool ellipsize = false;
|
|
private string label = null;
|
|
private Pango.Layout layout = null;
|
|
private int layoutWidth = -1;
|
|
private int layoutHeight = -1;
|
|
private Requisition requisition;
|
|
private string stockid = null;
|
|
|
|
public Gdk.Rectangle Allocation {
|
|
get {
|
|
return allocation;
|
|
}
|
|
set {
|
|
allocation = value;
|
|
}
|
|
}
|
|
|
|
public Widget Child {
|
|
get {
|
|
return child;
|
|
}
|
|
set {
|
|
child = value;
|
|
}
|
|
}
|
|
|
|
public bool Ellipsize {
|
|
get {
|
|
return ellipsize;
|
|
}
|
|
set {
|
|
ellipsize = value;
|
|
}
|
|
}
|
|
|
|
public Gdk.Pixbuf Icon {
|
|
get {
|
|
if (icon == null && StockId != null) {
|
|
icon = child.RenderIcon (StockId, IconSize.Menu, "");
|
|
}
|
|
|
|
return icon;
|
|
}
|
|
set {
|
|
icon = value;
|
|
}
|
|
}
|
|
|
|
public string Label {
|
|
get {
|
|
return label;
|
|
}
|
|
set {
|
|
label = value;
|
|
layout = null;
|
|
layoutWidth = -1;
|
|
layoutHeight = -1;
|
|
}
|
|
}
|
|
|
|
public Pango.Layout Layout {
|
|
get {
|
|
if (layout == null && Label != null) {
|
|
layout = child.CreatePangoLayout (label);
|
|
layout.GetPixelSize (out layoutWidth, out layoutHeight);
|
|
}
|
|
|
|
return layout;
|
|
}
|
|
}
|
|
|
|
public int LayoutWidth {
|
|
get {
|
|
if (Layout != null)
|
|
return layoutWidth;
|
|
else
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public int LayoutHeight {
|
|
get {
|
|
if (Layout != null)
|
|
return layoutHeight;
|
|
else
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public Requisition Requisition {
|
|
get {
|
|
return requisition;
|
|
}
|
|
set {
|
|
requisition = value;
|
|
}
|
|
}
|
|
|
|
public string StockId {
|
|
get {
|
|
return stockid;
|
|
}
|
|
set {
|
|
stockid = value;
|
|
icon = null;
|
|
}
|
|
}
|
|
|
|
public CustomNotebookPage (Widget child, string label)
|
|
{
|
|
Child = child;
|
|
Label = label;
|
|
}
|
|
|
|
public CustomNotebookPage (Widget child, Gdk.Pixbuf icon, string label)
|
|
{
|
|
Child = child;
|
|
Icon = icon;
|
|
Label = label;
|
|
}
|
|
|
|
public CustomNotebookPage (Widget child, string stockid, string label)
|
|
{
|
|
Child = child;
|
|
Label = label;
|
|
StockId = stockid;
|
|
}
|
|
}
|
|
|
|
class CustomNotebook : Container {
|
|
private readonly int tabCurvature = 1;
|
|
private readonly int tabOverlap = 2;
|
|
private ArrayList pages = new ArrayList ();
|
|
private bool closable;
|
|
private bool scrollable;
|
|
private PositionType tabPosition;
|
|
private int tabHBorder;
|
|
private int tabVBorder;
|
|
|
|
public bool Closable {
|
|
get {
|
|
return closable;
|
|
}
|
|
set {
|
|
closable = value;
|
|
}
|
|
}
|
|
|
|
private CustomNotebookPage CurrentPage {
|
|
get {
|
|
return (CustomNotebookPage)pages[0];
|
|
}
|
|
}
|
|
|
|
public bool Scrollable {
|
|
get {
|
|
return scrollable;
|
|
}
|
|
set {
|
|
scrollable = value;
|
|
}
|
|
}
|
|
|
|
public Gtk.PositionType TabPosition {
|
|
get {
|
|
return tabPosition;
|
|
}
|
|
set {
|
|
switch (value) {
|
|
case PositionType.Left:
|
|
case PositionType.Right:
|
|
Console.WriteLine ("PositionType.Left or Right is not supported by this widget");
|
|
break;
|
|
default:
|
|
tabPosition = value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*static CustomNotebook ()
|
|
{
|
|
Container.OverrideForall (CustomNotebook.GType);
|
|
}*/
|
|
|
|
public CustomNotebook () : base ()
|
|
{
|
|
closable = true;
|
|
scrollable = false;
|
|
tabPosition = PositionType.Top;
|
|
tabHBorder = 2;
|
|
tabVBorder = 2;
|
|
|
|
WidgetFlags |= WidgetFlags.NoWindow;
|
|
}
|
|
|
|
public void AppendPage (Widget child, string label)
|
|
{
|
|
pages.Add (new CustomNotebookPage (child, label));
|
|
child.Parent = this;
|
|
}
|
|
|
|
public void AppendPage (Widget child, string stockid, string label)
|
|
{
|
|
pages.Add (new CustomNotebookPage (child, stockid, label));
|
|
child.Parent = this;
|
|
}
|
|
|
|
public void AppendPage (Widget child, Gdk.Pixbuf icon, string label)
|
|
{
|
|
pages.Add (new CustomNotebookPage (child, icon, label));
|
|
child.Parent = this;
|
|
}
|
|
|
|
private void EllipsizeLayout (Pango.Layout layout, int width)
|
|
{
|
|
if (width <= 0) {
|
|
layout.SetText ("");
|
|
return;
|
|
}
|
|
|
|
int layoutWidth, layoutHeight;
|
|
layout.GetPixelSize (out layoutWidth, out layoutHeight);
|
|
if (layoutWidth <= width)
|
|
return;
|
|
|
|
// Calculate ellipsis width.
|
|
Pango.Layout ell = layout.Copy ();
|
|
ell.SetText ("...");
|
|
int ellWidth, ellHeight;
|
|
ell.GetPixelSize (out ellWidth, out ellHeight);
|
|
|
|
if (width < ellWidth) {
|
|
// Not even ellipsis fits, so hide text.
|
|
layout.SetText ("");
|
|
return;
|
|
}
|
|
|
|
// Shrink total available width by the width of the ellipsis.
|
|
width -= ellWidth;
|
|
string text = layout.Text;
|
|
Console.WriteLine ("layout text = {0}", text);
|
|
Console.WriteLine ("line count: {0}", layout.LineCount);
|
|
Pango.LayoutLine line = layout.Lines[0];
|
|
//Console.WriteLine ("layout = {0}", line.layout.Text);
|
|
//Console.WriteLine ("line = {0}", line.Length);
|
|
int idx = 0, trailing = 0;
|
|
if (line.XToIndex (width * 1024, out idx, out trailing)) {
|
|
text = text.Substring (0, idx - 1);
|
|
text += "...";
|
|
layout.SetText (text);
|
|
}
|
|
}
|
|
|
|
protected override bool OnExposeEvent (Gdk.EventExpose args)
|
|
{
|
|
int x, y, width, height, gapX, gapWidth;
|
|
int bw = (int)BorderWidth;
|
|
|
|
x = Allocation.X + bw;
|
|
y = Allocation.Y + bw;
|
|
width = Allocation.Width - 2 * bw;
|
|
height = Allocation.Height - 2 * bw;
|
|
|
|
switch (TabPosition) {
|
|
case PositionType.Top:
|
|
y += CurrentPage.Allocation.Height;
|
|
height -= CurrentPage.Allocation.Height;
|
|
break;
|
|
case PositionType.Bottom:
|
|
height -= CurrentPage.Allocation.Height;
|
|
break;
|
|
case PositionType.Left:
|
|
case PositionType.Right:
|
|
break;
|
|
}
|
|
|
|
gapX = gapWidth = 0;
|
|
switch (TabPosition) {
|
|
case PositionType.Top:
|
|
case PositionType.Bottom:
|
|
gapX = CurrentPage.Allocation.X - Allocation.X - bw;
|
|
gapWidth = CurrentPage.Allocation.Width;
|
|
break;
|
|
case PositionType.Left:
|
|
case PositionType.Right:
|
|
break;
|
|
}
|
|
|
|
Style.PaintBoxGap (Style, GdkWindow, StateType.Normal,
|
|
ShadowType.Out, args.Area, this,
|
|
"notebook", x, y, width, height,
|
|
TabPosition, gapX, gapWidth);
|
|
|
|
for (int i = pages.Count - 1; i >= 0; i--) {
|
|
CustomNotebookPage page = (CustomNotebookPage)pages[i];
|
|
Gdk.Rectangle pageAlloc = page.Allocation;
|
|
|
|
StateType state = page == CurrentPage ? StateType.Normal : StateType.Active;
|
|
Style.PaintExtension (Style, GdkWindow, state,
|
|
ShadowType.Out, args.Area, this,
|
|
"tab", pageAlloc.X, pageAlloc.Y,
|
|
pageAlloc.Width, pageAlloc.Height,
|
|
PositionType.Bottom);
|
|
|
|
// FIXME: Only add YThickness when TabPosition = Top;
|
|
y = pageAlloc.Y + Style.YThickness + FocusLineWidth + tabVBorder;
|
|
height = pageAlloc.Height - Style.YThickness - 2 * (tabVBorder + FocusLineWidth);
|
|
if (page.Icon != null) {
|
|
x = pageAlloc.X + (pageAlloc.Width + 1 -
|
|
page.Icon.Width -
|
|
page.LayoutWidth) / 2;
|
|
int iconY = y + (height - page.Icon.Height) / 2;
|
|
|
|
GdkWindow.DrawPixbuf (Style.BackgroundGC (State),
|
|
page.Icon, 0, 0, x, iconY,
|
|
page.Icon.Width,
|
|
page.Icon.Height,
|
|
Gdk.RgbDither.None, 0, 0);
|
|
x += page.Icon.Width + 1;
|
|
} else {
|
|
x = pageAlloc.X + (pageAlloc.Width - page.LayoutWidth) / 2;
|
|
}
|
|
|
|
y += (height - page.LayoutHeight) / 2;
|
|
if (page.Ellipsize) {
|
|
width = pageAlloc.Width - (page.Icon.Width + 1);
|
|
Pango.Layout layout = page.Layout;
|
|
EllipsizeLayout (layout, width);
|
|
Console.WriteLine ("ellLayout = {0}", layout.Text);
|
|
Style.PaintLayout (Style, GdkWindow, State,
|
|
true, args.Area, this, null,
|
|
x, y, layout);
|
|
} else {
|
|
Style.PaintLayout (Style, GdkWindow, State,
|
|
true, args.Area, this, null,
|
|
x, y, page.Layout);
|
|
}
|
|
}
|
|
|
|
return base.OnExposeEvent (args);
|
|
}
|
|
|
|
protected override void ForAll (bool include_internals, CallbackInvoker invoker)
|
|
{
|
|
foreach (CustomNotebookPage page in pages) {
|
|
invoker.Invoke (page.Child);
|
|
}
|
|
}
|
|
|
|
protected override void OnRealized ()
|
|
{
|
|
WidgetFlags |= WidgetFlags.Realized;
|
|
|
|
GdkWindow = ParentWindow;
|
|
Style = Style.Attach (GdkWindow);
|
|
}
|
|
|
|
protected override void OnSizeAllocated (Gdk.Rectangle allocation)
|
|
{
|
|
base.OnSizeAllocated (allocation);
|
|
|
|
if (pages.Count == 0)
|
|
return;
|
|
|
|
int bw = (int)BorderWidth;
|
|
|
|
Gdk.Rectangle childAlloc;
|
|
childAlloc.X = allocation.X + bw + Style.XThickness;
|
|
childAlloc.Y = allocation.Y + bw + Style.YThickness;
|
|
childAlloc.Width = Math.Max (1, allocation.Width - 2 * bw -
|
|
2 * Style.XThickness);
|
|
childAlloc.Height = Math.Max (1, allocation.Height - 2 * bw -
|
|
2 * Style.YThickness);
|
|
|
|
switch (TabPosition) {
|
|
case PositionType.Top:
|
|
childAlloc.Y += CurrentPage.Requisition.Height;
|
|
childAlloc.Height = Math.Max (1, childAlloc.Height -
|
|
CurrentPage.Requisition.Height);
|
|
break;
|
|
case PositionType.Bottom:
|
|
childAlloc.Height = Math.Max (1, childAlloc.Height -
|
|
CurrentPage.Requisition.Height);
|
|
break;
|
|
case PositionType.Left:
|
|
case PositionType.Right:
|
|
break;
|
|
}
|
|
|
|
foreach (CustomNotebookPage page in pages) {
|
|
page.Child.SizeAllocate (childAlloc);
|
|
}
|
|
|
|
// gtk_notebook_pages_allocate.
|
|
childAlloc.X = allocation.X + bw;
|
|
childAlloc.Y = allocation.Y + bw;
|
|
|
|
switch (TabPosition) {
|
|
case PositionType.Top:
|
|
childAlloc.Height = CurrentPage.Requisition.Height;
|
|
break;
|
|
case PositionType.Bottom:
|
|
childAlloc.Y = (allocation.Y + allocation.Height -
|
|
CurrentPage.Requisition.Height - bw);
|
|
childAlloc.Height = CurrentPage.Requisition.Height;
|
|
break;
|
|
case PositionType.Left:
|
|
case PositionType.Right:
|
|
break;
|
|
}
|
|
|
|
bool ellipsize = false;
|
|
int avgWidth = 0;
|
|
int tabX = childAlloc.X;
|
|
if (!scrollable) {
|
|
int tabWidth = 0;
|
|
foreach (CustomNotebookPage page in pages) {
|
|
tabWidth += page.Requisition.Width;
|
|
}
|
|
|
|
Console.WriteLine ("total tabwidth: {0}", tabWidth);
|
|
Console.WriteLine ("allocated width: {0}", childAlloc.Width);
|
|
|
|
if (tabWidth > childAlloc.Width) {
|
|
ellipsize = true;
|
|
avgWidth = childAlloc.Width / pages.Count;
|
|
tabWidth = childAlloc.Width;
|
|
Console.WriteLine ("average tabwidth: {0}", avgWidth);
|
|
|
|
int count = pages.Count;
|
|
foreach (CustomNotebookPage page in pages) {
|
|
if (page.Requisition.Width <= avgWidth) {
|
|
count--;
|
|
tabWidth -= page.Requisition.Width;
|
|
}
|
|
}
|
|
|
|
Console.WriteLine ("number of pages exceeding that: {0}", count);
|
|
Console.WriteLine ("space per page available: {0}", tabWidth / count);
|
|
|
|
// FIXME: check for TabPosition.
|
|
int maxWidth = tabWidth / count;
|
|
foreach (CustomNotebookPage page in pages) {
|
|
Gdk.Rectangle pageAlloc = page.Allocation;
|
|
pageAlloc.X = tabX;
|
|
pageAlloc.Y = childAlloc.Y;
|
|
|
|
if (page.Requisition.Width > maxWidth) {
|
|
pageAlloc.Width = maxWidth + tabOverlap;
|
|
page.Ellipsize = true;
|
|
} else {
|
|
pageAlloc.Width = page.Requisition.Width + tabOverlap;
|
|
}
|
|
|
|
pageAlloc.Height = childAlloc.Height;
|
|
tabX += pageAlloc.Width - tabOverlap;
|
|
|
|
if (page != CurrentPage) {
|
|
pageAlloc.Y += Style.YThickness;
|
|
pageAlloc.Height -= Style.YThickness;
|
|
}
|
|
|
|
page.Allocation = pageAlloc;
|
|
}
|
|
}
|
|
} else {
|
|
switch (TabPosition) {
|
|
case PositionType.Top:
|
|
case PositionType.Bottom:
|
|
foreach (CustomNotebookPage page in pages) {
|
|
Gdk.Rectangle pageAlloc = page.Allocation;
|
|
pageAlloc.X = tabX;
|
|
pageAlloc.Y = childAlloc.Y;
|
|
pageAlloc.Width = page.Requisition.Width + tabOverlap;
|
|
pageAlloc.Height = childAlloc.Height;
|
|
tabX += pageAlloc.Width - tabOverlap;
|
|
|
|
if (page != CurrentPage) {
|
|
pageAlloc.Y += Style.YThickness;
|
|
pageAlloc.Height -= Style.YThickness;
|
|
}
|
|
|
|
page.Allocation = pageAlloc;
|
|
}
|
|
break;
|
|
case PositionType.Left:
|
|
case PositionType.Right:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnSizeRequested (ref Requisition requisition)
|
|
{
|
|
requisition.Width = requisition.Height = 0;
|
|
|
|
foreach (CustomNotebookPage page in pages) {
|
|
if (!page.Child.Visible)
|
|
continue;
|
|
|
|
Requisition childReq = page.Child.SizeRequest ();
|
|
requisition.Width = Math.Max (requisition.Width, childReq.Width);
|
|
requisition.Height = Math.Max (requisition.Height, childReq.Height);
|
|
}
|
|
|
|
requisition.Width += 2 * Style.XThickness;
|
|
requisition.Height += 2 * Style.YThickness;
|
|
|
|
int tabWidth = 0;
|
|
int tabHeight = 0;
|
|
int tabMax = 0;
|
|
int padding;
|
|
foreach (CustomNotebookPage page in pages) {
|
|
Requisition pageReq;
|
|
if (page.Icon != null) {
|
|
pageReq.Width = page.Icon.Width + page.LayoutWidth +
|
|
Style.XThickness * 2;
|
|
pageReq.Height = Math.Max (page.Icon.Height, page.LayoutHeight) +
|
|
Style.YThickness * 2;
|
|
} else {
|
|
pageReq.Width = page.LayoutWidth + Style.XThickness * 2;
|
|
pageReq.Height = page.LayoutHeight + Style.YThickness * 2;
|
|
}
|
|
|
|
switch (TabPosition) {
|
|
case PositionType.Top:
|
|
case PositionType.Bottom:
|
|
pageReq.Height += (tabVBorder + FocusLineWidth) * 2;
|
|
tabHeight = Math.Max (tabHeight, pageReq.Height);
|
|
tabMax = Math.Max (tabMax, pageReq.Width);
|
|
break;
|
|
case PositionType.Left:
|
|
case PositionType.Right:
|
|
break;
|
|
}
|
|
|
|
page.Requisition = pageReq;
|
|
}
|
|
|
|
switch (TabPosition) {
|
|
case PositionType.Top:
|
|
case PositionType.Bottom:
|
|
padding = 2 * (tabCurvature + FocusLineWidth
|
|
+ tabHBorder) - tabOverlap;
|
|
tabMax += padding;
|
|
|
|
Requisition pageReq;
|
|
foreach (CustomNotebookPage page in pages) {
|
|
pageReq = page.Requisition;
|
|
pageReq.Width += padding;
|
|
tabWidth += pageReq.Width;
|
|
pageReq.Height = tabHeight;
|
|
page.Requisition = pageReq;
|
|
}
|
|
|
|
/*if (!Scrollable)
|
|
requisition.Width = Math.Max (requisition.Width,
|
|
tabWidth + tabOverlap);*/
|
|
requisition.Height += tabHeight;
|
|
break;
|
|
case PositionType.Left:
|
|
case PositionType.Right:
|
|
break;
|
|
}
|
|
|
|
requisition.Width += (int)BorderWidth * 2;
|
|
requisition.Height += (int)BorderWidth * 2;
|
|
}
|
|
}
|