Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Reputation Activity

  1. Like
    Czar got a reaction from markus_ja in UI layout   
    For me the most frustrating aspect of using SMS is layouts. Putting together anything beyond a trivial UI takes ages and is very frustrating to achieve.
    The Tlayout is not intuitive, it has weird and unexplainable side effects and takes a long time to get it right. Once you have it working then generally it is fine.
    We really need to have a more intuitive system to allow easy to create and maintain UI.
    I believe simple anchor (left, top, right, bottom)m, Align and "alignWithMargin" like Delphi has would be a great bonus to SMS.
    I have no idea what would be involved, or how much work it would be, but I would love to see this being developed.
  2. Like
    Czar reacted to jarto in Beware of box shadows!   
    I have been working on a new TW3StringGrid for Smart Mobile Studio. The original plan was to include it in 3.0, but there was a problem: It was slow on iOS. So, ever since the release, I've tried to crack this problem. How can Javascript that works beautifully on every other platform and browser be absolutely horrible on iOS? It was extremely fast on desktop browsers and  Android tablets. On iOS it took seconds to draw the grid and scrolling it was close to unusable.   After countless of hours of testing and trying, I finally found the reason: Box shadows in CSS. For example: .TW3ContainerBorder { border-radius: <?pas=EdgeRounding?>; border-top: 1px solid rgba(250, 250, 250, 0.7); border-left: 1px solid rgba(250, 250, 250, 0.7); border-right: 1px solid rgba(240, 240, 240, 0.5); border-bottom: 1px solid rgba(240, 240, 240, 0.5); -webkit-box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; -moz-box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; -ms-box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; -o-box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; box-shadow: 0px 0px 1px 1px <?pas=GetRGBA(clDlgShadowBaseColor, 0.3)?>; } .TW3FlatBorder { border-radius: <?pas=EdgeRounding?>; border-top: 1px solid rgba(44, 44, 44, 0.8); border-left: 1px solid rgba(44, 44, 44, 0.8); border-right: 1px solid rgba(44, 44, 44, 0.8); border-bottom: 1px solid rgba(44, 44, 44, 0.8); } I had used a TW3ContainerBorder for every cell in the grid. Replacing them with a flat border improved performance dramatically on iOS. Something like an order of magnitude faster.
      So if you've been having performance problems with iOS, that's most likely the reason.
  3. Like
    Czar reacted to lynkfs in Calendar Control   
    Easiest way :
    procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components var CalenderBox : TW3Panel := TW3Panel.Create(self); CalenderBox.SetBounds(10,10,252,266); CalenderBox.handle.id := 'CalenderBox'; var myCalendar : variant := new JObject; asm @myCalendar = new dhtmlXCalendarObject("CalenderBox"); end; myCalendar.disableDays("week", [7]); myCalendar.setDateFormat("%Y-%m-%d"); myCalendar.setHolidays("2019-03-19"); var yesterday : float := Now()-1; myCalendar.setInsensitiveRange(null, DateToStr(yesterday)); myCalendar.attachEvent("onClick", procedure(date:variant) begin writeln(myCalendar.getFormatedDate('%d-%m-%Y')); end); myCalendar.show(); end; make sure you include the necessary dhtmlx files in your index.html (Project Manager pane, right-click, add Template and select default.html from the Templates directory. This creates a new unit Custom Template. Then add the 2 lines below) . I used the cdn version (which contains the whole suite)
    <link rel="stylesheet" href="http://cdn.dhtmlx.com/edge/dhtmlx.css" type="text/css"> <script src="http://cdn.dhtmlx.com/edge/dhtmlx.js" type="text/javascript"></script> (alternatively you can import these files in code too)

  4. Like
    Czar reacted to DavidRM in Chat Scroller - Need Some Tips   
    I built this component to use in my Paintball Net game UI:
    unit UPBTInfoScroll; interface uses System.Types, System.Lists, System.Time, System.Colors, SmartCL.System, SmartCL.Theme, SmartCL.Components, SmartCL.Controls.Label, SmartCL.Scroll, SmartCL.Controls.ScrollBar, SmartCL.Css.Classes; type TPBTScrollItem = class(TW3CustomControl) protected FItemText: string; procedure InitializeItem; virtual; procedure SetItemText(aValue: string); public function CreationFlags: TW3CreationFlags; override; procedure InitializeObject; override; procedure UpdateDisplay; virtual; property ItemText: string read FItemText write SetItemText; end; TPBTScrollItemClass = class of TPBTScrollItem; TPBTScrollInfoItem = class(TPBTScrollItem) protected public procedure UpdateDisplay; override; property InfoText: string read ItemText write ItemText; end; TPBTScrollErrorItem = class(TPBTScrollInfoItem) end; TPBTChatType = (ctAnnounce, ctChat, ctSay, ctShout, ctWhisper, ctTell, ctPlan, ctTeamPlan, ctWizChat); TPBTScrollChatItem = class(TPBTScrollItem) private FChatType: TPBTChatType; FChatHeader: string; FChatText: string; FChatColor: TColor; public procedure UpdateDisplay; override; property ChatTYpe: TPBTChatType read FChatType; property ChatHeader: string read FChatHeader; property ChatText: string read FChatText; property ChatColor: TColor read FChatColor; end; TPBTScrollItems = class(TW3ScrollContent) private function GetItem(Index: Integer): TPBTScrollItem; function GetCount: integer; public function Add: TPBTScrollItem; overload; function Add(aScrollItemClass: TPBTScrollItemClass): TPBTScrollItem; overload; procedure Clear; virtual; procedure FinalizeObject; override; procedure Delete(aIndex: integer); published property Items[index: Integer]: TPBTScrollItem read GetItem; default; property Count: integer read GetCount; end; TPBTInfoScrollAddItemCallback = function: TPBTScrollItem; TPBTInfoScroll = class(TW3ScrollControl) private function GetItems: TPBTScrollItems; function GetScrollIsAtBottom: boolean; protected procedure InitializeObject; override; procedure Resize; override; function GetScrollContentClass: TW3ScrollContentClass; override; public function CreationFlags: TW3CreationFlags; override; procedure Clear; procedure ScrollToBottom; procedure RealignItems; procedure AddItem(aCallBack: TPBTInfoScrollAddItemCallback); procedure AddText(const aText: string); procedure AddChat(aChatType: TPBTChatType; const aChatHeader, aChatText: string; aChatColor: TColor); procedure AddInfo(const aInfoText: string); procedure AddError(const aErrorText: string); function MaxInfoWidth: integer; function MinInfoWidth: integer; published property Items: TPBTScrollItems read GetItems; property ScrollIsAtBottom: boolean read GetScrollIsAtBottom; end; implementation // TPBTScrollItem procedure TPBTScrollItem.InitializeItem; begin end; procedure TPBTScrollItem.SetItemText(aValue: string); begin if aValue <> FItemText then begin FItemText := aValue; UpdateDisplay; end; end; function TPBTScrollItem.CreationFlags: TW3CreationFlags; begin inherited; Include(Result, cfAllowSelection); end; procedure TPBTScrollItem.InitializeObject; begin inherited; SetContentSelectionMode(tsmText); end; procedure TPBTScrollItem.UpdateDisplay; begin InnerHTML := Format('<span style="user-select:text;-moz-user-select:text;-webkit-user-select:text;-ms-user-select:text;-khtml-user-select:text">%s</span>', [TString.EncodeTags(FItemText)]); end; // TPBTScrollInfoItem procedure TPBTScrollInfoItem.UpdateDisplay; begin inherited; end; // TPBTScrollErrorItem // TPBTScrollChatItem procedure TPBTScrollChatItem.UpdateDisplay; begin inherited; InnerHTML := Format('<span style="color:%s;user-select:text;-moz-user-select:text;-webkit-user-select:text;-ms-user-select:text;-khtml-user-select:text"><b>%s</b>: %s</span>', [ColorToWebStr(FChatColor), TString.EncodeTags(FChatHeader), TString.EncodeTags(FChatText)]); end; // TPBTScrollItems function TPBTScrollItems.GetItem(Index: Integer): TPBTScrollItem; begin Result := TPBTScrollItem(GetChildren[Index]); end; function TPBTScrollItems.GetCount: integer; begin Result := GetChildCount; end; function TPBTScrollItems.Add: TPBTScrollItem; begin Result := Add(TPBTScrollItem); end; function TPBTScrollItems.Add(aScrollItemClass: TPBTScrollItemClass): TPBTScrollItem; begin Result := aScrollItemClass.Create(Self); Result.InitializeItem; end; procedure TPBTScrollItems.Clear; begin // can't get rid of from [0]. Not sure why. while Count > 0 do GetChildren[Count - 1].Free; Height := 0; end; procedure TPBTScrollItems.FinalizeObject; begin Clear; inherited; end; procedure TPBTScrollItems.Delete(aIndex: integer); begin if aIndex < GetChildCount then GetChildren[aIndex].Free; end; // TPBTInfoScroll function TPBTInfoScroll.GetItems: TPBTScrollItems; begin Result := TPBTScrollItems(Content); end; function TPBTInfoScroll.GetScrollIsAtBottom: boolean; begin Result := (ScrollController.ContentTop <= -(Content.Height - (Height + 10))) end; procedure TPBTInfoScroll.InitializeObject; begin inherited; SetBarSize(CNT_SCROLLBAR_SIZE); ScrollBars := sbScrollBar; end; procedure TPBTInfoScroll.Resize; begin inherited; end; function TPBTInfoScroll.GetScrollContentClass: TW3ScrollContentClass; begin Result := TPBTScrollItems; end; function TPBTInfoScroll.CreationFlags: TW3CreationFlags; begin inherited; // Allow key-capture and selection include(result, cfKeyCapture); include(result, cfAllowSelection); end; procedure TPBTInfoScroll.Clear; begin Items.Clear; SetSize(ClientWidth, 0); ScrollController.Refresh; end; procedure TPBTInfoScroll.ScrollToBottom; begin ScrollController.ScrollTo(0, -(Content.Height - Height)); end; procedure TPBTInfoScroll.RealignItems; var ii: integer; begin ScrollController.Refresh; if Items.Count > 0 then begin Items.BeginUpdate; try Items[0].Top := 0; for ii := 1 to Items.Count - 1 do begin Items[ii].Top := Items[ii - 1].Top + Items[ii - 1].Height; end; finally Items.EndUpdate; end; end; end; procedure TPBTInfoScroll.AddItem(aCallBack: TPBTInfoScrollAddItemCallback); const margin = 5; MAX_ITEMS = 500; var lastItem, aItem: TPBTScrollItem; needRealign, wasAtBottom: boolean; begin Items.BeginUpdate; Content.BeginUpdate; try if Items.Count > 0 then lastItem := Items[Items.Count - 1]; needRealign := Items.Count > MAX_ITEMS; if needRealign then while Items.Count > (MAX_ITEMS div 3) * 2 do Items.Delete(0); if Content.Width <> (ClientWidth - GetBarSize) then Content.Width := (ClientWidth - GetBarSize); wasAtBottom := (ScrollController.ContentTop <= -(Content.Height - (Height + 10))); aItem := aCallBack; aItem.UpdateDisplay; if lastItem <> nil then aItem.Top := lastItem.Top + lastItem.Height else aItem.Top := 0; Content.Height := aItem.Top + aItem.Height + margin; if Content.Height <= Height then begin Content.Height := Height; wasAtBottom := True; end; finally Content.EndUpdate; Items.EndUpdate; end; if needRealign then RealignItems; ScrollController.Refresh; if wasAtBottom then ScrollToBottom; if needRealign then Invalidate; end; procedure TPBTInfoScroll.AddText(const aText: string); begin AddItem( lambda Result := Items.Add; Result.ItemText := aText; end ); end; procedure TPBTInfoScroll.AddChat(aChatType: TPBTChatType; const aChatHeader, aChatText: string; aChatColor: TColor); begin AddItem( lambda Result := Items.Add(TPBTScrollChatItem); TPBTScrollChatItem(Result).FChatType := aChatType; TPBTScrollChatItem(Result).FChatHeader := aChatHeader; TPBTScrollChatItem(Result).FChatText := aChatText; TPBTScrollChatItem(Result).FChatColor := aChatColor; end ); end; procedure TPBTInfoScroll.AddInfo(const aInfoText: string); begin AddItem( lambda Result := Items.Add(TPBTScrollInfoItem); TPBTScrollInfoItem(Result).InfoText := aInfoText; end ); end; procedure TPBTInfoScroll.AddError(const aErrorText: string); begin AddItem( lambda Result := Items.Add(TPBTScrollErrorItem); TPBTScrollErrorItem(Result).InfoText := aErrorText; end ); end; function TPBTInfoScroll.MaxInfoWidth: integer; var aMax: string; begin while aMax.Length < 70 do aMax += 'XXXXXXXXXX'; Result := MeasureText(aMax).tmWidth + GetBarSize; end; function TPBTInfoScroll.MinInfoWidth: integer; begin Result := MaxInfoWidth div 2; end; end.  
    My goal was to have it act like a scrolling chat. New items are added to the bottom, pushing up the items already there. By default scrolling "sticks" to the bottom of the view area, unless the player has manually scrolled it back to review something or whatever.
    Overall, it works. What I'm looking for are missed opportunities and maybe some solutions to a couple issues:
    The biggest issue is the build up of items in the scroll. Right now, I have it check for a maximum size, then prune it down to half that size. I would *prefer* if it could be indefinitely large. The solutions I've seen for that have relied on items being the same height. That constraint doesn't work for me. Resizing isn't exactly snappy/smooth. Just seems like there's probably a way to make that better. Also, as a sorta sub-goal, I wanted to share what I had done. SMS needs a lot more sharing going on. 😃
    So...hit me. Tell me how I'm doing it wrong and/or could do it better.
  5. Like
    Czar reacted to jarto in Update embedded Chromium   
    Hi guys,
    I've been a busy for a while working on updating the Embedded Chrome we use in the IDE. The one we've used so far has been from Henri Gourvest. Unfortunately it's not been updated for 3 years, but there's a new fork by Salvador Diaz Fau, which is actively updated: https://github.com/salvadordf/CEF4Delphi
  6. Like
    Czar reacted to lynkfs in scrolling big numbers   
    Got challenged the other day by trying to scroll large numbers of rows in a listbox.
    Browsers are very good at scrolling, but when row numbers become large and the scroll context becomes complex, scroll behaviour deteriorates.
    A simple un-optimised scrolling div is, rule of thumb, able to scroll comfortably up to a couple of hundred rows. Depending on browser and complexity.
    In the native framework I tweaked that a bit by setting all rows outside the visible viewport to 'display:none'. That extends comfortable scrolling somewhat, say to numbers in the low thousands. 
    A better way is to completely separate display from content. Meaning that the content needs to be held in some kind of memory structure, not in visual components, and that scrolling is redefined to re-using a small set of visual rows confined to the scroll-window.
    A structure to make that happen would be a <div> like component (TW3Panel) on a form with NativeScrolling set to true. Set up 2 child-panels on this component, where the first child-panel has dimensions equal to the maximum scrollable area, and a second childpanel dimensioned equal to this parent. The first child-panel is the scroller, which will always be completely empty. The second child-panel contains the visible rows, which will be refreshed on scroll-events. To keep this panel always in view, set the position attribute to '-webkit-sticky'.
    This demo shows that Chrome can readily handle 500,000 rows, even on mobile. FF a bit less.
    The good thing is that the number of rows doesn't really matter, scrolling behaviour stays the same regardless.
    Would be interesting to see if performance gets even better by pushing scrolling to the GPU, pretty sure Chrome does that by default.
    Infinite scrolling will be easy to implement using this structure too.
    procedure TForm1.W3Button1Click(Sender: TObject); begin //data   var column1 := TVariant.CreateArray;   for var i := 0 to 500000 do begin     column1.push(inttostr(i));   end;   var column2 := TVariant.CreateArray;   for var i := 1 to 500001 do begin     column2.push(inttostr(i));   end;   //column2.sort(); //sorting works too //scrolling setup   var rowHeight := 30;   W3Panel.NativeScrolling := true; //Parent panel (in visual designer : width 408, height 266)   var Panel1 : TW3Panel := TW3Panel.Create(W3Panel);      //scroller (always empty!)   Panel1.SetBounds (0,0,380,column1.length*rowHeight);    //but with large height   Panel1.BorderRadius := 0; //set up viewport   var Panel2 : TW3Panel := TW3Panel.Create(W3Panel);      //viewport, only the visual rows   Panel2.SetBounds(0,0,380,262);                          //dimensions same as grid-parent   Panel2.BorderRadius := 0;   Panel2.handle.style.position := '-webkit-sticky';   Panel2.handle.style.position := '-moz-sticky';   Panel2.handle.style.position := '-ms-sticky';   Panel2.handle.style.position := '-o-sticky';   Panel2.handle.style.position := 'sticky';   Panel2.handle.style.top := '0px'; //set up columns   Var CPanel1 : TW3Panel := TW3Panel.Create(Panel2);     //column 1   CPanel1.SetBounds(-2,-2,200,264);   CPanel1.BorderRadius := 0;   Var CPanel2 : TW3Panel := TW3Panel.Create(Panel2);     //column 2   CPanel2.SetBounds(200,-2,200,264);   CPanel2.BorderRadius := 0;   //initial fill viewport prior to first onscroll event   for var j := 0 to 8 do begin //only first couple of rows     var x : TW3Panel := TW3Panel.Create(CPanel1); //column 1     x.SetBounds(-2,j*rowHeight-2,200,rowHeight);     x.BorderRadius := 0;     x.innerHTML := column1[j];     x.onclick := procedure(sender:TObject) begin showmessage((sender as TW3Panel).innerHTML); end;     //     var y : TW3Panel := TW3Panel.Create(CPanel2); //column 2     y.SetBounds(-2,j*rowHeight-2,190,rowHeight);     y.BorderRadius := 0;     y.innerHTML := column2[j];     y.onclick := procedure(sender:TObject) begin showmessage((sender as TW3Panel).innerHTML); end;   end; //fill viewport while scrolling   var c1 := CPanel1.handle.children;   var c2 := CPanel2.handle.children;   W3Panel.onscroll := procedure(sender:tobject)   begin     var d : integer := trunc(W3Panel.handle.scrollTop/rowHeight);     for var k := 0 to 8 do begin       c1[k].innerHTML := column1[d+k];       c2[k].innerHTML := column2[d+k];     end;     //fall back : ide chrome browser and iOS don't handle 'sticky' very well,     //in that case set viewport position manually     if Panel2.handle.style.position <> 'sticky' then       if not w3_getIsSafari then         Panel2.top := W3Panel.handle.scrollTop;   end; end;  
    infinity scroll :
    add to end of W3Panel.onscroll procedure
        //infinity scroll :     if W3Panel.handle.scrollHeight - W3Panel.handle.scrollTop = W3Panel.handle.clientHeight then      W3Panel.handle.scrollTop := 0;  
  7. Like
    Czar reacted to jarto in RoadMap 2019   
    We'll be able to improve documentation in about 2 months. I do agree that it's currently the area where we need to improve. While waiting for that, I'm doing my best to help users here in the Forum.
  8. Like
    Czar reacted to jarto in Development updates   
    New update available:
    New controls: TW3SpinButton, TW3ArrowUpButton, TW3ArrowDownButton, TW3ArrowLeftButton and TW3ArrowRightButton. Add 1px margin to TW3ButtonBorder to prevent the border from being clipped. Bug fixes to Tween.Effects IDE:
    Bug fixes and changes to renaming of forms: Renaming in Project Manager will not change form class any more. Form class name can be renamed in Object Inspector. Improvements to Project Statistics: Only count Total time when Smart Mobile Studio IDE has focus. Only Count Design time when changes are made in Form Designer. Add clear button. Component Palette: Added new controls New icons for many existing controls
  9. Like
    Czar reacted to lynkfs in Quantum computing with Smart   
    Is it possible to do a bit of quantum computing using SMS ?
    The answer looks to be yes, using IBM's quantum computer resources which are partly made available for developers
    Basics first : IBM has released it's SDK to program these quantum computers using a visual composer, Python, a proprietary assembler QASM format and some run and execute utilities.
    There is however a second way of using its quantum resources, using the entry-points of is Q-experience REST server. Most if not all of the visual composer functions can be done by ajax-calls !
    To demonstrate : the first thing is to acquire an api-token. 
    (Create an account on https://quantumexperience.ng.bluemix.net/qx/experience. Log in and navigate to the Composer. Username > My Account, and then Advanced on the upper right. Then generate API Token. Api Tokens are personal and are not supposed to be shared.)
    The next thing is to generate a session token (access token). This can be done in code.
    This screenshot
    shows a couple of these REST server calls and its results :
    The first button (get access) generates a session token The second button queries which quantum computers are available, how many qubits can be used, if it is online and what type of system it is. Current results show 3 quantum systems - 2 real ones and 1 simulator The third button (current Temp) gives some processor info of the selected system. In this case the current temperature in Kelvin : the Melbourne processor is cooled to just above the absolute minimum. Next : the next button to implement will be to submit some code to one of the available processors for processing. Below is the project code for these REST calls
    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.Net.Http, ECMA.Json, SmartCL.Controls.Button,   SmartCL.Controls.Label, HTMLTableElement, SmartCL.Controls.ScrollBox,   SmartCL.Controls.Panel, SmartCL.Controls.ComboBox; type   TForm1 = class(TW3Form)     procedure W3Button3Click(Sender: TObject);     procedure W3Button2Click(Sender: TObject);     procedure W3Button1Click(Sender: TObject);   private     {$I 'Form1:intf'}   protected     procedure InitializeForm; override;     procedure InitializeObject; override;     procedure Resize; override;     DBRows : integer := 0;     FHttp : TW3HttpRequest;     smscursor: variant;     procedure GetAccessToken(Sender: TW3HttpRequest);     procedure ListAvailableSystems(Sender: TW3HttpRequest);     procedure GetTempKelvin(Sender: TW3HttpRequest);     AccessToken : string;   end; implementation { TForm1 } procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components end; procedure TForm1.InitializeObject; begin   inherited;   {$I 'Form1:impl'} end; { Button1 } procedure TForm1.W3Button1Click(Sender: TObject); begin //Get Access Token   var FHttp := TW3HttpRequest.Create;   FHttp.OnDataReady := GetAccessToken;   FHttp.open("POST",'https://quantumexperience.ng.bluemix.net/api/users/loginWithToken');   FHttp.RequestHeaders.Add("Content-type","application/json");   var api : variant := new JObject;   api.apiToken := TString.encodeURIComponent('a59d26ebf........1d6d6d4a28c430b5336aba');   FHttp.send(json.stringify(api)); end; procedure TForm1.GetAccessToken(Sender: TW3HttpRequest); begin   smscursor := JSON.parse(Sender.ResponseText);   AccessToken := smscursor.id;   W3Label1.Caption:= 'Access Token : ' + AccessToken; end; { Button2 } procedure TForm1.W3Button2Click(Sender: TObject); begin //List available Q systems   var FHttp := TW3HttpRequest.Create;   FHttp.OnDataReady := ListAvailableSystems;   FHttp.open("GET",'https://quantumexperience.ng.bluemix.net/api/Backends?access_token=' + AccessToken);   FHttp.RequestHeaders.Add("Content-type","application/json");   FHttp.send; end; procedure TForm1.ListAvailableSystems(Sender: TW3HttpRequest); begin   var W3TableElement1 : TW3TableElement := TW3TableElement.Create(W3Panel1); //add 5 columns to the grid   W3TableElement1.AddColumn('Name',200);      //title, width   W3TableElement1.AddColumn('Description',200);   W3TableElement1.AddColumn('Qubits',50);   W3TableElement1.AddColumn('System type',150);   W3TableElement1.AddColumn('Status',50);   smscursor := JSON.parse(Sender.ResponseText);   W3ComboBox1.Clear;   for var i := 0 to smscursor.length -1 do begin     W3TableElement1.AddCell(i+1,1,smscursor[i].name);     W3TableElement1.AddCell(i+1,2,smscursor[i].description);     W3TableElement1.AddCell(i+1,3,smscursor[i].nQubits);     if smscursor[i].simulator = true       then W3TableElement1.AddCell(i+1,4,'quantum simulator')       else W3TableElement1.AddCell(i+1,4,'quantum system');     W3TableElement1.AddCell(i+1,5,smscursor[i].status);     W3ComboBox1.add(smscursor[i].name);   end;   W3Panel1.NativeScrolling := true;   W3ComboBox1.OnChanged := procedure (Sender: TObject)   begin     writeln(W3ComboBox1.Items[W3ComboBox1.SelectedIndex]);   end; end; { Button3 } procedure TForm1.W3Button3Click(Sender: TObject); begin //Get Temp   var FHttp := TW3HttpRequest.Create;   FHttp.OnDataReady := GetTempKelvin;   //'https://quantumexperience.ng.bluemix.net/api/Backends/NAME/parameters?access_token=ACCESS-TOKEN';   FHttp.open("GET",'https://quantumexperience.ng.bluemix.net/api/Backends/' +                    W3ComboBox1.Items[W3ComboBox1.SelectedIndex] +                    '/parameters?access_token=' +                    AccessToken);   FHttp.RequestHeaders.Add("Content-type","application/json");   FHttp.send; end; procedure TForm1.GetTempKelvin(Sender: TW3HttpRequest); begin   If Sender.ResponseText = '{}' then   begin     W3Label3.Caption := 'Simulators are not cooled to (close to) absolute minimum';   end else   begin     smscursor := JSON.parse(Sender.ResponseText);     if smscursor.fridgeParameters.Temperature.value = ''       then W3Label3.Caption := 'Processor does not support Temp reading'       else W3Label3.Caption:= 'Current Temp : ' + smscursor.fridgeParameters.Temperature.value + ' Kelvin';   end; end; procedure TForm1.Resize; begin   inherited; end;   initialization   Forms.RegisterForm({$I %FILE%}, TForm1); end.  
    In the end hopefully it will be possible to recreate the classic Battleships game using quantum computing, as described here
  10. Like
    Czar reacted to jarto in Sound Playback in Built-in/Debugger Browser   
    Yes, I noticed the same when I tested all the featured demos. Funny thing is that audio did work in some of them. This will probably improve when we upgrade the embedded chrome in the internal browser.
  11. Like
    Czar reacted to lynkfs in inter-tab processing   
    Would it be possible to implement a 'client-server' architecture where both the client and the server are executed locally (but in separate spaces). Or just divide an app up in different parts where each part is executed in its own environment and communicates with the other parts as necessary. And all this pure locally. 
    The answer is yes: use separate browser tabs.
    Surprisingly there are multiple ways of doing this, and the candidate technologies enabling inter-tab communication are :
    local storage (really) shared web workers broadcast channelling webrtc The demo in this post is based on using localStorage and consists of two separate but standard Smart projects, dubbed 'server' and 'client'.
    The server-project is just a form with an embedded anchor html element (<a>). When clicked the href-attribute is set to the output of the client-project ('client.html') and the target-attribute to '_blank'. This has the effect of opening up a new browser-tab which runs the client-project.
    So now there are two browser tabs open, each running its own project.
    Communication between these tabs is possible using localStorage : mutations in localStorage generate storage-events and these events can be captured and used for communication purposes.
    This url (https://www.lynkfs.com/Experiments/webrtc/localstorage/server.html) opens up both tabs at once (you might have to allow pop-ups in Chrome or FireFox), and mimics a login process. 
    Server-code and Client-code (native framework but you'll get the idea)
    Login form :
      button.OnClick := procedure(sender:TObject)   begin //this sends 2 events to the server, which can then validate name and password     window.localStorage.setItem('name',name.handle.value);     window.localStorage.setItem('pw',  pw.handle.value);   end;   window.onstorage := procedure(e:variant)   begin //after validation the server sends a new event with the results     console.log(e.key);     console.log(e.oldValue);     console.log(e.newValue);     footer.SetBounds(100,300,200,30);     if (e.key = 'result') and (e.newValue = 'ok') then       footer.setInnerHTML('login successful');   end;  
    happy holidays
  12. Like
    Czar reacted to DavidRM in My SMS Project: Paintball Net Revival   
    Updated 5/2019 to add: Now online here: Paintball Net
    Back in the mid-90's, my brother created what he called an "action MUD". He called it "Paintball Net". PBN used ANSI text terminal commands to create a combined roll-and-scroll and animated text experience. ! (exclamation points) were trees, _ (underscores) were grass, ^ (up carets) were mountains, and more. Your "avatar" was a  "Y" (uppercase y) and enemies were * (asterisks). You used MUD-like commands to move around the world and target your paintball gun and buy and sell and more. I wish I had a screenshot of what the first version looked like, but you'll just have to imagine. 😃
    He asked me to create the GUI for the game. That was 1996, and I had just purchased Delphi 2 and wrapped up my first "learn Delphi" project. This sounded like a good next step, and "PBTerm" was born. I *do* have screenshots of that.

    Oh, yeah. Love those 16-color Windows graphics. 😃
    During the years it was online, the game evolved and upgraded to look more like this:

    We were never going to win any awards, but we had a very devoted player community. 😃
    Paintball Net was online from the summer of 1996 through the summer of 2000, when we took it offline to focus on other projects. The game was never huge, but we had thousands of players come through over that period. And since then, every year at least a few of the players have reached out and asked/begged/pleaded/demanded if we were going to put it back online.
    There really wasn't much chance of the original version going back online. The original server, written in ANSI C for Linux had proven rather fragile, and was a big part of why we took the game offline. It was taking hours every day just to keep it up and running, in addition to time spent managing the community of players. On top of that, a hard drive incident in 2008 had cost me the source code of a number of core third-party/modified components for PBTerm.
    This past summer, though, I realized I might be able to make the game live again using Smart Mobile Studio. I would do a straight port of the ANSI C server to Smart Pascal using Node.JS and WebSocket, and I would rebuild the PBTerm client as a browser-based client.
    I'm not going to say it was *easy*, but it has been a lot of fun. ANSI C converts to Pascal without a lot of painful gyrations. And Node.JS seems a LOT more flexible, stable, and powerful than the TCP sockets approach we were using before.
    Also, game development is a lot easier when you already own all the graphic and audio resources. 😃
    This is the server "in action"...

    Recreating the client has been more complicated. 20+ years of Delphi habits had to be adapted to the new reality of SMS and a browser-based UI. But that's coming together too.

    It might be obvious, but I'm not targeting this game at mobile. Paintball Net needed a mouse and keyboard in 1996, it's gonna need a mouse and keyboard in 2018. Also, I've made as few modifications to the gameplay as possible. I really wanted to bring back the original as much as I could.
    Today I got the handful of sound effects integrated, which was easier than I expected.
    I'm planning to start testing soon. I just need to line up a server to use and find a few volunteers.
    I'm excited. This would never have happened without Smart Mobile Studio.
    So I figured I would share.
    Merry Xmas!
  13. Like
    Czar reacted to jarto in Smart Mobile Studio 3.0.2 is released!   
    Smart Mobile Studio 3.0.2 is released. This version contains all the fixes and improvements from the development-channel. There are lots of bug fixes and improvements to the IDE thanks to all the help from our users here.
    The Smart Mobile Studio team wants to with everybody a Merry Christmas and Happy New Year.
    Release notes:
  14. Like
    Czar reacted to jarto in Development updates   
    New update available:
    TW3TabControl: AnimateTabs-property to control how tabs are changed. TW3ListBox: Prevent an exception if TW3Image is used as a line control and OnShowItem is not set. TW3ListMenu, TW3HeaderControl and TW3SimpleLabel: Don't set default caption to classname during initialization. DWScript: Capitalize day and month names correctly (January instead of january, Sunday instead of sunday) IDE:
    Improvements to the way the IDE reacts to a changed external file. Use caption while drawing generic controls instead of component name.  
  15. Like
    Czar reacted to IElite in FormatDateTime?   
    yes, I was just thinking that maybe the SMS team wanted the code base to be more like Delphi.  Delphi's FormatDateTime returns proper case
  16. Like
    Czar reacted to jarto in Development updates   
    New update available:
    TW3ListMenu: Add Items-property, so items can created in Object Inspector. Add OnSelected-event. IDE:
    Bug fix to renaming of units Show form source instead of designer when form is selected from Project Manager  
  17. Like
    Czar reacted to jarto in New to Node   
    Actually, the communication part between a NodeJS server and a Smart client app is pretty easy.
    Client: You read data from the server using simple http/https get. When you want to write something to the server, you do it with http/https post.
    Server: You can start with the NodeJS http server example. When your client sends a get or post, it comes to TServer.HandleRequest where you handle the request.
    You can start by adding some WriteLn to TServer.HandleRequest to print out what the headers and the content is. Then you can send GET and POST requests to it by using a browser (http://localhost:1881/whatever/url/you/want/to/send/it?params=whatever) or curl. With Curl you can easily send post commands. For example:
    curl -i -X POST -H 'Content-Type: application/json' -d '{"score": "Player": "10000"}' http://localhost:1881
    When you can see what's going on in the server, you can also make the client app and start sending those http get/post with TW3HttpRequest (SmartCL.Net.Http)
    I have done this earlier on the client side with Smart Mobile Studio and it worked nicely. There were hundreds of thousands of users on iOS and Android. The server was in Delphi but it can really be written in any language. I'd probably write my next server in Smart Mobile Studio using NodeJS.
  18. Like
    Czar got a reaction from IElite in Development updates   
    that is what I had done already-
  19. Like
    Czar reacted to IElite in TSpinButton? TSpinEdit?   
    I was in need of a TSpinButton for Incrementing years and months on my calendar
    Here is a little something I created. Surely it needs work (but it works fine for me). Maybe one can be created for the RTL?
    use as such
      fSpinBtn:= TW3SpinButton.Create(self);   fSpinBtn.setBounds(10, 10, 50, 32)   fSpinBtn.OnDownClick:= HandleDownClick;   fSpinBtn.OnUpClick:= HandleUpClick;  
    See code and attached screenshots below
    For the button icons\glyphs, I am using base64 vector images (so they resize with the buttons when the control resizes). The images are embedded in the style using Style.SetProperty (see code)
    unit SpinBtn; interface uses    System.Types,   System.Types.Convert,   System.Time,   System.Streams,   System.Reader,   System.Writer,   System.Device.Storage,   SmartCL.Device.Storage,   SmartCL.Application,   SmartCL.Components,   SmartCL.System,   SmartCL.Controls.Button;   type   TW3SpinButton = class(TW3CustomControl)   private    fUpBtn: TW3Button;    fDownBtn: TW3Button;    FOnUpClick: TNotifyEvent;    FOnDownClick: TNotifyEvent;    procedure BtnClick(Sender: TObject);   protected     procedure InitializeObject; override;     procedure FinalizeObject; override;     procedure Resize; override;   published     property OnUpClick: TNotifyEvent read FOnUpClick write FOnUpClick;     property OnDownClick: TNotifyEvent read FOnDownClick write FOnDownClick;   end; implementation procedure TW3SpinButton.BtnClick(Sender: TObject); begin   if Sender = FUpBtn then   begin     if Assigned(FOnUpClick) then FOnUpClick(Self);   end   else     if Assigned(FOnDownClick) then FOnDownClick(Self); end; procedure TW3SpinButton.InitializeObject; begin   inherited;   FUpBtn:= TW3Button.Create(self);   FUpBtn.handle.style.setProperty('background-image', 'url(data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTYuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjMycHgiIGhlaWdodD0iMzJweCIgdmlld0JveD0iMCAwIDQ0NC44MTkgNDQ0LjgxOSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDQ0LjgxOSA0NDQuODE5OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxnPgoJPHBhdGggZD0iTTQzMy45NjgsMjc4LjY1N0wyNDguMzg3LDkyLjc5Yy03LjQxOS03LjA0NC0xNi4wOC0xMC41NjYtMjUuOTc3LTEwLjU2NmMtMTAuMDg4LDAtMTguNjUyLDMuNTIxLTI1LjY5NywxMC41NjYgICBMMTAuODQ4LDI3OC42NTdDMy42MTUsMjg1Ljg4NywwLDI5NC41NDksMCwzMDQuNjM3YzAsMTAuMjgsMy42MTksMTguODQzLDEwLjg0OCwyNS42OTNsMjEuNDExLDIxLjQxMyAgIGM2Ljg1NCw3LjIzLDE1LjQyLDEwLjg1MiwyNS42OTcsMTAuODUyYzEwLjI3OCwwLDE4Ljg0Mi0zLjYyMSwyNS42OTctMTAuODUyTDIyMi40MSwyMTMuMjcxTDM2MS4xNjgsMzUxLjc0ICAgYzYuODQ4LDcuMjI4LDE1LjQxMywxMC44NTIsMjUuNywxMC44NTJjMTAuMDgyLDAsMTguNzQ3LTMuNjI0LDI1Ljk3NS0xMC44NTJsMjEuNDA5LTIxLjQxMiAgIGM3LjA0My03LjA0MywxMC41NjctMTUuNjA4LDEwLjU2Ny0yNS42OTNDNDQ0LjgxOSwyOTQuNTQ1LDQ0MS4yMDUsMjg1Ljg4NCw0MzMuOTY4LDI3OC42NTd6IiBmaWxsPSIjMDAwMDAwIi8+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg==)');   FUpBtn.handle.style.setProperty('background-repeat', 'no-repeat');   FUpBtn.handle.style.setProperty('background-position', 'center');   FUpBtn.handle.style.setProperty('background-size', 'contain');   fUpBtn.OnClick:= BtnClick;   FDownBtn:= TW3Button.Create(self);   FDownBtn.handle.style.setProperty('background-image', 'url(data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTYuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjMycHgiIGhlaWdodD0iMzJweCIgdmlld0JveD0iMCAwIDQ0NC44MTkgNDQ0LjgxOSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDQ0LjgxOSA0NDQuODE5OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxnPgoJPHBhdGggZD0iTTQzNC4yNTIsMTE0LjIwM2wtMjEuNDA5LTIxLjQxNmMtNy40MTktNy4wNC0xNi4wODQtMTAuNTYxLTI1Ljk3NS0xMC41NjFjLTEwLjA5NSwwLTE4LjY1NywzLjUyMS0yNS43LDEwLjU2MSAgIEwyMjIuNDEsMjMxLjU0OUw4My42NTMsOTIuNzkxYy03LjA0Mi03LjA0LTE1LjYwNi0xMC41NjEtMjUuNjk3LTEwLjU2MWMtOS44OTYsMC0xOC41NTksMy41MjEtMjUuOTc5LDEwLjU2MWwtMjEuMTI4LDIxLjQxNiAgIEMzLjYxNSwxMjEuNDM2LDAsMTMwLjA5OSwwLDE0MC4xODhjMCwxMC4yNzcsMy42MTksMTguODQyLDEwLjg0OCwyNS42OTNsMTg1Ljg2NCwxODUuODY1YzYuODU1LDcuMjMsMTUuNDE2LDEwLjg0OCwyNS42OTcsMTAuODQ4ICAgYzEwLjA4OCwwLDE4Ljc1LTMuNjE3LDI1Ljk3Ny0xMC44NDhsMTg1Ljg2NS0xODUuODY1YzcuMDQzLTcuMDQ0LDEwLjU2Ny0xNS42MDgsMTAuNTY3LTI1LjY5MyAgIEM0NDQuODE5LDEzMC4yODcsNDQxLjI5NSwxMjEuNjI5LDQzNC4yNTIsMTE0LjIwM3oiIGZpbGw9IiMwMDAwMDAiLz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8L3N2Zz4K)');   FDownBtn.handle.style.setProperty('background-repeat', 'no-repeat');   FDownBtn.handle.style.setProperty('background-position', 'center');   FDownBtn.handle.style.setProperty('background-size', 'contain');   fDownBtn.OnClick:= BtnClick; end; procedure TW3SpinButton.FinalizeObject; begin   FUpBtn.Free;   fUpBtn:= nil;   FDownBtn.Free;   fDownBtn:= nil;   inherited; end; procedure TW3SpinButton.Resize; begin   inherited;   if  (Handle.Valid and (csReady in ComponentState)) then   begin    fUpBtn.SetBounds(1,1, ClientWidth-2, (ClientHeight DIV 2)-2);    fDownBtn.SetBounds(1,(ClientHeight DIV 2), ClientWidth-2, (ClientHeight DIV 2)-2);   end; end; end.

  20. Like
    Czar reacted to lynkfs in wysiwyg   
    something like this (with more commands) would be possible
    procedure TForm1.InitializeObject; begin   inherited;   {$I 'Form1:impl'}   W3IFrameHtmlElement1.src := 'https://www.lynkfs.com/Experiments/wysiwyg/'; end;  
  21. Like
    Czar reacted to lynkfs in wysiwyg   
    Was looking for an easy to make wysiwyg editor. This one is based on 'document.designMode'.
    Mozilla: "When an HTML document has been switched to designMode, its document object exposes an execCommand method to run commands that manipulate the current editable region"
    IFrame's have an innate document element which can be used for that purpose.
    Have a form with an IFrameHtmlElement and 2 buttons ('bold' and 'italic') :
    procedure TForm1.InitializeForm; begin   inherited;   // this is a good place to initialize components   W3IframeHtmlElement1.handle.contentDocument.designMode := 'on';   W3IframeHtmlElement1.handle.contentDocument.body.innerHTML := 'this is some text';   W3IframeHtmlElement1.handle.focus(); end; procedure TForm1.W3Button1Click(Sender: TObject); //bold begin   W3IframeHtmlElement1.handle.contentDocument.execCommand('bold', false, null);   W3IframeHtmlElement1.handle.focus(); end; procedure TForm1.W3Button2Click(Sender: TObject); //italic begin   W3IframeHtmlElement1.handle.contentDocument.execCommand('italic', false, null);   W3IframeHtmlElement1.handle.focus(); end; Besides 'bold' and 'italic' execCommand supports a host of other edit commands as well.
    see https://codepen.io/chrisdavidmills/full/gzYjag/
  22. Like
    Czar reacted to lynkfs in lighthouse   
    Google has implemented a new service : web.dev
    Basically this measures some indicators of any url using their LightHouse tool.
    These indicators are grouped into Performance, Accessibility, Best Practices and SEO
    I created a minimal SMS project with only a single image on a form and run the test :
    https://web.dev/measure and url : https://www.lynkfs.com/Experiments/lighthouse/www/
    This gives scores of 95 / 27 / 77 / 89 for Performance, Accessibility, Best Practices and SEO respectively
    There are a couple of really simple things which will up these scores considerably.
    Scores were upped to 96 / 74 / 92 / 100 when doing this :
    Best Practices from 77 to 92 :
    1) in project options/linker unclick 'generate cache manifest' (deprecated)
    Performance from 95 to 96 :
    1) in project options/linker unclick 'store CSS as a separate file'  (95 to 96)
    2) add async to <script async src="lib/polyfill.custom.events.js" type="text/javascript"></script> in the index.html template
    SEO from 89 to 100 :
    1) add meta description tag to the head of index.html
    <meta name="Description" content="Put your description here.">
    Accessability from 27 to 74 :
    1) add alt attribute to images, even if only ''  :   W3Image1.handle.setAttribute('alt', ''); (27 to 58)
    2) add lang="en" to html element in index.html template : <html lang="en">   (58 to 74)
    3) tabindex=1 for TW3Display and TW3DisplayView. Should be 0 ?
    run test again on url : https://www.lynkfs.com/Experiments/lighthouse2/www/ to see these results
    All of the above could be made part of the standard settings for a new visual project
  23. Like
    Czar reacted to IElite in IDE & Documentation   
    If you press F12, you can switch back and forth between the form's unit code and the form. 
    If you right click on a form in the project manager and choose "View source", nothing happens if the actual form (and not it's unit) is displayed
    The items below are enabled in the Main Main> if You do NOT have debugging enabled, these do NOTHING but show a blank window.  Maybe disable them or display a message in the window to enable the debugger.

     Call Stack
     Call Scope
     Local Variables
     Debugger Protocol Log
    In addition, maybe there should be icons for these to the right of all the debugging icons
  24. Like
    Czar got a reaction from IElite in IDE & Documentation   
    I concur renaming a project is buggy.
    I would also love to be able to add a search path for units. At the moment we have to create a symlink inside the RTL folder to a network folder to store our common units. However, it would be much nicer if we could add a path to the IDE which is read when the RTL units are loaded.

    It would also be very excellent if when you go "open" it opens the last folder you were in rather than the SMS folder. We keep our projects on a network drive and it takes a significant number of clicks to take us back to the folder where are working.
  25. Like
    Czar reacted to IElite in IDE & Documentation   
    Well, one of the biggest issues for me was renaming files in the Project Manager. I brought this up many moons ago.
    e.g. When I right click on a form under "Forms" in the Project Manager and choose "Rename"
    After renaming it, I get a "Argument out of Range" error
    This does not happen on just my desktop. It also happens on my Laptop, and on my desktop at work
    So, it can't be device specific
    Furthermore, if this is the form1 created when I created the new project, and I rename it, if look at the forms unit (code), it will have only changed the name in the first line. None of the other lines where the form name exists has changed.
    If I add a new form, and then rename it, it renames the form name throughout the whole unit. Except this commented out line
    "{ TForm1 }"
  • Create New...