Jump to content

Ron

uniGUI Subscriber
  • Posts

    375
  • Joined

  • Last visited

  • Days Won

    31

Everything posted by Ron

  1. This is a Javascript issue, and you can load the pic in the html5 canvas, draw the rectangle, do some calculations and send the crop data to the server, and do the cropping there. I did this in JS from the bottom, and it was a bit of work - about one day. I wanted handles on the rectangle, and real-time upscaled result showing, so it was a little tricky to come up with very compressed code. The biggest problem is to find good routines for the resampling on the server side. Here is the script, which you load in a HTML frame and then respond to the events: <canvas id="cropcanvas"></canvas> <script type="text/javascript"> var cCanvas = document.getElementById("cropcanvas"); var cx = cCanvas.getContext("2d"); var rects = []; var bw=8; var mDelta = 1; var rDelta = 8; var rFill = false; var keepAspect = true; var stdAspect = 1.777; var activeRect = 0; var drX = 0; var drY = 0; var drW = 0; var drH = 0; var newDrX = 0; var newDrY = 0; var newDrW = 0; var newDrH = 0; var mcDown = false; var imgOriginal = new Image(); var cWidth = 1200; var cHeight = 400; var imgX = 0; var imgY = 0; var imgW = 0; var imgH = 0; var resImgW = 480; var resImgH = 270; var catchOnLine = false; var lineCol = "#DDDDDD"; var boxCol = "#FFFFFF"; var bgCol = "#CCCCCC" var borderCol = "#FFFFFF"; var backLineCol = "#000000"; function relMouseCoords(event){ var totalOffsetX = 0; var totalOffsetY = 0; var canvasX = 0; var canvasY = 0; var currentElement = this; do{ totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft; totalOffsetY += currentElement.offsetTop - currentElement.scrollTop; } while(currentElement = currentElement.offsetParent); canvasX = event.pageX - totalOffsetX; canvasY = event.pageY - totalOffsetY; return {x:canvasX, y:canvasY} } HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords; if(navigator.userAgent.match(/Firefox/)=="Firefox") var bType = 1; if(navigator.userAgent.match(/Chrome/)=="Chrome") var bType = 2; if(navigator.userAgent.match(/.NET/)==".NET") var bType = 3; function getRect(x, y) { for(i=0;i<rects.length;i++){ if ((x>=rects[i].xStart-mDelta) && (x<=rects[i].xStart + rects[i].xWidth+mDelta) && (y>=rects[i].yStart-mDelta) && (y<=rects[i].yStart + rects[i].yHeight +mDelta)) return rects[i].id; } if(catchOnLine) for(i=0;i<rects.length;i++){ if ( ((x>=drX-rDelta) && (x<=drX+rDelta) && (y>=drY) && (y<=drY+drH)) || ((x>=drX+drW-rDelta) && (x<=drX+drW+rDelta) && (y>=drY) && (y<=drY+drH)) || ((x>=drX-rDelta) && (x<=drX+drW+rDelta) && (y>=drY-rDelta) && (y<=drY+rDelta)) || ((x>=drX-rDelta) && (x<=drX+drW+rDelta) && (y>=drY+drH-rDelta) && (y<=drY+drH+rDelta)) ) return 0; } else for(i=0;i<rects.length;i++){ if ((x>=drX+rDelta) && (x<=drX+drW-rDelta) && (y>=drY+rDelta) && (y<=drY+drH-rDelta)) return 0; }; return -1; }; $("#cropcanvas").mousemove(function(event){ document.getElementById("cropcanvas").focus(); coords = cCanvas.relMouseCoords(event); if(!mcDown) activeRect = getRect(coords.x, coords.y) if(activeRect!=-1){ switch(activeRect){ case 0: document.getElementById("cropcanvas").style.cursor = 'move'; break; case 1: document.getElementById("cropcanvas").style.cursor = 'nw-resize'; break; case 2: document.getElementById("cropcanvas").style.cursor = 'ns-resize'; break; case 3: document.getElementById("cropcanvas").style.cursor = 'ne-resize'; break; case 4: document.getElementById("cropcanvas").style.cursor = 'ew-resize'; break; case 5: document.getElementById("cropcanvas").style.cursor = 'ew-resize'; break; case 6: document.getElementById("cropcanvas").style.cursor = 'sw-resize'; break; case 7: document.getElementById("cropcanvas").style.cursor = 'ns-resize'; break; case 8: document.getElementById("cropcanvas").style.cursor = 'se-resize'; break; } } else document.getElementById("cropcanvas").style.cursor = 'default'; if(mcDown){ if(keepAspect) switch(activeRect){ case 0: newDrX = coords.x - moveCX; newDrY = coords.y - moveCY;newDrH = drH; newDrW = drW;break; case 1: newDrH = drH + drY - coords.y;newDrY = coords.y;newDrW = newDrH * stdAspect; newDrX=drX+(drW-newDrW);break; case 2: newDrH = drH + drY - coords.y;newDrY = coords.y;newDrW = newDrH * stdAspect; newDrX=drX+(drW-newDrW)/2;break; case 3: newDrH = drH + drY - coords.y;newDrY = coords.y;newDrW = newDrH * stdAspect;newDrX=drX;break; case 4: newDrW = drW + drX - coords.x;newDrX = coords.x;newDrH = newDrW / stdAspect; newDrY=drY+(drH-newDrH)/2; break; case 5: newDrW = coords.x - drX;newDrH = newDrW / stdAspect;newDrY=drY+(drH-newDrH)/2;break; case 6: newDrW = drW + drX - coords.x;newDrX = coords.x;newDrH = newDrW / stdAspect;newDrY=drY;break; case 7: newDrH = coords.y - drY;newDrW = newDrH * stdAspect;newDrX=drX+(drW-newDrW)/2;newDrY=drY;break; case 8: newDrW = coords.x - drX;newDrH = newDrW / stdAspect;newDrY=drY;break; } else switch(activeRect){ case 0: newDrX = coords.x - moveCX; newDrY = coords.y - moveCY;newDrH = drH; newDrW = drW;break; case 1: newDrH = drH + drY - coords.y;newDrY = coords.y;newDrW = drW + drX-coords.x;newDrX = coords.x;break; case 2: newDrH = drH + drY - coords.y;newDrY = coords.y;break; case 3: newDrH = drH + drY - coords.y;newDrY = coords.y;newDrW = coords.x - drX;break; case 4: newDrW = drW + drX - coords.x;newDrX = coords.x; break; case 5: newDrW = coords.x - drX;break; case 6: newDrW = drW + drX - coords.x;newDrX = coords.x;newDrH = coords.y - drY;break; case 7: newDrH = coords.y - drY;break; case 8: newDrW = coords.x - drX;newDrH = coords.y - drY;break; } if((newDrH>50)&&(newDrW>50)&&(newDrX>imgX)&&(newDrX+newDrW<imgX+imgW)&&(newDrY>=imgY)&&(newDrY+newDrH<=imgY+imgH)){ drY = newDrY; drH = newDrH; drX = newDrX; drW = newDrW; drawDashRect(newDrX, newDrY, newDrW, newDrH); } } }); $("#cropcanvas").mousedown(function(event){ if(event.which===3) return; coords = cCanvas.relMouseCoords(event); downCX = coords.x; downCY = coords.y; mcDown = true; if(activeRect > -1){ moveCX = coords.x - drX; moveCY = coords.y -drY; // moveCX = coords.x - rects[activeRect-1].xStart; // moveCY = coords.y - rects[activeRect-1].yStart; } }); $("#cropcanvas").mouseout(function(event){ mcDown = false; document.getElementById("cropcanvas").style.cursor = 'default'; }); $("#cropcanvas").mouseup(function(event){ coords = cCanvas.relMouseCoords(event); mcDown = false; document.getElementById("cropcanvas").style.cursor = 'default'; }); //(x, y, w, h) function drawDashRect(){ cx.beginPath(); cx.strokeStyle = backLineCol; cx.fillStyle = bgCol; cx.lineWidth = 1.5; cx.rect(0, 0, cWidth, cHeight); cx.stroke(); cx.fill(); cx.save(); cx.beginPath(); cx.strokeStyle = "#000000"; if ( cx.setLineDash !== undefined ) cx.setLineDash([4,4]); cx.lineWidth = 1.5; cx.moveTo(cWidth / 2, 0); cx.lineTo(cWidth / 2, cHeight); cx.stroke(); cx.restore(); if((imgOriginal.height>imgOriginal.width)||(imgOriginal.height>cHeight)){ imgH = cHeight; imgW = imgOriginal.width * (imgH / imgOriginal.height); imgY = (cHeight - imgH) / 2; imgX = (cWidth / 2 - imgW) / 2; if(drX<imgX)drX = imgX; if(drY<imgY)drY = imgY; if(drW>imgW){drW = imgW; drH= imgW / stdAspect;} if(drH>imgH)drH = imgH; if(drY+drH>cHeight)drY=(cHeight-drH)/2; } else { imgW = cWidth / 2; imgH = imgOriginal.height * (imgW / imgOriginal.width); imgY = (cHeight - imgH) /2; imgX = 0; if(drX<imgX)drX = imgX; if(drY<imgY)drY = imgY; if(drW>imgW){drW = imgW; drH= imgW / stdAspect;} if(drH>imgH)drH = imgH; if(drY+drH>cHeight)drY=(cHeight-drH)/2; } cx.drawImage(imgOriginal, imgX, imgY , imgW, imgH); cx.save(); cx.beginPath(); cx.strokeStyle = lineCol; if ( cx.setLineDash !== undefined ) cx.setLineDash([4,4]); cx.lineWidth = 1.5; cx.rect(drX, drY, drW, drH); cx.stroke(); cx.restore(); rects = []; rects.push({id: 1, xStart: drX - bw/2, yStart: drY - bw/2, xWidth: bw, yHeight: bw}); rects.push({id: 2, xStart: drX + drW/2 - bw/2, yStart: drY- bw/2, xWidth: bw, yHeight: bw}); rects.push({id: 3, xStart: drX + drW - bw/2, yStart: drY - bw/2, xWidth: bw, yHeight: bw}); rects.push({id: 4, xStart: drX - bw/2, yStart: drY + drH/2 - bw/2, xWidth: bw, yHeight: bw}); rects.push({id: 5, xStart: drX + drW - bw/2, yStart: drY + drH/2 - bw/2, xWidth: bw, yHeight: bw}); rects.push({id: 6, xStart: drX - bw/2, yStart: drY + drH - bw/2, xWidth: bw, yHeight: bw}); rects.push({id: 7, xStart: drX + drW/2 - bw/2, yStart: drY + drH - bw/2, xWidth: bw, yHeight: bw}); rects.push({id: 8, xStart: drX + drW - bw/2, yStart: drY + drH - bw/2, xWidth: bw, yHeight: bw}); cx.beginPath(); cx.fillStyle = boxCol; cx.strokeStyle = boxCol; cx.lineWidth = 1.5; for(i=0;i<rects.length;i++){ cx.rect(rects[i].xStart, rects[i].yStart, rects[i].xWidth, rects[i].yHeight) } if(rFill)cx.fill();else cx.stroke(); //draw resulting img if(imgOriginal.height>imgOriginal.width){ cx.drawImage(imgOriginal, 1/(cHeight / imgOriginal.height) * (drX - imgX), 1/(cHeight / imgOriginal.height) * drY, 1/(cHeight / imgOriginal.height) * drW , 1/(cHeight / imgOriginal.height) * drH, cWidth / 2 + cWidth / 4 - resImgW / 2, cHeight / 2 - resImgH / 2 , resImgW, resImgH ); } else { cx.drawImage(imgOriginal, 1/(cWidth / 2 / imgOriginal.width) * drX, 1/(cWidth / 2 / imgOriginal.width) * (drY - imgY), 1/(cWidth / 2 / imgOriginal.width) * drW , 1/(cWidth / 2 / imgOriginal.width) * drH, cWidth / 2 + cWidth / 4 - resImgW / 2, cHeight / 2 - resImgH / 2 , resImgW, resImgH ); } cx.beginPath(); cx.strokeStyle = borderCol; cx.lineWidth = 2.5; cx.rect(cWidth / 2 + cWidth / 4 - resImgW / 2, cHeight / 2 - resImgH / 2 , resImgW, resImgH ); cx.stroke(); } imgOriginal.onload = function () { resizeCropCanvas(); }; window.addEventListener('resize', resizeCropCanvas, false); function resizeCropCanvas() { cCanvas.width = window.innerWidth; cCanvas.height = window.innerHeight; drX = 50; drY = 65; drW = 480; drH = 270; newDrX = drX; newDrY = drY; newDrW = drW; newDrH = drH; drawDashRect(); } imgOriginal.src = "/images/upload.png"; //resizeCanvas(); function getCropData(){ if(imgOriginal.height>imgOriginal.width) ajaxRequest(CropForm.cropFrame, ['cropData'], { x: 1/(cHeight / imgOriginal.height) * (drX - imgX), y: 1/(cHeight / imgOriginal.height) * drY, w: 1/(cHeight / imgOriginal.height) * drW , h: 1/(cHeight / imgOriginal.height) * drH }); } else ajaxRequest(CropForm.cropFrame, ['cropData'], { x: 1/(cWidth / 2 / imgOriginal.width) * drX, y: 1/(cWidth / 2 / imgOriginal.width) * (drY - imgY), w: 1/(cWidth / 2 / imgOriginal.width) * drW , h: 1/(cWidth / 2 / imgOriginal.width) * drH }); } } </script>
  2. As far as I know, regarding GPL, it does *not* require you to GPL-license any software you rent or sell, that merely connects to GPL licensed software, like the MySQL Community Server. However, if you modify MySQL and sell it, then you have to include the source code, if operating under GPL. But luckily, I am not in the business of selling database software, only applications that connect to the db, so I can then use the MySQL community edition freely. Think about it: if GPL would demand that the moment you have a single piece of GPL software in your stack, that ALL the rest of the software must then be open source, licenced under GPL, that would be a very strict and limiting scenario, right? That was clearly not the intention of GPL. The restrictions are there to prevent you from monetizing software that is given you for free. So if you are selling database software, GPL would restrict you. But I assume none of us are in the business of selling database software per se, but only applications that rely on database software. And we never even modify that database software. Who's got time for that? However, if I did modify the MySQL engine, I may have had to open source that particular code if using the Community Edition, but not my Unigui applications. If I did not want to open source my mod's, I'd have to get the Commercial Edition, especially if I wanted to sell that modified db engine as a required part of my software stack. Study the GPL terms closely, and e.g. read: When are you required to have a MySQL commercial license?
  3. The main form loads the deskscript.html file on load, and it is in this file that you manipulate the desktop apparance, including the icons, in javascript. Study that file. You can just add some javascript which defines another icon, to this file, and reload it. First of course store the icon, so you can reference it. You could have a bunch of icons already stored which the user may choose from. Then push the chosen icon into the icons array, with the correct x position. To get that x pos, read the last icon in the array, since the xpos is not a global var. You can just create an addIcon function, to do this job...and then run this function through an AddJS call, referencing the icon you want.
  4. MySQL comes in two versions, one community server which is completely free, as far as I know, and one paid version. Each customer has its own DLL, in a separate directory, and in that folder there is a text file telling the DLL which db to load. The text file is loaded by both the servermodule and the mainmodule. The alias defined in the Apache httpd.conf loads the dll in each directory. The VPS and db is backed up hourly by Idera Backup running a client instance on the VPS. In addition there is a full db replication going to a local machine at one of the clients' office, as mentioned earlier. During 9 months now, I've only had one issue where the VPS froze, only the db worked, but after a restart all was ok.
  5. I can tell you what I do, with my online appointment scheduling/invoicing app. To keep the costs down, I run several clients on a single VPS, but if they want to be separate, they can, but at higher cost. On a VPS with several clients, I run a single MySQL db instance, with several db's - one for each client. Backup is easy as I can backup the whole MySQL instance at once, and same with replication to a local db server at the client location. Setting up a new client takes me 5 minutes for the clean db, 5 minutes for file copy, 2 minutes for apache httpd.conf editing and 30 mins for app basic setup like company info, daytime schedule etc. All apps on a single VPS run on a single domain with different aliases, but the client can also get his own domain mapped to that first domain/alias. On a single VPS I can run maybe 20 clients with enough RAM. Each client is a small business with up to 5 concurrent internal users and up to around 20-30 online customer concurrent users, but then they use a smaller app not taking up so much RAM. I used Oracle earlier, and it was great, but the last 10 years I have used MySQL, and it is extremely stable, never ever had a db issue, and very simple to use. And free of course.
  6. +gustotc I am not sure what you are trying to do, please explain. For those who cannot download here, I've uploaded it to http://cashlessnews.com/webdesktop.zip
  7. Well, there was a time when I really wanted documentation - I can easily admit that. When I started using Unigui and looked at the examples, and found not a single piece of code that did anything, I was really scratching my head, wondering what was happening. At that time I thought to myself, "How come Farshad could not write just a single line to tell where the magic was happening?" Of course the code was there, buried within the Ext events for example....because the example was definitely working. But I did not have to search a lot to find this - after all there is not an unlimited number of places to search ! My point is that if you then spend 5 minutes searching and swearing, and eventually find the code, you will not easily forget how this was done. I would not really call this a steep learning curve. Tell me which other web dev system you can learn in a couple of weeks, a few hours each day, and which is so easy to master once you get the hang of it. Bottom line is that the need for documentation when using Unigui is not even close to the need of other systems, and that is why - that is why - Unigui has gained such popularity even with practically no documentation. Beat that! Of course the forum has been critical in this process, and if I should choose, I would go for the forum instead of the doc's, because you get the social support of seeing many others using it, and that is sweet.
  8. This is how I assume things work: When you initiate the app, an instance of mainmodule is created, and a unique session constant is created and associated with that instance, and this constant is also stored in the browser. As you go on using the instance, a check is performed for every request, comparing the browser stored constant with the mainmodule constant, and as long as these match, the session is considered alive. Also, a session timeout timer is running at the servermodule, and if this gets triggered, the session constant is cleared, effectively blocking any further requests from the browser, and the servermodule then reports the timeout and offers a reload to the browser. After using Unigui for a while, I do not really see such a great need for documentation. I know it sounds weird, but it is almost a good thing that you have to work a bit in the beginning, having a somewhat steep learning curve, because you then learn the stuff in a practical way, and that sticks.
  9. I use Apache 2.2, because I was not able to make IIS work, because I loaded images directly from the JS, and IIS did not find them....however I think I have a solution for that. Anyway Apache is working fine, the only thing I have to do, is restart the apache service each night, because it was not releasing memory.....I just made a restart batch file, did not look more into the issue. Sometimes one wishes for unlimited time to research all issues, but if I can make it work ok, somehow, that's pretty much ok with me. I suspect that with IIS one gets more control over resources....but I may be wrong. Apache is a bit easier to install and set up, than IIS, in my opinion. just copy some files and install the service manually, very simple... Also very easy to combine with serving PHP at the same time, and quick and easy to modify httpd.conf with aliases and redirects etc. I've always loved Apache... But of course, setting up IIS is pretty easy too when you've done it a couple of times...
  10. A JS clock I made as part of my webdesktop example at http://forums.unigui.com/index.php?/topic/5642-another-desktop-example/ It is based on an image background, which you can of course scale up/down as you like: analog clock.zip
  11. I guess you've got to see this from the bot's perspective. To do that, imagine that you make a bot, and think about how to do it practically... You use a http client, get the base URL, in return you get an html file, and you then parse that for links. Some links are images, and you download them, and some links are new pages, and you load them, and traverse the whole thing in up to so many levels as you like. The problem with a Unigui DLL is that there are no individual URLs for the various pages, by default, as far as I know. So you cannot access various parts of the site on demand, but you have to go through a keyhole so to speak, and then only by user interface manupulation can you trigger page changes. You can build something that does that, using IE as a COM object and remote control it...but that is not the way the google bots work - they depend upon the site being accessible at the individual page level. Now, if we can match each form with individual URLs, and make the DLL load each form when invoking each specific URL, then the bots may be able to traverse the site and rank it accordingly. Alternatively, if you can direct the bots to an XML document which contains the whole site structure and content in text form, with image links etc, then that may work too. I have not thought much about this, so its hard to say what's the best strategy etc.
  12. For websites, it is a problem that the bots cannot traverse the site structure because of the application layer. I made a clone of RT.com frontpage, top part of it, with the responsive feature, just to test how it would be to make a graphic dynamic site, and of course it worked fine. But it wont be understood well by the search engines..... Apart from that, it seems you can make anything. If it is possible to direct the bots to some text document with all the data that you want to be official, with image links etc, then maybe you could end up with something acceptable for websites & ranking.
  13. Hi Peter, sure - just PM me and I will see what I can do
  14. Hi Peter, You are asking a very good question. I have developed a scheduler system based on MySQL, and it has been running for 10 years, and this year I ported it to Unigui. The thing is that you have to work with two, if not three different date/time systems: 1. The pascal format 2. The database format, in my case MySQL 3. In my case also the Javascript format *Of course* these are all quite different, and what got me pulling whatever little hair I had left, was the fact that JS has issues with summertime correction, making it virtually impossible to use JS absolute datetime format for historical dates without having a database of offsets, whereas using relative JS datetime is perfectly ok. I had to use JS time format because the calendar component did not allow x columns for a single day, only a single column, so I had to write my own calendar in pure JS. I think this issue should be resolved first: will the built in calendar component really fulfill your needs? For instance I needed various state symbols, and could not figure out how to embed that in that calendar. But in the previous version, without JS, I remember that I had issues with interpreting time, and somehow ended up with storing time as a 5 character string, and date as MySQL "Date". I do not remember the problems on the top of my head, but I had to avoid both Datetime and Timestamp, to make things work the way I wanted.
  15. Ron

    Push Message

    Only way would be websockets then, as far as I can tell... I am going to try socket.io and the various JS websocket libraries until I find a way, as my customer is willing to pay a lot just for me TRYING to make that work, even if I end up with no solution...clearly desperate to get phone caller number showing up in client within 5 seconds after phone central resolves it, so I've set up a REST server using apache to catch the phone central's HTTP GET and then it's going to be interesting to see if Unigui can work with some websocket library...will post my results in some weeks.
  16. Davie - you are right about the lacking documentation. However, this is not unusual when it comes to startup frameworks like this, because of limited resources, continual development/debugging etc. As the product matures and the user base expands, documentation typically follows - often made by power users themselves. Surely, the demos could have been documented, and not much would be needed - just a couple of lines to indicate where the critical sections are. Because this is a type of framework where you obviously can do a lot of smart things with very little code. Only problem is that there is so little code that you can barely find it. I too struggled a bit with this in the start. As you get to know the framework, you realize that - of course - there is a limited number of "smart places" to insert code or otherwise "smart things" to do. In the beginning most things may look confusing. But the confusion itself is only the sure sign of impending insight, patiently waiting around the corner. Everybody agrees that we need more documentation, but everybody is also so occupied making this framework produce some cash, so who's got the time? One thing is the step into the client-server paradigm, another is the Unigui specific ways of solving things. I think of linear, desktop programming as a monologue: you always have the floor, and you always know what's coming next, because you and only you are in control. This is of course not entirely correct because nowadays its all event-driven, but at least you have a pretty linear execution flow, like you mentioned. Client-server programming - on the other hand - is more like a dialogue. You don't know all the steps ahead, and each of the parties involved needs to have their say. You build the road as you go, and who knows what's coming next? Of course a dialogue is a lot more complex than a monologue, just as relationships are more complex than being alone. But as often: with added complexities comes increased opportunities. Knowing our typical issues with relationships - as human beings - it may be a good thing to work within the client-server paradigm, as that may even enhance our relational skills. Any system insight is available as a resource within another field of our existence. Regarding Unigui-specific solutions there is a documentation project going on, however it would of course be a luxurious thing to have one single person dedicated to this full time, although that is what is really needed now.
  17. As requested, a simple project showing some canvas drawing with auto layout, in relation to calendar systems. The JS itself is straightforward in these cases, as you do the calculations, store the rects and then just repond to events. Of course drag and drop makes things quite a bit more complex. Notice that the javascript is loaded into a stringlist in unimainmodule. This way it gets loaded on app reload, so you can edit the JS in your favorite editor and just hit F5 on the browser to see the changes as the unigui app reloads. No new compilation necessary, unless you of course work with the server ajax responses. Notice also the onresize event in ExtClientEvents, to trigger the canvas update. Another thing with loading the JS this way, is that you can add stuff before you send it to the htmlframe, like variables etc., and at the end tuck on the </script> statement. Notice that all JS loads into the same namespace, so use different variable names to avoid creating funny little bugs. Kaj unigui canvas test.zip
  18. //Hi Davie - I've not tested this but I hope you get the idea... //you may have to store the variables in mainform or unimainmodule Procedure GetProperAge(Var Age:Integer); Var IRA:Boolean; IRA_LotsOfMoney:Boolean; IAmStupid:Boolean; Begin Age:=ReadAge; IAmStupid:=False; IRA_LotsOfMoney:=False; If age>70 then begin MessageDlg('Are you taking money from IRA?', mtConfirmation, mbYesNo, procedure(Sender: TComponent; Res: Integer) begin case res of mrYes: begin IRA:=True; MessageDlg('Are you taking money from IRA?', mtConfirmation, mbYesNo, procedure(Sender: TComponent; Res: Integer) begin if res=mrYes then IRA_LotsOfMoney:=True If IRA_LotsOfMoney Then DoOtherLogic //If IAmStupid Then DoSomeStupidLogic - never needed in this branch // Now save the data SaveMySettings(IRA_LotsOfMoney,IAmStupid); end;); //second message dlg - first branch end; //case 1 mrNo: begin IRA:=False; MessageDlg('Are you stupid?', mtConfirmation, mbYesNo, procedure(Sender: TComponent; Res: Integer) begin if res=mrYes then IAmStupid:=True; If IAmStupid Then DoSomeStupidLogic //If IRA_LotsOfMoney Then DoOtherLogic - not needed in this branch // Now save the data SaveMySettings(IRA_LotsOfMoney,IAmStupid); end;); //second message dlg - second branch end; //case 2 end); //first message dlg end; //if age... SaveMySettings(false, false); //if you are younger. end; // My function that ends up calling the GetProperAge procedure Procedure SomeFunction; Var Age:Integer; Begin ... GetProperAge(Age); ... //more logic <--- this must be moved into the branches to make sure they get executed after the other stuff //if this process depends on the results of the other stuff ... End;
  19. Full picture...well, I'm tempted say that programming itself involves a bunch of mental gyrations, and as you probably know, you never really get the full picture from any piece of abstract code...and that's why this suits some nerds like us and also why they pay us well - to think and try and create some order in this mess... As Henry Ford said, "Thinking is hard work - that's why so few do it." But you could probably do this with nested dialogs - you have this basic construct: MessageDlg('Dialog1', mtConfirmation, mbYesNo, procedure(Sender: TComponent; Res: Integer) begin answer1:=res; //next end); Then try this: MessageDlg('Dialog1', mtConfirmation, mbYesNo, procedure(Sender: TComponent; Res: Integer) begin uniMainModule.a1:=res; MessageDlg('Dialog2', mtConfirmation, mbYesNo, procedure(Sender: TComponent; Res: Integer) begin uniMainModule.a2:=res; MessageDlg('Dialog3', mtConfirmation, mbYesNo, procedure(Sender: TComponent; Res: Integer) begin uniMainModule.a3:=res; MessageDlg('Dialog4', mtConfirmation, mbYesNo, procedure(Sender: TComponent; Res: Integer) begin StoreResults(uniMainModule.a1, uniMainModule.a2, uniMainModule.a3, res); end;); end;); end;); end;); If that works, you may have your full picture
  20. OK, so you want to use one datamodule unit within two different projects, basically...without altering anything...can't you use some compiler directives to just alter the classname of the datamodule, depending on which project is compiled?
  21. Hi Davie, Lets say you have a wizard kind of thing and needs to ask a number of questions, like this in linear fashion with blocking calls: .. MessageDlg('Question 1.... MessageDlg('Question 2.... MessageDlg('Question 3.... MessageDlg('Question 4.... StoreResults ...in the client-server non-blocking world you instead get this structure: procedure StartProcess MessageDlg('Question 1....callBack1); Procedure CallBack1(res) unimainModule.answer1:=res; MessageDlg('Question 2....callBack2); Procedure CallBack2(res) unimainModule.answer2:=res; MessageDlg('Question 3....callBack3); Procedure CallBack3(res) unimainModule.answer3:=res; MessageDlg('Question 4....callBack4); Procedure CallBack4(res) StoreResults(unimainModule.answer1, unimainModule.answer2, unimainModule.answer3, res) So you store the results along the way and then trigger new questions or branch out in a more decision tree-like structure if you like. /Kaj
  22. You could create a canvas in javascript, in an htmlframe, and catch the events directly from the client, sending them with shiftstate info as an ajaxrequest to that htmlframe.
  23. Hi Davie, When I converted a Delphi app to web, using Unigui, I just moved all my data access components from the TDatamodule to the unigui Datamodule. Copy and paste...same with the code. Why do you need to re-use the Delphi version of the TDatamodule ? Kaj
  24. Hello, here is another desktop example using more javascript, and the idea was to get some transparency in the taskbar. I borrowed the code for the menu, from the other desktop sample in this forum. Best viewed in full HD, full screen (F11). Updated: some JS correction, added analog clock as part of datetime dialog etc. The code for autostart of browser is in the servermodule, triggered at onCreate. For those who cannot download here, I've uploaded it to http://cashlessnews.com/webdesktop.zip webdesktop.zip
  25. Hi, I agree that it is smart to check out the demos. Some times it may not be obvious how the demo is working, but by searching (also in ExtEvents property) you will eventually understand what happens. I myself could get a little frustrated due to lack of information on the various demo issues, but this only makes you search and get to know the various details of the framework faster, I suspect. It is a paradigm shift to go to client-server processing, if you have not been there before in some respects. Of course it helps to know about internet technology in general, and Javascript, HTML, CSS, JSON etc. I do not see much point in learning PHP really, but of course it's "nice" to know the basics of anything in the field. You can do a lot with Unigui without knowing much Javascript, and I suggest starting there first, and then when you feel comfortable, start experimenting with JS and ExtEvents. Like with all tools, there is a learning curve, but compared to lots of other framworks, I assume Unigui should not be too hard for most people. As you get the hang of it, you will discover that you can create webapps faster than you ever thought was physically possible....and then the fun starts Another tip: if you get stuck on a single issue, try to move on to another, and rather get back to it later. Don't worry, as almost anything can be solved, usually in a pretty simple way somehow.
×
×
  • Create New...