1 module easyd.gtk.widgets; 2 3 // (C) 2014-2019 by Matthias Rossmy 4 // This file is distributed under the "Fair Use License v2" 5 6 import easyd.base; 7 import easyd.gtk.base; 8 9 import core.vararg; 10 11 import gtk.Button; 12 import gtk.Entry; 13 import gtk.EditableIF; 14 import gtk.SpinButton; 15 import gtk.CheckButton; 16 import gtk.ScrolledWindow; 17 import gtk.TreeView; 18 import gtk.TreeIter; 19 import gtk.TreeViewColumn; 20 import gtk.TreePath; 21 import gtk.Widget; 22 import gtk.CellRenderer; 23 import gtk.CellRendererText; 24 import gtk.TreeStore; 25 import gdk.Pixbuf; 26 27 class Button : gtk.Button.Button 28 { 29 void delegate()[] onClick; 30 31 this(string s, void delegate() onclick=null) 32 { 33 super(s); 34 addOnClicked(&onClickFunc); 35 if(onclick !is null) 36 { 37 onClick ~= onclick; 38 } 39 } 40 41 this(StockID id, void delegate() onclick=null) 42 { 43 super(id); 44 addOnClicked(&onClickFunc); 45 if(onclick !is null) 46 { 47 onClick ~= onclick; 48 } 49 } 50 51 protected void onClickFunc(gtk.Button.Button b) 52 { 53 onClick.trigger(); 54 } 55 } 56 57 class LineEdit : Entry, IBindable!string 58 { 59 void delegate(string)[] onChange; 60 void delegate()[] onPressEnter; 61 62 this() 63 { 64 super(); 65 addOnChanged(&onChangeFunc); 66 addOnActivate(&onPressEnterFunc); 67 } 68 69 protected void onChangeFunc(EditableIF e) 70 { 71 onChange.trigger((cast(Entry)e).getText()); 72 } 73 74 protected void onPressEnterFunc(Entry e) 75 { 76 onPressEnter.trigger; 77 } 78 79 @property string value() 80 { 81 return getText; 82 } 83 alias value this; 84 85 @property void value(string val) 86 { 87 setText(val); 88 } 89 } 90 91 class SpinBox(T) : gtk.SpinButton.SpinButton, IBindable!T 92 { 93 this(real min=0, real max=100, real step=1) 94 { 95 super(min,max,step); 96 } 97 98 @property T value() 99 { 100 return getValue.to!T; 101 } 102 alias value this; 103 104 @property void value(T val) 105 { 106 setValue(val); 107 } 108 } 109 110 class CheckBox : gtk.CheckButton.CheckButton, IBindable!bool 111 { 112 this(string label="") 113 { 114 super(label); 115 } 116 117 @property bool value() 118 { 119 return getActive; 120 } 121 alias value this; 122 123 @property void value(bool val) 124 { 125 setActive(val); 126 } 127 } 128 129 class TreeView : ScrolledWindow 130 { 131 gtk.TreeView.TreeView treeView; 132 alias treeView this; 133 bool expandOnClick=true; 134 void delegate(TreeIter)[] onChangeCursor; 135 void delegate(TreeIter)[] onActivateRow; 136 protected int handleChangeCursor=1; 137 138 this() 139 { 140 super(); 141 treeView = new gtk.TreeView.TreeView(); 142 add(treeView); 143 treeView.addOnCursorChanged(&onCursorChangeFunc); 144 treeView.addOnRowActivated(&onRowActivatedFunc); 145 treeView.addOnButtonRelease(&onButtonReleaseFunc); 146 } 147 148 TreeViewColumn addCol(string name) 149 { 150 auto col = new TreeViewColumn; 151 appendColumn(col); 152 col.setTitle(name); 153 setHeadersVisible(getNColumns>1); 154 return col; 155 } 156 157 TreeViewColumn addTextCol(string name, int modelcol) 158 { 159 auto col = addCol(name); 160 col.add!CellRendererText("text",modelcol); 161 return col; 162 } 163 164 TreeIter addRow(...) 165 { 166 //writeln("addRow..."); 167 int x; 168 TreeIter it; 169 if(_arguments[0] == typeid(TreeIter)) 170 { 171 it = (cast(TreeStore)getModel).createIter(va_arg!(TreeIter)(_argptr)); 172 x = 1; 173 } 174 else 175 { 176 //writeln("Creating columns..."); 177 if(getNColumns==0) 178 { 179 for (int col=0; col < _arguments.length; col++) 180 { 181 if (_arguments[col] == typeid(string)) 182 { 183 addTextCol("",col); 184 } 185 else 186 { 187 throw new Exception("Can't auto-create view columns for a model that contains other types than strings"); 188 } 189 } 190 } 191 //writeln("Creating model..."); 192 if(getModel() is null) 193 { 194 GType[] types; 195 for (int col=0; col < _arguments.length; col++) 196 { 197 if (_arguments[col] == typeid(int)) 198 { 199 types ~= GType.INT; 200 } 201 if (_arguments[col] == typeid(string)) 202 { 203 types ~= GType.STRING; 204 } 205 if (_arguments[col] == typeid(Pixbuf)) 206 { 207 types ~= Pixbuf.getType; 208 } 209 } 210 setModel(new TreeStore(types)); 211 } 212 //writeln("Getting iterator..."); 213 it = (cast(TreeStore)getModel).createIter(); 214 x = 0; 215 } 216 //writeln("Setting values..."); 217 for (int col=0; x < _arguments.length; x++,col++) 218 { 219 if (_arguments[x] == typeid(int)) 220 { 221 (cast(TreeStore)getModel).setValue(it,col,va_arg!(int)(_argptr)); 222 } 223 if (_arguments[x] == typeid(string)) 224 { 225 (cast(TreeStore)getModel).setValue(it,col,va_arg!(string)(_argptr)); 226 } 227 if (_arguments[x] == typeid(Pixbuf)) 228 { 229 (cast(TreeStore)getModel).setValue(it,col,va_arg!(Pixbuf)(_argptr)); 230 } 231 } 232 //writeln("...finished addRow"); 233 return it; 234 } 235 236 void delRow(TreeIter it) 237 { 238 (cast(TreeStore)getModel).remove(it); 239 } 240 241 void clear() 242 { 243 if(getModel() !is null) 244 { 245 handleChangeCursor--; 246 (cast(TreeStore)getModel).clear; 247 handleChangeCursor++; 248 //GC.collect; 249 } 250 } 251 252 void setSelectedIter(TreeIter it, int col=0) 253 { 254 treeView.setCursor(it.getTreePath,getColumn(col),0); 255 } 256 257 /*Guid id(TreeIter it, int col=1) 258 { 259 if(it is null) return Guid.invalid; 260 //writeln(getModel.getValueString(it,col)); 261 return Guid(BigInt("0x" ~ getModel.getValueString(it,col))); 262 }*/ 263 264 TreeIter currentIter() 265 { 266 TreePath p; 267 TreeViewColumn c; 268 getCursor(p,c); 269 if(p) 270 { 271 return new TreeIter(getModel(),p); 272 }else{ 273 return null; 274 } 275 } 276 277 /*Guid currentId(int col=1) 278 { 279 return id(currentIter,col); 280 }*/ 281 282 protected void onCursorChangeFunc(gtk.TreeView.TreeView tv) 283 { 284 if(handleChangeCursor<1) return; 285 TreePath p; 286 TreeViewColumn c; 287 getCursor(p,c); 288 //writeln(p); 289 if(p) 290 { 291 onChangeCursor.trigger(new TreeIter(getModel(),p)); 292 handleChangeCursor--; 293 treeView.setCursor(p,c,false); 294 handleChangeCursor++; 295 } 296 } 297 298 protected void onRowActivatedFunc(TreePath p, TreeViewColumn c, gtk.TreeView.TreeView tv) 299 { 300 onActivateRow.trigger(new TreeIter(getModel(),p)); 301 treeView.setCursor(p,c,false); 302 } 303 304 protected bool onButtonReleaseFunc(GdkEventButton* e, Widget w) 305 { 306 //writeln("Release ",e.button); 307 if(e.button==1 && expandOnClick) 308 { 309 TreePath p; 310 TreeViewColumn c; 311 getCursor(p,c); 312 expandRow(p,false); 313 } 314 return false; 315 } 316 } 317 318 CellRenderer add(TRend)(TreeViewColumn col, ...) 319 { 320 auto rend = new TRend; 321 col.packStart(rend,0); 322 for (int x=0; x < _arguments.length; x+=2) 323 { 324 col.addAttribute(rend,va_arg!(string)(_argptr),va_arg!(int)(_argptr)); 325 } 326 return rend; 327 } 328