Hi Mike,
I thought I was doing something wrong, but from what I've been reading online, this is a GTK bug. But apparently it was supposed to have been fixed in 3.22, so I'm stumped. Perhaps I found a way to wake it up again?
Error:
Gtk-CRITICAL **: gtk_cell_layout_add_attribute: assertion 'GTK_IS_CELL_LAYOUT (cell_layout)' failed
What this code boils down to is... I'm dynamically populating a TreeView with a list of PgFontDescriptions. But this isn't in a ScrolledWindow yet and so it just goes on for 300+ lines off-screen. I did try putting it in a ScrolledWindow, to see if that would clear things up, but I it only showed two lines of the TreeView (with a scrollbar) and spit out a whole other set of errors:
(treeview_dynamic_fill_with_scrolled_window.exe:12156): Gtk-CRITICAL **: gtk_cell_layout_add_attribute: assertion 'GTK_IS_CELL_LAYOUT (cell_layout)' failed
(treeview_dynamic_fill_with_scrolled_window.exe:12156): Gtk-WARNING **: Allocating size to GtkWindow 0000021ebb85ae40 without calling gtk_widget_get_preferred_width/height(). How does the code know the size to allocate?
I'm finding no example code to guide me, so any help will be very much appreciated. Sorry for such a long message. I know you're likely tired after a day's work, so if it takes a while to answer, I get it. I'm pretty bagged myself ATM.
Without the scrolled window:
// Minimal TreeView with one column
import std.stdio;
import std.math;
import gtk.MainWindow;
import gtk.Main;
import gtk.Widget;
import gtk.Box;
import gtk.TreeView;
import gtk.TreeSelection;
import gtk.ListStore;
import gtk.TreeIter;
import gtk.TreePath;
import gtk.TreeViewColumn;
import gtk.CellRendererText;
import pango.PgCairoFontMap;
import pango.PgFontMap;
import pango.PgFontFamily;
import pango.PgFontDescription;
import singleton.S_FontList;
void main(string[] args)
{
Main.init(args);
TestRigWindow myTestRig = new TestRigWindow("Dynamically-filled TreeView");
Main.run();
} // main()
class TestRigWindow : MainWindow
{
AppBox appBox;
this(string title)
{
super(title);
addOnDestroy(&quitApp);
appBox = new AppBox();
add(appBox);
showAll();
} // this() CONSTRUCTOR
void quitApp(Widget widget)
{
writeln("Bye.");
Main.quit();
} // quitApp()
} // class TestRigWindow
class AppBox : Box
{
FontTreeView signTreeView;
this()
{
super(Orientation.VERTICAL, 10);
signTreeView = new FontTreeView();
packStart(signTreeView, false, false, 0);
} // this()
} // class AppBox
/*
*A TreeView needs:
* - at least one column, and
* - a ListStore or TreeStore to serve as both data model (TreeModel) and storage (ListStore or TreeStore).
*/
class FontTreeView : TreeView
{
FontFamilyColumn fontFamilyColumn; // where the data is displayed
FontSizeColumn fontSizeColumn;
FontPangoSizeColumn fontPangoSizeColumn;
FontStyleColumn fontStyleColumn;
FontWeightColumn fontWeightColumn;
FontListStore fontListStore; // where the data is stored
this()
{
super();
addOnRowActivated(&onRowActivated);
fontListStore = new FontListStore();
setModel(fontListStore);
fontFamilyColumn = new FontFamilyColumn(fontListStore);
appendColumn(fontFamilyColumn);
fontSizeColumn = new FontSizeColumn();
appendColumn(fontSizeColumn);
fontPangoSizeColumn = new FontPangoSizeColumn();
appendColumn(fontPangoSizeColumn);
fontStyleColumn = new FontStyleColumn();
appendColumn(fontStyleColumn);
fontWeightColumn = new FontWeightColumn();
appendColumn(fontWeightColumn);
} // this()
void onRowActivated(TreePath treePath, TreeViewColumn tvc, TreeView tv)
{
int columnNumber;
TreeIter treeIter = new TreeIter(fontListStore, treePath);
// find the column number...
if(tvc.getTitle() == "Sign Message")
{
columnNumber = 0;
}
else if(tvc.getTitle() == "Sign Description")
{
columnNumber = 1;
}
writeln("TreePath (row): ", treePath, " columnNumber: ", columnNumber);
// get the contents of the cell double-clicked by the user
// Because there are nothing but strings in the store, we don't have to
// do any more digging, just echo the string to the terminal.
auto value = fontListStore.getValue(treeIter, columnNumber);
writeln("cell contains: ", value.getString());
} // onRowActivated()
} // class FontTreeView
/*
* A TreeViewColumn needs:
* - a string that will become the title,
* - at least one CellRenderer (with suffix Accel, Class, Combo, Pixbuf, Progress, Spin, Spinner, Text, or Toggle)
* - a string description of the attribute (data) type
* - and a column number (starting from 0)
*/
class FontFamilyColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Font Family";
string attributeType = "text";
int columnNumber = 0; // numbering starts at '0'
this(FontListStore fontListStore)
{
cellRendererText = new CellRendererText();
addAttribute(cellRendererText, "font-desc", fontListStore.Column.FONT_DESC);
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontFamilyColumn
class FontSizeColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Size";
string attributeType = "text";
int columnNumber = 1; // numbering starts at '0'
this()
{
cellRendererText = new CellRendererText();
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontSizeColumn
class FontPangoSizeColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Pango Units";
string attributeType = "text";
int columnNumber = 2; // numbering starts at '0'
this()
{
cellRendererText = new CellRendererText();
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontPangoSizeColumn
class FontStyleColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Style";
string attributeType = "text";
int columnNumber = 3; // numbering starts at '0'
this()
{
cellRendererText = new CellRendererText();
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontStyleColumn
class FontWeightColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Weight";
string attributeType = "text";
int columnNumber = 4; // numbering starts at '0'
this()
{
cellRendererText = new CellRendererText();
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontWeightColumn
/*
* A ListStore needs:
* - an array of GType types (essentially, data types such as string, int, etc.)
* so the constructor knows what's being stored, and
* - a TreeIter for creating rows of data.
*
* Rows are added to the ListStore with the setValue() function which needs:
* - a TreeIter (could be thought of as the row number, but it's a pointer object)
* - a column number, and
* - the data to be stored.
*/
class FontListStore : ListStore
{
SysFontListPango sysFontListPango;
PgFontDescription[] fontList;
TreeIter treeIter;
enum Column
{
FAMILY = 0,
SIZE,
PANGO_SIZE,
STYLE,
WEIGHT,
FONT_DESC
} // enum Column
/*
* DYNAMIC LOAD FROM FONTS
*/
this()
{
super([GType.STRING, GType.STRING, GType.STRING, GType.STRING, GType.STRING, PgFontDescription.getType()]);
sysFontListPango = new SysFontListPango();
fontList = sysFontListPango.getList();
foreach(font; fontList)
{
treeIter = createIter();
setValue(treeIter, 0, font.getFamily());
setValue(treeIter, 1, font.getSize() / 1024);
setValue(treeIter, 2, font.getSize());
setValue(treeIter, 3, font.getStyle());
setValue(treeIter, 4, font.getWeight());
setValue(treeIter, 5, font);
}
} // this()
} // class FontListStore
class SysFontListPango
{
private:
PgFontMap _pgFontMap;
PgFontFamily[] _pgFontFamilies;
PgFontFamily _font;
PgFontDescription[] _pgFontDescriptions;
PgFontDescription _fontDesc;
int _fontSize = 9, counter = 1;
public:
this()
{
_pgFontMap = PgCairoFontMap.getDefault();
_pgFontMap.listFamilies(_pgFontFamilies);
counter = 1;
foreach(_font; _pgFontFamilies)
{
_fontDesc = new PgFontDescription(_font.getName(), _fontSize);
_pgFontDescriptions ~= _fontDesc;
if(fmod(counter, 4) == 0)
{
varyFontBySize();
}
if(fmod(counter, 5) == 0)
{
varyFontByWeight(PangoWeight.BOLD);
}
else if(fmod(counter, 6) == 0)
{
varyFontByWeight(PangoWeight.THIN);
}
_fontSize++;
counter++;
if(_fontSize > 19)
{
_fontSize = 9;
}
}
} // this()
void varyFontBySize()
{
_fontDesc.setStyle(PangoStyle.ITALIC);
} // varyFontBySize()
void varyFontByWeight(PangoWeight weight)
{
_fontDesc.setWeight(weight);
} // varyFontByWeight()
PgFontDescription[] getList()
{
return(_pgFontDescriptions);
} // getList()
void printList()
{
int counter = 1;
foreach(_fontDesc; _pgFontDescriptions)
{
writeln("counter: ", counter);
writeln("family: ", _fontDesc.getFamily());
writeln("gravity: ", _fontDesc.getGravity());
writeln("size in points: ", _fontDesc.getSize() / 1024); // pango _font units are 1024 x points
writeln("size in Pango units: ", _fontDesc.getSize()); // pango _font units are 1024 x points
writeln("stretch: ", _fontDesc.getStretch());
writeln("style: ", _fontDesc.getStyle());
writeln("variant: ", _fontDesc.getVariant());
writeln("weight: ", _fontDesc.getWeight());
writeln();
counter++;
} // foreach
} // printList()
} // class SysFontListPango
with the scrolled window:
// Minimal TreeView with one column
import std.stdio;
import std.math;
import gtk.MainWindow;
import gtk.Main;
import gtk.Widget;
import gtk.Box;
import gtk.ScrolledWindow;
import gtk.TreeView;
import gtk.TreeSelection;
import gtk.ListStore;
import gtk.TreeIter;
import gtk.TreePath;
import gtk.TreeViewColumn;
import gtk.CellRendererText;
import pango.PgCairoFontMap;
import pango.PgFontMap;
import pango.PgFontFamily;
import pango.PgFontDescription;
import singleton.S_FontList;
void main(string[] args)
{
Main.init(args);
TestRigWindow myTestRig = new TestRigWindow("Dynamically-filled TreeView");
Main.run();
} // main()
class TestRigWindow : MainWindow
{
AppBox appBox;
this(string title)
{
super(title);
setSizeRequest(750, 400);
addOnDestroy(&quitApp);
appBox = new AppBox();
add(appBox);
showAll();
} // this() CONSTRUCTOR
void quitApp(Widget widget)
{
writeln("Bye.");
Main.quit();
} // quitApp()
} // class TestRigWindow
class AppBox : Box
{
MyScrolledWindow myScrolledWindow;
this()
{
super(Orientation.VERTICAL, 10);
myScrolledWindow = new MyScrolledWindow();
packStart(myScrolledWindow, false, false, 0);
} // this()
} // class AppBox
class MyScrolledWindow : ScrolledWindow
{
FontTreeView fontTreeView;
this()
{
fontTreeView = new FontTreeView();
super();
add(fontTreeView);
} // this()
} // class MyScrolledWindow
/*
*A TreeView needs:
* - at least one column, and
* - a ListStore or TreeStore to serve as both data model (TreeModel) and storage (ListStore or TreeStore).
*/
class FontTreeView : TreeView
{
FontFamilyColumn fontFamilyColumn; // where the data is displayed
FontSizeColumn fontSizeColumn;
FontPangoSizeColumn fontPangoSizeColumn;
FontStyleColumn fontStyleColumn;
FontWeightColumn fontWeightColumn;
FontListStore fontListStore; // where the data is stored
this()
{
super();
addOnRowActivated(&onRowActivated);
fontListStore = new FontListStore();
setModel(fontListStore);
fontFamilyColumn = new FontFamilyColumn(fontListStore);
appendColumn(fontFamilyColumn);
fontSizeColumn = new FontSizeColumn();
appendColumn(fontSizeColumn);
fontPangoSizeColumn = new FontPangoSizeColumn();
appendColumn(fontPangoSizeColumn);
fontStyleColumn = new FontStyleColumn();
appendColumn(fontStyleColumn);
fontWeightColumn = new FontWeightColumn();
appendColumn(fontWeightColumn);
} // this()
void onRowActivated(TreePath treePath, TreeViewColumn tvc, TreeView tv)
{
int columnNumber;
TreeIter treeIter = new TreeIter(fontListStore, treePath);
// find the column number...
if(tvc.getTitle() == "Sign Message")
{
columnNumber = 0;
}
else if(tvc.getTitle() == "Sign Description")
{
columnNumber = 1;
}
writeln("TreePath (row): ", treePath, " columnNumber: ", columnNumber);
// get the contents of the cell double-clicked by the user
// Because there are nothing but strings in the store, we don't have to
// do any more digging, just echo the string to the terminal.
auto value = fontListStore.getValue(treeIter, columnNumber);
writeln("cell contains: ", value.getString());
} // onRowActivated()
} // class FontTreeView
/*
* A TreeViewColumn needs:
* - a string that will become the title,
* - at least one CellRenderer (with suffix Accel, Class, Combo, Pixbuf, Progress, Spin, Spinner, Text, or Toggle)
* - a string description of the attribute (data) type
* - and a column number (starting from 0)
*/
class FontFamilyColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Font Family";
string attributeType = "text";
int columnNumber = 0; // numbering starts at '0'
this(FontListStore fontListStore)
{
cellRendererText = new CellRendererText();
addAttribute(cellRendererText, "font-desc", fontListStore.Column.FONT_DESC);
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontFamilyColumn
class FontSizeColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Size";
string attributeType = "text";
int columnNumber = 1; // numbering starts at '0'
this()
{
cellRendererText = new CellRendererText();
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontSizeColumn
class FontPangoSizeColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Pango Units";
string attributeType = "text";
int columnNumber = 2; // numbering starts at '0'
this()
{
cellRendererText = new CellRendererText();
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontPangoSizeColumn
class FontStyleColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Style";
string attributeType = "text";
int columnNumber = 3; // numbering starts at '0'
this()
{
cellRendererText = new CellRendererText();
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontStyleColumn
class FontWeightColumn : TreeViewColumn
{
CellRendererText cellRendererText;
string columnTitle = "Weight";
string attributeType = "text";
int columnNumber = 4; // numbering starts at '0'
this()
{
cellRendererText = new CellRendererText();
super(columnTitle, cellRendererText, attributeType, columnNumber);
} // this()
} // class FontWeightColumn
/*
* A ListStore needs:
* - an array of GType types (essentially, data types such as string, int, etc.)
* so the constructor knows what's being stored, and
* - a TreeIter for creating rows of data.
*
* Rows are added to the ListStore with the setValue() function which needs:
* - a TreeIter (could be thought of as the row number, but it's a pointer object)
* - a column number, and
* - the data to be stored.
*/
class FontListStore : ListStore
{
SysFontListPango sysFontListPango;
PgFontDescription[] fontList;
TreeIter treeIter;
enum Column
{
FAMILY = 0,
SIZE,
PANGO_SIZE,
STYLE,
WEIGHT,
FONT_DESC
} // enum Column
/*
* DYNAMIC LOAD FROM FONTS
*/
this()
{
super([GType.STRING, GType.STRING, GType.STRING, GType.STRING, GType.STRING, PgFontDescription.getType()]);
sysFontListPango = new SysFontListPango();
fontList = sysFontListPango.getList();
foreach(font; fontList)
{
treeIter = createIter();
setValue(treeIter, 0, font.getFamily());
setValue(treeIter, 1, font.getSize() / 1024);
setValue(treeIter, 2, font.getSize());
setValue(treeIter, 3, font.getStyle());
setValue(treeIter, 4, font.getWeight());
setValue(treeIter, 5, font);
}
} // this()
} // class FontListStore
class SysFontListPango
{
private:
PgFontMap _pgFontMap;
PgFontFamily[] _pgFontFamilies;
PgFontFamily _font;
PgFontDescription[] _pgFontDescriptions;
PgFontDescription _fontDesc;
int _fontSize = 9, counter = 1;
public:
this()
{
_pgFontMap = PgCairoFontMap.getDefault();
_pgFontMap.listFamilies(_pgFontFamilies);
counter = 1;
foreach(_font; _pgFontFamilies)
{
_fontDesc = new PgFontDescription(_font.getName(), _fontSize);
_pgFontDescriptions ~= _fontDesc;
if(fmod(counter, 4) == 0)
{
varyFontBySize();
}
if(fmod(counter, 5) == 0)
{
varyFontByWeight(PangoWeight.BOLD);
}
else if(fmod(counter, 6) == 0)
{
varyFontByWeight(PangoWeight.THIN);
}
_fontSize++;
counter++;
if(_fontSize > 19)
{
_fontSize = 9;
}
}
} // this()
void varyFontBySize()
{
_fontDesc.setStyle(PangoStyle.ITALIC);
} // varyFontBySize()
void varyFontByWeight(PangoWeight weight)
{
_fontDesc.setWeight(weight);
} // varyFontByWeight()
PgFontDescription[] getList()
{
return(_pgFontDescriptions);
} // getList()
void printList()
{
int counter = 1;
foreach(_fontDesc; _pgFontDescriptions)
{
writeln("counter: ", counter);
writeln("family: ", _fontDesc.getFamily());
writeln("gravity: ", _fontDesc.getGravity());
writeln("size in points: ", _fontDesc.getSize() / 1024); // pango _font units are 1024 x points
writeln("size in Pango units: ", _fontDesc.getSize()); // pango _font units are 1024 x points
writeln("stretch: ", _fontDesc.getStretch());
writeln("style: ", _fontDesc.getStyle());
writeln("variant: ", _fontDesc.getVariant());
writeln("weight: ", _fontDesc.getWeight());
writeln();
counter++;
} // foreach
} // printList()
} // class SysFontListPango