1 module qui.lists; 2 3 import qui.qui;//used for Position & Cell in Matrix 4 import qui.misc; 5 import std.file; 6 import std.stdio; 7 8 class List(T){ 9 private: 10 T[] list; 11 uinteger taken=0; 12 public: 13 void add(T dat){ 14 if (taken==list.length){ 15 list.length+=10; 16 } 17 taken++; 18 list[taken-1] = dat; 19 } 20 void addArray(T[] dat){ 21 list.length = taken; 22 list ~= dat; 23 taken += dat.length; 24 } 25 void set(uinteger index, T dat){ 26 list[index]=dat; 27 } 28 void remove(uinteger index, uinteger count=1){ 29 integer i; 30 integer till=taken-count; 31 for (i=index;i<till;i++){ 32 list[i] = list[i+count]; 33 } 34 list.length-=count; 35 taken-=count; 36 } 37 void removeLast(uinteger count = 1){ 38 taken -= count; 39 if (list.length-taken>10){ 40 list.length=taken; 41 } 42 } 43 void shrink(uinteger newSize){ 44 list.length=newSize; 45 taken = list.length; 46 } 47 void insert(uinteger index, T[] dat){ 48 integer i; 49 T[] ar,ar2; 50 ar=list[0..index]; 51 ar2=list[index..taken]; 52 list.length=0; 53 list=ar~dat~ar2; 54 taken+=dat.length; 55 } 56 void insert(uinteger index, T dat){ 57 integer i; 58 T[] ar,ar2; 59 ar=list[0..index]; 60 ar2=list[index..taken]; 61 list.length=0; 62 list=ar~[dat]~ar2; 63 taken++; 64 } 65 void saveFile(string s, T sp){ 66 File f = File(s,"w"); 67 uinteger i; 68 for (i=0;i<taken;i++){ 69 f.write(list[i],sp); 70 } 71 f.close; 72 } 73 T read(uinteger index){ 74 return list[index]; 75 } 76 T[] readRange(uinteger index,uinteger i2){ 77 T[] r; 78 r.length = (i2-index); 79 r[0 .. r.length] = list[index .. i2]; 80 return r; 81 } 82 T readLast(){ 83 return list[taken-1]; 84 } 85 T[] readLast(uinteger count){ 86 T[] r; 87 r.length = count; 88 r[0 .. r.length] = list[taken-count..taken]; 89 return r; 90 } 91 integer length(){ 92 return taken; 93 } 94 T[] toArray(){ 95 uinteger i; 96 T[] r; 97 if (taken!=-1){ 98 r.length=taken; 99 for (i=0;i<taken;i++){//using a loop cuz simple '=' will just copy the pionter 100 r[i]=list[i]; 101 } 102 } 103 return r; 104 } 105 void loadArray(T[] dats){ 106 uinteger i; 107 list.length=dats.length; 108 taken=list.length; 109 for (i=0;i<dats.length;i++){ 110 list[i]=dats[i]; 111 } 112 } 113 void clear(){ 114 list.length=0; 115 taken=0; 116 } 117 integer indexOf(T dat, integer i=0, bool forward=true){ 118 if (forward){ 119 for (;i<taken;i++){ 120 if (list[i]==dat){break;} 121 if (i==taken-1){i=-1;break;} 122 } 123 }else{ 124 for (;i>=0;i--){ 125 if (list[i]==dat){break;} 126 if (i==0){i=-1;break;} 127 } 128 } 129 if (taken==0){ 130 i=-1; 131 } 132 return i; 133 } 134 } 135 ///represents an item in a linked list. contains the item, and pointer to the next item's container 136 private struct LinkedItem(T){ 137 T data; 138 LinkedItem!(T)* next = null;//mark it null to show the list has ended 139 } 140 ///a linked list, used where only reading in the forward direction is required 141 class LinkedList(T){ 142 private: 143 LinkedItem!(T)* firstItemPtr; 144 LinkedItem!(T)* lastItemPtr;//the pointer of the last item, used for appending new items 145 LinkedItem!(T)* nextReadPtr;//the pointer of the next item to be read 146 147 uinteger itemCount;//stores the total number of items 148 public: 149 this(){ 150 firstItemPtr = null; 151 lastItemPtr = null; 152 nextReadPtr = null; 153 itemCount = 0; 154 } 155 ~this(){ 156 //free all the memory occupied 157 clear(); 158 } 159 ///clears/resets the list. Frees all the occupied memory, & removes all items 160 void clear(){ 161 //make sure that the list is populated 162 if (firstItemPtr !is null){ 163 LinkedItem!(T)* nextPtr; 164 for (nextReadPtr = firstItemPtr; nextReadPtr !is null; nextReadPtr = nextPtr){ 165 nextPtr = (*nextReadPtr).next; 166 destroy(*nextReadPtr); 167 } 168 //reset all variables 169 firstItemPtr = null; 170 lastItemPtr = null; 171 nextReadPtr = null; 172 itemCount = 0; 173 } 174 } 175 ///adds a new item at the end of the list 176 void append(T item){ 177 LinkedItem!(T)* ptr = new LinkedItem!(T); 178 (*ptr).data = item; 179 (*ptr).next = null; 180 //add it to the list 181 if (firstItemPtr is null){ 182 firstItemPtr = ptr; 183 nextReadPtr = firstItemPtr; 184 }else{ 185 (*lastItemPtr).next = ptr; 186 } 187 //mark this item as last 188 lastItemPtr = ptr; 189 //increase item count 190 itemCount ++; 191 } 192 ///removes the first item in list 193 void removeFirst(){ 194 //make sure list is populated 195 if (firstItemPtr !is null){ 196 LinkedItem!(T)* first; 197 first = firstItemPtr; 198 //mark the second item as first, if there isn't a second item, it'll automatically be marked null 199 firstItemPtr = (*firstItemPtr).next; 200 //if nextReadPtr is firstItemPtr, move it to next as well 201 if (nextReadPtr is first){ 202 nextReadPtr = firstItemPtr; 203 } 204 //free memory occupied by first 205 destroy(*first); 206 //decrease count 207 itemCount --; 208 } 209 } 210 ///number of items that the list is holding 211 @property uinteger count(){ 212 return itemCount; 213 } 214 ///resets the read position, i.e: set reading position to first item 215 void resetRead(){ 216 nextReadPtr = firstItemPtr; 217 } 218 ///returns pointer of next item to be read, null if there are no more items 219 T* read(){ 220 T* r; 221 if (nextReadPtr !is null){ 222 r = &((*nextReadPtr).data); 223 //move read position 224 nextReadPtr = (*nextReadPtr).next; 225 }else{ 226 r = null; 227 } 228 return r; 229 } 230 } 231 232 ///Used in logging widgets. Holds upto certain number, after which older items are removed 233 class LogList(T){ 234 private: 235 List!T list; 236 uinteger readFrom, maxLen; 237 public: 238 this(uinteger maxLength=100){ 239 list = new List!T; 240 readFrom = 0; 241 maxLen = maxLength; 242 } 243 ~this(){ 244 delete list; 245 } 246 ///adds an item to the log 247 void add(T dat){ 248 if (list.length>=maxLen){ 249 list.set(readFrom,dat); 250 readFrom++; 251 }else{ 252 list.add(dat); 253 } 254 } 255 ///Returns array containing items, in first-added-last order 256 T[] read(uinteger count=0){ 257 T[] r; 258 if (count>list.length){ 259 count = list.length; 260 } 261 if (count > 0){ 262 uinteger i; 263 if (count>list.length){ 264 count = list.length; 265 } 266 r.length = count; 267 for (i = readFrom; i < count; i++){ 268 r[i] = list.read((readFrom+i)%count); 269 } 270 }else{ 271 r = null; 272 } 273 return r; 274 } 275 ///resets and clears the log 276 void reset(){ 277 list.clear; 278 readFrom = 0; 279 } 280 ///returns the max number of items that can be stored 281 @property uinteger maxCapacity(){ 282 return maxLen; 283 } 284 } 285 286 ///Used to store the widget's/terminal's display in a matrix 287 class Matrix{ 288 private: 289 Cell[][] matrix;//read as: matrix[y][x]; 290 //used to write by widgets 291 uinteger xPosition, yPosition; 292 293 //stores which part was updated 294 struct UpdateLocation{ 295 uinteger x, y; 296 uinteger length; 297 } 298 LinkedList!UpdateLocation updateAt; 299 300 Cell readAsStream(uinteger pos){ 301 return matrix[pos/width][pos%width]; 302 } 303 304 char[] cellToChar(Cell[] c){ 305 char[] r; 306 r.length = c.length; 307 for (uinteger i = 0; i < c.length; i++){ 308 r[i] = c[i].c; 309 } 310 return r; 311 } 312 313 void updateChars(QTerminal terminal, uinteger x, uinteger y, uinteger length){ 314 uinteger readPos = (y*width)+x, i; 315 Cell[] line; 316 line.length = length; 317 //read all content into line 318 for (i = 0; i < length; i++){ 319 line[i] = readAsStream(readPos); 320 readPos ++; 321 } 322 //start writing it to terminal 323 terminal.moveTo(cast(int)x, cast(int)y); 324 //set origin colors 325 RGBColor originBgColor, originTextColor; 326 originBgColor = line[0].bgColor; 327 originTextColor = line[0].textColor; 328 terminal.setColors(originTextColor, originBgColor); 329 330 length --; 331 uinteger writeFrom = 0; 332 for (i = 0; i <= length; i++){ 333 //check if colors have changed, or is it end 334 if (line[i].bgColor != originBgColor || line[i].textColor != originTextColor || i == length){ 335 if (writeFrom < i){ 336 terminal.setColors(originTextColor, originBgColor); 337 terminal.writeChars(cellToChar(line[writeFrom .. i])); 338 } 339 //if is at end, write the 'last-encountered' char too 340 if (i == length){ 341 terminal.setColors(line[i].textColor, line[i].bgColor); 342 terminal.writeChars(line[i].c); 343 } 344 } 345 } 346 } 347 public: 348 this(uinteger matrixWidth, uinteger matrixHeight, Cell fill){ 349 //set matrix size 350 matrix.length = matrixHeight; 351 //set width: 352 for (uinteger i = 0; i < matrix.length; i++){ 353 matrix[i].length = matrixWidth; 354 matrix[i][0 .. matrixWidth] = fill; 355 } 356 updateAt = new LinkedList!UpdateLocation; 357 //set updateAt to whole Matrix 358 UpdateLocation loc; 359 loc.x, loc.y = 0; 360 loc.length = width*height; 361 updateAt.append(loc); 362 } 363 ~this(){ 364 delete updateAt; 365 } 366 ///Clear the matrix, and put fill in every cell 367 void clear(Cell fill){ 368 for (uinteger row = 0; row < matrix.length; row++){ 369 matrix[row][0 .. matrix[row].length] = fill; 370 } 371 //set updateAt to whole Matrix 372 UpdateLocation loc; 373 loc.x, loc.y = 0; 374 loc.length = width*height; 375 updateAt.append(loc); 376 } 377 ///Change size of the matrix, width and height 378 bool changeSize(uinteger matrixWidth, uinteger matrixHeight, Cell fill){ 379 //make sure width & size are at least 1 380 bool r = true; 381 if (matrixWidth == 0 || matrixHeight == 0){ 382 r = false; 383 } 384 if (r){ 385 matrix.length = matrixHeight; 386 for (uinteger i = 0; i < matrix.length; i++){ 387 matrix[i].length = matrixWidth; 388 matrix[i][0 .. matrixWidth] = fill; 389 } 390 } 391 return r; 392 } 393 ///sets write position to (0, 0) 394 void resetWritePosition(){ 395 xPosition = 0; 396 yPosition = 0; 397 } 398 ///used to write to matrix, call Matrix.setWriteLimits before this 399 void write(char[] c, RGBColor textColor, RGBColor bgColor){ 400 uinteger i, xEnd, yEnd; 401 xEnd = width; 402 yEnd = height; 403 //add it to updateAt 404 UpdateLocation loc; 405 loc.x = xPosition; 406 loc.y = yPosition; 407 loc.length = c.length; 408 updateAt.append(loc); 409 for (i = 0; i < c.length; xPosition++){ 410 if (xPosition == xEnd){ 411 //move to next row 412 yPosition++; 413 xPosition = 0; 414 } 415 //check if no more space left 416 if (yPosition >= yEnd){ 417 //no more space left 418 break; 419 } 420 matrix[yPosition][xPosition].c = c[i]; 421 matrix[yPosition][xPosition].bgColor = bgColor; 422 matrix[yPosition][xPosition].textColor = textColor; 423 i++; 424 } 425 } 426 ///changes colors for whole matrix 427 void setColors(RGBColor textColor, RGBColor bgColor){ 428 for (uinteger i = 0; i < matrix.length; i++){ 429 for(uinteger j = 0; j < matrix[i].length; j++){ 430 matrix[i][j].textColor = textColor; 431 matrix[i][j].bgColor = bgColor; 432 } 433 } 434 //set updateAt to whole Matrix 435 UpdateLocation loc; 436 loc.x, loc.y = 0; 437 loc.length = width*height; 438 updateAt.append(loc); 439 } 440 ///move to a different position to write 441 bool moveTo(uinteger x, uinteger y){ 442 bool r = true; 443 if (x > matrix[0].length-1 || y > matrix.length-1){ 444 r = false; 445 } 446 if (r){ 447 xPosition = x; 448 yPosition = y; 449 } 450 return r; 451 } 452 ///returns number of rows/lines in matrix 453 @property uinteger height(){ 454 return matrix.length; 455 } 456 ///returns number of columns in matrix 457 @property uinteger width(){ 458 return matrix[0].length; 459 } 460 ///returns the point ox x-axis where next write will start from 461 @property uinteger writePosX(){ 462 return xPosition; 463 } 464 ///returns the point ox y-axis where next write will start from 465 @property uinteger writePosY(){ 466 return yPosition; 467 } 468 ///read a cell from the matrix 469 Cell read(uinteger x, uinteger y){ 470 return matrix[y][x]; 471 } 472 ///read a complete row from matrix 473 Cell[] readRow(uinteger y){ 474 return matrix[y][]; 475 } 476 ///insert a matrix into this one at a position 477 bool insert(Matrix toInsert, uinteger x, uinteger y){ 478 uinteger matrixWidth, matrixHeight; 479 matrixHeight = toInsert.height; 480 matrixWidth = toInsert.width; 481 bool r = true; 482 if (matrixHeight + y > this.height || matrixWidth + x > this.width){ 483 r = false; 484 }else{ 485 uinteger row = 0; 486 uinteger endAtRow = matrixHeight; 487 for (;row<endAtRow; row++){ 488 matrix[y + row][x .. x+matrixWidth] = toInsert.readRow(row); 489 //add this row to updateAt 490 UpdateLocation loc; 491 loc.x = x; 492 loc.y = y+row; 493 loc.length = matrixWidth; 494 updateAt.append(loc); 495 } 496 } 497 //debug{toFile("/home/nafees/Desktop/a");} 498 return r; 499 } 500 /*debug{ 501 void toFile(string fname){ 502 File f = File(fname, "w"); 503 for (uinteger i = 0; i < matrix.length; i++){ 504 for (uinteger j = 0; j < matrix[i].length; j++){ 505 f.write(matrix[i][j].c); 506 } 507 f.write('|','\n'); 508 } 509 f.close; 510 } 511 }*/ 512 ///Write contents of matrix to a QTerminal 513 void flushToTerminal(QTerminal terminal){ 514 //make sure that there was some change that needs to be flushed 515 if (updateAt.count > 0){ 516 //start going through all update-needy 517 uinteger i, count; 518 count = updateAt.count(); 519 UpdateLocation* ptr; 520 for (i = 0; i < count; i++){ 521 ptr = updateAt.read(); 522 if (ptr is null){ 523 break; 524 } 525 if ((*ptr).length > 0){ 526 updateChars(terminal, (*ptr).x, (*ptr).y, (*ptr).length); 527 } 528 updateAt.removeFirst(); 529 } 530 terminal.flush(); 531 } 532 } 533 }