PDA

View Full Version : ezForm



Obscurity
09-16-2015, 12:53 AM
Simba/Includes/ezForm.simba
By Obscurity;

Last Updated: 2015-10-26

http://puu.sh/kZ2JS/4b311f33d7.png (http://puu.sh/kRSfT/68f8106bbc.png)

http://puu.sh/kZ2OL/4c951f7b30.png (http://puu.sh/kSVeX/86edc6bc86.png)

Click the thumbnails for full-size




Introduction



eZForm is a tool for easily creating and manipulating forms for your Simba scripts. These forms can run simultaneously with your scripts, allowing you to update variables, options, and more on the fly! You can even add images from a URL with a single line of code!


Examples



eZExample 1


http://puu.sh/l8vMD/613461d63b.png
program eZTutorial;
{$i ezForm.simba}

var
myForm:eZForm;

myButton,
myMemo:eZElement;

procedure pButtonHandler();native;
begin
myForm.height(135);
myMemo.height(80).multiple(true).text('Now I''m multi-line...');
myButton.disabled(true).offsetTop(95);
end;

begin
myForm.create('Tutorial');

myMemo:=myForm.addMemo('I''m single-line...','s8','',[10,10],[230,20],nil);
myButton:=myForm.addButton('Multi-line','b s08','',[10,35],[230,30],pButtonHandler);

myForm.show();

repeat wait(1);until false;
end.


eZExample 2


http://puu.sh/kB2JJ/601e39e3b0.png
program eZTutorial;
{$i ezForm.simba}

var
myForm:eZForm;

myCheckbox:eZElement;

procedure pCheckboxHandler();native;
begin
myForm.find().isnt(myCheckbox).disabled(myCheckbox .checked());
end;

begin
myForm.create('Tutorial');

myCheckbox:=myForm.addCheckbox('Disable components','i s8','hCheckbox',[10,10],pCheckboxHandler);
myForm.addMemo('','s08','',[10,30],[230,20],nil);
myForm.addButton('Button','b s08','',[10,55],[230,30],nil);

myForm.show();

repeat wait(1);until false;
end.


eZExample 3


http://puu.sh/kB9oH/87eced3f93.gif
program eZTutorial;
{$i ezForm.simba}

var
myForm:eZForm;

myButton,
myListbox:eZElement;

procedure pButtonHandler();native;
begin
myListbox.prop('cols',2);
myButton.prop('disabled',true);
end;

begin
myForm.create('Tutorial');

myListbox:=myForm.addListbox(['First','Second','Third','Fourth','Fifth','Sixth', 'Seventh','Eighth','Nineth','Tenth'],'s8','',[10,10],[230,100],nil);
myButton:=myForm.addButton('Two Columns','b s08','',[10,115],[230,30],pButtonHandler);

myForm.show();

repeat wait(1);until false;
end.


eZExample 4


http://puu.sh/l8wHM/fd7ffb6f5d.png
program eZTutorial;
{$i ezForm.simba}

var
myForm:eZForm;

begin
myForm.create('Tutorial');

myForm.addGroupbox('Tooltip','b s10','',[10,10],[230,50]);
myForm.addLabel('Hover over me. I have a tooltip!','s8','',[20,35]).title('This is a tooltip!');

myForm.show();

repeat wait(1);until false;
end.


eZExample 5


http://puu.sh/kB9Ne/ce4ff5f6a9.gif
program eZTutorial;
{$i ezForm.simba}

var
myForm:eZForm;

procedure pButtonHandler();native;
begin
myForm.find('#hMemo')[0].text('');
end;

procedure pMemoHandler();native;
var
Memo_Color,
Memo_Length:integer;
Memo_Value:string;
begin
Memo_Value:=myForm.find('#hMemo')[0].val();
Memo_Length:=length(Memo_Value);
Memo_Color:=round(Memo_Length/12*255);

myForm.find('#hLabel')[0].color(Memo_Color).text('Characters: '+toStr(Memo_Length)+'/12');

myForm.find('#hButton')[0].disabled(Memo_Length=0)
end;

begin
myForm.create('Tutorial');

myForm.addLabel('Characters: 0/12','i s08','hLabel',[10,10]);
myForm.addMemo('','s8','hMemo',[10,30],[230,20],pMemoHandler).maxLength(12);
myForm.addButton('Clear','b s08','hButton',[10,55],[230,30],pButtonHandler).disabled(true);

myForm.show();

repeat wait(1);until false;
end.


eZExample 6


http://puu.sh/kZ0km/7f00e025a9.gif
program eZTutorial;
{$i ezForm.simba}

var
myForm:eZForm;

myImage:eZElement;

procedure pButtonHandler(vSender:tObject);native;
begin
case myImage.src() of
'http://puu.sh/kYXD8/e9dde9e433':myImage.src('http://puu.sh/kYXCm/2631effd0c');
'http://puu.sh/kYXCm/2631effd0c':myImage.src('http://puu.sh/kYXD8/e9dde9e433');
end;
end;

begin
myForm.create('Tutorial');

myImage:=myForm.addImage('http://puu.sh/kYXCm/2631effd0c','',[10,10],[230,230],nil);
myForm.addButton('Invert','b s08','hInverted',[10,260],[230,30],pButtonHandler);

myForm.show();

repeat wait(1);until false;
end.


eZExample 7


http://puu.sh/kB8ai/9cb7bd8be7.png
program eZTutorial;
{$i ezForm.simba}

var
myForm:eZForm;

myCombobox,
myText:eZElement;

procedure pButtonHandler();native;
begin
myText.text('You submitted: '+myCombobox.val());
end;

begin
myForm.create('Tutorial');

myCombobox:=myForm.addCombobox(['First','Second','Third','Fourth','Fifth'],'s8','',[10,10],230,nil).readOnly(true);
myForm.addButton('Submit','b s08','',[10,40],[230,30],pButtonHandler);
myText:=myForm.addLabel('You submitted: ','s08','',[10,80]);

myForm.show();

repeat wait(1);until false;
end.


eZExample 8


http://puu.sh/kMJqd/d55a4762e6.png
program eZTutorial;
{$i eZForm.simba}

var
myForm:ezForm;

procedure eButtonHandler(vSender:tObject);native;
var
_Sender:eZElement;
begin
_Sender:=vSender.toElement();

if _Sender.equals('#addButton') then
myForm.find('#progressBar')[0].val('+10')
else if _Sender.equals('#subtractButton') then
myForm.find('#progressBar')[0].val('-10')
else if _Sender.equals('#setButton') then
myForm.find('#progressBar')[0].val(+50);
end;

begin
myForm.create('Tutorial');

myForm.addProgressbar(90,'progressBar',[10,10],[230,20]);
myForm.addButton('Add 10','b s8','addButton',[10,40],[115,30],eButtonHandler);
myForm.addButton('Subtract 10','b s8','subtractButton',[125,40],[115,30],eButtonHandler);
myForm.addButton('Set as 50','b s8','setButton',[10,70],[230,30],eButtonHandler);

myForm.show();

repeat wait(1);until false;
end.


eZExample 9


http://puu.sh/kYK1a/37c0792d95.png
program new;
{$i ezForm.simba}

var
myForm:eZForm;

begin
myForm.create('Tutorial');

myForm.addLabel('Username','c8421504 i s08','',[10,10]);
myForm.addMemo('eZForm','','',[10,30],[230,20],nil).prop('maxlength',12);
myForm.addLabel('Password','c8421504 i s08','',[10,60]);
myForm.addMemo('Rocks my socks!','','',[10,80],[230,20],nil).prop('maxlength',20).prop('password',true);

myForm.show();
repeat wait(1);until false;
end.


eZExample 10


http://puu.sh/ldcaK/0436a7ade3.png
program eZTutorial;
{$i ezForm.simba}

var
myForm:eZForm;

begin
myForm.create('Tutorial');

myForm.addTab(['Memo','Picture','Button'],'s8','tabList',[10,10],[230,120],nil).select(1);
myForm.addMemo('Memo','c8421504 i s08','',[10,10],[200,70],nil).parent('#tabList0');
myForm.addImage('http://puu.sh/ldbMk/00ed57d427.png','',[10,10],[200,70],nil).parent('#tabList1');
myForm.addButton('Button','b s08','',[10,10],[200,70],nil).parent('#tabList2');

myForm.show();

repeat wait(1);until false;
end.


Getting Started



