1namespace gui; 2 3import "Window" 4 5public struct AnchorValue 6{ 7 AnchorValueType type; 8 9 union 10 { 11 int distance; 12 float percent; 13 }; 14 property int 15 { 16 set { distance = value; type = offset; } 17 get { return distance; } 18 } 19 property double 20 { 21 set { percent = (float) value; type = relative; } 22 get { return (double) percent; } 23 } 24 25 char * OnGetString(char * stringOutput, void * fieldData, bool * needClass) 26 { 27 if(type == offset) 28 { 29 sprintf(stringOutput, "%d", distance); 30 } 31 else if(type == relative) 32 { 33 int c; 34 int last = 0; 35 sprintf(stringOutput, "%f", percent); 36 c = strlen(stringOutput)-1; 37 for( ; c >= 0; c--) 38 { 39 if(stringOutput[c] != '0') 40 last = Max(last, c); 41 if(stringOutput[c] == '.') 42 { 43 if(last == c) 44 { 45 stringOutput[c+1] = '0'; 46 stringOutput[c+2] = 0; 47 } 48 else 49 stringOutput[last+1] = 0; 50 break; 51 } 52 } 53 } 54 if(needClass) *needClass = false; 55 return stringOutput; 56 } 57 58 bool OnGetDataFromString(char * stringOutput) 59 { 60 char * end; 61 if(strchr(stringOutput, '.')) 62 { 63 float percent = (float)strtod(stringOutput, &end); 64 65 if(end != stringOutput) 66 { 67 this.percent = percent; 68 type = relative; 69 return true; 70 } 71 } 72 else if(stringOutput[0]) 73 { 74 int distance = strtol(stringOutput, &end, 0); 75 if(end != stringOutput) 76 { 77 this.distance = distance; 78 type = offset; 79 return true; 80 } 81 } 82 else 83 { 84 distance = 0; 85 type = 0; 86 } 87 return false; 88 } 89}; 90 91public struct MiddleAnchorValue 92{ 93 AnchorValueType type; 94 95 union 96 { 97 int distance; 98 float percent; 99 }; 100 property int 101 { 102 set { distance = value; type = none; } 103 get { return distance; } 104 } 105 property double 106 { 107 set { percent = (float) value; type = middleRelative; } 108 get { return (double) percent; } 109 } 110 111 char * OnGetString(char * stringOutput, void * fieldData, bool * needClass) 112 { 113 if(type == middleRelative) 114 { 115 int c; 116 int last = 0; 117 sprintf(stringOutput, "%f", percent); 118 c = strlen(stringOutput)-1; 119 for( ; c >= 0; c--) 120 { 121 if(stringOutput[c] != '0') 122 last = Max(last, c); 123 if(stringOutput[c] == '.') 124 { 125 if(last == c) 126 { 127 stringOutput[c+1] = '0'; 128 stringOutput[c+2] = 0; 129 } 130 else 131 stringOutput[last+1] = 0; 132 break; 133 } 134 } 135 } 136 else if(type == none && distance) 137 { 138 sprintf(stringOutput, "%d", distance); 139 } 140 if(needClass) *needClass = false; 141 return stringOutput; 142 } 143 144 bool OnGetDataFromString(char * stringOutput) 145 { 146 if(strchr(stringOutput, '.')) 147 { 148 percent = (float)strtod(stringOutput, null); 149 type = middleRelative; 150 } 151 else 152 { 153 distance = strtol(stringOutput, null, 0); 154 type = none; 155 } 156 return true; 157 } 158}; 159 160public enum AnchorValueType { none, offset, relative, middleRelative, cascade, vTiled, hTiled }; 161 162public struct Anchor 163{ 164 union { AnchorValue left; MiddleAnchorValue horz; }; 165 union { AnchorValue top; MiddleAnchorValue vert; }; 166 AnchorValue right, bottom; 167 168 char * OnGetString(char * stringOutput, void * fieldData, bool * needClass) 169 { 170 char tempString[256]; 171 char * anchorValue; 172 bool subNeedClass; 173 174 tempString[0] = '\0'; 175 anchorValue = left.OnGetString(tempString, null, &subNeedClass); 176 if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "left = "); strcat(stringOutput, anchorValue); } 177 178 //if(((!left.type && !right.type) && horz.distance) || horz.type == middleRelative) 179 if(!right.type && ((!left.type && horz.distance) || horz.type == middleRelative)) 180 { 181 tempString[0] = '\0'; 182 anchorValue = horz.OnGetString(tempString, null, &subNeedClass); 183 if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "horz = "); strcat(stringOutput, anchorValue); } 184 } 185 186 tempString[0] = '\0'; 187 anchorValue = top.OnGetString(tempString, null, &subNeedClass); 188 if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "top = "); strcat(stringOutput, anchorValue); } 189 190 tempString[0] = '\0'; 191 anchorValue = right.OnGetString(tempString, null, &subNeedClass); 192 if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "right = "); strcat(stringOutput, anchorValue); } 193 194 // if(((!top.type && !bottom.type) && vert.distance) || vert.type == middleRelative) 195 if(!bottom.type && ((!top.type && vert.distance) || vert.type == middleRelative)) 196 { 197 tempString[0] = '\0'; 198 anchorValue = vert.OnGetString(tempString, null, &subNeedClass); 199 if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "vert = "); strcat(stringOutput, anchorValue); } 200 } 201 202 tempString[0] = '\0'; 203 anchorValue = bottom.OnGetString(tempString, null, &subNeedClass); 204 if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "bottom = "); strcat(stringOutput, anchorValue); } 205 206 return stringOutput; 207 } 208 209 bool OnGetDataFromString(char * string) 210 { 211 this = Anchor {}; 212 return class::OnGetDataFromString(string); 213 } 214 215 bool OnSaveEdit(DropBox dropBox, void * object) 216 { 217 return dropBox.Save(); 218 } 219 220 Window OnEdit(Window listBox, Window master, int x, int y, int w, int h, Window control) 221 { 222 char * string = ""; 223 AnchorDropBox comboBox 224 { 225 editText = true; 226 parent = listBox; 227 master = master; 228 position = Point { x, y }; 229 //clientSize = Size { h = h }; 230 //size.w = w; 231 size = { w, h }; 232 anchorValue = this; 233 control = control; 234 borderStyle = 0; 235 }; 236 237 comboBox.Create(); 238 239 { 240 char tempString[MAX_F_STRING] = ""; 241 bool needClass = false; 242 char * result = OnGetString(tempString, null, &needClass); 243 if(result) string = result; 244 } 245 comboBox.contents = string; 246 return comboBox; 247 } 248}; 249 250private class AnchorButton : Button 251{ 252 toggle = true, bevel = false; 253 254 void OnRedraw(Surface surface) 255 { 256 int cw = clientSize.w; 257 int ch = clientSize.h; 258 259 surface.SetForeground(black); 260 if(checked) 261 { 262 surface.SetBackground(Color { 85,85,85 }); 263 surface.Area(0,0, cw-1, ch-1); 264 } 265 else 266 surface.LineStipple(0xAAAA); 267 268 surface.Rectangle(0,0,cw-1,ch-1); 269 270 if(active) 271 { 272 surface.LineStipple(0xAAAA); 273 surface.Rectangle(2,2,cw-3,ch-3); 274 } 275 } 276 277 bool AnchorEditor::NotifyClicked(Button button, int x, int y, Modifiers mods) 278 { 279 AnchorDropBox anchorDropBox = (AnchorDropBox)master; 280 Anchor anchor = anchorDropBox.anchorValue; 281 Window control = anchorDropBox.control; 282 DataBox dropMaster = (DataBox)anchorDropBox.master; 283 int id = button.id; 284 285 switch(id) 286 { 287 case 0: anchor.left.type = button.checked ? offset : none; break; 288 case 1: anchor.top.type = button.checked ? offset : none; break; 289 case 2: anchor.right.type = button.checked ? offset : none; break; 290 case 3: anchor.bottom.type = button.checked ? offset : none; break; 291 } 292 293 if(anchor.horz.type == middleRelative && (id == 0 || id == 2)) 294 { 295 anchorDropBox.relButtons[0].checked = false; 296 anchorDropBox.relButtons[2].checked = false; 297 } 298 if(anchor.vert.type == middleRelative && (id == 1 || id == 3)) 299 { 300 anchorDropBox.relButtons[1].checked = false; 301 anchorDropBox.relButtons[3].checked = false; 302 } 303 anchorDropBox.relButtons[id].checked = false; 304 305 //anchor.horz.type = none; 306 //anchor.vert.type = none; 307 308 { 309 int vpw, vph; 310 int x,y,w,h; 311 Window parent = control.parent; 312 313 // Fix Anchor 314 x = control.position.x; 315 y = control.position.y; 316 w = control.size.w; 317 h = control.size.h; 318 319 vpw = parent.clientSize.w; 320 vph = parent.clientSize.h; 321 if(control.nonClient) 322 { 323 vpw = parent.size.w; 324 vph = parent.size.h; 325 } 326 else if(((BorderBits)control.borderStyle).fixed) 327 { 328 if(!control.dontScrollHorz && parent.scrollArea.w) vpw = parent.scrollArea.w; 329 if(!control.dontScrollVert && parent.scrollArea.h) vph = parent.scrollArea.h; 330 } 331 332 if(anchor.left.type == offset) anchor.left.distance = x; 333 else if(anchor.left.type == relative) anchor.left.percent = (float)x / vpw; 334 if(anchor.top.type == offset) anchor.top.distance = y; 335 else if(anchor.top.type == relative) anchor.top.percent = (float)y / vph; 336 if(anchor.right.type == offset) anchor.right.distance = vpw - (x + w); 337 //else if(anchor.right.type == relative) anchor.right.percent = (float) (x + w) / vpw; 338 else if(anchor.right.type == relative) anchor.right.percent = (float) (vpw - (x + w)) / vpw; 339 if(anchor.bottom.type == offset) anchor.bottom.distance = vph - (y + h); 340 //else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (y + h) / vph; 341 else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (vph - (y + h)) / vph; 342 343 if(!anchor.left.type && !anchor.right.type) 344 { 345 anchor.horz.distance = (x + w / 2) - (vpw / 2); 346 //anchor.horz.type = anchor.horz.distance ? offset : 0; 347 } 348 else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw; 349 if(!anchor.top.type && !anchor.bottom.type) 350 { 351 anchor.vert.distance = (y + h / 2) - (vph / 2); 352 //anchor.vert.type = anchor.vert.distance ? offset : 0; 353 } 354 else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph; 355 } 356 357 { 358 char tempString[1024] = ""; 359 bool needClass = false; 360 char * string = anchor.OnGetString(tempString, null, &needClass); 361 anchorDropBox.contents = string; 362 } 363 364 dropMaster.SetData(&anchor, false); 365 anchorDropBox.anchorValue = anchor; 366 return true; 367 } 368} 369 370private class AnchorRelButton : Button 371{ 372 toggle = true; 373 bevel = false; 374 text = "%"; 375 //bevelOver = true; 376 377 void OnRedraw(Surface surface) 378 { 379 int cw = clientSize.w; 380 int ch = clientSize.h; 381 382 if(checked) 383 { 384 surface.SetForeground(black); 385 } 386 else 387 { 388 surface.SetForeground(Color{170,170,170}); 389 } 390 surface.WriteText(5,2, "%", 1); 391 392 if(active) 393 { 394 surface.LineStipple(0xAAAA); 395 surface.Rectangle(3,3,cw-4,ch-4); 396 } 397 } 398 399 bool AnchorEditor::NotifyClicked(Button button, int x, int y, Modifiers mods) 400 { 401 AnchorDropBox anchorDropBox = (AnchorDropBox)master; 402 Anchor anchor = anchorDropBox.anchorValue; 403 Window control = anchorDropBox.control; 404 DataBox dropMaster = (DataBox)anchorDropBox.master; 405 int id = button.id; 406 407 if((id == 0 || id == 2) && ((!anchor.left.type && !anchor.right.type) || anchor.left.type == middleRelative)) 408 { 409 if(button.checked) anchor.horz.type = middleRelative; else anchor.horz.type = none; 410 anchorDropBox.relButtons[(id + 2)%4].checked = button.checked; 411 } 412 else if((id == 1 || id == 3) && ((!anchor.top.type && !anchor.bottom.type) || anchor.top.type == middleRelative)) 413 { 414 if(button.checked) anchor.vert.type = middleRelative; else anchor.vert.type = none; 415 anchorDropBox.relButtons[(id + 2)%4].checked = button.checked; 416 } 417 else 418 { 419 switch(id) 420 { 421 case 0: anchor.left.type = button.checked ? relative : (anchor.left.type ? offset : none); break; 422 case 1: anchor.top.type = button.checked ? relative : (anchor.top.type ? offset : none); break; 423 case 2: anchor.right.type = button.checked ? relative : (anchor.right.type ? offset : none); break; 424 case 3: anchor.bottom.type = button.checked ? relative : (anchor.bottom.type ? offset : none); break; 425 } 426 anchorDropBox.buttons[id].checked = true; 427 if(anchor.horz.type == middleRelative) anchor.horz.type = none; 428 if(anchor.vert.type == middleRelative) anchor.vert.type = none; 429 } 430 431 { 432 int vpw, vph; 433 int x,y,w,h; 434 Window parent = control.parent; 435 436 // Fix Anchor 437 x = control.position.x; 438 y = control.position.y; 439 w = control.size.w; 440 h = control.size.h; 441 442 vpw = parent.clientSize.w; 443 vph = parent.clientSize.h; 444 if(control.nonClient) 445 { 446 vpw = parent.size.w; 447 vph = parent.size.h; 448 } 449 else if(((BorderBits)control.borderStyle).fixed) 450 { 451 if(!control.dontScrollHorz && parent.scrollArea.w) vpw = parent.scrollArea.w; 452 if(!control.dontScrollVert && parent.scrollArea.h) vph = parent.scrollArea.h; 453 } 454 455 if(anchor.left.type == offset) anchor.left.distance = x; 456 else if(anchor.left.type == relative) anchor.left.percent = (float)x / vpw; 457 if(anchor.top.type == offset) anchor.top.distance = y; 458 else if(anchor.top.type == relative) anchor.top.percent = (float)y / vph; 459 if(anchor.right.type == offset) anchor.right.distance = vpw - (x + w); 460 //else if(anchor.right.type == relative) anchor.right.percent = (float) (x + w) / vpw; 461 else if(anchor.right.type == relative) anchor.right.percent = (float) (vpw - (x + w)) / vpw; 462 if(anchor.bottom.type == offset) anchor.bottom.distance = vph - (y + h); 463 //else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (y + h) / vph; 464 else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (vph - (y + h)) / vph; 465 466 if(!anchor.left.type && !anchor.right.type) 467 { 468 anchor.horz.distance = (x + w / 2) - (vpw / 2); 469 //anchor.horz.type = anchor.horz.distance ? offset : none; 470 } 471 else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw; 472 if(!anchor.top.type && !anchor.bottom.type) 473 { 474 anchor.vert.distance = (y + h / 2) - (vph / 2); 475 //anchor.vert.type = anchor.vert.distance ? offset : none; 476 } 477 else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph; 478 } 479 480 { 481 char tempString[1024] = ""; 482 bool needClass = false; 483 char * string = anchor.OnGetString(tempString, null, &needClass); 484 anchorDropBox.contents = string; 485 } 486 487 dropMaster.SetData(&anchor, false); 488 anchorDropBox.anchorValue = anchor; 489 return true; 490 } 491} 492 493private class AnchorEditor : Window 494{ 495 interim = true; 496 borderStyle = deepContour; 497 size.h = 92; 498 499 bool OnKeyDown(Key key, unichar ch) 500 { 501 if(key == escape) 502 return master.OnKeyDown(key, ch); 503 return true; 504 } 505} 506 507private class AnchorDropBox : DropBox 508{ 509 Anchor anchorValue; 510 Window control; 511 Button relButtons[4], buttons[4]; 512 513 AnchorEditor anchorEditor 514 { 515 master = this; 516 autoCreate = false; 517 }; 518 519 Window OnDropDown() 520 { 521 int c; 522 Button 523 { 524 anchorEditor, 525 anchor = Anchor { left = 28, top = 28, right = 28, bottom = 28 }, 526 inactive = true, disabled = true 527 }; 528 for(c = 0; c<4; c++) 529 { 530 Button button = buttons[c] = AnchorButton 531 { 532 anchorEditor, id = c, 533 size = Size { (c%2)?10:28, (c%2)?28:10 } 534 }; 535 Button relButton = relButtons[c] = AnchorRelButton 536 { 537 anchorEditor, id = c; 538 }; 539 540 switch(c) 541 { 542 case 0: 543 if(anchorValue.left.type && anchorValue.left.type != middleRelative) button.checked = true; 544 if(anchorValue.left.type == relative || anchorValue.horz.type == middleRelative) relButton.checked = true; 545 546 button.anchor = Anchor { left = 0 }; 547 relButton.anchor = Anchor { left = 5, vert = 16 }; 548 break; 549 case 1: 550 if(anchorValue.top.type && anchorValue.top.type != middleRelative) button.checked = true; 551 if(anchorValue.top.type == relative || anchorValue.vert.type == middleRelative) relButton.checked = true; 552 553 button.anchor = Anchor { top = 0 }; 554 relButton.anchor = Anchor { top = 5, horz = 16 }; 555 break; 556 case 2: 557 if(anchorValue.right.type && anchorValue.right.type != middleRelative) button.checked = true; 558 if(anchorValue.right.type == relative || anchorValue.horz.type == middleRelative) relButton.checked = true; 559 560 button.anchor = Anchor { right = 0 }; 561 relButton.anchor = Anchor { right = 5, vert = 16 }; 562 break; 563 case 3: 564 if(anchorValue.bottom.type && anchorValue.bottom.type != middleRelative) button.checked = true; 565 if(anchorValue.bottom.type == relative || anchorValue.vert.type == middleRelative) relButton.checked = true; 566 567 button.anchor = Anchor { bottom = 0 }; 568 relButton.anchor = Anchor { bottom = 5, horz = 16 }; 569 break; 570 } 571 } 572 anchorEditor.Create(); 573 return anchorEditor; 574 } 575 576 void OnCloseDropDown(Window anchorEditor) 577 { 578 // TOFIX: Patch for update bug 579 master.Update(null); 580 anchorEditor.Destroy(0); 581 } 582 583 bool DataBox::NotifyTextEntry(AnchorDropBox dropBox, char * string, bool save) 584 { 585 Anchor anchor = dropBox.anchorValue; 586 Window control = dropBox.control; 587 588 if(save) 589 { 590 if(anchor.OnGetDataFromString(string)) 591 { 592 SetData(&anchor, false); 593 dropBox.anchorValue = anchor; 594 } 595 } 596 else 597 { 598 char tempString[1024] = ""; 599 bool needClass = false; 600 char * string = anchor.OnGetString(tempString, null, &needClass); 601 dropBox.contents = string; 602 } 603 return true; 604 } 605} 606