Open dmknght opened 4 years ago
A working C code would be helpful of course.
The first error is very easy, put
discard init(val, gtype)
in front of the foor loop.
For the other error with
gtk_entry_set_text: assertion 'text != NULL' failed
I should know more about all the listview stuff. I read about it in the Krause book 12 years ago, I should read it again. Well I will see what I can do, maybe I have to ask Mr Bassi again...
You seems to be using
https://developer.gnome.org/gtk3/stable/GtkComboBox.html
that is really hard. May
https://developer.gnome.org/gtk3/stable/GtkComboBoxText.html
be sufficient for your tasks? I was going to make an example for GtkComboBoxText, but maybe will delay it to next winter, as we have really not that many GTK users currently.
For your example, I have no good idea what is wrong, I would have to look for a working C example first.
I think I have to stop for today. You linked to
That is really very advanced GTK use, and it is more than 3 years old, maybe it will not work with current GTK. We should better use simpler GTK examples which are based on well working official C examples.
A working C code would be helpful of course.
The first error is very easy, put
discard init(val, gtype)
in front of the foor loop.
For the other error with
gtk_entry_set_text: assertion 'text != NULL' failed
I should know more about all the listview stuff. I read about it in the Krause book 12 years ago, I should read it again. Well I will see what I can do, maybe I have to ask Mr Bassi again...
Thank you. This fixed the first problem for me.
You seems to be using
https://developer.gnome.org/gtk3/stable/GtkComboBox.html
that is really hard. May
https://developer.gnome.org/gtk3/stable/GtkComboBoxText.html
be sufficient for your tasks? I was going to make an example for GtkComboBoxText, but maybe will delay it to next winter, as we have really not that many GTK users currently.
For your example, I have no good idea what is wrong, I would have to look for a working C example first.
From what i understand it needs to use ListStore as its model (honestly i don't understand what the hell is it) and it needs to use the newComboBoxWithModelAndEntry()
. I've tested newComboBoxTextWithEntry()
and the completion works but the combo box still doesn't show the text. I'm having solution for it but it might be bad.
The python code runs fine. It must be convert the value in tree list to text somehow.
Ah so it works. My idea is appendText
for the ComboBoxText()
and use model for the Completion. It works but i don't really happy with the current code. I meant i have to generate 2 list of object for only 1 thing. It is acceptable for now but it is not the best optimization in my opinion. Anyway thank you for the advice. I didn't understand the flow yesterday and it took me 8 hours in mess. So in this case, the core job is we use cast
to get Entry
from ComboBox
and use completion for Entry
. It is very simple. My code:
import strutils
import re
import gintro / [gtk, gobject, glib]
proc convertLayout(data: string): string =
#[
Convert all weird text to "GB - English (UK)"
]#
let findAllText = findAll(data, re"([a-zA-Z0-9_\/\(\),\-]+)")
result = findAllText[0].toUpper() & " -"
for text in findAllText[1 .. findAllText.high]:
result &= " " & text
proc getLayouts(): seq[string] =
#[
Read data from path and parse ! layout section
]#
const path = "/usr/share/X11/xkb/rules/xorg.lst"
# We add a variable to check when we start parsing lines
# After parse, we stop after ! character
var flag = false
for line in lines(path):
# If the section is not ! Layout and we parsed (checked by flag)
if line.startsWith("!") and line != "! layout" and flag == true:
return result
# We start parsing layout section
elif flag == false and line == "! layout":
flag = true
# It should be sub sections
else:
# This sub section should belong to layout
if flag == true and not isEmptyOrWhitespace(line):
result.add(convertLayout(line))
proc createArea(boxMain: Box) =
#[
Steps
https://athenajc.gitbooks.io/python-gtk-3-api/content/gtk-group/gtkentrycompletion.html
https://stackoverflow.com/a/39426800
Create ListStore
Add items to ListStore == BUG == Items don't show text in ComboBoxTextWithEntry
Create EntryCompletion
set entrycompletion model to liststore
set TextColumn of EntryCompletion = 0
Create new ComboBoxTextWithEntry
Get Entry from ComboBoxTextWithEntry
set Entry's completion to EntryCompletion
]#
# TODO full completion. By now it only complete first character
var
iter: TreeIter
val: Value
let
# Create List store
gtype = gStringGetType() # init type. Work with gintro 0.7.3
listLayouts = newListStore(1, cast[pointer]( unsafeaddr gtype))
setKeyboadLayout = newComboBoxTextWithEntry()
discard init(val, gtype)
# Add items to ListStore
for item in getLayouts():
setString(val, item)
listLayouts.append(iter)
listLayouts.setValue(iter, 0, val)
setKeyboadLayout.appendText(item)
# Create new completion
let
valueCompletion = newEntryCompletion()
valueCompletion.setModel(listLayouts)
valueCompletion.setTextColumn(0)
# Create new ComboBox and access Entry inside it
let
# setKeyboadLayout = newComboBoxWithModelAndEntry(listLayouts)
# setKeyboadLayout = newComboBoxTextWithEntry()
setKeyboadLayoutEntry = cast[Entry](setKeyboadLayout.getChild())
setKeyboadLayoutEntry.setCompletion(valueCompletion)
boxMain.add(setKeyboadLayout)
proc stop(w: Window) =
mainQuit()
proc main =
gtk.init()
let
mainBoard = newWindow()
boxMain = newBox(Orientation.vertical, 3)
mainBoard.title = "Keyboard Selector"
# TODO add icon here
createArea(boxMain)
mainBoard.add(boxMain)
mainBoard.setBorderWidth(3)
mainBoard.show()
boxMain.showAll()
mainBoard.connect("destroy", stop)
gtk.main()
main()```
So i think this autocompletion should be in your examples because it is interesting and it is useful in real world cases. Can you please add it in your official examples?
Great that it works for you now somehow.
When the Python code works fine, then we should get it in Nim too. Working C code would be better of course.
I will investigate that python soon.
For the addition to the official examples -- well we should only add what we fully understand, and what could be easily translated to C. As C is the only code where one may get help from GTK forum.
Great that it works for you now somehow.
When the Python code works fine, then we should get it in Nim too. Working C code would be better of course.
I will investigate that python soon.
For the addition to the official examples -- well we should only add what we fully understand, and what could be easily translated to C. As C is the only code where one may get help from GTK forum.
Thank you for your work :D I agree with you about the add when we fully understand the code. Well by now the problem is the ListStore model can work with ComboBoxWithModelAndEntry with no error. So should we close this issue or keep it open?
I think we should let this issue open for now.
Is the Python example from
https://athenajc.gitbooks.io/python-gtk-3-api/content/gtk-group/gtkentrycompletion.html
exactly what you intent?
In that case I may ask someone on GTK forum for a C version and then create a Nim version from it.
I think we should let this issue open for now.
Is the Python example from
https://athenajc.gitbooks.io/python-gtk-3-api/content/gtk-group/gtkentrycompletion.html
exactly what you intent?
In that case I may ask someone on GTK forum for a C version and then create a Nim version from it.
The URL is the completion of the Entry object and it is easy. My problem is the Completion for the ComboBoxText so the stackoverflow URL is the example i used. As you can see, both uses ListStore for the model (which is the data) of the completion. The example in StackOverflow can display data of ListStore on ComboBoxText. Actually i don't know if C code supports it or Python did something else for easier usage. I hope you can get me because my English is not very good :p
There is some more example available which we may port to Nim.
https://gitlab.gnome.org/GNOME/gtk/-/blob/3.24.20/tests/testentrycompletion.c
The problem for me is that I do not know much about advanced listview stuff, so even when I would get something working I could be not sure if it really correct. So I would really prefer just porting a working and correct example from another language.
What we may do is starting from some available C code and ask on GTK forum how to extent it to what you want, in C. But most of the time there is no one available on that forum beside E. Bassi.
Well in this case i think maybe gtk C doesn't support the thing i want or it is too complex so the method in my code is acceptable
Have just translated the stackoverflow python code to Nim.
I don't know if that is of some use for you, but was not that hard. Indeed I was surprised that it worked immediately after I had removed some compiler error messages. If the window is small, on my wayland screen there is some garbage left from the popup sometimes. Well maybe we should compare to the python code more carefully, but I am not sure if that python code is really fine. Have to watch TV new now, bye.
import gintro/[gtk, gobject, glib]
import strutils
type
CompletingComboBoxText = ref object of ComboBoxText
completionOptions: seq[string]
populator: proc(s: string): seq[string]
staticOptionsModel: ListStore
# we need the following two procs for now -- later we will not use that ugly cast...
proc typeTest(o: gobject.Object; s: string): bool =
let gt = g_type_from_name(s)
return g_type_check_instance_is_a(cast[ptr TypeInstance00](o.impl), gt).toBool
proc listStore(o: gobject.Object): gtk.ListStore =
assert(typeTest(o, "GtkListStore"))
cast[gtk.ListStore](o)
proc bye(w: Window) =
mainQuit()
echo "Bye..."
proc dynamicOptionPopulator(text: string): seq[string] =
# Some fake returns for the populator
const fakeDynamicOptions = [
"_5Hf0fFKvRVa71ZPM0",
"_8261sbF1f9ohzu2Iu",
"_0BV96V94PJIn9si1K",
"_0BV1sbF1f9ohzu2Iu",
"_0BV0fFKvRVa71ZPM0",
"_0Hf0fF4PJIn9si1Ks",
"_6KvRVa71JIn9si1Kw",
"_5HKvRVa71Va71ZPM0",
"_8261sbF1KvRVa71ZP",
"_0BKvRVa71JIn9si1K",
"_0BV1KvRVa71ZPu2Iu",
"_0BV0fKvRVa71ZZPM0",
"_0Hf0fF4PJIbF1f9oh",
"_61sbFV0fFKn9si1Kw",
"_5Hf0fFKvRVa71ozu2",
]
for fakeDynamicOption in fakeDynamicOptions:
if fakeDynamicOption.startswith(text):
result.add(fakeDynamicOption)
proc updateCompletion(entry: Entry; self: CompletingComboBoxText) =
var
iter: TreeIter
val: Value
# Get the current content of the entry
let text = entry.getText()
# Get the completion which needs to be updated
let completion = entry.getCompletion()
if text.startsWith("_") and len(text) >= completion.getMinimumKeyLength():
# Fetch the options from the populator for a given text
self.completionOptions = self.populator(text)
# Create a temporary model for the completion and fill it
let gtype = typeFromName("gchararray")
let dynamicModel = newListStore(1, cast[pointer]( unsafeaddr gtype))
discard init(val, gtype)
for completionOption in self.completionOptions:
setString(val, completionOption)
dynamicModel.append(iter)
dynamicModel.setValue(iter, 0, val)
completion.setModel(dynamicModel)
else:
# Restore the default static options
completion.setModel(self.staticOptionsModel)
proc newCompletingComboBoxText(staticOptions: openArray[string], populator: proc(s: string): seq[string]): CompletingComboBoxText =
var self = newComboBoxTextWithEntry(CompletingComboBoxText)
self.populator = populator
let completion = gtk.newEntryCompletion()
completion.setInlineCompletion
completion.setTextColumn(0)
completion.setMinimumKeyLength(2)
# Set the completion model to the combobox model such that we can also autocomplete these options
self.staticOptionsModel = listStore(self.getModel)
completion.setModel(self.staticOptionsModel)
# The child of the combobox is the entry if 'has_entry' was set to True
let entry = cast[Entry](self.getChild())
entry.setCompletion(completion)
# Set the active option of the combobox to 0 (which is an empty field)
self.setActive(0)
# Fill the model with the static options (could also be used for a history or something)
for option in staticOptions:
self.appendText(option)
# Connect a listener to adjust the model when the user types something
entry.connect("changed", updateCompletion, self)
return self
proc demo() =
gtk.init()
let window = gtk.newWindow()
window.connect("destroy", bye)
# Add some static options
const fakeStaticOptions = [
"comment",
"if",
"the_GUI",
"the_system",
"payload_json",
"x1",
"payload_json",
"payload_vectval"
]
# Add the the Combobox
let ccb = newCompletingComboBoxText(fakeStaticOptions, dynamicOptionPopulator)
window.add(ccb)
# Show it
window.showAll()
gtk.main()
when isMainModule:
demo()
Have just translated the stackoverflow python code to Nim.
I don't know if that is of some use for you, but was not that hard. Indeed I was surprised that it worked immediately after I had removed some compiler error messages. If the window is small, on my wayland screen there is some garbage left from the popup sometimes. Well maybe we should compare to the python code more carefully, but I am not sure if that python code is really fine. Have to watch TV new now, bye.
import gintro/[gtk, gobject, glib] import strutils type CompletingComboBoxText = ref object of ComboBoxText completionOptions: seq[string] populator: proc(s: string): seq[string] staticOptionsModel: ListStore # we need the following two procs for now -- later we will not use that ugly cast... proc typeTest(o: gobject.Object; s: string): bool = let gt = g_type_from_name(s) return g_type_check_instance_is_a(cast[ptr TypeInstance00](o.impl), gt).toBool proc listStore(o: gobject.Object): gtk.ListStore = assert(typeTest(o, "GtkListStore")) cast[gtk.ListStore](o) proc bye(w: Window) = mainQuit() echo "Bye..." proc dynamicOptionPopulator(text: string): seq[string] = # Some fake returns for the populator const fakeDynamicOptions = [ "_5Hf0fFKvRVa71ZPM0", "_8261sbF1f9ohzu2Iu", "_0BV96V94PJIn9si1K", "_0BV1sbF1f9ohzu2Iu", "_0BV0fFKvRVa71ZPM0", "_0Hf0fF4PJIn9si1Ks", "_6KvRVa71JIn9si1Kw", "_5HKvRVa71Va71ZPM0", "_8261sbF1KvRVa71ZP", "_0BKvRVa71JIn9si1K", "_0BV1KvRVa71ZPu2Iu", "_0BV0fKvRVa71ZZPM0", "_0Hf0fF4PJIbF1f9oh", "_61sbFV0fFKn9si1Kw", "_5Hf0fFKvRVa71ozu2", ] for fakeDynamicOption in fakeDynamicOptions: if fakeDynamicOption.startswith(text): result.add(fakeDynamicOption) proc updateCompletion(entry: Entry; self: CompletingComboBoxText) = var iter: TreeIter val: Value # Get the current content of the entry let text = entry.getText() # Get the completion which needs to be updated let completion = entry.getCompletion() if text.startsWith("_") and len(text) >= completion.getMinimumKeyLength(): # Fetch the options from the populator for a given text self.completionOptions = self.populator(text) # Create a temporary model for the completion and fill it let gtype = typeFromName("gchararray") let dynamicModel = newListStore(1, cast[pointer]( unsafeaddr gtype)) discard init(val, gtype) for completionOption in self.completionOptions: setString(val, completionOption) dynamicModel.append(iter) dynamicModel.setValue(iter, 0, val) completion.setModel(dynamicModel) else: # Restore the default static options completion.setModel(self.staticOptionsModel) proc newCompletingComboBoxText(staticOptions: openArray[string], populator: proc(s: string): seq[string]): CompletingComboBoxText = var self = newComboBoxTextWithEntry(CompletingComboBoxText) self.populator = populator let completion = gtk.newEntryCompletion() completion.setInlineCompletion completion.setTextColumn(0) completion.setMinimumKeyLength(2) # Set the completion model to the combobox model such that we can also autocomplete these options self.staticOptionsModel = listStore(self.getModel) completion.setModel(self.staticOptionsModel) # The child of the combobox is the entry if 'has_entry' was set to True let entry = cast[Entry](self.getChild()) entry.setCompletion(completion) # Set the active option of the combobox to 0 (which is an empty field) self.setActive(0) # Fill the model with the static options (could also be used for a history or something) for option in staticOptions: self.appendText(option) # Connect a listener to adjust the model when the user types something entry.connect("changed", updateCompletion, self) return self proc demo() = gtk.init() let window = gtk.newWindow() window.connect("destroy", bye) # Add some static options const fakeStaticOptions = [ "comment", "if", "the_GUI", "the_system", "payload_json", "x1", "payload_json", "payload_vectval" ] # Add the the Combobox let ccb = newCompletingComboBoxText(fakeStaticOptions, dynamicOptionPopulator) window.add(ccb) # Show it window.showAll() gtk.main() when isMainModule: demo()
Thank you very much. From your code i can see my method is the same:
Have done a short test with the original Python code run with python2. It has the same problem, the popup box generates garbage on the screen when the box is larger than the window. Maybe a wayland or gtk issue, but I think not a Nim/gintro one. I think we can let this issue open for a few weeks, it has now some useful Nim code. I intent to close a lot of the issues soon, will start with the old once.
Well imo it can be the problem of C code. In this case the text isn't there but all lines (rows) are still there. If you like to add this completion as examples, i can help you write 2 examples with the entry and combobox :D
I'm writing a simple program that the ComboBox has auto completion like the Entry. I completed this but i'm having 2 issues:
Gtk-CRITICAL **: 04:36:12.088: gtk_entry_set_text: assertion 'text != NULL' failed
. Can you please check my code and help me correct this issue?GLib-GObject-WARNING **: 04:36:05.559: ../../../gobject/gvalue.c:180: cannot initialize GValue with type 'gchararray', the value has already been initialized as 'gchararray'
. I completed this code by combining ListView example and google. I'm using nim 1.2.0 from Debian and gintro 0.7.3. My code:proc convertLayout(data: string): string =
[
]# let findAllText = findAll(data, re"([a-zA-Z0-9_\/(),-]+)") result = findAllText[0].toUpper() & " -" for text in findAllText[1 .. findAllText.high]: result &= " " & text
proc getLayouts(): seq[string] =
[
]# const path = "/usr/share/X11/xkb/rules/xorg.lst"
We add a variable to check when we start parsing lines
After parse, we stop after ! character
var flag = false for line in lines(path):
If the section is not ! Layout and we parsed (checked by flag)
proc createArea(boxMain: Box) =
[
]#
TODO full completion. By now it only complete first character
var iter: TreeIter val: Value
let
Create List store
Add items to ListStore
for item in getLayouts(): discard init(val, gtype) setString(val, item) listLayouts.append(iter) listLayouts.setValue(iter, 0, val)
Create new completion
let valueCompletion = newEntryCompletion()
valueCompletion.setModel(listLayouts) valueCompletion.setTextColumn(0)
Create new ComboBox and access Entry inside it
let setKeyboadLayout = newComboBoxWithModelAndEntry(listLayouts) setKeyboadLayoutEntry = cast[Entry](setKeyboadLayout.getChild())
setKeyboadLayoutEntry.setCompletion(valueCompletion)
boxMain.add(setKeyboadLayout)
proc stop(w: Window) = mainQuit()
proc main = gtk.init() let mainBoard = newWindow() boxMain = newBox(Orientation.vertical, 3)
mainBoard.title = "Keyboard Selector"
TODO add icon here
createArea(boxMain) mainBoard.add(boxMain) mainBoard.setBorderWidth(3)
mainBoard.show() boxMain.showAll() mainBoard.connect("destroy", stop) gtk.main()
main()```