Download eZForm.simba (https://raw.githubusercontent.com/ObscuritySRL/eZForm/master/ezForm.simba) from Github and place it into your Includes folder.

Download ProSocks.dll (https://github.com/Brandon-T/ProSocks/releases/download/v0.5/Prosocks.dll) from Github and place it into your Plugins folder.

Read the quick guide to using eZForm found here (https://villavu.com/forum/showthread.php?t=114765).


Thanks



Firstly, I want to thank Olly;. Since eZForm's release, I've been pestering him with endless questions regarding forms and he's been incredibly patient with me.

Secondly, Brandon;'s ProSocks helped solve the issue raised in the f248a16 (https://github.com/ObscuritySRL/eZForm/commit/f248a16) commit.

Ross
09-16-2015, 01:08 AM
AWESOME! Repped!

Incurable
09-16-2015, 02:07 AM
Could you give an example of a complete script form, and why it's easier to use than SPF?

Obscurity
09-16-2015, 02:21 AM
Incurable;

If you look at the screenshot from my ogLivid script...
http://puu.sh/jY51s/421468b38a.png
...And then look at the code, you can see that it's ugly (shutup) and incredibly long.

To make that same form using ezForm:
ezForm.new('ogLivid',[290,290]);
ezForm.addGroupBox('ogLivid','s14 b','',[10,10],[270,270]);
ezForm.addGroupBox('Map Location','s10 i','',[25,40],[240,65]);
ezForm.addButton('Set Location','b','',[35,65],[220,30],pSetLocation);
ezForm.addGroupBox('Perform Actions','s10 i','',[25,110],[240,155]);
ezForm.addCheckbox('Cure Diseased livid','s8','hCure',[35,135],pCure);
ezForm.addCheckbox('Deposit Trade wagon','s8','hDeposit',[35,160],pDeposit);
ezForm.addCheckbox('Encourage Drained Pauline','s8','hEncourage',[35,185],pEncourage);
ezForm.addCheckbox('Fertilise Empty patch','s8','hFertilise',[35,210],pFertilise);
ezForm.addCheckbox('Fix Broken fence','s8','hFix',[35,235],pFix);
ezForm.show();

http://puu.sh/kcQFo/8f32b9a2f8.png

You can change settings on the fly and it'll edit the live script. If I wanted to only enourage Pauline if the checkbox is checked:
if ezForm.getComponent('hEncourage').getState() then
//~ Encourage Pauline;

Or, if you wanted checking it to run a procedure, you can see changing the value of hEncourage will run the pEncourage procedure. :).

Edit: I just realized I have to add c# (color) to fonts as well. Currently you can supply any of:
(*
b or bold
i or italic
s or strikeout
u or underline
s# or size#
*)

Incurable
09-16-2015, 02:48 AM
-snip-

Well I'm convinced, great work. :D

Clarity
09-16-2015, 07:43 AM
Very nice work - I love making scripting tools like this. Looking forward to what this looks like in a few months, and what cool stuff people make with it!

+Rep

Joopi
09-16-2015, 09:34 AM
Oh man that's sick!

The Mayor
09-16-2015, 12:24 PM
The thing the SPF lacks is customizability. If something like this was compatible with the SRL player management system (multiplayer/loading/saving/encrypting/decrypting armys) I can see it replacing the SPF.

rj
09-16-2015, 02:12 PM
stuff
[/SIMBA]

Plus you could theoretically put that code into a loop and make it even shorter.

pretty cool pretty cool

Ross
09-16-2015, 02:12 PM
The thing the SPF lacks is customizability. If something like this was compatible with the SRL player management system (multiplayer/loading/saving/encrypting/decrypting armys) I can see it replacing the SPF.

Besides loading and saving settings for multiple accounts, is there any other use for armies/multiplayer?


-snip-

Yeah a for..to..do loop with a tStringArray etc. and incEx() for the y variable could make this super easy. It's what I do for my Smart Graphics Proggies.

StickToTheScript
09-16-2015, 03:07 PM
Nice work! Repped!

The Mayor
09-17-2015, 09:14 AM
Besides loading and saving settings for multiple accounts, is there any other use for armies/multiplayer?

Yes, multiple players within the same script. That's what multiplayer means.

Obscurity
09-17-2015, 01:49 PM
I think he more meant - what is the use of armies apart from the obvious gold farming.

bonsai
09-20-2015, 11:36 AM
Yes, multiple players within the same script. That's what multiplayer means.


I think he more meant - what is the use of armies apart from the obvious gold farming.

Well, I don't do any farming but I have a handful of accounts and I don't like remembering the signins for them.

The player manager does a nice job of partitioning this information from the script writer so people aren't posting scripts with hard coded logins or making people add them in before running.

Here's some code (http://pastebin.com/raw.php?i=pwTWvaUc) I hacked up the last time someone (?) was messing with the forms.

It's has a similar flavor but is centered on making the player manager easier, not making forms more moldable.

Obscurity
10-02-2015, 03:37 AM
After all of the good responses, I decided to spend some time on ezForm today. The updated ezForm.simba will be attached to the original post.

I tried to make it very easy to use, and have the feel of JS (or jQuery, to more precise). I'm sure some won't like this, but I'd be willing to hear you out, so please share!

I made the following using ezForm. It's a simple form for Ross' AIO Combat (https://villavu.com/forum/showthread.php?t=114183):
http://puu.sh/kvswD/611e04b2cc.png

It works without his AIO script. It's just a demo! If you'd like to toy around with it, please:

Save this (http://puu.sh/kvspt/de18d2f497.png) image as RossAIOCombat.png at C:\Simba\RossAIOCombat.png.
Download and place ezForm.simba into C:\Simba\Includes.
Copy and play the following script:
program ezFormTest;
{$i ezForm.simba}

procedure hButtonHandler();native;
begin
ezForm.find('hEdit').text('');
end;



procedure hItemsHandler(vSender:tObject);native;
var
_AlchItems,
_LootItems:boolean;
begin
_AlchItems:=ezForm.find('hAlchItems').is('checked' );
_LootItems:=ezForm.find('hLootItems').is('checked' );

ezForm.find('hLootItemsList').prop('disabled',not _LootItems);
ezForm.find('hAlchItems').prop('disabled',not _LootItems);
ezForm.find('hAlchItemsList').prop('disabled',not (_AlchItems and _LootItems));
end;



procedure hListHandler(vSender:tObject);native;
var
_Sender:tZComponent;
begin
_Sender:=tZComponent(vSender);
_Sender.text(replaceRegExpr('[^0-9$,\s]',_Sender.text(),'$1',true));
end;



begin
ezForm.new('Ross'' AIO Combat',[400,465]);

ezForm.addImage('RossAIOCombat.png','hImage',[0,0],[400,125],nil);
ezForm.addLabel('Ross'' AIO Combat','b s16','',[17,7]);
ezForm.addLabel('Ross'' AIO Combat','b c65535 s16','',[15,5]);

ezForm.addGroupBox('Options','b s14','',[10,130],[380,325]);

ezForm.addGroupBox('Abilities','b i s10','',[20,160],[360,95]);
ezForm.addLabel('Note: This script does not support Legacy combat.','i c255 s8','',[30,180]);
ezForm.addCheckbox('Use regeneration','s8','hRegeneration',[30,200],nil);
ezForm.addCheckbox('Use thresholds','s8','hThresholds',[200,200],nil);
ezForm.addCheckbox('Use ultimates','s8','hUltimates',[30,225],nil);

ezForm.addGroupBox('Looting','b i s10','',[20,265],[360,180]);
ezForm.addCheckbox('Bury bones','s8','hBury',[30,285],nil);
ezForm.addCheckbox('Loot charms','s8','hCharms',[200,285],nil);

ezForm.addCheckbox('Loot items','s8','hLootItems',[30,305],hItemsHandler);
ezForm.addLabel('Supply a list of model IDs seperated by commas:','c8421504 i s8','',[40,325]);
ezForm.addEdit('123456, 234567, 345678, 567890','s8','hLootItemsList',[40,345],[330,20],hListHandler).prop('disabled',true);

ezForm.addCheckbox('Alch items','s8','hAlchItems',[40,370],hItemsHandler).prop('disabled',true);
ezForm.addLabel('Supply a list of texture IDs seperated by commas:','c8421504 i s8','',[50,390]);
ezForm.addEdit('987654, 876543, 765432','s8','hAlchItemsList',[50,410],[320,20],hListHandler).prop('disabled',true);

ezForm.show();

{This is just to make the script persistent}
repeat until false;
end.


Without spacing, that's a mere 20 lines of code to create that form - excluding the optional even handlers, obviously!

There are a few things to note. When creating an element (I hate "component"), you typically supply a caption or text, some font details, a handle to reference the element later, a point and dimensions, and then an event handler for things such as clicks.

So, if we wanted to add an edit box that had the initial text, "Hi mom!", we'd:
ezForm.addEdit('Hi mom!'...);

If we wanted to add some font styles, instead of having plain text, we'd:
ezForm.addEdit('Hi mom!','c255 bold i underline s s16'...);
This is important. Fonts have some options:
(*
b or bold
c# or color#
i or italic
s or strikeout
u or underline
s# or size#
*)

If we wanted to reference the edit later, we could do:
someEdit:=ezForm.addEdit(...);
//~ Some code
someEdit.text('Hi mom!');

{Or...}

ezForm.addEdit('Hi mom!','b','hSomeEdit'...);
//~ Some code
ezForm.find('hSomeEdit').text('My text has changed!');

If we wanted to disable, set a maxlength, and recolor the edit (let's assume it's stored in someEdit), we'd:
someEdit.prop('color',255).prop('disabled',true).p rop('maxlength',12);

Of course, there's a lot more, but have a peak at the prop() methods and others.



So, using Ross' AIO Combat, you can see at the top of his script (https://raw.githubusercontent.com/SRLRoss/AIO-Combat/master/AIOCombat.simba) has has constants that the user must specify before running the script. Well, the great thing about ezForms, you can change the elements while the script runs and have it update and have the script react on the fly! That the following example...

You can see Ross uses:
USE_THRESHOLDS = true;
//~ Some code
if (not USE_THRESHOLDS) or (useSGS()) then
To have it automatically update to what the user wants, using the sample script above:
USE_THRESHOLD := ezForm.find('hThresholds');
//~ Some code
if (not USE_THRESHOLDS.is('checked')) or (useSGS()) then



I'd love to add more on what it can do, but I have to head to bed! Keep in mind, I've only worked on this a bit over 2-3 days, so it's not by any means complete. I just want a community opinion as I go, since I want to write this for y'all. :).

Cheers to Ross; for allowing me to use his script as an example. :).

Ross
10-02-2015, 03:43 AM
+Repped. Awesome work, would love to see this officially supported.

rj
10-03-2015, 04:17 AM
One quick suggestion that I'd think would make this maybe slightly easier to use

function tZComponent.prop(vProperty:string;vValue:variant): tZComponent;overload;

you could make vProperty a enum so that we can only enter checked, colored, disabled, etc etc

Obscurity
10-04-2015, 12:26 AM
Just to make sure I'm understanding, rj;, you want something like:
eZForm.find('someEdit').prop(eZPropDisabled);

(I only used eZProp... because currently things like tags are eZTagEdit)

rj
10-04-2015, 12:28 AM
Just to make sure I'm understanding, rj;, you want something like:
eZForm.find('someEdit').prop(eZPropDisabled);

(I only used eZProp... because currently things like tags are eZTagEdit)

Yea

Zyt3x
10-14-2015, 08:45 PM
Stickified :)

Obscurity
10-14-2015, 09:25 PM
Cheers, Zyt3x;!

Going to try and put some work into ezForm and ogLib tonight. I want to have a {$DEFINE DARKSCAPE} and such. :-).

