DaSpamer Grandmaster Cheater Supreme Reputation: 52
Joined: 13 Sep 2011 Posts: 1578
|
Posted: Sun Feb 02, 2020 11:03 pm Post subject: ComboBox Suggested Items/Search functionality |
|
|
Well came up with a solution for drop-down list.
Having 50-80 items in a list and looking for specific ones can be annoying a bit especially when you don't exactly remember the name or when the autocomplete suggests a different ones without the option to view what other could partly match...
Anyway this is an example that narrows our item list by alphanumeric text, until user has found the target or has pressed enter, then it will reset the list.
When clicking on text area if a current text is a valid item it will clear it, clicking on dropdown will display the previous available items (if did not narrow it down to 1, otherwise the complete list);
basically take it as it is, and only modifiy/add stuff the onChange procedure at the doAction call area...
heres a demo try writing example or word and select item (narrow the list or just whatever...)
NOTE: tried to explain what was I doing and in general the logic behind this, if it does not work as you hoped to or didn't understand something feel free to post or pm me.
Code: | local myItems = { 'Some word';
'Another Word';
'Well heres a thing';
'Another thing';
'I got this';
'You got this';
'Just an Example';
'Example 1';
'Example2';
'Example 4 ';
'Example - 7 and some randoma$$ words that our capture dont care about';
};
itemList = itemList or createStringList();
itemList.clear();
-- prepare our static stringlist that holds our items;
-- NOTE: we shouldn't assign directly to checkbox items as we manipulate them by removing and adding items to it, and once remove we cannot retrieve it from itself..
for _,line in pairs(myItems) do
itemList.add(line);
end
local doAction = function(sender,item)
local isExample,number = item:lower():match('(example).-([%d]*)[%D]*$') -- capture example and attempt to capture number if exists;
if (isExample) then
local color = 0xFF;
local ratio = 0x10;
if (tonumber(number)) then
color = color - ratio * number;
end
sender.Color = tonumber(("%02X%02X%02X"):format(color,color,color),16);
elseif (item:lower():find('word',0,true)) then -- third paramter for plain
showMessage(item)
end
end
local f = createForm();
f.borderStyle = 'bsSizeable'
local cb = createComboBox(f);
cb.items = itemList; -- assign our items ...
cb.AutoDropDown = true; -- when user clicks on the text a dropdown with all our items opens...
cb.AutoComplete = false; -- just annoying and does not work good... we better just force our user to type the correct letter;
cb.DropDownCount = 15; -- suit as you think..
cb.top = 10;
cb.left = 10;
cb.width = f.width - cb.left * 2;
cb.onKeyPress = function(sender,key)
local _key = string.byte(key)
local text = sender.Text;
local items = sender.Items;
local itemsText = items.Text:lower();
if (_key == 8) then -- backspace.. so let's remove last character; we can't tell if user highlighted whole text and tries to delete it.. so we gonna delete the text whenever user has clicked..
_key = 0;
text = text:sub(0,#text-1);
elseif (_key == 13) then -- enter we do not really care
return nil;
else -- prevent from user write a letter that do not match of the items that left;
text = text .. key;
if (not itemsText:find(text:lower(),0,true)) then -- does not exist so abort;
return nil;
end
end
local ourText = text:lower();
-- if its a character or number then proceed checking and attempt to remove irrelevant items.. we can add here space and special symbols as well...
if ((#text >= 0) and ( (_key >= 0x30 and _key <=0x39) or ( _key >= 0x41 and _key <= 0x5A) or ( _key >= 0x61 and _key <=0x7A))) then
for i=items.Count-1,0,-1 do
if(not items.String[i]:lower():find(ourText,0,true)) then
items.delete(i)
end
end
else -- if its not a number or letter (backspace for example) try to re-add items from original list;
for i=0,itemList.Count-1 do
local cdl_s = itemList.String[i]:lower()
if(cdl_s:find(ourText,0,true) and not itemsText:find(cdl_s,0,true)) then
items.add(itemList.String[i])
end
end
end
sender.DropDownCount = 15; -- when removing item our DropDownCount changes but does not increase when adding back items... so we have to update it;
return key
end
cb.onKeyUp = function(sender,key)
if (key == 13) then -- let user to select first item by pressing enter;
sender.Text = sender.items.String[0];
sender.onChange(sender);
return nil;
end
return key
end
cb.onMouseUp = function(sender,button,x,y)
-- clean up text as user just pressed the text area if a valid item is selected...
-- it seems that the dropdown arrow is 18 pixel (win10 64bit fhd monitor wih normal dpi) so if we do not click it then clear the text;
if (button == 0 and sender.ItemIndex >= 0 and (x <= cb.width - 18)) then
sender.clear();
sender.Items = itemList;
end
end
cb.onChange = function(sender)
-- this part of the code tries to auto automatically select item if we have only 1 item available, and filteres invalid text given
if (sender.Items.Count == 1 ) then -- try to auto assign if only 1 item left..
local str = sender.items.String[0]
sender.Text = str;
sender.Items = itemList; -- re-assign our item list so we could dropdown and see items in the order we set it && and full item list...
elseif (sender.Items.Count > 1) then
sender.ItemIndex = sender.Items.indexOf(sender.Text); -- re update itemindex in case somewhat it has invalid text and a change event triggered;
end
if (sender.ItemIndex < 0) then -- do not contiue if we do not have valid item (probably manually assigned itemIndex or bad text)
return
end
-- Item successfully has been selected successfully now we can do our ting
-- Lets work with current item and call doAction that will either change our ComboBox color or display a message as we wrote above...
local text = sender.Text;
doAction(sender,text);
end |
Edit:
Removed some unnecessary actions..
_________________
|
|