protected override bool OnExposeEvent(Gdk.EventExpose args)
{
using (var context = Gdk.CairoHelper.Create(args.Window)) {
var scalef = GtkWorkarounds.GetScaleFactor(this);
context.LineWidth = 1;
var alloc = Allocation;
int width = alloc.Width;
int height = alloc.Height;
context.Rectangle(args.Area.X, args.Area.Y, args.Area.Width, args.Area.Height);
var backgroundColor = Styles.CodeCompletion.BackgroundColor.ToCairoColor();
var textColor = Styles.CodeCompletion.TextColor.ToCairoColor();
var categoryColor = Styles.CodeCompletion.CategoryColor.ToCairoColor();
context.SetSourceColor(backgroundColor);
context.Fill();
int xpos = iconTextSpacing;
int yPos = (int)-vadj.Value;
//when there are no matches, display a message to indicate that the completion list is still handling input
if (filteredItems.Count == 0)
{
context.Rectangle(0, yPos, width, height - yPos);
context.SetSourceColor(backgroundColor);
context.Stroke();
noMatchLayout.SetText(DataProvider.ItemCount == 0 ? NoSuggestionsMsg : NoMatchesMsg);
int lWidth, lHeight;
noMatchLayout.GetPixelSize(out lWidth, out lHeight);
context.SetSourceColor(textColor);
context.MoveTo((width - lWidth) / 2, yPos + (height - lHeight - yPos) / 2 - lHeight / 2);
Pango.CairoHelper.ShowLayout(context, noMatchLayout);
return(false);
}
Iterate(true, ref yPos, delegate(CategorizedCompletionItems category, int ypos) {
if (ypos >= height)
{
return;
}
if (ypos < -rowHeight)
{
return;
}
// window.DrawRectangle (this.Style.BackgroundGC (StateType.Insensitive), true, 0, yPos, width, rowHeight);
int x = 2;
if (category.CompletionCategory != null && !string.IsNullOrEmpty(category.CompletionCategory.Icon))
{
var icon = ImageService.GetIcon(category.CompletionCategory.Icon, IconSize.Menu);
context.DrawImage(this, icon, 0, ypos);
x = (int)icon.Width + 4;
}
context.Rectangle(0, ypos, Allocation.Width, rowHeight);
context.SetSourceColor(backgroundColor);
context.Fill();
// layout.SetMarkup ("<span weight='bold' foreground='#AAAAAA'>" + (category.CompletionCategory != null ? category.CompletionCategory.DisplayText : "Uncategorized") + "</span>");
// window.DrawLayout (textGCInsensitive, x - 1, ypos + 1 + (rowHeight - py) / 2, layout);
// layout.SetMarkup ("<span weight='bold'>" + (category.CompletionCategory != null ? category.CompletionCategory.DisplayText : "Uncategorized") + "</span>");
categoryLayout.SetMarkup((category.CompletionCategory != null ? category.CompletionCategory.DisplayText : "Uncategorized"));
int px, py;
categoryLayout.GetPixelSize(out px, out py);
context.MoveTo(x, ypos + (rowHeight - py) / 2);
context.SetSourceColor(categoryColor);
Pango.CairoHelper.ShowLayout(context, categoryLayout);
}, delegate(CategorizedCompletionItems curCategory, int item, int itemidx, int ypos) {
if (ypos >= height)
{
return(false);
}
if (ypos < -rowHeight)
{
return(true);
}
const int categoryModeItemIndenting = 0;
if (InCategoryMode && curCategory != null && curCategory.CompletionCategory != null)
{
xpos = iconTextSpacing + categoryModeItemIndenting;
}
else
{
xpos = iconTextSpacing;
}
bool drawIconAsSelected = SelectionEnabled && item == SelectedItemIndex;
string markup = DataProvider.HasMarkup(item) ? (DataProvider.GetMarkup(item) ?? "<null>") : GLib.Markup.EscapeText(DataProvider.GetText(item) ?? "<null>");
string description = DataProvider.GetDescription(item, drawIconAsSelected);
if (string.IsNullOrEmpty(description))
{
layout.SetMarkup(markup);
}
else
{
layout.SetMarkup(markup + " " + description);
}
string text = DataProvider.GetText(item);
if (!string.IsNullOrEmpty(text))
{
int [] matchIndices = DataProvider.GetHighlightedTextIndices(item);
if (matchIndices != null)
{
Pango.AttrList attrList = layout.Attributes ?? new Pango.AttrList();
for (int newSelection = 0; newSelection < matchIndices.Length; newSelection++)
{
int idx = matchIndices [newSelection];
var bold = new AttrWeight(Weight.Bold);
bold.StartIndex = (uint)idx;
bold.EndIndex = (uint)(idx + 1);
attrList.Insert(bold);
if (item != SelectedItemIndex)
{
var highlightColor = (item == SelectedItemIndex) ? Styles.CodeCompletion.SelectionHighlightColor : Styles.CodeCompletion.HighlightColor;
var fg = new AttrForeground((ushort)(highlightColor.Red * ushort.MaxValue), (ushort)(highlightColor.Green * ushort.MaxValue), (ushort)(highlightColor.Blue * ushort.MaxValue));
fg.StartIndex = (uint)idx;
fg.EndIndex = (uint)(idx + 1);
attrList.Insert(fg);
}
}
layout.Attributes = attrList;
}
}
Xwt.Drawing.Image icon = DataProvider.GetIcon(item);
int iconHeight, iconWidth;
if (icon != null)
{
if (drawIconAsSelected)
{
icon = icon.WithStyles("sel");
}
iconWidth = (int)icon.Width;
iconHeight = (int)icon.Height;
}
else if (!Gtk.Icon.SizeLookup(IconSize.Menu, out iconWidth, out iconHeight))
{
iconHeight = iconWidth = 24;
}
int wi, he, typos, iypos;
layout.GetPixelSize(out wi, out he);
typos = he < rowHeight ? ypos + (int)Math.Ceiling((rowHeight - he) / 2.0) : ypos;
if (scalef <= 1.0)
{
typos -= 1; // 1px up on non HiDPI
}
iypos = iconHeight < rowHeight ? ypos + (rowHeight - iconHeight) / 2 : ypos;
if (item == SelectedItemIndex)
{
var barStyle = SelectionEnabled ? Styles.CodeCompletion.SelectionBackgroundColor : Styles.CodeCompletion.SelectionBackgroundInactiveColor;
context.SetSourceColor(barStyle.ToCairoColor());
if (SelectionEnabled)
{
context.Rectangle(0, ypos, Allocation.Width, rowHeight);
context.Fill();
}
else
{
context.LineWidth++;
context.Rectangle(0.5, ypos + 0.5, Allocation.Width - 1, rowHeight - 1);
context.Stroke();
context.LineWidth--;
}
}
if (icon != null)
{
context.DrawImage(this, icon, xpos, iypos);
xpos += iconTextSpacing;
}
context.SetSourceColor((drawIconAsSelected ? Styles.CodeCompletion.SelectionTextColor : Styles.CodeCompletion.TextColor).ToCairoColor());
var textXPos = xpos + iconWidth + 2;
context.MoveTo(textXPos, typos);
layout.Width = (int)((Allocation.Width - textXPos) * Pango.Scale.PangoScale);
layout.Ellipsize = EllipsizeMode.End;
Pango.CairoHelper.ShowLayout(context, layout);
int textW, textH;
layout.GetPixelSize(out textW, out textH);
layout.Width = -1;
layout.Ellipsize = EllipsizeMode.None;
layout.SetMarkup("");
if (layout.Attributes != null)
{
layout.Attributes.Dispose();
layout.Attributes = null;
}
string rightText = DataProvider.GetRightSideDescription(item, drawIconAsSelected);
if (!string.IsNullOrEmpty(rightText))
{
layout.SetMarkup(rightText);
int w, h;
layout.GetPixelSize(out w, out h);
const int leftpadding = 8;
const int rightpadding = 3;
w += rightpadding;
w = Math.Min(w, Allocation.Width - textXPos - textW - leftpadding);
wi += w;
typos = h < rowHeight ? ypos + (rowHeight - h) / 2 : ypos;
if (scalef <= 1.0)
{
typos -= 1; // 1px up on non HiDPI
}
context.MoveTo(Allocation.Width - w, typos);
layout.Width = (int)(w * Pango.Scale.PangoScale);
layout.Ellipsize = EllipsizeMode.End;
Pango.CairoHelper.ShowLayout(context, layout);
layout.Width = -1;
layout.Ellipsize = EllipsizeMode.None;
}
if (Math.Min(maxListWidth, wi + xpos + iconWidth + 2) > listWidth)
{
WidthRequest = listWidth = Math.Min(maxListWidth, wi + xpos + iconWidth + 2 + iconTextSpacing);
win.ResetSizes();
}
else
{
//workaround for the vscrollbar display - the calculated width needs to be the width ofthe render region.
if (Allocation.Width < listWidth)
{
if (listWidth - Allocation.Width < 30)
{
WidthRequest = listWidth + listWidth - Allocation.Width;
win.ResetSizes();
}
}
}
return(true);
});
return(false);
}
}