Edit:

So I'm in a pickle. The is method...
vCheckbox.is('checked');
vEdit.is('visible');
//~ Etc
..is breaking codehints. So, I need opinions. I can leave it as is and have codehints look like...
http://puu.sh/kKDDl/e59f248af2.png
...or I can rename it be and have codehints like...
http://puu.sh/kKDIh/46337d65e5.png

An alternative suggested by Ross is equals. But keep in mind, it can be used for:
vCheckbox.equals('button');
//~ Etc

Paradoxs
10-15-2015, 01:50 AM
So it would look like this?

vCheckbox.be('checked');
vEdit.be('visible');
//~ Etc

If that's the case, there's no complaint from me. If it lets have have codehints and this same functionality then it's really all the same, different syntax same logic :P

Obscurity
10-15-2015, 01:52 AM
So it would look like this?

vCheckbox.be('checked');
vEdit.be('visible');
//~ Etc

If that's the case, there's no complaint from me. If it lets have have codehints and this same functionality then it's really all the same, different syntax same logic :P

That's correct. I like be because it's short. Ross;' suggestion of equals wouldn't be bad, but I feel like that'd be better for comparing two components.

Paradoxs
10-15-2015, 01:59 AM
I agree, I think be is the better option. Equals is definitely something that should be used for comparing objects. I wonder why "is" is breaking code hints

Olly
10-15-2015, 02:16 AM
I agree, I think be is the better option. Equals is definitely something that should be used for comparing objects. I wonder why "is" is breaking code hints

Because it's a keyword on which the parser works on.

Obscurity
10-15-2015, 02:21 AM
Updated eZForm (linked it on Github now). Will update all of the examples tomorrow. It's safe to use as an include now, as I don't expect too much to change in the future that would break backward compatibility. Just adding properties, controls, etc.

Bed time!

AFools
10-15-2015, 07:43 AM
dumb question; this is compatible with osrs yeah?

Obscurity
10-15-2015, 10:05 AM
dumb question;

Works with anything, as it is a separate include from reflection, ogLib, SRL, etc.

Edit:

All examples have been added to the original post and updated for the new eZForm. I've also recently pushed an update which allows for methods to be called on arrays of components. Check it out here (https://github.com/ObscuritySRL/eZForm/commit/585f35e1aa901b3daa5b218286184c350019fcca).

Edit 2:

I've removed radioButtons and added progressBars and some useful methods. Check it out here (https://github.com/ObscuritySRL/eZForm/commit/f3f61fee6cc26d4ebbbe9e7abb70dd669cd058f3). An example progressBar has been added to the original post.

Obscurity
10-21-2015, 03:37 AM
:: Automated Message ::
Added eZForm.addImageURL() and More

https://avatars.githubusercontent.com/u/10840155?s=13 ObscuritySRL (https://github.com/ObscuritySRL) updated on Tuesday, October 20, 2015 (https://github.com/ObscuritySRL/eZForm/commit/0ec729693849a3703f650fc186f7188e0bc6c43f)


66 additions, 11 deletions.

Added eZForm.addImageURL(). If the URL passed is an image, even if it
doesn't end in GIF, JPG, etc, it will automatically be downloaded and
added to the form at the specific point with the specified dimensions.

Added tZComponent.prop('handle').

