Jump to content

lynkfs

Moderators
  • Content count

    471
  • Joined

  • Last visited

  • Days Won

    27

lynkfs last won the day on September 11

lynkfs had the most liked content!

About lynkfs

  • Rank

Profile Information

  • Gender
    Male
  • Location
    Australia

Recent Profile Visitors

509 profile views
  1. lynkfs

    ShowModal and Measuring Text

    the problem is in your UpdateUI proc this works : FMessageLabel.Caption := FMessageText; tMetrics := FMessageLabel.MeasureText(FMessageText); FMessageLabel.SetSize(tMetrics.tmWidth, Round(tMetrics.tmHeight * 1.5)); FMessageLabel.Top := padding; FMessageLabel.Left := padding; //FMessagePanel.Width := FMessageLabel.Width + padding * 4 + margin * 2 + border * 2; FMessagePanel.Width := tMetrics.tmWidth + padding * 4 + margin * 2 + border * 2; //FMessagePanel.Height := FMessageLabel.Height + padding * 4 + margin * 2 + border * 2; FMessagePanel.Height := tMetrics.tmHeight + padding * 4 + margin * 2 + border * 2; //FMessagePanel.SetBounds((ClientWidth - FMessagePanel.Width) div 2, // (ClientHeight - FMessagePanel.Height) div 2, // FMessagePanel.Width, FMessagePanel.Height); FMessagePanel.SetBounds((ClientWidth - FMessagePanel.Width) div 2, (ClientHeight - FMessagePanel.Height) div 2, tMetrics.tmWidth + padding * 4 + margin * 2 + border * 2, tMetrics.tmHeight + padding * 4 + margin * 2 + border * 2); basically the SetSize call on line 3 results in FMessageLabel.Width and Height having a value of zero (wrong), however in the DOM both FMessageLabel.handle.style.width and height at that point show correct values (i.e. '124px'). My guess is that this has to do with dimensioning a child element before the parent is ready. Maybe @jarto could shine some light on that. Anyway, dimensioning everything on the basis of a separate var (tMetrics) rather than on fluid parent / child element dimensions overcomes that problem.
  2. lynkfs

    canvas font rendering

    the canvas font property is the same as the css font property : it is a shorthand form for specifying 'font-family', 'font-size', 'font-style', 'font-variant' and 'font-weight' in 1 statement. so "font: bold 24px verdana" specifies font-weight, font-size and font-family. all possible font attribute values at https://developer.mozilla.org/en-US/docs/Web/CSS/font and .../font-family
  3. lynkfs

    canvas font rendering

    yep if you google 'canvas font shadow' or 'canvas font effects' you'll get plenty of links to what effects you can achieve with text on canvas. All of these are doable in SMS. To get really out there, have a look at blotter.js - a library which allows you to create amazing text on canvas effects https://codepen.io/RMKNGY/pen/bKJxvd
  4. lynkfs

    Background uploading files

    quick search 1) links which state there is a problem on edge with the anchor tag and download attribute https://caniuse.com/#feat=download https://stackoverflow.com/questions/18394871/download-attribute-on-a-tag-not-working-in-ie https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14603958/ 2) link which states that it all should work on edge. However look at the 'known issues' tab https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7260192/ 3) link with a possible solution, which will require some work before it is usable https://catonrug.blogspot.com/2018/01/anchor-download-attribute-internet-explorer.html suppose depends on how desperate you are to have it working in Edge
  5. lynkfs

    Background uploading files

    amazing app 💥 - looks absolutely wonderful As to Edge, I don't know why these guys (MS) bother at all In my experience Edge is completely buggy (latest : doesn't even allow localStorage on win10) and is far behind implementing even the simplest of html5 / w3c specs (detail/summary tags, doh) Edge is the new IE (I'll have a look later if there is a workaround) Cheers
  6. lynkfs

    add preexisting pas/form

    is this what you're after ? Forms, when declared 'external' in the project manager in the ide, consist of a .pas and a .smf file (when declared 'internal' the files are embedded in the .sproj project file). Copying both form files to a new project effectively copies that form (probably easiest if you declare the new form in the new project first and then do the copying)
  7. lynkfs

    OpenStreetMap component?

    you can use a simple IFrameHtmlElement on a form and set src to something like this W3IFrameHtmlElement1.Src := "//www.openstreetmap.org/export/embed.html?bbox=10.970685482025146%2C49.5968664515866%2C10.98160743713379%2C49.603138573344914&layer=mapnik&marker=49.60000261331038%2C10.976146459579468";
  8. lynkfs

    a basic JSON question

    if you include ECMA.Json then you don't need to asm block your parse statements don't know what your TR1 variable is, but define it as a variant. Do a console.log(@TR1); // {"business":"lynkfs","departments":[{"deptname":"marketing","staff":[{"first and after parsing you can access your fields as in TR1.business and TR1.departments[0].deptname etc . Below is what I call my dogs breakfast. Just a set of steps to convert from one data structure to another. Multiple stringify's and parse's in there step 1 : create a record structure step2 : change some values programmatically step3 : change record structure to json step4: create a TDataSet from json step5 : save json to local storage step 6: retrieve localstorage step 7: create a SQLite db from json step 8: save complete SQLite db to local storage and retrieve it again step 9: save json to a MYSql db on server step 10: and retrieve it again unit Form1; interface uses System.Types, System.Types.Convert, System.Objects, System.Time, SmartCL.System, SmartCL.Time, SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils, SmartCL.Forms, SmartCL.Fonts, SmartCL.Theme, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Button, ECMA.JSON, System.DataSet, SmartCL.Storage.Local, System.Sqlite, W3C.XMLHttpRequest, W3C.HTML5, W3C.DOM, System.Streams, W3C.Console, system.structure, system.structure.json, system.json; type TForm1 = class(TW3Form) procedure W3Button1Click(Sender: TObject); private {$I 'Form1:intf'} protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; Procedure DoStuff; end; // record types type JStrC = class(TJSonStructure) //record firstname : string; //external 'firstname'; surname : string; //external 'surname'; end; JStrB = class(TJSonStructure) //record deptname : string; //external 'deptname'; staff : Array of JStrC; //external 'staff'; end; JStrA = class(TJSonStructure) //record business : string; //external 'business' departments : Array of JStrB; //external 'departments'; end; var document external 'document': variant; var window external 'window': variant; var console external 'console': variant; implementation { TForm1 } Procedure TForm1.DoStuff; begin // // step1 : set up a leveled structure, (either records or classes) // i.e. business unit with departments with employees per department writeln('Step1'); // /* //business unit var StrA01 : JStrA; StrA01.business := 'lynkfs'; //department marketing var StrB01 : JStrB; StrB01.deptname := 'marketing'; //staff Keith Ansell var StrC01 : JStrC; StrC01.firstname := 'Claire'; StrC01.surname := 'Adams'; StrB01.staff.Add(StrC01); //staff Charles Bailey var StrC02 : JStrC; StrC02.firstname := 'Vicky'; StrC02.surname := 'Anderson'; StrB01.staff.Add(StrC02); StrA01.departments.Add(StrB01); //department frontdesk var StrB02 : JStrB; StrB02.deptname := 'front desk'; //staff Keith Ansell var StrC03 : JStrC; StrC03.firstname := 'Keith'; StrC03.surname := 'Ansell'; StrB02.staff.Add(StrC03); //staff Charles Bailey var StrC04 : JStrC; StrC04.firstname := 'Charles'; StrC04.surname := 'Bailey'; StrB02.staff.Add(StrC04); StrA01.departments.Add(StrB02); */ //business unit var StrA01 := JStrA.Create; StrA01.business := 'lynkfs'; //department marketing var StrB01 := JStrB.Create; StrB01.deptname := 'marketing'; //staff Claire Adams var StrC01 := JStrC.Create; StrC01.firstname := 'Claire'; StrC01.surname := 'Adams'; StrB01.staff.Add(StrC01); //staff Vicky Anderson var StrC02 := JStrC.Create; StrC02.firstname := 'Vicky'; StrC02.surname := 'Anderson'; StrB01.staff.Add(StrC02); StrA01.departments.Add(StrB01); //department frontdesk var StrB02 := JStrB.Create; StrB02.deptname := 'front desk'; //staff Keith Ansell var StrC03 := JStrC.Create; StrC03.firstname := 'Keith'; StrC03.surname := 'Ansell'; StrB02.staff.Add(StrC03); //staff Charles Bailey var StrC04 := JStrC.Create; StrC04.firstname := 'Charles'; StrC04.surname := 'Bailey'; StrB02.staff.Add(StrC04); StrA01.departments.Add(StrB02); // check writeln(inttostr(StrA01.departments.length) + ' departments'); for var i := 0 to StrA01.departments.length -1 do begin writeln(StrA01.departments[i].deptname + ' ' + inttostr(StrA01.departments[i].staff.length) + ' staff'); for var j := 0 to StrA01.departments[i].staff.length -1 do begin writeln(StrA01.departments[i].staff[j].firstname + ' ' + StrA01.departments[i].staff[j].surname); end; end; var jsontext: string := ''; asm @jsontext = JSON.stringify(@StrA01); console.log(@jsontext); // {"business":"lynkfs","departments":[{"deptname":"marketing","staff":[{"firstname":"Vicky","surname":"Anderson"}]},{"deptname":"front desk","staff":[{"firstname":"Keith","surname":"Ansell"},{"firstname":"Charles","surname":"Bailey"}]},{"deptname":"new department","staff":[]}]} end; StrA01.Write('business','lynkfs'); window.alert(StrA01.ToJson); // // step2 : depending on business logic, add/delete/change data in these arrays at will writeln('Step2'); // // employee Claire Adams leaves StrA01.departments[0].staff.Delete(0); //or coding to that effect // a new empty department is created var StrB := JStrB.Create; StrB.deptname := 'new department'; StrA01.departments.add(StrB); // check writeln(inttostr(StrA01.departments.length) + ' departments'); for var i := 0 to StrA01.departments.length -1 do begin writeln(StrA01.departments[i].deptname + ' ' + inttostr(StrA01.departments[i].staff.length) + ' staff'); for var j := 0 to StrA01.departments[i].staff.length -1 do begin writeln(StrA01.departments[i].staff[j].firstname + ' ' + StrA01.departments[i].staff[j].surname); end; end; // // step3 : Turn object to json writeln('Step3'); // var textdata: string := ''; asm @textdata = JSON.stringify(@StrA01); console.log(@textdata); // {"business":"lynkfs","departments":[{"deptname":"marketing","staff":[{"firstname":"Vicky","surname":"Anderson"}]},{"deptname":"front desk","staff":[{"firstname":"Keith","surname":"Ansell"},{"firstname":"Charles","surname":"Bailey"}]},{"deptname":"new department","staff":[]}]} end; // // step4 : Define and populate TW3DataSet from json writeln('Step4'); // var DataSet := TW3DataSet.Create; // note TW3Dataset is not leveled Dataset.FieldDefs.Add('business',ftString); Dataset.FieldDefs.Add('deptname',ftString); Dataset.FieldDefs.Add('firstname',ftString); Dataset.FieldDefs.Add('surname',ftString); DataSet.CreateDataset; var v := json.parse(textdata); For var i := 0 to v.departments.length -1 do begin For var j := 0 to v.departments[i].staff.length -1 do begin DataSet.Append; Dataset.Fields.FieldByName('business').AsString := v.business; Dataset.Fields.FieldByName('deptname').AsString := v.departments[i].deptname; Dataset.Fields.FieldByName('firstname').AsString := v.departments[i].staff[j].firstname; Dataset.Fields.FieldByName('surname').AsString := v.departments[i].staff[j].surname; DataSet.Post; end; If v.departments[i].staff.length = 0 then begin //empty department DataSet.Append; Dataset.Fields.FieldByName('business').AsString := v.business; Dataset.Fields.FieldByName('deptname').AsString := v.departments[i].deptname; DataSet.Post; end; end; // check DataSet.First; while not DataSet.Eof do begin writeln(inttostr(DataSet.recno+1) + ' ' + Dataset.Fields.FieldByName('business').AsString + ' ' + Dataset.Fields.FieldByName('deptname').AsString + ' ' + Dataset.Fields.FieldByName('firstname').AsString + ' ' + Dataset.Fields.FieldByName('surname').AsString); DataSet.Next; end; // // step5 : save json to local storage (persistent on specific device) writeln('Step5'); // step 5 only needs to be run once // var LocalStorage := TW3LocalStorage.Create; LocalStorage.Open('mytreasure'); LocalStorage.SetKeyStr('json',textdata); LocalStorage.Close; //bypassing SmartCL.Storage.Local : window.localStorage.setItem('pete',textdata); // // step6 : retrieve json from local storage (persistent on specific device) writeln('Step6'); // textdata := ''; LocalStorage.Open('mytreasure'); textdata := LocalStorage.GetKeyStr('json','unknown'); LocalStorage.Close; var v1 := json.parse(textdata); // check writeln(inttostr(v1.departments.length) + ' departments'); for var i := 0 to v1.departments.length -1 do begin writeln(v1.departments[i].deptname + ' ' + inttostr(v1.departments[i].staff.length) + ' staff'); for var j := 0 to v1.departments[i].staff.length -1 do begin writeln(v1.departments[i].staff[j].firstname + ' ' + v1.departments[i].staff[j].surname); end; end; //Bypassing SmartCL.Storage.Local v1 := json.parse(window.localStorage.getItem('pete')); // check writeln('/////////////////////pete/////////////////////////////'); writeln(inttostr(v1.departments.length) + ' departments'); for var i := 0 to v1.departments.length -1 do begin writeln(v1.departments[i].deptname + ' ' + inttostr(v1.departments[i].staff.length) + ' staff'); for var j := 0 to v1.departments[i].staff.length -1 do begin writeln(v1.departments[i].staff[j].firstname + ' ' + v1.departments[i].staff[j].surname); end; end; // // step7 : save json to SQLite writeln('Step7'); // var db : TSQLiteDatabase; var res : TSQLiteResult; db := TSQLiteDatabase.Create; db.Run('CREATE TABLE `business` (id INTEGER, business TEXT)'); db.Run('CREATE TABLE `departments` (id INTEGER, busid INTEGER, deptname TEXT)'); db.Run('CREATE TABLE `staff` (id INTEGER, deptid INTEGER, busid INTEGER, firstname TEXT, surname TEXT)'); var v2 := json.parse(textdata); db.Run("INSERT INTO `business`(`id`,`business`) VALUES (0,'" + v2.business + "')"); for var i := 0 to v2.departments.length -1 do begin db.Run("INSERT INTO `departments`(`id`,`busid`,`deptname`) VALUES (" + inttostr(i) + ",0,'" + v2.departments[i].deptname + "')"); for var j := 0 to v2.departments[i].staff.length -1 do begin db.Run("INSERT INTO `staff`(`id`,`deptid`,`busid`,`firstname`,`surname`) VALUES (" + inttostr(j) + "," + inttostr(i) + ",0,'" + v2.departments[i].staff[j].firstname + "','" + v2.departments[i].staff[j].surname + "')"); end; end; // check // res := db.Exec("SELECT a.business, b.deptname, c.firstname, c.surname " + // "from business a, departments b, staff c " + // "where c.busid = a.id and c.deptid = b.id and b.busid = a.id"); // or something a bit simpler res := db.Exec("SELECT surname FROM staff"); //writeln(res.columns[0]); //title of first field : 'business' var rows := res.values; for var i := 0 to rows.length -1 do begin var columns := rows[i].values; for var j := 0 to columns.length-1 do begin writeln(columns[j]); end; end; // or alternatively, same result // // for var i := 0 to res.values.length -1 do begin //rows // for var j := 0 to res.values[i].values.length-1 do begin //columns // writeln(res.values[i].values[j]); //cell // end; // end; // // step8 : save sqlite db to localstorage writeln('Step8'); // var MyStream : TStringStream; MyStream := TStringStream.Create; db.SaveToStream(MyStream,true); var textdata3 := MyStream.DataString; console.log(textdata3); //save textdata3 to local storage var LocalStorage2 := TW3LocalStorage.Create; LocalStorage2.Open('sqlite'); LocalStorage2.SetKeyStr('stream',textdata3); LocalStorage2.Close; //read textdata3 from local storage LocalStorage2.Open('sqlite'); textdata3 := LocalStorage2.GetKeyStr('stream','unknown'); LocalStorage2.Close; //populate stream with localstorage data and revive sqlite db from stream MyStream.DataString := textdata3; MyStream.Position := 0; console.log(mystream.datastring); var db2 := TSQLiteDatabase.Create; db2.LoadFromStream(MyStream); writeln(db2.active); res := db2.Exec("SELECT surname FROM staff"); //test for var i := 0 to res.values.length -1 do begin //rows for var j := 0 to res.values[i].values.length-1 do begin //columns writeln(res.values[i].values[j]); //cell end; end; /* // // step9 : save json to server (persistent over all devices) writeln('Step8'); // var s := "UPDATE `test` SET `webjson`='" + textdata + "'"; var FHttp := JXMLHttpRequest.Create; FHttp.open("POST",'...../smsdmlmysql.php'); FHttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); var encodedstr1 := browserapi.window.encodeURIComponent(S); var sql_statement := 'sql_statement=' + encodedstr1; FHttp.send(sql_statement); // // step10 : retrieve json from server writeln('Step9'); // s := "select * from test"; var FHttp2 := JXMLHttpRequest.Create; FHttp2.open("POST",'...../smsdbmysql.php'); FHttp2.setRequestHeader("Content-type","application/x-www-form-urlencoded"); var encodedstr2 := browserapi.window.encodeURIComponent(S); var sql_statement2 := 'sql_statement=' + encodedstr2; FHttp2.send(sql_statement2); JGlobalEventHandlers(FHttp2).onLoad := lambda(e:JEvent) var smscursor := JSON.parse(FHttp2.responseText); for var i := 0 to smscursor.rows.length -1 do begin textdata := smscursor.rows[i].webjson; end; writeln(textdata); result :=true; end; */ end; procedure TForm1.W3Button1Click(Sender: TObject); begin DoStuff; end; procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} end; procedure TForm1.Resize; begin inherited; end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end.
  9. lynkfs

    Measuretext not doing a great job :(

    I've noticed the inconsistent measuretext function too. However in your case you can use textAlign in the canvas LBitmap.Canvas.Context.DC.textAlign := 'right'; LBitmap.Canvas.TextOut(400, 70, s, clwhite); //400-wdth
  10. lynkfs

    memo lines ?

    interesting. Basically you would need to keep Text(string) and Lines(array of string) in sync at all times, and only sync when data changes in either one of them I suppose you could define a Lines array, and override the js push method (for this array only) Lines = [] Lines.push = function(data) { ... update Memo.text with data .... return Array.prototype.push.call(this, data); } and in this override update Memo.Text (or re-create Text from Lines). That would cover the use case of Memo1.Lines.Add(data) and I suppose similarly for deletes. The other way around (changing Text instead of Lines) you would need to extend the SetText setter to update Lines (and not get into an infinite loop) Looking forward to see your solution
  11. lynkfs

    Resize Bitmap / Image

    There are some good discussions in this link : https://stackoverflow.com/questions/10333971/html5-pre-resize-images-before-uploading May be helpful
  12. lynkfs

    memo lines ?

    Something like Memo1.Text := #' line-01 line-02 line-03 '; MyArray := StrSplit(Memo1.Text, #10); will work
  13. lynkfs

    no-code

    Setting up a blog in WordPress is a no-brainer of course. Setting one up in Smart is pretty easy too. This one repurposes a treeview as a vertical collapsible menu and a series of Google docs in an iFrame. Using Google docs is a bit of a short-cut but it does provide the basics in a single package : perfect formatting capabilities, editing online and authorisation for editing source, or able to comment, or viewing for anyone. As for the subject (a no-code/lo-code framework) this obviously is unfinished ('intro' and the beginning of 'framework' entries only). I may do some more work on it when time permits. If you have thoughts on the subject and make it a collaborative effort then let me know. By the way, the form under 'Design' is a proof of concept for using the jsPlumb library (included in Smart in the libraries directory). A very useful library, check it out. Panels are draggable, links are connectable by mouse and touch etc...
  14. lynkfs

    calling external javascript

    ok, they changed the entry point from a function call to a var, and renamed it to 'math' //function mathjs: Variant; external 'mathjs'; var mathjs external 'math': variant; point script.src to 'https://cdnjs.cloudflare.com/ajax/libs/mathjs/5.1.0/math.min.js' and use as before (instead of referencing the cdn or a local url you can of course store whatever version of the library you like on one of your own servers and point the script.src to that)
  15. lynkfs

    calling external javascript

    this code works var document external 'document': variant; var console external 'console': variant; function mathjs: Variant; external 'mathjs'; implementation { TForm1 } procedure TForm1.W3Button1Click(Sender: TObject); begin var Script : THandle := document.createElement('script'); Script.src := 'lib/math.js'; //'https://cdnjs.cloudflare.com/ajax/libs/mathjs/5.1.0/math.min.js'; document.head.appendChild(Script); Script.onload := procedure begin console.log('loaded'); //... do your thing console.log('1.2 / (2.3 + 0.7) [Execute] = ' + mathjs.eval('1.2 / (2.3 + 0.7)')); end; end; Obviously there is a difference between the local library and the cdn library. The latter doesn't recognise the function 'mathjs', or its called differently. I'll have a look later on
×