internal static CompletionListFilterResult DefaultFilterItems(ICompletionDataList dataList, IReadOnlyList <int> currentFilteredItems, string oldCompletionString, string completionString, CompletionDataMatcher matcher = null) { List <int> filteredItems; var newCategories = new List <CategorizedCompletionItems> (); matcher = matcher ?? new CompletionDataMatcher { StringMatcher = CompletionMatcher.CreateCompletionMatcher(completionString), MatcherId = -1, MatchString = completionString }; if (oldCompletionString == null || !completionString.StartsWith(oldCompletionString, StringComparison.Ordinal)) { // We are filtering the list from scratch (not reusing previous results) // This is the most slow operation since we may have to filter a very large amount of items. // To improve performance, when there are many items, we try to parallelize the filtering // Use multiple threads when we can split the work in chunks of at least 4000 items. int numFilterThreads = Math.Max(Math.Min(dataList.Count / 4000, Environment.ProcessorCount / 2), 1); // When completion string is empty the matching algorithm is not executed, so there is no need to parallelize if (string.IsNullOrEmpty(completionString)) { numFilterThreads = 1; } filteredItems = new List <int> (); int slice = dataList.Count / numFilterThreads; var results = new(Task, List <int>) [numFilterThreads - 1];
public void FilterWords() { filteredItems.Clear(); categories.Clear(); var matcher = CompletionMatcher.CreateCompletionMatcher(CompletionString); for (int newSelection = 0; newSelection < win.DataProvider.ItemCount; newSelection++) { if (string.IsNullOrEmpty(CompletionString) || matcher.IsMatch(win.DataProvider.GetText(newSelection))) { CompletionCategory completionCategory = win.DataProvider.GetCompletionCategory(newSelection); GetCategory(completionCategory).Items.Add(filteredItems.Count); filteredItems.Add(newSelection); } } categories.Sort(delegate(Category left, Category right) { return(right.CompletionCategory != null ? right.CompletionCategory.CompareTo(left.CompletionCategory) : -1); }); SelectFirstItemInCategory(); CalcVisibleRows(); UpdatePage(); OnWordsFiltered(EventArgs.Empty); }
public void FilterWords() { categories.Clear(); var matcher = CompletionMatcher.CreateCompletionMatcher(CompletionString); if (oldCompletionString == null || !CompletionString.StartsWith(oldCompletionString)) { filteredItems.Clear(); for (int newSelection = 0; newSelection < win.DataProvider.ItemCount; newSelection++) { if (string.IsNullOrEmpty(CompletionString) || matcher.IsMatch(win.DataProvider.GetText(newSelection))) { var completionCategory = win.DataProvider.GetCompletionCategory(newSelection); GetCategory(completionCategory).Items.Add(newSelection); filteredItems.Add(newSelection); } } } else { var oldItems = filteredItems; filteredItems = new List <int> (); foreach (int newSelection in oldItems) { if (string.IsNullOrEmpty(CompletionString) || matcher.IsMatch(win.DataProvider.GetText(newSelection))) { var completionCategory = win.DataProvider.GetCompletionCategory(newSelection); GetCategory(completionCategory).Items.Add(newSelection); filteredItems.Add(newSelection); } } } filteredItems.Sort(delegate(int left, int right) { var lt = win.DataProvider.GetText(left); var rt = win.DataProvider.GetText(right); /* int r1; * int r2; * matcher.CalcMatchRank (lt, out r1); * matcher.CalcMatchRank (rt, out r2); * if (r1 == r2) { * if (lt.Length != rt.Length) * return lt.Length.CompareTo (rt.Length);*/ return(lt.CompareTo(rt)); /* } * return r1.CompareTo (r2);*/ }); categories.Sort(delegate(Category left, Category right) { return(left.CompletionCategory != null ? left.CompletionCategory.CompareTo(right.CompletionCategory) : -1); }); SelectFirstItemInCategory(); CalcVisibleRows(); UpdatePage(); OnWordsFiltered(EventArgs.Empty); oldCompletionString = CompletionString; }
public void FilterWords() { categories.Clear(); var matcher = CompletionMatcher.CreateCompletionMatcher(CompletionString); if (oldCompletionString == null || !CompletionString.StartsWith(oldCompletionString)) { filteredItems.Clear(); for (int newSelection = 0; newSelection < win.DataProvider.ItemCount; newSelection++) { if (string.IsNullOrEmpty(CompletionString) || matcher.IsMatch(win.DataProvider.GetText(newSelection))) { var completionCategory = win.DataProvider.GetCompletionCategory(newSelection); GetCategory(completionCategory).Items.Add(newSelection); filteredItems.Add(newSelection); } } } else { var oldItems = filteredItems; filteredItems = new List <int> (); foreach (int newSelection in oldItems) { if (string.IsNullOrEmpty(CompletionString) || matcher.IsMatch(win.DataProvider.GetText(newSelection))) { var completionCategory = win.DataProvider.GetCompletionCategory(newSelection); GetCategory(completionCategory).Items.Add(newSelection); filteredItems.Add(newSelection); } } } filteredItems.Sort(delegate(int left, int right) { var lt = win.DataProvider.GetText(left); var rt = win.DataProvider.GetText(right); var result = lt.CompareTo(rt); if (result == 0) { return(right.CompareTo(left)); } return(result); }); categories.Sort(delegate(Category left, Category right) { return(left.CompletionCategory != null ? left.CompletionCategory.CompareTo(right.CompletionCategory) : -1); }); SelectFirstItemInCategory(); CalcVisibleRows(); SetAdjustments(); OnWordsFiltered(EventArgs.Empty); oldCompletionString = CompletionString; }
/// <summary> /// Gets a code completion matcher for the provided string. It will try to reuse an existing one. /// </summary> CompletionDataMatcher GetCompletionDataMatcher(string partialWord) { // It keeps the last used matcher in a field, and will reuse it if the requested word doesn't change. // 'partialWord' doesn't usually change during the lifetime of CompletionDataList, so in general // the same matcher will be used by all calculations required for a key press if (lastMatcher != null && partialWord == lastMatcher.MatchString) { return(lastMatcher); } return(lastMatcher = new CompletionDataMatcher { MatcherId = lastMatcherId++, StringMatcher = CompletionMatcher.CreateCompletionMatcher(partialWord), MatchString = partialWord }); }
public WordComparer(string filterWord) { this.filterWord = filterWord ?? ""; matcher = CompletionMatcher.CreateCompletionMatcher(filterWord); }
static CompletionListFilterResult DefaultFilterWords(ICompletionDataList dataList, List <int> filteredItems, string oldCompletionString, string CompletionString) { var newCategories = new List <CategorizedCompletionItems> (); var matcher = CompletionMatcher.CreateCompletionMatcher(CompletionString); if (oldCompletionString == null || !CompletionString.StartsWith(oldCompletionString, StringComparison.Ordinal)) { filteredItems.Clear(); for (int newSelection = 0; newSelection < dataList.Count; newSelection++) { if (string.IsNullOrEmpty(CompletionString) || matcher.IsMatch(dataList [newSelection].DisplayText)) { var completionCategory = dataList [newSelection].CompletionCategory; GetCategory(newCategories, completionCategory).Items.Add(newSelection); filteredItems.Add(newSelection); } } } else { var oldItems = filteredItems; filteredItems = new List <int> (); foreach (int newSelection in oldItems) { if (string.IsNullOrEmpty(CompletionString) || matcher.IsMatch(dataList [newSelection].DisplayText)) { var completionCategory = dataList [newSelection].CompletionCategory; GetCategory(newCategories, completionCategory).Items.Add(newSelection); filteredItems.Add(newSelection); } } } filteredItems.Sort(delegate(int left, int right) { int rank1, rank2; var data1 = dataList [left]; var data2 = dataList [right]; if (data1 == null || data2 == null) { return(0); } if (data1.PriorityGroup != data2.PriorityGroup) { return(data2.PriorityGroup.CompareTo(data1.PriorityGroup)); } if (string.IsNullOrEmpty(CompletionString)) { return(CompareTo(dataList, left, right)); } if (!matcher.CalcMatchRank(data1.CompletionText, out rank1)) { return(0); } if (!matcher.CalcMatchRank(data2.CompletionText, out rank2)) { return(0); } return(rank2.CompareTo(rank1)); }); // put the item from a lower priority group with the highest match rank always to position #2 if (filteredItems.Count > 0) { int idx = 0; int rank; var data = dataList[filteredItems [0]]; int firstGrp = data.PriorityGroup; matcher.CalcMatchRank(data.CompletionText, out rank); for (int i = 1; i < filteredItems.Count; i++) { var curData = dataList[filteredItems [i]]; if (curData.PriorityGroup == firstGrp) { continue; } int curRank; matcher.CalcMatchRank(curData.CompletionText, out curRank); if (curRank > rank) { idx = i; rank = curRank; } } if (idx != 0) { var tmp = filteredItems [idx]; for (int i = idx; i > 1; i--) { filteredItems [i] = filteredItems [i - 1]; } filteredItems [1] = tmp; } } newCategories.Sort(delegate(CategorizedCompletionItems left, CategorizedCompletionItems right) { if (left.CompletionCategory == null) { return(1); } if (right.CompletionCategory == null) { return(-1); } return(left.CompletionCategory.CompareTo(right.CompletionCategory)); }); return(new CompletionListFilterResult(filteredItems, newCategories)); }
protected int FindMatchedEntry(string partialWord, out bool hasMismatches) { // default - word with highest match rating in the list. hasMismatches = true; int idx = -1; StringMatcher matcher = null; if (!string.IsNullOrEmpty(partialWord)) { matcher = CompletionMatcher.CreateCompletionMatcher(partialWord); string bestWord = null; int bestRank = int.MinValue; int bestIndex = 0; int bestIndexPriority = int.MinValue; for (int i = 0; i < list.filteredItems.Count; i++) { int index = list.filteredItems [i]; var data = DataProvider.GetCompletionData(index); if (bestIndexPriority > data.PriorityGroup) { continue; } string text = data.DisplayText; int rank; if (!matcher.CalcMatchRank(text, out rank)) { continue; } if (rank > bestRank || data.PriorityGroup > bestIndexPriority) { bestWord = text; bestRank = rank; bestIndex = i; bestIndexPriority = data.PriorityGroup; } } if (bestWord != null) { idx = bestIndex; hasMismatches = false; // exact match found. if (string.Compare(bestWord, partialWord ?? "", true) == 0) { return(idx); } } } CompletionData currentData; int bestMruIndex; if (idx >= 0) { currentData = completionDataList [list.filteredItems [idx]]; bestMruIndex = cache.GetIndex(currentData); } else { bestMruIndex = int.MaxValue; currentData = null; } for (int i = 0; i < list.filteredItems.Count; i++) { var mruData = completionDataList [list.filteredItems [i]]; int curMruIndex = cache.GetIndex(mruData); if (curMruIndex == 1) { continue; } if (curMruIndex < bestMruIndex) { int r1 = 0, r2 = 0; if (currentData == null || matcher != null && matcher.CalcMatchRank(mruData.DisplayText, out r1) && matcher.CalcMatchRank(currentData.DisplayText, out r2)) { if (r1 >= r2 || PartialWord.Length <= 1) { bestMruIndex = curMruIndex; idx = i; currentData = mruData; } } } } return(idx); }
public virtual int [] GetHighlightedIndices(CompletionData completionData, string completionString) { var matcher = CompletionMatcher.CreateCompletionMatcher(completionString); return(matcher.GetMatch(completionData.DisplayText)); }
public virtual CompletionSelectionStatus FindMatchedEntry(ICompletionDataList completionDataList, MruCache cache, string partialWord, List <int> filteredItems) { // default - word with highest match rating in the list. int idx = -1; if (DefaultCompletionString != null && DefaultCompletionString.StartsWith(partialWord, StringComparison.OrdinalIgnoreCase)) { partialWord = DefaultCompletionString; } StringMatcher matcher = null; if (!string.IsNullOrEmpty(partialWord)) { matcher = CompletionMatcher.CreateCompletionMatcher(partialWord); string bestWord = null; int bestRank = int.MinValue; int bestIndex = 0; int bestIndexPriority = int.MinValue; for (int i = 0; i < filteredItems.Count; i++) { int index = filteredItems [i]; var data = completionDataList [index]; if (bestIndexPriority > data.PriorityGroup) { continue; } string text = data.DisplayText; int rank; if (!matcher.CalcMatchRank(text, out rank)) { continue; } if (rank > bestRank || data.PriorityGroup > bestIndexPriority) { bestWord = text; bestRank = rank; bestIndex = i; bestIndexPriority = data.PriorityGroup; } } if (bestWord != null) { idx = bestIndex; // exact match found. if (string.Compare(bestWord, partialWord ?? "", true) == 0) { return(new CompletionSelectionStatus(idx)); } } } CompletionData currentData; int bestMruIndex; if (idx >= 0) { currentData = completionDataList [filteredItems [idx]]; bestMruIndex = cache.GetIndex(currentData); } else { bestMruIndex = int.MaxValue; currentData = null; } for (int i = 0; i < filteredItems.Count; i++) { var mruData = completionDataList [filteredItems [i]]; int curMruIndex = cache.GetIndex(mruData); if (curMruIndex == 1) { continue; } if (curMruIndex < bestMruIndex) { int r1 = 0, r2 = 0; if (currentData == null || matcher != null && matcher.CalcMatchRank(mruData.DisplayText, out r1) && matcher.CalcMatchRank(currentData.DisplayText, out r2)) { if (r1 >= r2 || partialWord.Length == 0 || partialWord.Length == 1 && mruData.DisplayText [0] == partialWord [0]) { bestMruIndex = curMruIndex; idx = i; currentData = mruData; } } } } return(new CompletionSelectionStatus(idx)); }
protected int FindMatchedEntry(string partialWord, out bool hasMismatches) { // default - word with highest match rating in the list. hasMismatches = true; if (partialWord == null) { return(-1); } int idx = -1; var matcher = CompletionMatcher.CreateCompletionMatcher(partialWord); string bestWord = null; int bestRank = int.MinValue; int bestIndex = 0; if (!string.IsNullOrEmpty(partialWord)) { for (int i = 0; i < list.filteredItems.Count; i++) { int index = list.filteredItems[i]; string text = DataProvider.GetText(index); int rank; if (!matcher.CalcMatchRank(text, out rank)) { continue; } if (rank > bestRank) { bestWord = text; bestRank = rank; bestIndex = i; } } } if (bestWord != null) { idx = bestIndex; hasMismatches = false; // exact match found. if (string.Compare(bestWord, partialWord ?? "", true) == 0) { return(idx); } } if (string.IsNullOrEmpty(partialWord) || partialWord.Length <= 2) { // Search for history matches. string historyWord; if (wordHistory.TryGetValue(partialWord, out historyWord)) { for (int xIndex = 0; xIndex < list.filteredItems.Count; xIndex++) { string currentWord = DataProvider.GetCompletionText(list.filteredItems[xIndex]); if (currentWord == historyWord) { idx = xIndex; break; } } } } return(idx); }
public void FilterWords() { var newCategories = new List <Category> (); var matcher = CompletionMatcher.CreateCompletionMatcher(CompletionString); if (oldCompletionString == null || !CompletionString.StartsWith(oldCompletionString, StringComparison.Ordinal)) { filteredItems.Clear(); for (int newSelection = 0; newSelection < win.DataProvider.ItemCount; newSelection++) { if (string.IsNullOrEmpty(CompletionString) || matcher.IsMatch(win.DataProvider.GetText(newSelection))) { var completionCategory = win.DataProvider.GetCompletionCategory(newSelection); GetCategory(newCategories, completionCategory).Items.Add(newSelection); filteredItems.Add(newSelection); } } } else { var oldItems = filteredItems; filteredItems = new List <int> (); foreach (int newSelection in oldItems) { if (string.IsNullOrEmpty(CompletionString) || matcher.IsMatch(win.DataProvider.GetText(newSelection))) { var completionCategory = win.DataProvider.GetCompletionCategory(newSelection); GetCategory(newCategories, completionCategory).Items.Add(newSelection); filteredItems.Add(newSelection); } } } filteredItems.Sort(delegate(int left, int right) { int rank1, rank2; var data1 = win.DataProvider.GetCompletionData(left); var data2 = win.DataProvider.GetCompletionData(right); if (data1 == null || data2 == null) { return(0); } if (data1.PriorityGroup != data2.PriorityGroup) { return(data2.PriorityGroup.CompareTo(data1.PriorityGroup)); } if (string.IsNullOrEmpty(CompletionString)) { return(win.DataProvider.CompareTo(left, right)); } if (!matcher.CalcMatchRank(data1.CompletionText, out rank1)) { return(0); } if (!matcher.CalcMatchRank(data2.CompletionText, out rank2)) { return(0); } return(rank2.CompareTo(rank1)); }); // put the item from a lower priority group with the highest match rank always to position #2 if (filteredItems.Count > 0) { int idx = 0; int rank; var data = win.DataProvider.GetCompletionData(filteredItems [0]); int firstGrp = data.PriorityGroup; matcher.CalcMatchRank(data.CompletionText, out rank); for (int i = 1; i < filteredItems.Count; i++) { var curData = win.DataProvider.GetCompletionData(filteredItems [i]); if (curData.PriorityGroup == firstGrp) { continue; } int curRank; matcher.CalcMatchRank(curData.CompletionText, out curRank); if (curRank > rank) { idx = i; rank = curRank; } } if (idx != 0) { var tmp = filteredItems [idx]; for (int i = idx; i > 1; i--) { filteredItems [i] = filteredItems [i - 1]; } filteredItems [1] = tmp; } } newCategories.Sort(delegate(Category left, Category right) { if (left.CompletionCategory == null) { return(1); } if (right.CompletionCategory == null) { return(-1); } return(left.CompletionCategory.CompareTo(right.CompletionCategory)); }); categories = newCategories; //SelectFirstItemInCategory (); CalcVisibleRows(); SetAdjustments(); OnWordsFiltered(EventArgs.Empty); oldCompletionString = CompletionString; }
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(win.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); } var matcher = CompletionMatcher.CreateCompletionMatcher(CompletionString); Iterate(true, ref yPos, delegate(Category 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(Category 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; } string markup = win.DataProvider.HasMarkup(item) ? (win.DataProvider.GetMarkup(item) ?? "<null>") : GLib.Markup.EscapeText(win.DataProvider.GetText(item) ?? "<null>"); string description = win.DataProvider.GetDescription(item, item == SelectedItem); if (string.IsNullOrEmpty(description)) { layout.SetMarkup(markup); } else { layout.SetMarkup(markup + " " + description); } string text = win.DataProvider.GetText(item); if (!string.IsNullOrEmpty(text)) { int [] matchIndices = matcher.GetMatch(text); 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 != SelectedItem) { var highlightColor = (item == SelectedItem) ? 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 = win.DataProvider.GetIcon(item); int iconHeight, iconWidth; if (icon != null) { if (item == SelectedItem) { 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 == SelectedItem) { var barStyle = SelectionEnabled ? Styles.CodeCompletion.SelectionBackgroundColor : Styles.CodeCompletion.SelectionBackgroundInactiveColor; context.Rectangle(0, ypos, Allocation.Width, rowHeight); context.SetSourceColor(barStyle.ToCairoColor()); context.Fill(); } if (icon != null) { context.DrawImage(this, icon, xpos, iypos); xpos += iconTextSpacing; } context.SetSourceColor((item == SelectedItem ? 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 = win.DataProvider.GetRightSideDescription(item, item == SelectedItem); 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); } }
protected override bool OnExposeEvent(Gdk.EventExpose args) { Gdk.Window window = args.Window; var alloc = Allocation; int width = alloc.Width; int height = alloc.Height; int lineWidth = width - margin * 2; int xpos = margin + padding; int yPos = margin; if (PreviewCompletionString) { layout.SetText(string.IsNullOrEmpty(CompletionString) ? MonoDevelop.Core.GettextCatalog.GetString("Select template") : CompletionString); int wi, he; layout.GetPixelSize(out wi, out he); window.DrawRectangle(this.Style.BaseGC(StateType.Insensitive), true, margin, yPos, lineWidth, he + padding); window.DrawLayout(string.IsNullOrEmpty(CompletionString) ? this.Style.TextGC(StateType.Insensitive) : this.Style.TextGC(StateType.Normal), xpos, yPos, layout); yPos += rowHeight; } //when there are no matches, display a message to indicate that the completion list is still handling input if (filteredItems.Count == 0) { Gdk.GC gc = new Gdk.GC(window); gc.RgbFgColor = new Gdk.Color(0xff, 0xbc, 0xc1); window.DrawRectangle(gc, true, 0, yPos, width, height - yPos); layout.SetText(win.DataProvider.ItemCount == 0? NoSuggestionsMsg : NoMatchesMsg); int lWidth, lHeight; layout.GetPixelSize(out lWidth, out lHeight); gc.RgbFgColor = new Gdk.Color(0, 0, 0); window.DrawLayout(gc, (width - lWidth) / 2, yPos + (height - lHeight - yPos) / 2, layout); gc.Dispose(); return(true); } var textGCInsensitive = this.Style.TextGC(StateType.Insensitive); var textGCNormal = this.Style.TextGC(StateType.Normal); var fgGCNormal = this.Style.ForegroundGC(StateType.Normal); var matcher = CompletionMatcher.CreateCompletionMatcher(CompletionString); var highlightColor = HighlightColor; Iterate(true, ref yPos, delegate(Category category, int ypos) { if (ypos >= height - margin) { return; } // window.DrawRectangle (this.Style.BackgroundGC (StateType.Insensitive), true, 0, yPos, width, rowHeight); Gdk.Pixbuf icon = ImageService.GetPixbuf(category.CompletionCategory.Icon, IconSize.Menu); window.DrawPixbuf(fgGCNormal, icon, 0, 0, margin, ypos, icon.Width, icon.Height, Gdk.RgbDither.None, 0, 0); layout.SetMarkup("<span weight='bold'>" + category.CompletionCategory.DisplayText + "</span>"); window.DrawLayout(textGCInsensitive, icon.Width + 4, ypos, layout); layout.SetMarkup(""); }, delegate(Category curCategory, int item, int ypos) { if (ypos >= height - margin) { return(false); } int itemIndex = filteredItems[item]; if (InCategoryMode && curCategory != null && curCategory.CompletionCategory != null) { xpos = margin + padding + 8; } else { xpos = margin + padding; } string markup = win.DataProvider.HasMarkup(itemIndex) ? (win.DataProvider.GetMarkup(itemIndex) ?? "<null>") : GLib.Markup.EscapeText(win.DataProvider.GetText(itemIndex) ?? "<null>"); string description = win.DataProvider.GetDescription(itemIndex); if (string.IsNullOrEmpty(description)) { layout.SetMarkup(markup); } else { if (item == selection) { layout.SetMarkup(markup + " " + description); } else { layout.SetMarkup(markup + " <span foreground=\"darkgray\">" + description + "</span>"); } } int mw, mh; layout.GetPixelSize(out mw, out mh); if (mw > listWidth) { WidthRequest = listWidth = mw; win.WidthRequest = win.Allocation.Width + mw - width; win.QueueResize(); } string text = win.DataProvider.GetText(itemIndex); if ((!SelectionEnabled || item != selection) && !string.IsNullOrEmpty(text)) { int[] matchIndices = matcher.GetMatch(text); if (matchIndices != null) { Pango.AttrList attrList = layout.Attributes ?? new Pango.AttrList(); for (int newSelection = 0; newSelection < matchIndices.Length; newSelection++) { int idx = matchIndices[newSelection]; Pango.AttrForeground fg = new Pango.AttrForeground(highlightColor.Red, highlightColor.Green, highlightColor.Blue); fg.StartIndex = (uint)idx; fg.EndIndex = (uint)(idx + 1); attrList.Insert(fg); } layout.Attributes = attrList; } } Gdk.Pixbuf icon = win.DataProvider.GetIcon(itemIndex); int iconHeight, iconWidth; if (icon != null) { iconWidth = icon.Width; iconHeight = icon.Height; } else if (!Gtk.Icon.SizeLookup(Gtk.IconSize.Menu, out iconWidth, out iconHeight)) { iconHeight = iconWidth = 24; } int wi, he, typos, iypos; layout.GetPixelSize(out wi, out he); typos = he < rowHeight ? ypos + (rowHeight - he) / 2 : ypos; iypos = iconHeight < rowHeight ? ypos + (rowHeight - iconHeight) / 2 : ypos; if (item == selection) { if (SelectionEnabled) { window.DrawRectangle(this.Style.BaseGC(StateType.Selected), true, margin, ypos, lineWidth, he + padding); window.DrawLayout(this.Style.TextGC(StateType.Selected), xpos + iconWidth + 2, typos, layout); } else { window.DrawRectangle(this.Style.DarkGC(StateType.Prelight), false, margin, ypos, lineWidth - 1, he + padding - 1); window.DrawLayout(textGCNormal, xpos + iconWidth + 2, typos, layout); } } else { window.DrawLayout(textGCNormal, xpos + iconWidth + 2, typos, layout); } if (icon != null) { window.DrawPixbuf(fgGCNormal, icon, 0, 0, xpos, iypos, iconWidth, iconHeight, Gdk.RgbDither.None, 0, 0); } layout.SetMarkup(""); if (layout.Attributes != null) { layout.Attributes.Dispose(); layout.Attributes = null; } return(true); }); /* * int n = 0; * while (ypos < winHeight - margin && (page + n) < filteredItems.Count) { * * bool hasMarkup = win.DataProvider.HasMarkup (filteredItems[page + n]); * if (hasMarkup) { * layout.SetMarkup (win.DataProvider.GetMarkup (filteredItems[page + n]) ?? "<null>"); * } else { * layout.SetText (win.DataProvider.GetText (filteredItems[page + n]) ?? "<null>"); * } * string text = win.DataProvider.GetText (filteredItems[page + n]); * if ((!SelectionEnabled || page + n != selection) && !string.IsNullOrEmpty (text)) { * int[] matchIndices = Match (CompletionString, text); * if (matchIndices != null) { * Pango.AttrList attrList = layout.Attributes ?? new Pango.AttrList (); * for (int newSelection = 0; newSelection < matchIndices.Length; newSelection++) { * int idx = matchIndices[newSelection]; * Pango.AttrForeground fg = new Pango.AttrForeground (0, 0, ushort.MaxValue); * fg.StartIndex = (uint)idx; * fg.EndIndex = (uint)(idx + 1); * attrList.Insert (fg); * } * layout.Attributes = attrList; * } * } * * Gdk.Pixbuf icon = win.DataProvider.GetIcon (filteredItems[page + n]); * int iconHeight, iconWidth; * if (icon != null) { * iconWidth = icon.Width; * iconHeight = icon.Height; * } else if (!Gtk.Icon.SizeLookup (Gtk.IconSize.Menu, out iconWidth, out iconHeight)) { * iconHeight = iconWidth = 24; * } * * int wi, he, typos, iypos; * layout.GetPixelSize (out wi, out he); * typos = he < rowHeight ? ypos + (rowHeight - he) / 2 : ypos; * iypos = iconHeight < rowHeight ? ypos + (rowHeight - iconHeight) / 2 : ypos; * if (page + n == selection) { * if (SelectionEnabled) { * window.DrawRectangle (this.Style.BaseGC (StateType.Selected), true, margin, ypos, lineWidth, he + padding); * window.DrawLayout (this.Style.TextGC (StateType.Selected), xpos + iconWidth + 2, typos, layout); * } else { * window.DrawRectangle (this.Style.DarkGC (StateType.Prelight), false, margin, ypos, lineWidth - 1, he + padding - 1); * window.DrawLayout (this.Style.TextGC (StateType.Normal), xpos + iconWidth + 2, typos, layout); * } * } else * window.DrawLayout (this.Style.TextGC (StateType.Normal), xpos + iconWidth + 2, typos, layout); * if (icon != null) * window.DrawPixbuf (this.Style.ForegroundGC (StateType.Normal), icon, 0, 0, xpos, iypos, iconWidth, iconHeight, Gdk.RgbDither.None, 0, 0); * ypos += rowHeight; * n++; * if (hasMarkup) * layout.SetMarkup (string.Empty); * if (layout.Attributes != null) { * layout.Attributes.Dispose (); * layout.Attributes = null; * } * } */ return(true); }
protected override bool OnExposeEvent(Gdk.EventExpose args) { using (var context = Gdk.CairoHelper.Create(args.Window)) { 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); context.Color = this.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.Color = backgroundColor; context.Stroke(); noMatchLayout.SetText(win.DataProvider.ItemCount == 0 ? NoSuggestionsMsg : NoMatchesMsg); int lWidth, lHeight; noMatchLayout.GetPixelSize(out lWidth, out lHeight); context.Color = textColor; context.MoveTo((width - lWidth) / 2, yPos + (height - lHeight - yPos) / 2 - lHeight); PangoCairoHelper.ShowLayout(context, noMatchLayout); return(false); } var matcher = CompletionMatcher.CreateCompletionMatcher(CompletionString); Iterate(true, ref yPos, delegate(Category 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.GetPixbuf(category.CompletionCategory.Icon, IconSize.Menu); Gdk.CairoHelper.SetSourcePixbuf(context, icon, 0, ypos); context.Paint(); x = icon.Width + 4; } context.Rectangle(0, ypos, Allocation.Width, rowHeight); context.Color = 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.Color = textColor; PangoCairoHelper.ShowLayout(context, categoryLayout); }, delegate(Category 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; } string markup = win.DataProvider.HasMarkup(item) ? (win.DataProvider.GetMarkup(item) ?? "<null>") : GLib.Markup.EscapeText(win.DataProvider.GetText(item) ?? "<null>"); string description = win.DataProvider.GetDescription(item); if (string.IsNullOrEmpty(description)) { layout.SetMarkup(markup); } else { if (item == SelectedItem) { layout.SetMarkup(markup + " " + description); } else { layout.SetMarkup(markup + " <span foreground=\"darkgray\">" + description + "</span>"); } } string text = win.DataProvider.GetText(item); if (!string.IsNullOrEmpty(text)) { int[] matchIndices = matcher.GetMatch(text); if (matchIndices != null) { Pango.AttrList attrList = layout.Attributes ?? new Pango.AttrList(); for (int newSelection = 0; newSelection < matchIndices.Length; newSelection++) { int idx = matchIndices [newSelection]; var fg = new AttrForeground((ushort)(highlightColor.R * ushort.MaxValue), (ushort)(highlightColor.G * ushort.MaxValue), (ushort)(highlightColor.B * ushort.MaxValue)); fg.StartIndex = (uint)idx; fg.EndIndex = (uint)(idx + 1); attrList.Insert(fg); } layout.Attributes = attrList; } } Gdk.Pixbuf icon = win.DataProvider.GetIcon(item); int iconHeight, iconWidth; if (icon != null) { iconWidth = icon.Width; iconHeight = icon.Height; } else if (!Gtk.Icon.SizeLookup(Gtk.IconSize.Menu, out iconWidth, out iconHeight)) { iconHeight = iconWidth = 24; } int wi, he, typos, iypos; layout.GetPixelSize(out wi, out he); typos = he < rowHeight ? ypos + (rowHeight - he) / 2 : ypos; iypos = iconHeight < rowHeight ? ypos + (rowHeight - iconHeight) / 2 : ypos; if (item == SelectedItem) { context.Rectangle(0, ypos, Allocation.Width, rowHeight / 2); context.Color = SelectionEnabled ? selectedItemColor.Foreground : selectedItemInactiveColor.Background; context.Fill(); context.Rectangle(0, ypos + rowHeight / 2, Allocation.Width, rowHeight / 2); context.Color = SelectionEnabled ? selectedItemColor.Background : selectedItemInactiveColor.Background; context.Fill(); context.Rectangle(0.5, ypos + 0.5, Allocation.Width - 1, rowHeight - 1); if (!SelectionEnabled) { context.SetDash(new double[] { 4, 4 }, 0); } context.Color = SelectionEnabled ? selectionBorderColor : selectionBorderInactiveColor; context.Stroke(); } if (icon != null) { Gdk.CairoHelper.SetSourcePixbuf(context, icon, xpos, iypos); context.Paint(); xpos += iconTextSpacing; } context.Color = textColor; context.MoveTo(xpos + iconWidth + 2, typos); PangoCairoHelper.ShowLayout(context, layout); if (wi + xpos + iconWidth + 2 > listWidth) { WidthRequest = listWidth = 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(); } } } layout.SetMarkup(""); if (layout.Attributes != null) { layout.Attributes.Dispose(); layout.Attributes = null; } return(true); }); return(false); } }