A total of 1 files were affected:
ezForm.simba (https://github.com/ObscuritySRL/eZForm/blob/master/ezForm.simba)



« Download ZIP (https://github.com/ObscuritySRL/eZForm/archive/master.zip) »

Obscurity
10-27-2015, 02:14 AM
:: Automated Message ::
Added Passwords, Image URLs, Methods, and More!

https://avatars.githubusercontent.com/u/10840155?s=13 ObscuritySRL (https://github.com/ObscuritySRL) updated on Monday, October 26, 2015 (https://github.com/ObscuritySRL/eZForm/commit/f248a16a53dddb0b18965afba99bc5cabf387455)


181 additions, 72 deletions.

eZForm now requires ProSocks. This went without question, as various
functions, such as getPage() and rewriteFile() would cause access
violations when used in event handlers. See initial post of the eZForm
thread for more details.

Changed various variable names to be consistent with their methods.

Added the password property and methods to edits and memos. An example
has been added to the initial post of the eZForm thread.

Added the handle property and methods to all components.

Added the src property and methods to images. An example has been added
to the initial post of the eZForm thread.

Removed tZForm.addImageURL(). If a URL, requiring the preceding http://,
is passed to tZForm.addImage(), it'll automatically download and add the
image.

A total of 1 files were affected:
ezForm.simba (https://github.com/ObscuritySRL/eZForm/blob/master/ezForm.simba)



« Download ZIP (https://github.com/ObscuritySRL/eZForm/archive/master.zip) »

Brandon
10-28-2015, 01:57 AM
...




getTClient().MFiles.RewriteFile(.....);

//OR

getTClient().getMFiles().RewriteFile(....); //I don't have Simba installed to test which of the above is correct..


Will work from any thread. I don't think there's a way to do it with Sockets though..

These are the only interfaces I see that are exported: https://github.com/MerlijnWajer/Simba/blob/master/Units/MMLAddon/LPInc/Classes/MML/lptclient.pas#L148

Lama
11-02-2015, 04:28 PM
This is awesome. Can you call multiple forms in a single script? For example, I could call a form to declarePlayers with, close that form on submit, then bring up a live form for the user to interact with live?

EDIT: There seems to be a conflict with ogLib:

program new;
{$i ogLib/lib/core/core.simba}
{$i ezForm.simba}

begin
end.

Throws a too many parameters error inside ezForm.simba, line 162: if length(_StringArray) then

Obscurity
11-02-2015, 06:16 PM
This is awesome. Can you call multiple forms in a single script? For example, I could call a form to declarePlayers with, close that form on submit, then bring up a live form for the user to interact with live?

EDIT: There seems to be a conflict with ogLib:

program new;
{$i ogLib/lib/core/core.simba}
{$i ezForm.simba}

begin
end.

Throws a too many parameters error inside ezForm.simba, line 162: if length(_StringArray) then
I've got that error too, not sure how I fixed it but my scripts work with ogLib now. May even have been something as dumb as restarting Simba.

I didn't add multiple forms because I wanted it to be easy for everyone to use - and having never used SPF, I didn't personally think there'd be much demand for it.

I want eZForm to reflect the community here. If people want, or think that multiple forms would be useful, I'd be very happy to add them.

Should add a poll to the OP. :-).

Lama
11-02-2015, 06:45 PM
I've got that error too, not sure how I fixed it but my scripts work with ogLib now. May even have been something as dumb as restarting Simba.

I didn't add multiple forms because I wanted it to be easy for everyone to use - and having never used SPF, I didn't personally think there'd be much demand for it.

I want eZForm to reflect the community here. If people want, or think that multiple forms would be useful, I'd be very happy to add them.

Should add a poll to the OP. :-).

Well, not necessarily have multiple forms per se, but like, un-show the one and only, modify it, then re-show. Would something like work?

EDIT: So I'm just here, finaegling with the too many parameters error and I stumbled upon a fix(?)

program new;
{$DEFINE SRLCOMPATIBILITY}
{$i srl-6/srl.simba}
{$i ezForm.simba}
{$i ogLib/lib/core/core.simba}

begin
end.
This throws no errors.

I guess the order in which you include matters?

Clarity
11-02-2015, 11:33 PM
I guess the order in which you include matters?
Yes, it does. Just like the order of code matters in your scripts :)

Obscurity
11-03-2015, 12:00 AM
A heads up - I'm making eZForm support multiple forms. This will require some script updates. I'll explain.

After discussing it with some people, I had two approaches:

Option 1:
eZForm.new('First form');
eZForm.new('Second form');

//~ ...

eZForm[0].find('#SomeCheckbox')[0].checked(true);

Option 2:
var
myForm:eZForm;
mySecondForm:eZForm;

begin
myForm.create('First form');
mySecondForm.create('Second form');

//~ ...

myForm.find('#SomeCheckbox')[0].checked(true);

I've decided to go with option 2, as it seemed to be the general preference. For those of you with scripts using eZForm, this will only mean using eZForm as a type now. Should be a very easy update for you, not so much for me. :P.

Edit - It's coming along great (no thanks to Lama):
http://puu.sh/l7ud3/7b35425989.png

Added a lot of methods to eZForm and such! It's crazy-customizable now! Auto-detects and adds padding/adjust size, etc!

Lama
11-03-2015, 03:54 AM
(no thanks to Lama)

Hey now, let's not get too hasty here.

https://puu.sh/l7umC/e926099e0c.png

I think I'm helping a lot.

Bring on the innovation.

Obscurity
11-04-2015, 03:19 AM
:: Automated Message ::
Multi-form Support, Added Methods, Etc

https://avatars.githubusercontent.com/u/10840155?s=13 ObscuritySRL (https://github.com/ObscuritySRL) updated on Tuesday, November 11, 2015 (https://github.com/ObscuritySRL/eZForm/commit/45c91b32f748c840ff0d59895960cb47545552d8)


653 additions, 584 deletions.

Added support for multiple forms. Forms must be assigned to variables,
using the eZForm type, and created using the eZForm.create() method.
Size and padding will automatically be calculated.

tZComponent and tZComponentArray have been renamed to eZElement and
eZElementArray.

Elements that don't support height, such as combobox, edit, etc, no
longer require it as a parameter.

Renamed handle methods and variables to ID.

Simplified eZElement.be() and eZElement.prop() methods, greatly
decreasing include size.

Added numerous methods to the eZForm type, matching several element
methods. For example, eZForm.disabled().

Added various methods, such as eZElement.cols(), eZElement.disabled(),
eZElement.id(), eZElement.password(), eZElement.tagName(),
eZElement.title(), etc.

Added the style property to elements. This returns the control's font
color, size, style (bold, italic, etc).

Changed combobox, edit, and memo methods to use the value property
instead of text.

The tObject.toComponent() method has been renamed to
tObject.toElement().

Image URLs now support HTTPS URLs.

A total of 1 files were affected:
ezForm.simba (https://github.com/ObscuritySRL/eZForm/blob/master/ezForm.simba)



« Download ZIP (https://github.com/ObscuritySRL/eZForm/archive/master.zip) »



Edit - Examples in the original post have been updated to the new eZForm.

A massive apology for the many changes, not backward compatible, but they were required to make eZForm support multiple forms, which seemed to be the general preference. I think you'll find they were worth it. :).

Due to a temporary glitch, removing elements from a visible form has been temporarily disabled. For some reason, it's causing eZForm to crash. I'll look into this more as I get time.

If you aren't happy with the calculated size, the eZForm.height() and eZForm.width() methods are your friend.

eZElement.hide(), eZElement.show(), and eZElement.visible() methods, when called from an event handler, are causing unexpected results when changing the visible state of an element. Again, fixed as I get time.

It was damn-near rewritten, so if I forgot something, post!

Lama
11-04-2015, 03:21 AM
Wooooooooooooooooooooooooooooooooooooooooooooooooo oooooooooooooooooooooo! Can't wait to put this to good use! :) +Rep

StickToTheScript
11-04-2015, 03:35 AM
Awe... I cant give hims more reps... :(

Daniel
11-06-2015, 03:09 PM
Nice work Obscurity;! :-)

I started on something similar quite a few years ago but never finished, the result of which can be found in the SSRL section, and now pasted here:

{================================================= =============================)
[ SPL - Simba Presentation Library ]
[ version 1.0 ]
[------------------------------------------------------------------------------]
[ ]
(================================================= =============================}

{ SSRLers! Currently what is not implemented are the following:
* SPL_EnableNonButtonEventHandlers (in fact, no events of any kind yet!)
* SPL_UseLapeOptionalParametres (no need, yet!)
* SPL_MultipleForms (this is already enabled by default. Atm, not defining this will make no difference)

Enjoysies! :D }

{$Define SPL} // Using SPL?
{$Define SPL_Prefix} // Prefix all user-editable identifiers with SPL_?
{$Define SPL_DisplayErrors} // Output errors.
{$Define SPL_CheckForUpdates} // Check for updates to the SPL library?
{$Define SPL_EnableNonButtonEventHandlers} // Enable OnClick/OnChange support for events for controls other than the TButton?
{$Define SPL_UseLapeOptionalParametres} // Enable Lape optional parametres?
{$Define SPL_MultipleForms} // Enable support for multiple form creation?
{$Define SPL_StringIdentifiers} // Use strings as identifiers for controls?
{$Define SPL_Unicode} // Enable Unicode support.

{$ifDef Windows}
{$ifDef Windows8}
const CRLF = #$D;
{$else}
const CRLF = #$D#$A;
{$endIf}
{$else}
const CRLF = #$D;
{$endIf}

const
// DNU prefix == DO NOT USE (i.e. not recommmended to call them inside your scripts)
DNUSPL_FullName = 'Simba Presentation Library';
DNUSPL_Acronym = 'SPL';
DNUSPL_Version = 0.01;

{$ifDef SPL_Prefix} SPL_ERR_RangeCheck = $1; {$else} ERR_RangeCheck = $1; {$endIf}
{$ifDef SPL_Prefix} SPL_ERR_Unassigned = $2; {$else} ERR_Unassigned = $2; {$endIf}
{$ifDef SPL_Prefix} SPL_ERR_InvalidIdentifier = $4; {$else} ERR_InvalidIdentifier = $4; {$endIf}
{$ifDef SPL_Prefix} SPL_ERR_InvalidTabControl = $8; {$else} ERR_InvalidTabControl = $8; {$endIf}
{$ifDef SPL_Prefix} SPL_ERR_InvalidTabPage = $10; {$else} ERR_InvalidTabPage = $10; {$endIf}
{$ifDef SPL_Prefix} SPL_ERR_InvalidParent = $20; {$else} ERR_InvalidParent = $20; {$endIf}
{$ifDef SPL_Prefix} SPL_ERR_InvalidLength = $40; {$else} ERR_InvalidLength = $40; {$endIf}

DNUSPL_Err_Str_PrependText = '[' + DNUSPL_Acronym + '][ERROR] %s, Form %u: ';
DNUSPL_Err_Str_ImplicitCast = '[' + DNUSPL_Acronym + '][WARNING] %s, Form %u: Implicit cast made with identifier "%s" down to "%s".';
DNUSPL_Err_Str_RangeCheck = DNUSPL_Err_Str_PrependText + 'Out of range.';
DNUSPL_Err_Str_Unassigned = DNUSPL_Err_Str_PrependText + 'Unable to validate controls existence';
DNUSPL_Err_Str_InvalidIdentifier = DNUSPL_Err_Str_PrependText + 'The control with identifier "%s" does not exist.';
DNUSPL_Err_Str_InvalidTabControl = DNUSPL_Err_Str_PrependText + 'The tab control with identifier "%s" does not exist.';
DNUSPL_Err_Str_InvalidTabPage = DNUSPL_Err_Str_PrependText + 'The tab with the caption "%s" does not exist.';
DNUSPL_Err_Str_InvalidParent = DNUSPL_Err_Str_PrependText + 'Invalid parent control "%s".';
DNUSPL_Err_Str_InvalidLength = DNUSPL_Err_Str_PrependText + '"%s" does not have the same length as "%s".';

DNUSPL_ComponentPrecede = 'frm' + #$5f;
{$ifDef SPL_Prefix} SPL_COMP_TabSheet = 0; {$else} COMP_TabSheet = 0; {$endIf}
{$ifDef SPL_Prefix} SPL_COMP_Tab = 1; {$else} COMP_Tab = 1; {$endIf}
{$ifDef SPL_Prefix} SPL_COMP_Button = 2; {$else} COMP_Button = 2; {$endIf}
{$ifDef SPL_Prefix} SPL_COMP_TextBox = 3; {$else} COMP_TextBox = 3; {$endIf}
{$ifDef SPL_Prefix} SPL_COMP_DropDown = 4; {$else} COMP_DropDown = 4; {$endIf}
{$ifDef SPL_Prefix} SPL_COMP_Text = 5; {$else} COMP_Text = 5; {$endIf}
{$ifDef SPL_Prefix} SPL_COMP_Picture = 6; {$else} COMP_Picture = 6; {$endIf}
{$ifDef SPL_Prefix} SPL_COMP_CheckBox = 7; {$else} COMP_CheckBox = 7; {$endIf}
{$ifDef SPL_Prefix} SPL_COMP_MemoBox = 8; {$else} COMP_MemoBox = 8; {$endIf}

type
Float = Extended;
TString = {$ifDef SPL_Unicode} UnicodeString; {$else} AnsiString; {$endIf}
TProcedure = procedure;

TFormRect = record
X, Y: Integer;
Width, Height: Word;
end;

TEventHandler = record
Name: TString;
ProcToCall: TProcedure;
end;

var
DNUSPLComponentCount: Word;
DNUSPLFormCount: SmallInt;
DNUSPLLastError: Cardinal;

DNUSPLForms: array of TForm;
DNUSPLProcArray: array of TEventHandler;

function Rect(const X, Y, Width, Height: Integer): TFormRect;
begin
Result.X := X;
Result.Y := Y;
Result.Width := Width;
Result.Height := Height;
end;

// Ensures Pascal identifier validity.
// identifier = letter | underscore { letter | digit | underscore }
function SPL_Trim(const Str: TString): TString;
var
I, strLen: Integer;
tmpOrd: Byte;
begin
strLen := Length(Str);
for I := 1 to strLen do
if(not(Str[I] = #32)) then
begin
tmpOrd := Ord(Str[I]);

if(InRange(tmpOrd, 65, 90)) then
Result := Result + Chr(tmpOrd + 32) else
if(InRange(tmpOrd, 97, 122) xor (tmpOrd = 95) xor ((InRange(tmpOrd, 48, 57){ and not(I = 1)}))) then
Result := Result + Str[I];
end;
end;

// Rather self-explanatory.
function {$ifDef SPL_Prefix} SPL_GetLastError {$else} GetLastSPLError {$endIf}: Cardinal;
begin
Result := DNUSPLLastError;
end;

// Find's all components and free's them when a form wants to close.
procedure DNUSPLOnFormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
I: Integer;
begin
CanClose := False;

for I := 0 to (TForm(Sender).ComponentCount - 1) do
TForm(Sender).Components[I].Free;

CanClose := True;
end;

// Unsafely creates a form.
function DNUSPL_CreateForm(const X, Y, Width, Height: Integer; const ACaption: TString; const ABorderStyle: TBorderStyle): Integer;
begin
Inc(DNUSPLFormCount);
SetLength(DNUSPLForms, DNUSPLFormCount);
SetLength(DNUSPLProcArray, DNUSPLFormCount);

Writeln(DNUSPLFormCount);

DNUSPLForms[DNUSPLFormCount - 1] := TForm.Create(nil);
DNUSPLForms[DNUSPLFormCount - 1].SetBounds(X, Y, Width, Height);
DNUSPLForms[DNUSPLFormCount - 1].ClientWidth := Width;
DNUSPLForms[DNUSPLFormCount - 1].ClientHeight := Height;
if((X = 0) and (Y = 0)) then
DNUSPLForms[DNUSPLFormCount - 1].Position := poMainFormCenter;
DNUSPLForms[DNUSPLFormCount - 1].BorderStyle := ABorderStyle;
DNUSPLForms[DNUSPLFormCount - 1].Caption := ACaption;
DNUSPLForms[DNUSPLFormCount - 1].OnCloseQuery := @DNUSPLOnFormCloseQuery;

if(Assigned(DNUSPLForms[DNUSPLFormCount - 1])) then
Result := DNUSPLFormCount - 1 else Result := -1;
end;

function DNUSPL_ShowForm(const AForm: Integer; const APauseScript: Boolean): Boolean;
begin
Result := False;
if(not(InRange(AForm, 0, (DNUSPLFormCount - 1))) or not(Assigned(DNUSPLForms[AForm]))) then
begin
{$ifDef SPL_DisplayErrors} Writeln(Format(DNUSPL_Err_Str_RangeCheck, ['DNUSPL_ShowForm', AForm])); {$endIf}
DNUSPLLastError := {$ifDef SPL_Prefix} SPL_ERR_RangeCheck {$else} ERR_RangeCheck {$endIf};
Exit;
end;

if(APauseScript) then
Result := DNUSPLForms[AForm].ShowModal = mrOk
else begin
DNUSPLForms[AForm].Show;
Result := DNUSPLForms[AForm].Showing;
end;
end;

function DNUSPL_AddControl(const AControlType, AForm: Integer; const ABounds: TFormRect;
const AAdditionalParametres: TVariantArray; {$ifDef SPL_StringIdentifiers}
const AParent, AIdentifier: TString{$else}const AParent: Integer{$endIf}):
{$ifDef SPL_StringIdentifiers} Boolean{$else}) Integer{$endIf};
var
tmpControl: TControl;
parentControl: TWinControl;
tmpParentd{$ifDef SPL_StringIdentifiers}, tmpIdentd{$endIf} : TString;

paramsLength, I: Word;
begin
{$ifDef SPL_StringIdentifiers} Result := False; {$else} Result := -1; {$endIf}
if(not(InRange(AForm, 0, (DNUSPLFormCount - 1))) or not(Assigned(DNUSPLForms[AForm]))) then
begin
{$ifDef SPL_DisplayErrors} Writeln(Format(DNUSPL_Err_Str_RangeCheck, ['AddControl', AForm])); {$endIf}
DNUSPLLastError := {$ifDef SPL_Prefix} SPL_ERR_RangeCheck {$else} ERR_RangeCheck {$endIf};
Exit;
end;

{$ifDef SPL_StringIdentifiers}
tmpIdentd := SPL_Trim(AIdentifier);
if(not(tmpIdentd = Lowercase(AIdentifier))) then
{$ifDef SPL_DisplayErrors} Writeln(Format(DNUSPL_Err_Str_ImplicitCast, ['AddControl', AForm, AIdentifier, tmpIdentd])); {$else} Null; {$endIf}

if(not(AParent = '')) then
begin
tmpParentd := SPL_Trim(AParent);
if(not(tmpParentd = Lowercase(AParent))) then
{$ifDef SPL_DisplayErrors} Writeln(Format(DNUSPL_Err_Str_ImplicitCast, ['AddControl', AForm, AParent, tmpParentd])); {$else} Null; {$endIf}
end;
{$else}
if(not(AParent = 0)) then
tmpParentd := IntToStr(AParent);
{$endIf}

paramsLength := Length(AAdditionalParametres);
if(tmpParentd = '') then
parentControl := DNUSPLForms[AForm]
else begin
parentControl := TWinControl(DNUSPLForms[AForm].FindComponent(DNUSPL_ComponentPrecede + tmpParentd));

if(not(Assigned(parentControl))) then
begin
{$ifDef SPL_DisplayErrors} Writeln(Format(DNUSPL_Err_Str_InvalidParent, ['AddControl', AForm, tmpParentd])) {$endIf}
Exit;
end;
end;

case (AControlType) of
{$ifDef SPL_Prefix} SPL_COMP_TabSheet {$else} COMP_TabSheet {$endIf}:
begin
tmpControl := TPageControl.Create(DNUSPLForms[AForm]);
tmpControl.Parent := DNUSPLForms[AForm];
if(Rect(0, 0, 0, 0) = ABounds) then
tmpControl.Align := alClient
else
tmpControl.SetBounds(ABounds.X, ABounds.Y, ABounds.Width, ABounds.Height);
end;

{$ifDef SPL_Prefix} SPL_COMP_Tab {$else} COMP_Tab {$endIf}:
begin
tmpControl := TTabSheet.Create(DNUSPLForms[AForm]);

if(parentControl is TPageControl) then
TTabSheet(tmpControl).PageControl := TPageControl(parentControl)
else begin
{$ifDef SPL_DisplayErrors}
Writeln(Format(DNUSPL_Err_Str_InvalidTabControl, ['AddControl', AForm, tmpIdentd]));
{$endIf}
DNUSPLLastError := {$ifDef SPL_Prefix} SPL_ERR_InvalidTabControl {$else} ERR_InvalidTabControl {$endIf};
Exit;
end;

if(paramsLength > 0) then
tmpControl.Caption := AAdditionalParametres[0];
end;

{$ifDef SPL_Prefix} SPL_COMP_Button {$else} COMP_Button {$endIf}:
begin
tmpControl := TButton.Create(DNUSPLForms[AForm]);
tmpControl.Parent := parentControl;
tmpControl.SetBounds(ABounds.X, ABounds.Y, ABounds.Width, ABounds.Height);

if(paramsLength > 0) then
tmpControl.Caption := AAdditionalParametres[0];
end;

{$ifDef SPL_Prefix} SPL_COMP_TextBox {$else} COMP_TextBox {$endIf}:
begin
tmpControl := TEdit.Create(DNUSPLForms[AForm]);
tmpControl.Parent := parentControl;
tmpControl.SetBounds(ABounds.X, ABounds.Y, ABounds.Width, ABounds.Height);
TEdit(tmpControl).Text := '';
end;

{$ifDef SPL_Prefix} SPL_COMP_DropDown {$else} COMP_DropDown {$endIf}:
begin
tmpControl := TComboBox.Create(DNUSPLForms[AForm]);
tmpControl.Parent := parentControl;
tmpControl.SetBounds(ABounds.X, ABounds.Y, ABounds.Width, ABounds.Height);
TComboBox(tmpControl).Style := csDropDownList;

if(paramsLength > 0) then
begin
for I := 0 to (paramsLength - 1) do
TComboBox(tmpControl).Items.Add(AAdditionalParamet res[I]);

TComboBox(tmpControl).ItemIndex := 0;
end;
end;

{$ifDef SPL_Prefix} SPL_COMP_Text {$else} COMP_Text {$endIf}:
begin
tmpControl := TLabel.Create(DNUSPLForms[AForm]);
tmpControl.Parent := parentControl;
tmpControl.SetBounds(ABounds.X, ABounds.Y, ABounds.Width, ABounds.Height);

if(paramsLength > 0) then
tmpControl.Caption := AAdditionalParametres[0];
if(paramsLength > 1) then
TLabel(tmpControl).Font.Size := AAdditionalParametres[1];
if(paramsLength > 2) then
TLabel(tmpControl).Font.Color := AAdditionalParametres[2];
end;

{$ifDef SPL_Prefix} SPL_COMP_Picture {$else} COMP_Picture {$endIf}:
begin
tmpControl := TImage.Create(DNUSPLForms[AForm]);
tmpControl.Parent := parentControl;
tmpControl.SetBounds(ABounds.X, ABounds.Y, ABounds.Width, ABounds.Height);

if(paramsLength > 0) then
TImage(tmpControl).Picture.Bitmap.Assign(GetMufasa Bitmap(AAdditionalParametres[0]).ToTBitmap);
if(paramsLength > 1) then
TImage(tmpControl).Stretch := AAdditionalParametres[1];
if(paramsLength > 2) then
begin
TImage(tmpControl).SetBounds(0, 0, DNUSPLForms[AForm].ClientWidth, DNUSPLForms[AForm].ClientHeight);
tmpControl.SendToBack;
end;
end;

{$ifDef SPL_Prefix} SPL_COMP_CheckBox {$else} COMP_CheckBox {$endIf}:
begin
tmpControl := TCheckBox.Create(DNUSPLForms[AForm]);
tmpControl.Parent := parentControl;
tmpControl.SetBounds(ABounds.X, ABounds.Y, ABounds.Width, ABounds.Height);

if(paramsLength > 0) then
tmpControl.Caption := AAdditionalParametres[0];
if(paramsLength > 1) then
TCheckBox(tmpControl).Checked := AAdditionalParametres[1];
end;

{$ifDef SPL_Prefix} SPL_COMP_MemoBox {$else} COMP_MemoBox {$endIf}:
begin
tmpControl := TMemo.Create(DNUSPLForms[AForm]);
tmpControl.Parent := parentControl;
if(ABounds = Rect(0, 0, 0, 0)) then
tmpControl.Align := alClient
else
tmpControl.SetBounds(ABounds.X, ABounds.Y, ABounds.Width, ABounds.Height);

if(paramsLength > 0) then
for I := 0 to (paramsLength - 1) do
TMemo(tmpControl).Lines.Add(AAdditionalParametres[I]);
end;
end;

{$ifDef SPL_StringIdentifiers}
tmpControl.Name := DNUSPL_ComponentPrecede + tmpIdentd;
Result := Assigned(tmpControl);
{$else}
tmpControl.Name := DNUSPL_ComponentPrecede + IntToStr(DNUSPLComponentCount);
if(Assigned(tmpControl)) then
Result := DNUSPLComponentCount else Result := -1;
Inc(DNUSPLComponentCount);
{$endIf}
end;

{$ifDef SPL_Prefix}
function SPL_DeleteComponent(const AForm: Integer; const {$ifDef SPL_StringIdentifiers} AIdentifier: TString {$else} AIdentifier: Integer {$endIf}): Boolean;
{$else}
function DeleteComponent(const AForm: Integer; const {$ifDef SPL_StringIdentifiers} AIdentifier: TString {$else} AIdentifier: Integer {$endIf}): Boolean;
{$endIf}
var
tmpControl: TControl;
tmpIdentd: TString;
begin
Result := False;
if(not(InRange(AForm, 0, (DNUSPLFormCount - 1))) or not(Assigned(DNUSPLForms[AForm]))) then
begin
{$ifDef SPL_DisplayErrors} Writeln(Format(DNUSPL_Err_Str_RangeCheck, ['DeleteComponent', AForm])); {$endIf}
DNUSPLLastError := {$ifDef SPL_Prefix} SPL_ERR_RangeCheck {$else} ERR_RangeCheck {$endIf};
Exit;
end;

{$ifDef SPL_StringIdentifiers}
tmpIdentd := SPL_Trim(AIdentifier);
if(not(tmpIdentd = Lowercase(AIdentifier))) then
{$ifDef SPL_DisplayErrors} Writeln(Format(DNUSPL_Err_Str_ImplicitCast, ['DeleteComponent', AForm, AIdentifier, tmpIdentd])); {$else} Null; {$endIf}
{$else}
if(not(AIdentifier = 0)) then
tmpIdentd := IntToStr(AIdentifier);
{$endIf}

// tmpControl := TControl({$ifDef SPL_Prefix} SPL_FindComponent {$else} FindSPLComponent {$endIf}(
// TComponent(DNUSPLForms[AForm]), AIdentifier));
tmpControl := TControl(DNUSPLForms[AFOrm].FindComponent(DNUSPL_ComponentPrecede + tmpIdentd));

if(tmpControl is TTabSheet) then
TTabSheet(tmpControl).PageControl.SelectNextPage(F alse, True);

//tmpControl.Parent := nil;
tmpControl.Free;

Result := (not(Assigned(tmpControl)));
end;

function {$ifDef SPL_Prefix} SPL_CreateFormEx {$else} CreateFormEx {$endIf}(
const ABounds: TFormRect; const ACaption: TString; const ABorderStyle: TBorderStyle): Integer;
var
Params: TVariantArray;
begin
Params := [ABounds.X, ABounds.Y, ABounds.Width, ABounds.Height, ACaption, ABorderStyle];
ThreadSafeCall('DNUSPL_CreateForm', Params);
end;

function {$ifDef SPL_Prefix} SPL_ShowForm {$else} ShowForm {$endIf}(
const AForm: Integer; const PauseScript: Boolean): Boolean;
var
Params: TVariantArray;
begin
Params := [AForm, PauseScript];
Result := Boolean(ThreadSafeCall('DNUSPL_ShowForm', Params));
end;

function {$ifDef SPL_Prefix} SPL_AddTabSheetEx {$else} AddTabSheetEx {$endIf}
(const AForm: Integer; const ABounds: TFormRect{$ifDef SPL_StringIdentifiers}; const ANewIdentifier: TString): Boolean {$else} ): Integer {$endIf};
begin
Result := DNUSPL_AddControl({$ifDef SPL_Prefix} SPL_COMP_TabSheet {$else} COMP_TabSheet {$endIf}, AForm, ABounds, [], {$ifDef SPL_StringIdentifiers} '', ANewIdentifier {$else} 0 {$endIf});
end;

function {$ifDef SPL_Prefix} SPL_AddTabSheet {$else} AddTabSheet {$endIf}
(const AForm: Integer{$ifDef SPL_StringIdentifiers}; const ANewIdentifier: TString): Boolean {$else} ): Integer {$endIf};
begin
Result := DNUSPL_AddControl({$ifDef SPL_Prefix} SPL_COMP_TabSheet {$else} COMP_TabSheet {$endIf}, AForm, Rect(0, 0, 0, 0), [], {$ifDef SPL_StringIdentifiers} '', ANewIdentifier {$else} 0 {$endIf});
end;

function {$ifDef SPL_Prefix} SPL_AddTabsEx {$else} AddTabsEx {$endIf}(
const AForm: Integer; {$ifDef SPL_StringIdentifiers} const AParent: TString;
const AIdentifiers: array of TString; {$else} const AParent: Integer; {$endIf}
const ACaptions: array of TString): {$ifDef SPL_StringIdentifiers} Boolean {$else} TIntegerArray {$endIf};
var
I, Count: Integer;
begin
Count := Length(ACaptions);
if(Count > 0) then
begin
{$ifDef SPL_StringIdentifiers}
if(not(Count = Length(AIdentifiers))) then
begin
{$ifDef SPL_DisplayErrors} Writeln(Format(DNUSPL_Err_Str_InvalidLength, ['AddTabsEx', AForm, 'AIdentifiers', 'ACaption'])); {$endIf}
Exit;
end;

Result := False;
{$else}
SetLength(Result, Count);
{$endIf}

for I := 0 to (Count - 1) do
begin
{$ifNDef SPL_StringIdentifiers} Result[I] := {$endIf}
DNUSPL_AddControl({$ifDef SPL_Prefix} SPL_COMP_Tab {$else} COMP_Tab {$endIf},
AForm, Rect(0, 0, 0, 0), [ACaptions[I]], AParent {$ifDef SPL_StringIdentifiers}, AIdentifiers[I] {$endIf});
end;
end;
end;

function {$ifDef SPL_Prefix} SPL_AddTabs {$else} AddTabs {$endIf}
(const AForm: Integer; {$ifDef SPL_StringIdentifiers} const AIdentifiers: array of TString;
{$endIf} const ACaptions: array of TString): {$ifDef SPL_StringIdentifiers} Boolean {$else} TIntegerArray {$endIf};
var
I: Integer;
tmpParentd: {$ifDef SPL_StringIdentifiers} TString {$else} Integer {$endIf};
begin
if(not(InRange(AForm, 0, (DNUSPLFormCount - 1))) or not(Assigned(DNUSPLForms[AForm]))) then
begin
{$ifDef SPL_DisplayErrors} Writeln(Format(DNUSPL_Err_Str_RangeCheck, ['AddTabs', AForm])); {$endIf}
DNUSPLLastError := {$ifDef SPL_Prefix} SPL_ERR_RangeCheck {$else} ERR_RangeCheck {$endIf};
Exit;
end;

for I := 0 to (DNUSPLForms[AForm].ComponentCount - 1) do
if(DNUSPLForms[AForm].Components[I] is TPageControl) then
begin
tmpParentd := {$ifDef SPL_StringIdentifiers} Copy(DNUSPLForms[AForm].Components[I].Name, Length(DNUSPL_ComponentPrecede), Length(DNUSPLForms[AForm].Name)) {$else} I {$endIf};
Exit;
end;

Writeln(tmpParentd);
Result := {$ifDef SPL_Prefix} SPL_AddTabsEx {$else} AddTabsEx {$endIf}(AForm, {$ifDef SPL_StringIdentifiers} tmpParentd, AIdentifiers, {$else} tmpParentd, {$endIf} ACaptions);
end;

procedure {$ifDef SPL_Prefix} SPL_Setup {$else} SetupSPL {$endIf};
{$ifDef SPL_CheckForUpdates}
var
pageVer: TString;
tmpVer: Float;
{$endIf}
begin
DNUSPLLastError:= -1;
DNUSPLFormCount := 0;

{$ifDef SPL_CheckForUpdates}
pageVer := GetPage('http://****/srl/spl/latest_version.txt');
writeln(pagever);
tmpVer := StrToFloatDef(pageVer, -1.0);
if(not(tmpVer = -1.0)) then
begin
if(tmpVer > DNUSPL_Version) then
begin
Writeln(' *** A new ' + DNUSPL_FullName + ' (' + FloatToStr(tmpVer) + ') has been released.');
Writeln(' [' + DNUSPL_Acronym + '] Current Version: ' + FloatToStr(DNUSPL_Version) + '.');
Writeln(' - It is highly recommended that you cease this script and download it immediately.');
if(MessageDlg('[' + DNUSPL_Acronym + '] Update', 'A newer version of ' + DNUSPL_FullName +
' (' + FloatToStr(tmpVer) + ') is available for download. It is highly recommended that you ' +
'stop this script and install this new update.' + CRLF + CRLF + 'Stop the script now?',
mtConfirmation, [mbOK, mbCancel]) = mrOk) then
begin
Writeln(' [' + DNUSPL_Acronym + '] Good choice! Terminating script...');
TerminateScript;
end else
Writeln(' [' + DNUSPL_Acronym + '] Continuing on then...');
end else
Writeln(' [' + DNUSPL_Acronym + '] You'#39're on the latest version.');
end else
Writeln(' [' + DNUSPL_Acronym + '] Unable to check for updates.');
{$endIf}
end;

begin
SPL_Setup;
SPL_CreateFormEx(Rect(0, 0, 800, 600), 'Test', bsSingle);
SPL_AddTabSheetEx(0, Rect(0, 0, 0, 0), 'test1 yeah');
// Of course, the generic DNUSPL_AddControl will be simplified to AddTab, AddButton, AddCheckBox, etc.
DNUSPL_AddControl(SPL_COMP_Tab, 0, Rect(0, 0, 50, 50), ['test page'], 'test1 yeah', 'w00t 231#');
DNUSPL_AddControl(SPL_COMP_Tab, 0, Rect(0, 0, 0, 0), ['2'], 'test1 yeah', 'w11t23');
DNUSPL_AddControl(SPL_COMP_Button, 0, Rect(50, 50, 75, 23), ['click me!'], 'w11t23', 'thisbutton');
SPL_ShowForm(0, True);
end.


Take anything from that if you like. :) Who knows? I may continue it some day.

Obscurity
11-06-2015, 08:38 PM
That is wicked, Daniel;, thanks! I was going to look into tabs and such soon, so you just saved me a lot of trouble - as I see your example uses them!

Edit: TBorderStyle can not be used in Lape, but so far it's going along smoothly. Thanks again!

Obscurity
11-08-2015, 03:36 AM
:: Automated Message ::
Added Tab Elements, Parent Method, Etc

https://avatars.githubusercontent.com/u/10840155?s=13 ObscuritySRL (https://github.com/ObscuritySRL) updated on Saturday, November 07, 2015 (https://github.com/ObscuritySRL/eZForm/commit/68f8468cf49b484cf860c73f150eaf9dec82a348)


183 additions, 40 deletions.

Fixed automatic sizing issues.

Added the tab and tabList elements.

Added the eZForm.addTab() method. If an ID is passed, for example iTabs,
the tabs created will be given the IDs iTabs0, iTabs1, iTabs2, etc. An
example has been added to the initial post of the eZForm thread.

Added the select property and methods to tabList elements. These will
return or set the selected tab in a tabList.

Added the parent property and methods to all elements. These will return
or set the parent of an element. An example has been added to the
initial post of the eZForm thread.

A total of 1 files were affected:
ezForm.simba (https://github.com/ObscuritySRL/eZForm/blob/master/ezForm.simba)



« Download ZIP (https://github.com/ObscuritySRL/eZForm/archive/master.zip) »



Thanks to Daniel; for his help with tabs!

Lama
11-08-2015, 03:38 AM
Woop woop! Good stuff good stuff... I'm glad this is progressing so much as of late! What more can you do? A+ work.

Obscurity
11-11-2015, 09:13 PM
:: Automated Message ::
Bug Fixes, Auto-Sizing Images, Etc

https://avatars.githubusercontent.com/u/10840155?s=13 ObscuritySRL (https://github.com/ObscuritySRL) updated on Wednesday, November 11, 2015 (https://github.com/ObscuritySRL/eZForm/commit/1aeca8fb936ea67fb6e713036ed98bd4d1d1be42)


22 additions, 4 deletions.

Images now automatically size themselves if the dimensions parameter is
set to [0,0] when using eZForm.addImage().

Changing the visible properties of multiple elements will now work as
expected. Previously, hiding or showing more then a single element in
one thread would seemingly ignore the rest.

eZForm.show() is now a function and will return the current form. This
is useful for setting a custom dimensions and changing properties on the
fly, for example:
eZForm.show().height(240);

A total of 1 files were affected:
ezForm.simba (https://github.com/ObscuritySRL/eZForm/blob/master/ezForm.simba)



« Download ZIP (https://github.com/ObscuritySRL/eZForm/archive/master.zip) »

Obscurity
11-17-2015, 09:02 PM
:: Automated Message ::
Added Remove Methods, Bug Fixes, Other Methods

https://avatars.githubusercontent.com/u/10840155?s=13 ObscuritySRL (https://github.com/ObscuritySRL) updated on Tuesday, November 17, 2015 (https://github.com/ObscuritySRL/eZForm/commit/86c78d005c1cf98609ae054970ad849f5b2e04f6)


136 additions, 47 deletions.

Fixed bugs for image and tab elements.

Fixed eZForm.find() methods to function correctly. This issue was making
methods such as eZElement.parent() fail to execute properly.

Re-added eZForm.remove() methods. Previously, adding or removing an
element from a form after the form had been shown would cause Simba to
crash.

Added the eZElement.append() method. This method will append a string to
the end of any control, add an item to a combobox or listbox, etc.

Added the eZElement.empty() methods. These can be used to completely
empty the contents of a combobox or listbox. Alternatively, an index may
be specified.

Removed the optional multiple property from listboxes.

Added the multiple property to tabs. With this enabled, if a list of
tabs is too wide, they will span multiple lines.

Changed the return types of various methods. For example, listbox.val()
previously returned the selected text. It now returns the selected
index. listbox.text() now returns the selected text.

Added the eZElement.selections() methods. These return a full list of
possible string selections of an element. For example,
combobox.selections(). Alternatively, if passed a stringArray, it will
change the possible selections.

A total of 1 files were affected:
ezForm.simba (https://github.com/ObscuritySRL/eZForm/blob/master/ezForm.simba)



« Download ZIP (https://github.com/ObscuritySRL/eZForm/archive/master.zip) »

Hitac
11-21-2015, 02:17 PM
Cannot download eZForm.simba since it opens the source code page (or is it supposed to copy it to a simba file?)

Lama
11-21-2015, 08:51 PM
Cannot download eZForm.simba since it opens the source code page (or is it supposed to copy it to a simba file?)

Right click the link and choose 'Save link as...', the popup will automatically give it the .simba extension and you can save it wherever :)

Hitac
11-22-2015, 08:50 AM
Thanks ;)

Obscurity
12-06-2015, 04:06 AM
:: Automated Message ::
Fix For ProSocks v0.5, Added Edit and Memo Methods

https://avatars.githubusercontent.com/u/10840155?s=13 ObscuritySRL (https://github.com/ObscuritySRL) updated on Saturday, December 05, 2015 (https://github.com/ObscuritySRL/eZForm/commit/c2b8ddfc1ae7a849fa05ded9bf9f9521bf0a2876)


89 additions, 55 deletions.

Added eZElement.copy(), eZElement.cut(), eZElement.paste(), and
eZElement.selectAll() methods for Edit and Memo elements.

Added the eZElement.selections() method for TabList elements.

Fixed tPicture.loadFromURL() to correctly use ProSocks v0.5.

A total of 1 files were affected:
ezForm.simba (https://github.com/ObscuritySRL/eZForm/blob/master/ezForm.simba)



« Download ZIP (https://github.com/ObscuritySRL/eZForm/archive/master.zip) »

Obscurity
12-09-2015, 01:18 AM
Fixed Tab Event Handlers and Form Methods



:: Automated Message ::









ObscuritySRL (https://github.com/ObscuritySRL) updated on Tuesday, December 08, 2015 (https://github.com/ObscuritySRL/eZForm/commit/321606c2eb4f961ad5fae41283fc9051da6c5ec0)




https://avatars.githubusercontent.com/u/10840155?s=45 (https://github.com/ObscuritySRL)




Fixed tab event handlers to occur after the tab has been switched.
Previously, it would supply the last tab rather than the current.

Fixed form window styles.

Fixed eZForm.prop('width') and eZForm.width() to return the correct
values.

Fixed eZElement.parent() methods to ensure that the elements are owned
by the same form.

Fixed eZElement.offsetTop() to return the correct value for tabs.

Added the tComponent.getForm() method to be used internally. This
differs from tComponent.getOwner() in that if the component is a child
or grandchild of a tab, the tab's tPageControl would be returned.


43 additions, 11 deletions.







A total of 1 files were affected:
ezForm.simba (https://github.com/ObscuritySRL/eZForm/blob/master/ezForm.simba)


« Download ZIP (https://github.com/ObscuritySRL/eZForm/archive/master.zip) »

fady
12-16-2015, 10:37 PM
I wasn't sure where I should post this.

The prosocks.dll linked from the oglib setup thread doesn't work with ezForm. shoots an error in line 1664 unknown declaration "init" in ezForm.simba, the line is _Socket.init();

and the prosocks.dll linked from the ezForm thread doesn't work with the oglib setup script from the oglib thread. shoots an error at line 41 of the setup script, Unknown declaration "pro_initSocket"

Just thought I'd let you know in case you weren't aware.

Edit: Also the prosocks.dll from the ezForm thread is 1996 KB, while the one from the oglib thread is 2054 KB, so I'm assuming its just different versions.

Obscurity
12-18-2015, 11:34 PM
fady; Yes, ezForm requires the newest. I don't recall what ogLib uses ProSocks for - I'll take a look at it over the next few days.

Ross
12-19-2015, 12:47 AM
recall what ogLib uses ProSocks for

auto-updater.

Obscurity
12-27-2015, 04:57 AM
:: Automated Message ::
Added Element Saving, Animations, Etc





ObscuritySRL (https://github.com/ObscuritySRL) updated on Saturday, December 26, 2015 (https://github.com/ObscuritySRL/eZForm/commit/444428f)





https://avatars.githubusercontent.com/u/10840155?s=45 (https://github.com/ObscuritySRL)







Added Element Saving, Animations, Etc



:: 444428f :: (https://github.com/ObscuritySRL/eZForm/commit/444428f)





Added animation methods. This will work for certain properties such as color, height, offsetleft, offsettop, width, and more.

Added the eZElement.children() method.

Added the eZElement.load() and eZElementArray.load() methods. These will load the previously saved values or selected text for checkboxes, comboboxes, edits, and listboxes. To load an element, it must be given an ID.

Added eZElement.offsetBottom() and eZElement.offsetRIght() methods. These will return the bottom and right-most coordinates respectively.

Added the eZElement.save() and eZElementArray.save() methods. These will save the current values or selected text for checkboxes, comboboxes, edits, and listboxes. To save an element, it must be given an ID.







[/TR]




« Repository (https://github.com/ObscuritySRL/eZForm) »





Edit:
Here's a script to demonstrate animations and saving.
program form;
{$i ezForm.simba}

var
form:eZForm;
height:int32;

procedure pSave();
begin
form.find().save();
end;

begin
form.create('Form');

form.addMemo('','s10','memo',[10,10],[200,25],nil);
form.addCombobox(['Combobox1','Combobox2','Combobox3'],'s10','combobox',[10,45],200,nil).readOnly(true);
form.addCheckbox('Checkbox','s10','checkbox',[10,80],nil);
form.addListbox(['Listbox1','Listbox2','Listbox3'],'s10','listbox',[10,105],[200,85],nil);

form.show().find().load();

height:=form.height();

addOnTerminate('pSave');

repeat
wait(100);
form.animate('height',height+75,500);
form.find('#memo')[0].animate('color',255,500);
form.animate('height',height,500);
form.find('#memo')[0].animate('color',0,500);
until false;
end.
Run it. Play with it, filling in some boxes, selecting list options, etc. Then, end it and restart it.

Obscurity
01-03-2016, 06:38 AM
:: Automated Message ::
Added Default Handler Param, New Methods





ObscuritySRL (https://github.com/ObscuritySRL) updated on Sunday, January 03, 2016 (https://github.com/ObscuritySRL/eZForm/commit/33eff85)





https://avatars.githubusercontent.com/u/10840155?s=45 (https://github.com/ObscuritySRL)







Added Default Handler Param, New Methods



:: 9c43554 :: (https://github.com/ObscuritySRL/eZForm/commit/9c43554)





Added default event handlers for creating elements. From now on, you'll
no longer need to specify nil if the element has no handler specified.

Added the eZForm.children() method. Unlike the eZForm.find() method,
this method will not return grand-children.

Added the eZElement.cols() method to go along with the cols property for
listboxes.







Fixed Out Of Memory Error, eZElement.parent(), Etc



:: 33eff85 :: (https://github.com/ObscuritySRL/eZForm/commit/33eff85)





Fixed a bug which was causing the eZElement.parent() method to return
the incorrect element.

Fixed an error caused internally when tComponent.getForm() was called.

Fixed a bug where getting or setting certain element properties, such as
height, on tabs would cause an infinite loop.


[/TR]




[/TR]




« Repository (https://github.com/ObscuritySRL/eZForm) »

AFools
01-03-2016, 06:51 AM
Thank you; i didn't even notice the 26th revision - 'pSave'.

Great work.

Obscurity
02-18-2016, 02:36 AM
:: Automated Message ::
Added Methods, Fixed Flashing, Etc





ObscuritySRL (https://github.com/ObscuritySRL) updated on Wednesday, February 17, 2016 (https://github.com/ObscuritySRL/eZForm/commit/c8f8107)





https://avatars.githubusercontent.com/u/10840155?s=45 (https://github.com/ObscuritySRL)







Added Methods, Fixed Flashing, Etc



:: c8f8107 :: (https://github.com/ObscuritySRL/eZForm/commit/c8f8107)





Added eZElement.empty() for edit and memo.

Added eZElement.readOnly() method.

Fixed flashing issues when rapidly changing or assigning selections to
combobox and listboxes.







[/TR]




« Repository (https://github.com/ObscuritySRL/eZForm) »

Brotein
03-06-2016, 02:38 AM
Awesome work, using this for setups from now on!

http://i.imgur.com/QnYWUAU.png

Wolfskull
04-04-2016, 09:21 AM
Hey guys
Anyone know of a simpler way to edit the image in an image element?

At the moment I've been doing

DrawBitmap(MyBitmap,tImage(mapImage).getCanvas(),1 0,10);

But this really likes to give access violation exceptions, so I'm a bit at a loss.
(If anyone's curious i'm rewriting this Radial Walker Utility by tls in EZForm)

kristi
04-30-2016, 05:39 PM
I'm not sure I understood it right, but I cannot seem to assign a procedure to the vEventHandler parameter? I tried this but it only crashed Simba:

program new;
{$I ezForm.simba}
var
Form : ezForm;

procedure buttonPressed();
begin
Writeln('Yay you pressed me!');
end;

procedure loadForm();
begin
Form.create('Test');
Form.addButton('Press me', 's12', '', [10, 10], [100, 25], @buttonPressed);
Form.show();

while true do
Wait(1);
end;

begin
loadForm();
end.

Lucidity
04-30-2016, 06:14 PM
snip

I forget the reason, i remember obs told me awhile back that it had to be native. Try something like this.


program new;
{$i ezForm.simba}
var
Form : ezForm;

procedure buttonPressed; native;
begin
//whatever you want here
end;

procedure loadForm();
begin
Form.create('Test');
Form.addButton('Press me', 's12', '', [10, 10], [100, 25], buttonPressed);
Form.show();
end;

begin
loadForm();
repeat
wait(100);
until false;
end.

kristi
04-30-2016, 06:26 PM
I forget the reason, i remember obs told me awhile back that it had to be native. Try something like this.


program new;
{$i ezForm.simba}
var
Form : ezForm;

procedure buttonPressed; native;
begin
//whatever you want here
end;

procedure loadForm();
begin
Form.create('Test');
Form.addButton('Press me', 's12', '', [10, 10], [100, 25], buttonPressed);
Form.show();
end;

begin
loadForm();
repeat
wait(100);
until false;
end.

Tried that before, it solves the crashing but pressing the button doesn't do anything.


program new;
{$I ezForm.simba}
var
Form : ezForm;

procedure buttonPressed(); native;
begin
Writeln('Yay you pressed me!');
end;

procedure loadForm();
begin
Form.create('Test');
Form.addButton('Press me', 's12', '', [10, 10], [100, 25], buttonPressed);
Form.show();

while true do
Wait(1);
end;

begin
loadForm();
end.

Lucidity
04-30-2016, 06:46 PM
snip

because when it's called natively i don't think you're able to do that. It does call the procedure though, I had it set a boolean to true and i had writeLn(boolean); and it changed its values

Obscurity
05-01-2016, 01:34 AM
Brotein;
Looks nice, mate!


Wolfskull;
I haven't used EZForm in a while but I think it's the src method:
someImage := Form.AddImage(...);

//~ ...

SomeImage.src('http://...');


kristi; Lucidity;
Open your Simba console:
https://gyazo.com/100ca86a6c52c54bb5a682c74a85c9a9.png

Dissimulo
05-01-2016, 02:53 AM
Thanks for the include Obscurity, really awesome! Can't post a picture because I don't have enough posts yet...

Quick feature request: would it be possible to add a slider of some sort? I would like to be able to select from a predefined range of values for setting mouse speeds

Lucidity
05-01-2016, 05:47 AM
Thanks for the include Obscurity, really awesome! Can't post a picture because I don't have enough posts yet...

Quick feature request: would it be possible to add a slider of some sort? I would like to be able to select from a predefined range of values for setting mouse speeds

You can always do a combo box!

ezForm.addCombobox(['Option 1', 'Option 2']... etc

kristi
05-01-2016, 02:20 PM
You can always do a combo box!

ezForm.addCombobox(['Option 1', 'Option 2']... etc

Aha, interesting. How would I go about using the built-in debug box in Simba?

Brandon
05-01-2016, 04:40 PM
Aha, interesting. How would I go about using the built-in debug box in Simba?



procedure buttonPressed;
begin
GetTClient().WriteLn('Yay you pressed me!');
end;

Leafy
12-31-2016, 05:25 AM
M8, code doesnt talk for itself. Add some fking descriptions

aids

Citrus
12-31-2016, 05:48 AM
M8, code doesnt talk for itself. Add some fking descriptions

aids

Please spread your cancer somewhere else. There are 10 examples in the OP. If that isn't enough then maybe learning isn't for you.

Leafy
12-31-2016, 05:53 AM
Please spread your cancer somewhere else. There are 10 examples in the OP. If that isn't enough then maybe learning isn't for you.

The examples are cool, but I need spoilers for my cancer

Laquisha
12-31-2016, 08:21 AM
The examples are cool, but I need spoilers for my cancer

Don't did up these garbage threads mate, let them die.