BLAISE PASCAL MAGAZINE ALL ABOUT AND DELPHI PRISM(.Net) , & PASCAL AND RELATED LANGUAGES Pascal8

Delphi 2010 – what a feeling! - Bob Swart page 7 Gestures could be the new ’must’ in our computers future Counters - David Dirkse page 11 Learning counting again, - could wel be a hobby... Virus in Delphi? - Nick Hodges page 14 Nick explains how to get rid of the virus and block it. Dezign for databases - Marco Roessen page 16 A fantastic alternative for its expensive competitors, and it’s even cheaper. Customizing the T-Field data display - Henk Schreij page 18 Diving deeper into the possibility’s Using and Lazarus to create applications for OSX - Jeremy North page 20 Working on the Mac is hot Writing Delphi Components II: Custom Properties and Windows Controls - Marco Cantù page 22 In the new Delphi versions it looks all different. My Top Five Delphi 2010 New Features - Pawel Glowacki page 24 Except for guestures ther is a lot of news... Fast Graphic deformation by using Scanlines - Peter Bijlsma page 28 Control your own image or blow it up! Berlusconi on the edge Wide Information Bus (Introduction) - Fikret Hasovic page 33 What is it and what the use for it? Freehand Drawing (Introduction) - David Dirkse page 36 shows how to create your own paint program

October 2009 Publisher: Foundation for Supporting the Pascal in collaboration with the Dutch Pascal User Group (Pascal Gebruikers Groep) © Stichting Ondersteuning Programeertaal Pascal Cover price Europe: € 10.00 / UK £ 10.00 / US $ 10.00 BLAISE PASCAL MAGAZINE 8 ALL ABOUT DELPHI AND DELPHI PRISM(.Net) ,LAZARUS & PASCAL AND RELATED LANGUAGES

CONTENTS Volume 8, ISSN 1876-0589 Editor in chief Articles Detlef . Overbeek, Netherlands Delphi 2010 – what a feeling! - Bob Swart page 7 Tel.: +31 (0)30 68.76.981 / Mobile: +31 (0)6 21.23.62.68 Gestures could be the new ’must’ in our computers future News and Press Releases Counters - David Dirkse page 11 email only to [email protected] Learning counting again, - could wel be a hobby... Authors Virus in Delphi? - Nick Hodges page 14 B Peter Bijlsma, Nick explains how to get rid of the virus and block it. Marco Cantù, Dezign for databases - Marco Roessen page 16 D David Dirkse, Frans Doove, A fantastic alternative for its expensive competitors, and it’s even cheaper. G Primož Gabrijel!i!, N Jeremy North, Customizing the T-Field data display - Henk Schreij O Tim Opsteeg, page 18 P Herman Peeren, Diving deeper into the possibility’s S Henk Schreij, Rik Smit, Bob Swart, V Hallvard VassBotn. Using Free Pascal and Lazarus to Editors create applications for OSX - Jeremy North page 20 Rob van den Bogert, W. (Wim) van Ingen Schenau, Working on the Mac is hot M.J. (Marco) Roessen. Writing Delphi Components II: Custom Properties Corrector and Windows Controls - Marco Cantù page 22 A.W. (Bert) Jonker, M. L. E. J.M. (Miguel) van de Laar Translations In the new Delphi versions it looks all different. M. L. E. J.M. (Miguel) van de Laar, My Top Five Delphi 2010 Kenneth Cox (Official Translator) New Features - Pawel Glowacki page 24 Except for guestures ther is a lot of news... Copyright See the notice at the bottom of this page. Trademarks All trademarks used are acknowledged as Fast Graphic deformation by using Scanlines the property of their respective owners. - Peter Bijlsma page 28 Caveat Whilst we endeavour to ensure that what is Control your own image or blow it up! Berlusconi on the edge published in the magazine is correct, we cannot accept responsibility for any errors or omissions. If you notice Wide Information Bus (Introduction) something which may be incorrect, please contact the Editor - Fikret Hasovic page 33 and we will publish a correction where relevant. What is it and what the use for it? Freehand Drawing (Introduction) Subscriptions (prices have changed) - David Dirkse page 36 1: Printed version: subscription € 50.-- (including code, programs and printed magazine, 4 issues shows how to create your own paint program per year including postage. 2: Non printed subscription € 30.-- (including code, programs and download magazine) = Code Downloadable in the pdf file: click and you go straight Subscriptions can be taken out online at to the download link www.blaisepascal.eu or by written order, or by sending an email to [email protected] Subscriptions can start at any date. All issues published in the year of the subscription will be sent as well. Cover price in Europe: € 12.50 / UK £ 12.00 / US $ 18.00 plus postage. Columns Subscriptions are parallel to the calender Foreword, page 4 year. Subscriptions will not be prolonged without notice. Books - Frans Doove Receipt of payment will be sent by email. Invoices will be View at the new Windows 7 page 5 sent with the March issue. Subscription can be paid by sending the payment to: DELPHI CONTEST is prolongued until november ABN AMRO Bank Account no. 44 19 60 863 or by credit card: Paypal or TakeTwo Advertisers Foundation for Supporting the Pascal Programming Language (Stichting Ondersteuning Programeertaal Pascal) Advantage Database Server page 3 IBAN: NL82 ABNA 0441960863 Components for Developers page 40 BIC ABNANL2A VAT no.: 81 42 54 147 Datanamic page 6 (Stichting Programmeertaal Pascal) Fastreport for VCL page 38 Subscription department Fastreport for .Net page 39 Edelstenenbaan 21 3402 XA IJsselstein, The Netherlands RT science page 15 Tel.: + 31 (0) 30 68.76.981/Mobile: + 31 (0) 6 21.23.62.68 [email protected] Copyright notice All material published in Blaise Pascal is copyright © SOPP Stichting Ondersteuning Programeertaal Pascal unless otherwise noted and may not be copied, distributed or republished without written permission. Authors agree that code associated with their articles will be made available to subscribers after publication by placing it on the website of the PGG for download, and that articles and code will be placed on distributable data storage media. Use of program listings by subscribers for research and study purposes is allowed, but not for commercial purposes. Commercial use of program listings and code is prohibited without the written permission of the author.

Page 2 / 2116 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4

Foreword by Detlef Overbeek Editor The summer holidays are over and we all are back to However, one thing is true: business. For us as editors, things were a bit different. Due Write once, Run anywhere. to all the extra work with the special issue and publishing That's what “we” are missing badly. Espacially for the the first Portuguese edition, we had to abandon our holiday Mac. We need the future and the future is twofold: plans. multi O.S. and Internet.

Now we have reached issue eight, with some very Second, interesting articles about the new Delphi 2010 – which I it's nearly impossible for beginners to get acquainted with think is the best yet – and a nice article about how to Delphi. There's the 30-day trial version, but you can't morph your own portrait. Just for fun, we did this with a learn Delphi in 30 days. This is not only bad; it's short- picture of Berlusconi, an interesting politician whom sighted. claims to be the ultimate defender of freedom. But the coding is also very interesting. I can easily imagine that Codegear is very busy creating the generation - which is why we would like to With Delphi 2010, we all hoped there would be the first suggest to Embarcadero: if you don’t have the time or cross compiler for and Mac. man power to produce a special version, please offer Too bad. international user groups - with registered members – It didn't work out that way. to purchase an educational license. We still have to wait. Nothing needs to be changed, perhaps there could be There are some major improvements: The help file is better some sort of splash screen: 'Licensed exclusively for non- than ever: easy and quickly accessible, more items, more commercial use'. specific about Delphi and one thing I do love particularly is Leave it up to the user groups to determine which of their the tagged bar with the components - classic, but members are eligible for this version. With this, we would very effective. be in a position to convince people of the enormous Great. quality of Delphi. The total program is much faster and more stable. It’s very much faster to install, it was quite annoying with It is nonsense to think that people can't get their hands on 2009. But… a pirated copy: the internet is huge. You should trust people. Most of them don't want a Now some things that aren't so good. For Delphi to be pirated copy; they use it in their work or their hobby, attractive to a very large group of , two major and they want their own, legal copy – but at an acceptable changes are necessary. price. People who use it professionally should pay the commercial price, but students (of Delphi), hobbyists and First, a cross compiler must be available as soon as starters should be able to have ready access to a less possible. Very soon. expensive version.

To illustrate my point: in order to better object We need the starters and beginners. oriented aspects of programming I took a course on at the University of Amsterdam. Besides learning a lot and Two years ago, when Embarcadero took over Codegear, obtaining insight into many issues, I soon realized how it was promised to me personally. much we are pampered with our Delphi IDE. I was very enthusiastic. But now, going into the third year, there is still nothing Java still does not have anything comparable to RAD. Java available. I regard this as unacceptable. is a beautiful language, but it cannot compete with Delphi (Pascal) : it's not fast, , coding is labour-intensive, I sincerely hope that this problem can be resolved quickly. its graphic support is not very sophisticated and what sometimes is forgotten, at low level the Java compiler is Detlef Overbeek, almost never competitive in terms of speed and there for it is almost impossible to run technical applications at low e-mail: [email protected] (engine) level. Skype Detlef.Overbeek + 31 (0)30 6876981 But it runs on a lot of Platforms. mobiel + 31 (0)6 21.23.62.68 - which is nice until you discover that under Linux the environment moves at a snail's pace.

Page 4 / 2118 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Book reviews by Frans Doove

Paul McFedries: Here it is evident that the author has the reader in mind; he 7 Unleashed writes for both IT professionals and home users of the software. Part 1 (Chapters 1–5) lets the user get acquainted with this 2010, Pearson Education version of Windows and become familiar with it. ISBN 13: 978–0–6723–3069–8 Part 2 discusses the maintenance of the Windows 7 system. ISBN 10: 0–672–33069–5 Part 3 discusses relatively advanced topics. Part 4 discusses security aspects, English; paperbound, 791 (including table of contents). Part 5 addresses problem solving, Recommended price: € 40. Part 6 deals with networking, and Part 7 discusses scripting.

My opinion of this book is very positive. It has many extensive and clearly worded explanations, as well as many code examples and overviews. Readers have the option of registering the book. When a definitive version of Windows 7 is released, registered readers will receive an updated version of the book free of charge, along with all the examples and code in the book. As far as I can determine, at the time of writing of this review this is the only book on Windows 7 that is actually available in English or Dutch, although dozens of books on Windows 7 (in English) have been announced.

After getting acquainted with a sizeable new book, I often arrive at the conclusion that the there is a direct relationship between the size of the book and the degree of difficulty of the software forming the subject of the book (and I also had this fear with the present book). This conclusion arose from my experience with comparable books on Windows Vista. I must admit that I was not previously acquainted with any books by this author, but it turns out that he has written a large number of books on similar subjects.

As a native Dutch speaker, I found the title somewhat puzzling at first. According to my English–Dutch dictionary, 'unleashed' has several possible meanings, and the examples include a flood of words and venting your rage. My impression is that the author did William . Stanek: not have the latter intention in mind, but instead aimed to write an Windows 7 Administrator's Pocket Consultant introduction to a new, complex and extensive bit of software that can do a lot of things and hopefully will cause fewer problems 2010, Microsoft Press, than its predecessor. ISBN 978– 0–7356– 600–7, English, paperbound, 680 pages. The first thing that struck me about this book was its extensive Recommended price: € 30. table of contents. First there is a high-level overview on two pages divided into seven sections, followed by a full table of contents of This book has an introduction and seventeen chapters. Each the 31 chapters that extends over fourteen pages and is in turn chapter consists of roughly 40 pages, which is a consequence of followed by a seven-page introduction. the systematic approach. The principal target group of the author is not individual users of I consider such an extensive table of contents extremely important Windows 7, but instead system administrators. The author as an introduction and an aid to studying the book, and especially further differentiates this group into administrators who already useful to obtain an overview of the topics addressed by the book work with Windows, users with a certain amount of and thereby the capabilities of the software it describes. Naturally, responsibility for computer administration, and administrators it is difficult to master a subject discussed in a book totalling who migrate to Windows 7 from an earlier version of Windows nearly 800 pages, and the table of contents is an essential aid in or from an entirely different system. this regard. This book is actually an extensive user's guide to Windows 7. My However, I think that individual users can also use this book to impression is that the author does not assume that readers are fully considerable benefit, although the book devotes more attention familiar with the previous version of Windows, but instead aims to the everyday activities of system administrators than to the the book at all users. specific aspects of Windows 7. These aspects are actually The book consists of 31 chapters and two appendices, grouped embedded in the text, but I fear that this makes the book more into in seven sections. The sixteen-page table of contents gives an difficult for individual users, despite the fact that the text has an overview of the topics discussed in the book open and accessible style.

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 5 / 2119 DEVELOPERS 4 Book reviews (continuation)

The book begins with an extensive table of contents for the Chapter 3 deals with major topics such as user policies and seventeen chapters, grouped into sections. It occupies seventeen computer policies, which are the rules that govern the users and pages. I always find an extensive and readily comprehensible the computer for activities such as using a network. table of contents a very positive feature, not only because it Chapter 4 is dedicated to automation of the Windows 7 gives the reader a quick overview of the book and makes it configuration. easier to find everything, but also because it helps the reader Chapter 5 discusses the administration of user access and grasp the subject matter. I regard this as extremely important security. Chapter 6 deals with configuring computers under from a learning perspective. Windows 7. Chapter 7 discusses the configuration of Windows 7 features and options, which differ from those of previous The following capsule description of the contents is intended to Windows versions. Chapter 8 discusses the operation of the give an idea of how the author presents the topics. hardware devices (options) and drivers. Chapter 9 deals with Chapter 1 provides an introduction to Windows 7, including program installation and maintenance. installation and architecture. Chapter 2 discusses working with Windows PE (the replacement for MS DOS) and the recovery environment (RE).

Page 6 / 2120 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Delphi 2010 – what a feeling! by Bob Swart Touch en Gestures starter expert Biolife Fields DELPHI 2010 / Win32 With the data persistent in the TClientDataSet, we can double- One of the new features of Delphi 2010 is the native support click on this component to start the Fields Editor. Right-click in for touch, gestures and multi-touch (supported by Windows 7). the Fields Editor and select “Add All Fields” to see the available Although it has always been possible to support simple touch fields from the biolife table in the Fields Editor. In order to see in Delphi applications, where the touch screen simply emulates them all (except one) on the form, we can simple drag them from a mouse (so you can touch the buttons on the screen without the Fields Editor and drop them on the form. All, except for using a keyboard or mouse), it was not yet possible to have Length_In, which I don't need (unless you don't use centimetres as Delphi (out-of-the-box) respond to special gestures or multi- your measurement type, in which case you could decide to skip the touch events. These features are now possible with the release Length (cm) field instead of course). Each of these fields will be of Delphi 2010, and hence the topic of this article. transformed into a label and data-aware control when dragged onto the form. Most fields will end up being represented by a TDBEdit In order to play along, you need a copy of Delphi 2010 (you can control, with the exception of Notes (inside a TDBMemo) and download and install the 30-day trial edition if you wish). Start Graphic (in a TDBImage). After moving the TDBImage controls Delphi 2010. In order to create a new application, I do File | around, my version of the form looks as follows: New – Other, which brings me to the Object Repository. This is the first area where we can see some changes already: a handy filter option at the top, to hide the icons and wizards that I'm not looking for. Just enter a few characters like “App” in order to filter the contents of the Object Repository down to the App- specific icons and wizards. A nice way to help me find my way without getting lost in the dozens of items.

Figure 2: Note that I'm not using a TDBNavigator control on purpose, since I want to use the touchscreen with the simple touch and gesture functionality for navigation. Touch and Action Speaking of touch: now we're getting to the interesting part of the article: the touch and gesturing support in Delphi 2010. We need to start by adding a TActionList component on the form. Figure 1: This will help to connect gestures to (standard) actions later. to start with Delphi 2010 already contains a number of pre-defined gestures, which can be connected to actions (saving a lot of work This filter is especially important now that the Object Inspector compared to writing individual event handling code), as I'll shows all icons in all catagories, even when they are not show shortly. The TActionList component does not have to be applicable at this time (for example in the ActiveX category, “filled” with (standard) actions right away, because we can do where a number of wizards cannot be used until an AxtiveX library project has been created first). The benefit is that you will that “on the fly” (when needed). However, we do need a special always see what's possible, even if it's not applicable just yet. The TGestureManager component on the form as well filter will also hide these items, although this is not visible in the (see screenshot above), and we should assign this screenshot above. TGestureManager component to the GestureManager After starting a new VCL Forms Application, we first continue by subproperty of the Form's Touch property. building a small database application. Just use a TclientDataSet in Gestures order to produce a stand-alone executable (without the need for Using the Object Inspector, we can expand the Touch property database drivers). As data contents, I'd like to show the biolife in order to view the GestureManager subproperty (assigned to table, which can be found in the biolife.xml file in the Common the TGestureManager control on the form). We also see a Files\CodeGear Shared\Data (in the future this might Gestures subproperty, with a list of standard (and later also become the Common Files\Embarcadero Shared\Data directory custom) gestures supported by Delphi 2010. The list of standard perhaps). gestures starts with Left, Right, etc. Next to each gesture in the As soon as the FileName property of the TClientDataSet Object Inspector, we see a checkbox (to indicate that the gesture component is pointing to the biolife.xml file, we can use the is “hooded” to an action or event) as well as a little drawing that Object Inspector to set the Active property of the TClientDataSet to True to show all data at design-time. By clearing the FileName depicts the gesture movement (albeit without direction, so the property while Active is set to True, the data remains visible, but horizontal line for “Left” and “right” looks the same). this time we force the data to be stored in the DFM file itself, and For each gesture we can use the Object Inspector to create a no longer outside of the application. This is a special trick that I New Action (for which we then need to implement the use every now and then, to embed the data inside the executable. OnExecute event handler), or we can select an existing standard Note that there are consequences to this approach: first of all, the action (which is then added to the TActionList component). For DFM file will become about 2 MB in size (so it takes a while to our example, let's connect the Left gesture to a Standard Action save or compile the project – especially the linking stage). from the Database category, namely TDataSetPrior (in order to Second, and sometimes worse, is the fact that since the data is move to the previous record). The screenshot on the next page embedded in the executable itself, you cannot make any changes shows the different submenus that have to be used to connect the to the data. This may often be a show stopper, unless you're TDataSetPrior action to the Left gesture. building a brochure or catalog that you don't want or need people to change anyway (like a city plan with pictures for example). For Delphi 2010 has just been released at the time of writing – see our demo, I'm assuming we do not need the biolife data to be http://www.eBob42.com and http://www.bobswart.nl for more changed by the user, so we're on our way to produce a standalone information and ordering possibilities of Delphi 2010 en RAD executable indeed. Studio 2010.

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 7 / 2121 DEVELOPERS 4 Delphi 2010 – what a feeling! (continuation 1)

Figure 3: the steps to get to the list of gestures After we've connected the Left gesture, it's just as easy to connect the Right gesture to the TDataSetNExt action, the ChevronLeft gesture to the TDataSetFirst, and the ChevronRight gesture to the TDataSetLast action. The two chevron gestures can be compared to “bigger than” and “smaller than” characters, but then drawn with your finger on the touchscreen.

Action! The only thing left to do is compile the project and run it. If you have a touch screen (like the LG L1510SF 1024x768 Flatron that I purchased for a good price) then you can move your finger over the screen to make the gesture movements required. If you do not have a touch screen, then you can still emulate this behaviour by using the mouse: click with the left mouse button and “drag” the gesture movement around the screen. It's not the same, but at least you can test your gesture movements without the need to purchase a touchscreen yourself. Either way, you can use the Left, Right, ChevronLeft and ChevronRight gestures now to navigate through the records of the biolife table without the need for a keyboard or TDBNavigator control.

Custom Gestures Apart from the built-in standard gestures, we can also create our Figuur 4: zorro is in the air? own custom gestures with Delphi 2010. This can be done with the (a famous tv-character in The Netherlands about an outlaw hero TGestureManager control: right-click on it, and select Custom who uses his sword to draw a “Z” on the chest of his Gestures. Inside the dialog that follows, you can click on the government victims) When making custom gestures, it's Create button to create a new gesture, where you need to move important to realise that the gesture must be one fluent your finger over the touch screen (or drag with the mouse) to draw movement. As a result, you cannot make an X gesture, since that the initial path of the gesture. Once the initial path is drawn, we requires two separate gestures. For the X-gesture that I created, can still make some modifications to it, to ensure it will be I had to change the sensitivity, which is set to 80% by default, to recognised correctly. As an example, let's draw the “Z” character ensure that it's easily possible to have the “Z”-gesture be (see next screenshot), and give it the name “Zorro” recognised when drawn on screen by an end user.

Page 8 / 2122 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Delphi 2010 – what a feeling! (continuation 2)

A high sensitivity requires that you redraw the blue dots After all this work, it's very fortunate that we do not have to draw exactly, and lower sensitivity extend the grey area around them the custom gestures for each new application, but we can simply (until it gets too fuzzy where you might confuse one gesture store (export to a .dgf file – Delphi Gesture File) and load or with another). We can also use the Custom Gesture dialog to import the .dgf in the TGestureManager of another application remove dots from the gesture line, add new dots, zoom in again. Once we have a custom gesture, we can work with it (i.e. and/or out, modify the coordinates and play a simulation of the respond to the recognised gesture) in two ways. First of all, we can gesture, as well as a test where you need to redraw the gesture use the OnGesture event of the form itself. In this event handler, to see if it is recognised correctly. It may take a while, but in the we get the EventInfo of type TGestureEventInfo, as well as a var end you will have a near perfect custom gesture. parameter Handled to indicate – when set to True - that we've When you click on OK, you are returned to the Custom Gesture handled this gesture. dialog of the GestureManager component where a preview of Note that we will only get inside the OnGesture event handler if the gesture shape is drawn as well as the name we've given it, we didn't make one of the standard and already connected gestures and the ID (which starts by -1 and counts further down). such as the Left, Right, ChevronLeft or ChevronRight gestures. When inside the OnGesture event handler, we can use the EventInfo.GestureID field to identify the ID of the custom gesture. In our case, that value was -1, so my event handler can be implemented as follows: procedure TForm1. FormGesture( Sender : TObject ; const EventInfo: TGestureEventInfo; var Handled : Boolean ); begin if EventInfo. GestureID = -1 then ShowMessage()'Zorro' else ShowMessage(( IntToStr EventInfo. GestureID)) end; If an unrecognised gesture is made, then the GestureID is equal to 0 (which may be an indication that you need to work on the sensitivity of your custom gestures, or explain more clearly how the users should make their gesture). We have to remember for ourselves what the ID values are of our custom gestures, of course. Fortunately, there is also another way to connect an action to the custom gesture. If you take a look at the third screenshot again, you'll see the Object Inspector with the Touch property and the Gesture subproperty. Figure 5: Zorro is listed now

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 9 / 2123 DEVELOPERS 4 Delphi 2010 – what a feeling! (continuation 2)

Right below that, the standard gestures are listed. However, as The following screenshot shows the TTouchKeyboard on my soon as we add a custom gesture, a new entry “Custom” is machine, using the US-International keyboard layout, at the shown in the Object Inspector – right above the standard bottom of the Touching Biolife form:7 Obviously, placing the gestures. virtual keyboard at the bottom of the form is not a very effective Custom contains the list of (currently only one) custom gestures way to handle input. It would be more convenient to use some that have been added to the TGestureManager. In this case, just kind of pop-up dialog that shows the virtual keyboard only when the Zorro gesture, including the image preview of the “Z”, as we needed for example. But once the virtual keyboard is shown, we saw before in the Custom Gesture dialog. can use the keys on the screen as touch buttons and click on the This means that we can now make a connection between the keys to produce the input text. And if you have no touch screen gesture and an action. In this case, I'd like to create a new action, but a mouse attached to your machine, then you can obviously select this action in the Object Inspector when done, and then still use the mouse to click on the buttons (so as a software implement the OnExecute event handler of the new action, for developer you do not need to have a touch screen to work with example as follows: the TTouchKeyboard – only when it comes to multi-touch and interactive gestures you need Windows 7 and the special procedure TForm1. Action1Execute( Sender : TObject ); begin hardware). ShowMessage('Zorro also likes to touch Delphi 2010') end; Once the gesture is connected to a custom action and its OnExecute is implemented, the Ongesture event handler of the form will no longer respond to his Zorro gesture (have a try for yourself if you wish). Running the demo project we've created so far – and which I've called Touching Biolife – does not show a GUI different from a “normal” non-touching GUI. If you take a look at the next screenshot, there's no indication (yet) we're dealing with a touch- and gesture-enabled application. The lack of a TDBNavigator may lead you to wonder how to navigate to the next record, but that's about it.

Figure 8: the virtual touchpad Deployment A final word: in order to turn the current demo application into a Figure 7: now you can try really standalone executable, we should add the MidasLib unit to Sweeping your finger over the screen from left to right (for the the uses clause of the project, so we do not need to deploy the next record) or from right to left (for the previous one) may be a MIDAS.DLL. This results in a truly standalone executable that bit strange at first, but you'll quickly get the hang of it. The effect we can place on a USB-stick for example in order to show an is of course much nicer if the form would contain a city map or application that doesn't need mouse or keyboard in order to run. street plan, where you can “move” the map around with your fingers. This can also be done with gestures, and even better with Bob Swart the so-called Multi-Touch support which can be found in Windows 7 (but which also requires special, more expensive, hardware). Using Multi-Touch and interactive gestures, the To get more information about Delphi 2010 EventInfo structure of the Ongesture event will hold field values licenses, please see my website at for the inertia (speed of the gesture), as well as the start and stop http://www.bobswart.nl/CodeGear coordinates of the gesture. Since this is only supported by or send me an e-mail at Windows 7, in combination with special hardware compatible [email protected] with the multi-touch and interactive gestures, I'll leave an example behind for now (until I can get my hands on the special (also to ask about subscription or renewals). multi-touch hardware that is). Bob Swart - is Reseller for BeNeLux Touch Keyboard (Belgium Netherlands Luxemburg) One more thing I can show you is the final step to make the application completely independent from mouse and keyboard: for deployment in a kiosk or bus station for example. Since these applications sometimes still need some textual input, Delphi 2010 contains a special TTouchKeyboard component. One which shows the keyboard layout for the current locale (which means that users from France will get the accents available on the keyboard when they need them).

Page 10 / 2124 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Counters by David Dirkse starter expert DELPHI / Win32 Using a calculator: This article covers some fundamental arithmetic operations in 1208 : 44 = 27.4545... remove digits right of the decimal point ICT applications with emphasis on the operators mod and div. 1208 div 44 = 27. div also is an operator, like + - * or mod Computers are only able to handle . Only problems that are expressable in numbers can be solved by a computer. Rounding In daily life , numbers may be grouped in the following Assume a drawing application, using a paintbox with squares categories: of 20 * 20 pixels. A MouseMove generates an event and category example supplies quantity Kilogram, degrees,meters,seconds the (x,y) coördinates. X div 20 is the number of squares left of factor 15%, half, double the mouse X so...... index 4 stars hotel, 2nd left, house number (X div 20) * 20 ..... is the X position rounded down to a code Pincode, bus 147, ASCII code multiple of 20. In case we want to round to the nearest multiple of 20 we Arithmetic and math start with counting. calculate: Below, a simple counting device is pictured ((X + 10) div 20) * 20...... {note: 10 = 20 div 2 } To round upward to the next multiple of 20: ((X + 19) div 20) * 20...... {note: 19 = 20 - 1}

Two dimensional tables

Figure1: note: 'stand' is Dutch for 'state'. 0, 4 are the lowest and highest state.

It is not interesting how this counter performs it's functions. It may be mechanical, by pinwheels, electronical or electro- mechanical using relays. Figure: 2 two dimensions The “reset” signal forces the counter in it's first state '0'. A next increment signal forces the next state '1'. In state '4', the The fields are numbered 0 to 23. highest of this counter, a next increment again forces state '0' Calling N the number of a field, than N = column + row * 6. and an 'overflow'signal is generated. In digital technology, this For the columns, we notice a modulo 6 counter. overflow is called a 'carry'. ( example: 23 mod 6 = 5) Assume that N increments take place after a reset. Table below For a known value of N, the column and row can be calculated : lists state T of the counter after increment N. column = N mod 6 row = N div 6 N 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 The computer memory is a one dimensional table of bytes. In case of a two dimensional table, a small calculation is necessary T 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 to obtain the memory location. We notice that the counter has 5 distinct states Therefore it is In Delphi, the elements of a two dimensional array are stored in called a modulo 5 counter. To express T as a function of N , the memory as outlined in the table below: (values 0,1,2,3,... in sequential order) some (new) notation is required, we write : T = N mod 5 T is the remainder of the division of N by 5. mod is an operator, just like + - * In the table above we read 14 mod 5 = 4 In case of a modulo 44 counter (counting 0..43 ) which received 1208 increments, it's state will be T = 1208 mod 44 To program this operation in delphi, we simply write: T := 1208 mod 44. Using a handheld calculator we proceed : 1208 : 44 = 27.4545... remove digits left of the decimal point and multiply 0.4545... * 44 = 20 Please note : in rare occasions a very small rounding number is Figure 3: Let's define above structure both as a one- and as a two necessary to obtain an integer number. dimensional table by using the absolute directive. var A1 : array [0..23 ] of byte ; The number of state transitions from highest to 0 we call C , A2 : array [0..5 , 0..3 ] of byte absolute A1 ; // A1,A2 the number of carries. So, A1[9] is the same element as A2[2,1] Notation: In general, using an array of rcount rows : C = N div 5 A2[ col, row] = A1[col * rcount + row]. is the number of carries out of a modulo 5 counter after N A1[ i + 4] adresses the element 1 right of i, A1[ i – 3] adresses increments. the element left down of i. We notice, that C is the integer division of N by 5. This approach may result in considerable time saving with some board games requiring extensive analyses. Using simple + and – To program the calculation in Delphi, type C := 1208 div 44 operations, fields can be scanned up, down or diagonally. More time consuming operations like multiplication are avoided.

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 11 / 2125 DEVELOPERS 4 Counters (continuation 1)

Location on the screen The total counter T0..T3 may be regarded as a modulo (2 * 4 * 5 * 3) = 120 counter. N = 120 causes state 0 0 0 0 and one carry out of T3. Say N = 68. What will be the state of each individual counter? 68 mod 2 = 0, so T0 = 0 86 div 2 = 43, is the number of carries out of T0 , increments to T1 T1 = 43 mod 4 = 3 43 div 4 = 10, increments to T2 T2 = 10 mod 5 = 0. 10 div 5 = 2, increments to T3 T3 = 2 mod 3 = 2. Figure 4: So, counter states are 2 0 3 0 (written left to right) In figure 4 above a black rectangle constitutes 100 * 100 pixels At this point, the reader may get worried about the usefulness of on the screen. this exercise. Continue reading and see...... : A mouse move presents the (x,y) coördinates of the cursor so A pancake restaurant offers the following choices: column i = x div 100 type of flour: white(0) of whole wheat (1) ...counter 0 row j = y div 100 size : small(0) medium(1) large(2) extra large(3) ...counter 1 Each field has an orange area. type : plain(0) apple (1) porc (2) cheese(3) banana(4).counter 2 finish : sugar(0) molasses(1)jam (2) ...counter 3 To test if we are positioned in this area, we program : var orange : boolean; We want to convert an order into a smallest possible number, so x100 , y 100 :; word to encode an order...... x100 := x mod 100; Now note, that each choice is represented by an individual y100 := y mod 100; counter stage mentioned before. The counter state 2 0 3 0 orange := ( X100 > 25 ) applies to the order and (x100 <) 75 white flour.....extra large.....plain...... jam and (y100 >) 25 and (y100 < 75 ); code N for this order is : 68. How do we encode order ...... whole wheat(1), large(2), Sudoku A Sudoku puzzle typically has a board with columns 1..9, rows apple(1), sugar(0) ? 1..9 and groups 1..9. So counter state = 0 1 2 1, asked is N. Refer to the picture below. T2 is increased once, this requires 2 * 4 increments of T0 since T0T1 together constitute a modulo 2 * 4 = 8 counter. So, N = 8 for the moment. T1 is increased 2 times, this requires 2 * 2 increments of T0. So now N = 8 + 4 = 12. T0 is increased once which makes N = 12 + 1 = 13, which is the -pancake-code of this order. Note: to obtain state T of an individual counter stage requires N = T * (modulus of preceding counters) increments into T0.

Number systems

Figure 5: Notice, that we count from 1..9, which is unsuitable for mod and div operations. Therefore , conversion is needed from 1..9 to 0..8 Above is pictured an 8 stage counter we recognize as a byte. before mod and div operators may be applied. Given column i, An individual counter , counting 0,1,01... is called a bit. 11100110 row j , we want to calculate the field that contains this element. is a shorthand notation we are used to in number sytems. The This can be done using following function: modulus of the byte is 2^8 = 256 . If we replace the counters by function IJtoGroupNr( i , j : byte ) : byte ; modulo 10 types, counting 0...9 , N would appear as a decimal //return group Nr of field [i,j] number. Conversion from the binary (2) to the decimal (10) number var x , y : byte ; begin system is accomplished by connecting N also to modulo 10 xi := ( -13 ) div ; counters. N mod 10 than is the state of T0 after N increments. N div yj := ( -13 ) div ; 10 is the number of carries out of T0 into T1 etc. Program below result := x + 31 * y + ; converts a positive integer (in binary in the computer memory) to a end; string of decimal digits. (displayed in component edit2) procedure setN ( nn : cardinal ; t : byte ); Serially connected counters //displays number with base t const digitconvert = '0123456789abcdef'; var s : string ; m : byte ; begin if nn = 0 then begin form1. edit2 . text := '0' ; exit ; end ; s := '' ; repeat m := nn mod t ; Figure 5: schematic view nn := nn div t ; In the picture above, 4 counters are serially connected. The carry of insert ( digitconvert[+],,); m11 s until nn = 0 ; a stage is the increment of the next. Counter T0 is modulo 2, T1 is form1 . edit2 . text := s ; modulo 4, T2 is modulo 5 and counter T3 is of the type modulo 3. end;

Page 12 / 2126 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Counters (continuation 1)

Bit fields mod and div are relatively slow operations because they involve Remarks: division. For reason of speed it is better to avoid them. This is 1.6K + 2 cannot be prime, since is is a multiple of 2. possible if the modulus is a multiple of 2. N div 2 yields the same 6K+3 is a multiple of 3. result as N shr 1, a shift of 1 bit to the right.. only 6K-1 (or 6K+5 , which amounts to the same) and 6K+1 may be prime. In general: N div (2 ^ i) = N shr i 2. A number P is a multiple of m if P mod m = 0 also N mod (2 ^ i) = N and (2^ i – 1) Instead of N mod 8 the operation N and 7 has the same answer and Say P = 63 and m = 7. Than 63 div 7 = 9 and 63 mod 7 = 0 , is much faster. 63 is not prime. Suppose P = 67 , we test P for being prime by division by 3,5,7,11,13... Suppose we are programming a game and we need a 67 div 7 = 9 and 67 div 11 = 6, but .....6 < 11 , for the 2 dimensional array of first time the quotient is smaller than the divisor. We can 1000 * 1000 bits and 3 procedures/functions: savely assume now that P is prime, because a prime factor should be found earlier. 1. The procedure setbit(i , j : word) forces the value '1' into column i, row j 3. The program uses 2 goto statements and labels. 2. procedure clearbit(i , j : word) makes column i, row j a '1' Some programmers consider this an atrocity but here it results 3. Function testbit(i , j : word) : byte; in easy readable code. supplies the value of column i, row j. Reason is the two crossing loops. If anybody knows a nice way to rebuilt the code according to the rules of 'structured How to program this structure? programming' , please let me know. We simply put all bits in a 1 dimensional array of bytes, for reasons of fast access. Calculation of the GCD (greatest common divisor) So this array must contain 1000 * 1000 / 8 = 125000 bytes. The GCD of two numbers is best calculated using the 'Euclidian Theorem'. This amounts to the arithmetic rule ...... GCD(A,B) = GCD(A-B , B). Var BitArray : array [0..124999] of byte ; An example: procedure setbit ( i , j : word ); GGD(3094,2310) = GGD(3094-2310,2310) = GGD(784,2310) = var AbitNr : integer ; GGD(2310,784) = GGD(1526,784) = GGD(742,784) = byteNr , bitNr : byte ; GGD(784,742) = GGD(42,742) = GGD(742-17*42,42) = begin GGD(28,42) = GGD(14,28) = GGD(0,14) = 14 ABitNr := i + 1000 * j ; Program below calculates the GCD of numbers A and B by // bitnumber in array , counted 0..999 in row 0, 1000..1999 in row 1 ByteNr := ABitNr shr 3 ; //div 8 = index in byte array repeatedly applying the Euclidian Theorem. bitNr := AbitNr and $7 ; //bitnumber in byte function GGD ( A , B : cardinal ) : cardinal ; BitArray [ byteNr ] := BitArray [ byteNr ] or (1 shl bitNr ); var r : cardinal ; end; begin repeat procedure clearbit ( i , j : word ); rA := mod B ; var AbitNr : integer ; AB := ; byteNr , bitNr : byte ; Br := ; begin until r := 0 ; ABitNr := i + 1000 * j ; result := A ; // bitnumber in array , counted 0..999 in row 0, 1000..1999 in row 1 end; ByteNr := ABitNr shr 3 ; //div 8 = index in byte array bitNr := AbitNr and $7 ; //bitnumber in byte This concludes my article. BitArray [ byteNr ] := BitArray [ byteNr ] and ($ff xor ( 1 shl bitNr )); end; David Dirkse function testbit ( i , j : word ) : byte ; Born 1945 in Amsterdam, David joined Control Data var AbitNr : integer ; Corporation in 1968, after studying electrical byteNr , bitNr : byte ; begin engineering. As a hardware engineer, he was ABitNr := i + 1000 * j ; // bitnumber in array responsible for the installation and maintenance of ByteNr := ABitNr shr 3 ; //div 8 = index in byte array mainframes at scientific data centers in the bitNr := AbitNr and $7 ; //bitnumber in byte Netherlands. result := ( BitArray [ byteNr ] shr bitnr ) and $1 ; With the decline of CDC around 1990, he studied end; mathematics and became a math teacher. His hobbies are programming, in particular educational software, math algorithms, and puzzle The next 250 primes solving. A -non prime- number may be written as a unique product of http://home.hccnet.nl/david.dirkse prime factors. Primes play an important role in coding theory and in mathematics in general. For this occasion I wrote a small program to generate the next 250 primes.

To avoid redundant work the following trics are applied:

– any prime ( > 3) has may be written as 6K-1 or 6K+1, where K = 1,2,3,4...... – P is prime when (P mod m <> 0) and (P div m < m) – where divisor m performs steps 5,7,11,13,17,19,23,25,29..... so alternating 2,4 – increments.

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 13 / 2127 DEVELOPERS 4 Frequently Asked Questions over de W32/Induc-A Virus (Compile-A-Virus) door Nick Hodges

starter expert DELPHI 4-5-6-7 The virus creates this file as part of its actions. If that file is present, you are likely infected (unless you know that you Abstract: This is a set of Frequently Asked Questions about the yourself created this file for some reason). W32/Induc-A “compile-a-virus” virus that can attack old If you have a SYSCONST.BAK in your \lib directory, then you versions of the Delphi development tool. can open up SYSCONST.DCU in a hex editor or even in a text editor like notepad. You can search for the code What versions of Delphi are affected? "CreateFile(pchar(d+$bak$),0,0,0,3,0,0);" in that DCU file. If it This virus affects only Delphi versions 4 – 7 released between is present, you are infected. 1998 and 2002. The W32/Induc virus does not affect newer versions of Delphi from v2005 thru v2009 or the upcoming If I have it, how did I get it? v2010. If you have the virus, you got it buy running an EXE or DLL file on your machine that was already infected with this virus. What versions of Delphi are NOT affected? Delphi is a very popular development tool, particularly among This virus does not affect more current versions of Delphi. ISV and MicroISV developers. Ii you received an infected binary Delphi 2006, 2007, 2009, and the new 2010 release are not you may have received it from an application download. affected by this virus. What are the implications of being infected? What is this virus? If your machine is infected, the EXE and DLL files that you This virus is called "Compile-a-Virus". It is also referred to as produce will infect any unprotected machine where your EXE or "W32/Induc-A". DLL is run and that has Delphi 4 – 7 installed. But note again that this virus doesn't do anything malicious apart Is the Delphi IDE or the language distributing this virus? from spreading itself. However, if you detect that you have the No, the versions of Delphi that are vulnerable to this attack (v4 virus and have distributed known infected files, it is prudent to thru v7) do not come with this virus nor is the virus in the notify file recipients and point them to this FAQ for more language. It is “caught” by downloading and running an infected information. EXE or DLL. How do I remove the virus from my Delphi installation? Is Delphi Prism affected? To remove the virus you should No, Delphi Prism is not affected by this virus. - Delete the infected SYSCONST.DCU file on your system - Replace it with the SYSCONST.DCU file from your What does this virus do? installation media. Delphi versions 4 -7 include a complete This virus does nothing to versions of Delphi newer than Delphi install image on their CD, so you can simply copy that file 7 (2002). If a machine is infected, the virus W32/Induc-A from your DVD to your installation. doesn't do anything malicious or create damage other than spread itself. How do I make sure that it doesn't come back? or What the virus does do is embed itself into an installation of I don't have the virus. How do I make sure that I don't get it? Delphi version 4, 5, 6 or 7. Then, when an infected version of This virus does not affect Delphi version 2005 thru 2010. Delphi builds an EXE or a DLL, it embeds itself into that However, if you are running older copies of Delphi v4 thru v7 resulting binary. When the code for that EXE or DLL is run, it then the most effective way to ensure that you don’t get the virus then looks for installed versions of Delphi 4 thru 7 and replicates is to move your copy of DCC32.EXE to a different directory. itself into any installations that it finds. Then, that installation The IDE of these older versions doesn’t require the command will in turn produce EXE and DLL files that will look to line compiler, so this will not affect the execution of the product. replicate itself anywhere it is run. You can also prevent the virus from doing anything to your Again, the virus looks only for an installation of Delphi 4 -7. installation again by leaving a file named SYSCONST.BAK in Specifically, if it finds one of those Delphi versions, it searches the same location where you found it. The file can be empty. for the SYSCONST.PAS file. It opens that file, injects code into The virus checks for the presence of this file, and if it finds it, it it, compiles the file, and replaces the shipped version of does nothing. Leaving a blank SYSCONST.BAK file in the SYSCONST.DCU with the new infected version. It then deletes same location as your SYSCONST.DCU file will ensure that the the SYSCONST.PAS file it created. (The virus doesn’t alter any virus will do nothing. *.PAS files on the system). The injected code simply causes the In addition, you can mark all of the files in your \lib directory as execution of code containing SYSCONST.DCU to replicate the read-only. This will prevent the virus from changing them. virus. How do I tell if I have executable files on my system that are Is this a problem unique to Delphi? spreading this virus? This particular virus seeks out Delphi v4 thru v7 but this type of This is a relatively new virus, and so virus scanning software is virus is not in any way unique to Delphi and could effect any just starting to recognize it. A number of vendors are already development environment from Eclipse to Visual Studio. identifying binaries with this infection, and undoubtedly, most will follow suit soon. The best way to detect the virus is to Who is vulnerable to this infection? ensure that your anti-virus software knows about W32/Induc-A Installations of Delphi 4 - 7 can be affected by W32/Induc-A. If and run a virus scan on your system. an infected EXE or DLL file is run on a machine without Delphi The binaries I am producing are infected, what can I do? 4 - 7 installed on it, then the virus does nothing. Virus scanners Of course you first need to rid your system of the virus – See are now starting to report this infection as a virus to those people above.The only way to get rid of the virus that is already in an with infected binaries. existing EXE or DLL is to recompile that binary with a clean system. How do I know if I've been infected? Detecting if your Delphi installation has been infected is fairly Does this affect packages built with Delphi 4 - 7? easy. It only affects Delphi version from 4 to 7. The easiest way It is possible but unlikely. By default, packages are not affected. to tell if you have been infected is to search for the presence of A package can become infected if you manually choose not to SYSCONST.BAK in the \lib directory of your Delphi link against our RTL.DCP file and manually link in an infected installation. SYSCONST.DCU.

Page 14 / 2128 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 FAQ’s over de W32/Induc-A Virus (Compile-A-Virus) - vervolg

The overwhelming majority of developers will not have done Is C++Builder affected? this, and if you have, then you’ll be able to recompile those No. It is theoretically possible for a C++Builder EXE to become packages with a clean system. infected, but a C++Builder developer would have to take a rather lengthy set of steps and actively change and recompile a What else can I do to protect myself? number of different things on his system in order for the virus to There are a number of additional things you can do to protect affect C++Builder binaries. yourself against this virus. As mentioned above, you can mark I produce shareware and/or an ISV application built with all of the DCU files in your \lib directory as read-only. And Delphi? What does this mean? while you are at it, you might consider labeling all of the source If you are running newer versions of Delphi 2005 thru 2010 then code in the \source directory as read-only as well. it doesn’t affect you. If you are a Shareware or ISV vendor running an older version of Delphi v4 thru v7, then you should To be absolutely safe, you can do a file compare between your check that your machine is not infected. If it is infected you \lib directory and the \lib directory on the install image on your should clean it. CD. If you have distributed infected executables to your customers, If you need a file compare tool, there is a very powerful, open you should immediately recompile your product and distribute a source tool called FreeFileSync which can be found at: new, cleaned version. It would also be prudent to notify file http://sourceforge.net/projects/freefilesync/ recipients and point them to this FAQ for more information. As Keep in mind that it is possible that you may have altered these anti-virus programs begin to see this virus in binaries, customers DCU files yourself, so if they show up as different, be sure that will be getting reports of your binaries being infected and you’ll you yourself haven’t altered them. So far, this virus only affects want to be ready with a clean binary for them. the SYSCONST.DCU file. In any event, it is highly recommended that you ensure that the files in the \lib directory of your Delphi 4 – 7 installation match those of the install image on your CD.

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 15 / 2129 DEVELOPERS 4 DeZign for Databases v5 by Marco Roessen

starter expert all DELPHI versions First impressions Many applications use a database for storing data. A database When you install DeZign for Databases and run it the first time, usually is a collection of tables with their internal relations. you will automatically be presented a demo database. This demo Creating a database can be done completely from code. database gives us the opportunity to discover the possibilities of Another possibility is to use a tool supplied with the database DeZign for Databases. engine. Using these tools a database can be visually designed; Figure 1 shows the two main interface elements: the designer on the the tables and their relations are graphically represented. right-hand side and the “object browser” on the left-hand side. Examples of these tools are mysqladmin used for MySQL Double clicking a table in the designer or Object browser will open databases and SQL Server Management Studio for MSSQL an interface. This interface is used for adding, removing or databases. Often databases created with these tools and the modifying fields (figure 2). chosen data types are specific for these database engines. It is not easy to convert these designs to other database engines. Creating a new database This article is about DeZign for Databases v5, a database Creating a new database design is relatively easy. When you create engine independent tool for designing and creating databases. a new project you will be asked which database engine you will be DeZign for Database is one the products developed by the using. The currently supported database engines are DB2, dBase, relatively young Dutch company Datanamic. The products they DBISAM, ElevateDB, Firebird, FoxPro, Informix, Interbase, have developed are: - DeZign for Databases V5 Powerful database design and modeling tool. Design, create, reverse engineer and modify databases. - DB Data Difftective V1 Compare and synchronize database content. - DB Schema Difftective V1 Compare and synchronize database schemas (structure). - DB Data Generator V2 Quickly generate test data for your databases. - DB MultiRun V1 Execute multiple SQL scripts against multiple databases. - DB Zipper V2 Archive and extract database data. An easy way to migrate and backup data. DeZign for Databases is Datanamic's most prominent product. You can download trial versions of all of the above products. Please check the website (www.datanamic.com) for more details. Figure 2: Modifying the properties of a table

Figure 1: DeZign for Databases designer overview

Page 16 / 2130 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 DeZign for Databases v5 (continuation)

MaxDB, MS Access, MS SQL server, MySQL, NexusDB, Oracle, When generating a database it is possible to add a version to the Paradox, Pervasive PostgreSQL, SQL Anywhere Studio, SQLite design. By using versions, it is always possible to revert to an and Sybase ASE. For a complete list of the supported database older version of the design. You can also create a so called SQL engine versions and functionality you can check the complete modify script. This script can be used to modify an existing overview available at database structure to fit the structure of an older or newer design http://www.datanamic.com/dezign/supporteddatabases.html. It is also possible to create your own DBMS database definition Importing a database structure file. These definition files can be used by DeZign for Databases to Another nice feature is the possibility of importing an existing support database engines that are (not yet) supported by default. database structure. This feature is useful for investigating an You can find more information about this subject in the extensive already existing database structure. All tables, relations, triggers, help file. After choosing the database engine, you will be code, etc are displayed clearly. You can modify this imported presented an empty workspace where you can add tables. When structure with the same tools that are available when designing a tables are added you will be presented a dialog containing the new database (modify tables and fields, create a database or a SQL properties of this newly created table. You use this dialog to set modify script, etc). One of the properties of a database design is table properties and add fields. the target database engine. If you have to modify your initial A nice feature of the program is called “Domains”. A domain is an choice for some reason (e.g. use a more powerful database engine) alias for a specific data type with specific properties set. If you, for this is possible. The project will be converted to the other database instance, use the VARCHAR data type with the property maxchars engine target. If there are incompatibilities, they will be displayed. set to 75 a lot, you can create a domain with these properties. You This function is also useful for converting imported databases to can give this domain a descriptive name. This domain will be another target engine. There is one thing I want to warn you about available from the list with data types (starting with an @). If you when using DeZign for Databases: If you want to change the have to modify the data type or one of the properties for some structure of an existing database (filled with data) using an SQL reason, you will only have to modify the domain. All fields using modify script, you have to take good care that there will be no loss this domain will be updated automatically. of data. When a modification of the structure of a database is incompatible with the current existing database (e.g. changing a When all tables are defined, we can set the internal connections by string field to an integer field), there is a possibility that you will adding “Relationships”. For instance you can add an “Identifying lose all existing data. In these cases the SQL script created will relationship” by clicking the corresponding toolbar button. After remove the existing table (DROP TABLE) and therefore all clicking the button you can draw a line between the tables that existing data and create a new table from scratch. It is wise to have to be linked. Default the table relation will be set between the check the script and backup the database before executing the SQL fields that have the same name in both tables. If this is not the modify script. It would be nice if DeZign for Databases warned intended relationship, you can manually change it (figure 3). you about the possible loss of data.

Creating the database Conclusion When the whole database design is ready, you can check it DeZign for Databases is an excellent tool for designing and (Database / Check model Ctrl+F9). If there are any problems or modifying databases. Its database engine independency is big plus. warnings they will be displayed in the bottom : the The program is easy to use and gives you all the tools necessary MessageWindow. When all problems and warnings have been for every day database design. The automatic versioning feature is resolved, you can create the database (F9). An SQL script will be also very useful. DeZign for Databases is relatively cheap created for SQL based database engines. Other (non-SQL) compared to other database design tools, despite the extensive set databases will be created as a file (e.g. an MSAccess.mdb file). of features.

About the author:

Marco Roessen Graduated HTS-Electronics, specialisation Technical ComputerScience, in 1993. Since then he has been working as an informatics engineer at the Centre for sleep and wake research firstly at Leiden University since 1995 at Medisch Centrum Haaglanden, Den Haag. There he develops tailored sleep research software; started with assembler and MS Pascal, later using Turbo, Borland and Delphi Pascal. Currently also C#. He is co-developer of algorithms for automatic biomedical signal analysis. Figure 3: Changing a relationship

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 17 / 2131 DEVELOPERS 4 Customizing the T-Field data display by Henk Schreij starter expert DELPHI 2..2010 / Win32 When you display a database field, you sometimes want to show something other than what is stored in the field. For example, you might want to show 'male' or 'female' when the stored value is '1' or '0', or show figures with two decimal places, such as 1.50 instead of 1.5. The usual approach in such cases is to create persistant fields and use their OnGetText events or Display Format properties. You can also achieve the desired result without persistant fields, as described in this article.

Persistant fields For a change, here we use SqlServerExpress (Microsoft's free database application) for our example. For those of you who are used to working with Paradox or Access, it's easy to do the same Figure 4. Specifying the DisplayFormat property thing with these applications. of the persistant field 'Paid' The example table in Figure 1 has four fields: ID (autoincrement), Name (string 15), Amount (float or real; may be A FloatField has the property DisplayFormat, but some other field empty), and Date (date and time; may be empty). types (such as StringField) do not. The specific properties depend on the field type. For example, a Boolean field has the DisplayValues property (Yes; No or T; F), an Integer field has the MaxValue and MinValue properties, and so on.

Figure 1. Structure of the test table in SqlServer 2005 If you fill the table with some data and display it as an AdoTable in a DBGrid, the presentation of the numbers leaves something to be desired. We are used to seeing numbers with two decimal Figure 5. Rendering of floating-point values places instead of the numbers shown in Figure 2. with DisplayFormat set to '0.00' Persistant fields are thus very handy when you have special wishes for fields that are not available at runtime. However, they also have disadvantages. To start with, they end up in your code: type TForm1 = class (TForm ) ADOTable1: TADOTable; ADOTable1ID: TAutoIncField; ADOTable1Name: TStringField; ADOTable1Paid: TFloatField; ADOTable1Date: TDateTimeField; DBGrid1 : TDBGrid ; Figure 2. Default display of floating-point numbers DataSource1: TDataSource; private The usual solution here is to right-click AdoTable1 (or Table1 if {Private declarations } you're using Paradox) to bring up the Fields Editor. In the Fields public Editor, you again right-click and select 'Add all Fields' as shown {Public declarations } in Figure 3. end ; With a large number of tables, this can result in pages full of 'filler' code. A more serious problem is that your fields are no longer flexible. If there are any persistant fields (even just one), no fields are created at runtime and all non-persistant fields are hidden. This can drive you crazy when (perhaps years later) you add a field to table and it remains invisible no matter what you do. You usually end up deleting the table (or AdoTable) and building it again from scratch, after which the field is suddenly visible. However, it's easy to forget to check the properties, such as DisplayFormat, Figure 3. Using 'Add all Fields' to make persistant fields and then other things are suddenly messed up. For these reasons, persistant fields are not especially popular. This gives you what are called persistant fields, which remain permanently in your program. This is an extension to the normal DisplayFormat without persistant fields situation in which the fields are created at runtime when the It's also possible to specify the DisplayFormat property without table is opened. creating persistant fields. To do this, you have to specify the field The advantage of persistant fields is that you can configure the property in the code immediately after you open the table. properties and events of each field separately. The Object You can use the table's OnAfterOpen event for this, as shown in Inspector gives you convenient access for viewing or setting the Figure 6. configurations, such as in Figure 4 where you see the Display (Note: If you open the table in the event OnShow of your form, Format property of the Amount field. If you type '0.00' here, the you do not need to use OnAfterOpen. In this case, you can numbers will always be displayed with two decimal places as specify the property in the OnShow event immediately after the illustrated in Figure 5. line containing AdoTable1.Open.)

Page 18 / 2132 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Customizing the T-Field data display (continuation 1)

Figure 6. DisplayFormat is not one of the listed properties Figure 8. Using OnGetText to convert 0 and 1 to ' m ' and '' f Unfortunately, you won't see DisplayFormat in the dropdown list if you simply try to specify this property, since DisplayFormat is OnGetText without persistant fields not a general TField property, but instead only a property of a Using OnGetText without persistant fields is a bit more difficult. number field or date field. For this reason, you need a typecast to Two steps are necessary in this case. First you have to tell the TFloatField or its general ancestor TNumericField. program that the OnGetText event of the Gender field points to a specific procedure, and then you have to specify this procedure. procedure TForm1. ADOTable2AfterOpen( DataSet : TDataSet ); begin (AdoTable2. FieldByName('Paid' ) as Incidentally, this is how Delphi always works. You can see this if TNumericField). DisplayFormat := '0.00' ; you examine the previous example in Figure 8 more closely. To end; do this, you have to look in the code of the form itself (the .dfm This lets you specify the properties of a TField without creating file), where the OnGetText event is linked to the procedure. It's persistant fields. very easy to view the code in the .dfm file: simply right-click the form, select 'View as Text', and look for the persistant field, where you will see: Using OnGetText with persistant fields In the introduction to this article we mentioned that you may object ADOTable1Sex: TIntegerField FieldName = 'Sex' have a table where '0' and '1' stand for 'male' and 'female', which OnGetText = ADOTable1SexGetText you want to show as 'mf ' and ' , and that you can do this by using end; OnGetText. To restore the normal form view, right-click this code and select To try this out, add a Gender field (of type Integer) to your table 'View as Form'. in SqlServer (or Access, Paradox, or whatever you're using). Here again you have two options: ' with '' or without ' persistant fields. Now: how it works without persistant fields. The first step is the code that references the procedure: First: how it works with persistant fields. If you already had persistant fields before you added the Gender procedure TForm1. ADOTable2AfterOpen( DataSet : TDataSet ); begin field, you won't see the new field in the DBGrid. (AdoTable2. FieldByName('Paid' ) as What's worse, if you use Add Fields as shown in Figure 3, there's TNumericField). DisplayFormat := '0.00' ; a good chance that you won't even see the field itself. This is AdoTable2. FieldByName('Sex' ). OnGetText := SexGetText; because AdoTable1 can't see that a new field has been added end; unless you have AdoTable1 open at design time. To achieve this, set the Active property of the table to True before you invoke Add Incidentally, you can also put the code for the first step in the Field. OnCreate event of the form (which is actually the usual practice). Once you have added the Gender field to the table as a persistant field, you can view the events of this field as shown in Figure 7. The second step is to specify the action in SexGetText. An OnGetText event expects three parameters (Sender, Text, and DisplayText), so you have to specify them as well. See the Help entry for OnGetText for more explanation. The resulting code is:

procedure TForm1. SexGetText (: Sender TField; var Text : string ; DisplayText: Boolean ); begin if Sender . AsInteger = 0 then Text := 'm' else Text := 'f' ; end; Figure 7. Events of the persistent Integer field 'Gender' Don't forget to declare this procedure, including its parameters, If you double-click OnGetText, you will see a framework. Put in the private declarations. The easiest way to do this is to use the following code in this framework Ctrl+Shift+C to complete the code automatically. procedure TForm1. ADOTable1SexGetText(: Sender Also be sure to set the ReadOnly property of this DBGrid field to TField ; var Text : string ; DisplayText: Boolean ); True. It's very confusing for users if what is displayed is not the begin same as what they have to enter, so you have to arrange for data if Sender . AsInteger = 0 then Text := 'm' entry outside your DBGrid. else Text := 'f' ; end; There is also a way to accept data entry that does not match the Here you should note that the type of Sender is TField rather field content and have it be stored in the table. For this, you use than TObject, which means that you can use AsInteger to read the counterpart of OnGetText, which is called OnSetText. the numerical value directly, and that Text is a variable that you can use specify the text to be displayed. Unfortunately, it isn't possible to use OnSetText to enter a letter The result is shown in Figure 8. (such as 'mf ' or ' ' ) in an integer field, since a number field won't accept letters. You'll hear an error beep before you even get to OnSetText.

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 19 / 2133 DEVELOPERS 4 Customizing the T-Field data display (continuation 2)

Consequently, we have to devise another example for OnSetText. procedure TForm1. FormCreate( Sender : TObject ); begin OnSetText without persistant fields AdoTable1. FieldByName('Sex' ). OnGetText:= GeslachtGetText; For our example for OnSetText we will use a date field, since a AdoTable1. FieldByName('Date' ).OnSetText:= date field accepts all characters. DatumSetText; The objective here is to have the current date be stored when the end; user enters a space character. procedure TForm1. ADOTable1AfterOpen( DataSet : TDataSet ); begin This can be done with or without persistant fields; the example (AdoTable1. FieldByName('Paid' ) as TNumericField). DisplayFormat:= '0.00' ; here is without persistant fields. The full code, including the end; previous DisplayFormat and OnGetText, is as follows: procedure TForm1. SexGetText (: Sender TField; unit Unit1; var Text : string ; DisplayText: Boolean ); begin interface if Sender . AsInteger = 1 then Text := 'm' uses Windows , Messages , SysUtils , Variants , Classes , else Text := 'f' ; Graphics , Controls , Forms , DB , Grids , DBGrids , ADODB ; end; type procedure TForm1. DateSetText( Sender : TField ; TForm1 = class (TForm ) const Text : string ); ADOConnection1: TADOConnection; begin DBGrid1 : TDBGrid ; if Trim ( Text ) = '' then DataSource1: TDataSource; Sender . AsDateTime:= Date ADOTable1: TADOTable; else Sender . AsDateTime:= StrToDateTime( Text ); procedure FormShow ( Sender : TObject ); end; procedure FormCreate( Sender : TObject ); procedure ADOTable1AfterOpen( DataSet : TDataSet ); end. private procedure SexGetText(: Sender TField; This example, which stores the current date when a space var Text : string ; DisplayText: Boolean ); character is entered or nothing is entered, can easily be extended procedure DateSetText(:; Sender TField const Text:); string to provide other useful functions, such as storing yesterday's date public {Public declarations } or tomorrow's date if the user enters '–' or '+', entering the date end ; and time without seconds, and so on. You can also add a good var Form1 : TForm1 ; automatic error handling mechanism, such as adding the month implementation and year automatically if only the day is entered. {$R *.dfm} procedure TForm1 . FormShow ( Sender : TObject ); One final remark: the example shows how this works with a begin DBGrid, but it also works with a DBEdit or the like, since the ADOTable1.; Open end; code is linked to a TField rather than the component that displays the data.

Using Free Pascal and Lazarus to create applications for OSX. by Jeremy North starter expert Having come from using Delphi and Visual Studio development run. Follow the installation instructions found on the website to environments and constantly hearing how an OSX based system install each package. After you have installed both Free Pascal and does everything better than a Windows based system I was Lazarus, run Lazarus. By default Lazarus installs into the bitterly disappointment when I started exploring the and /Developer/lazarus folder. developer tools by Apple. If you want to use a Pascal language on OSX your options are pretty limited. One option is Free Pascal. Free Pascal has been around for a number of years now and is updated regularly. It supports many operating systems include Win32, Linux, WinCE and OSX. To support Free Pascal there is an open source integrated development environment called Lazarus. Let's be honest here, Lazarus is pretty much a knock off of the old Borland IDE circa Delphi 7, which can be both a positive and negative, with a few nice additions thrown in. Lazarus has its own version of the VCL called LCL. It is basically compatible with Delphi's VCL. I say basically because it isn't 100% and in some areas it is far from it. You need to download the appropriate packages from the Free Pascal and Lazarus websites for your version for your MAC. Make sure you download the correct packages. Figure 1: the IDE of Lazarus Free Pascal - (http://www.freepascal.org/) Launch Lazarus and go into the Environment | Options dialog. Lazarus - (http://www.lazarus.freepascal.org/) Make sure that the Compiler Path and FPC Source Directory Before installing either package be sure to install the Apple options are set to the install location of Free Pascal. If you install developer tools. You can download these tools from the Apple to the default locations these will be /usr/local/bin/fpc and Developer website (http://developer.apple.com). You will /usr/local/share/fpcsrc/ respectively. have to create a developer account which is free - unless you select one of the paid account types. I signed up using the iPhone Features not in Delphi developer program which gives you access to the iPhone specific As mentioned earlier, Lazarus has some features that are not tools (SDK versions, simulator etc.) but also to the desktop available in the Delphi. It also has some of Delphi features that are specific tools. Be warned, the downloads are not small (nor fast - not so good and then it just has some features of its own that are at least from my side of the world). not so good. After installing the tools, install Free Pascal NOTE: These lists are nowhere near exhaustive. before Lazarus. This should make things a lot easier in the long

Page 20 / 2134 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Using Free Pascal and Lazarus to create applications for OSX (continuation)

Figure 4: compiler options for the project my Mac Book Pro. This project consisted of one form. The form had a main menu (with some items in it – two had event handlers), a memo and a status bar. When trying to import this project the Good Figure 2: the options form IDE crashed. A second application I tried to import did work Lazarus includes a viewer for comparing files. however the imported project didn't have any unit paths assigned Although nothing could replace Beyond Compare on my to it (which is done automatically when you create a new project). systems for that. This means you need to set these paths manually. The second Customizable number of recent project and files. This project didn't include the status bar or the main menu. feature is included Delphi in 2010. The tab order dialog allows you to change a forms entire Using Free Pascal with XCode and Interface Builder tab order within the same dialog. So you don't have to keep When you install Free Pascal the later versions include an XCode reopening the dialog with a different parent selected like for Integration product. This product allows you to use the XCode you do in Delphi. and Interface Builder tools to create applications using Free Not so good Pascal. While I didn't really have a lot of time to use this product, By default a dialog displays to tell you that you have it showed considerable promise and something that will hopefully finished running your application. This dialog is very see regular updates in the future. annoying. It can be switched off in the options located in the environment options dialog shown earlier. Uncheck the Show message on stop check box. The Importing of Delphi projects and files didn't work very well and was error prone. Eventually I gave up. Lots of setting up of custom paths to compiler and units required for projects - compounded by my importing woes mentioned earlier. Stability While writing this article and generally exploring Lazarus, stabi- lity can be an issue. Trying to create a standard action using the component editor for the action list resulted in an Access Viol- ation that required Lazarus to be restarted. Somehow I managed to get a Debugger error (refer to screen capture). Clicking OK didn't prevent me from debugging the application though.

Figure 4: a debugger error under Mac While I had issues creating a new NIB (or XIB) file modifying the one included when creating the template was a simple. Every control I dropped onto the design surface worked and recompiling the application also worked fine. Conclusion Figure 3: a debugger error under Mac If you want to write Pascal code on your Mac and do not want to Target Widget Type use either a Virtual Machine or Boot Camp then Lazarus and Free The default widget framework used by Lazarus is Carbon. Pascal is an option to keep an eye on. The OSX (I tested under Carbon is the older API although it is still used in a lot of the Leopard – Snow Leopard was released just prior to completing the native Apple applications that come with newer versions of article) version seems a little rough around the edges. If you're a OSX. The new widget set, Cocoa is available although it is listed developer that is interested in writing applications for the Mac in as Pre-Alpha in the LCL Widget Type drop down. When I tried Pascal, certainly check out the Free Pascal and Lazarus to target Cocoa a project failed to compile. combination. I'm sure they'd appreciate any assistance you gave Cross Platform, not so much them with bug reports or submitting fixes to the team behind the Cross Platform seems to be a popular phrase lately. With products. One advantage of Lazarus is, if there is something in it Embarcadero recently announcing it will be creating Linux and that you don't like. You have the on your disk and a OSX compatible compilers. While the details are sketchy at the Build Lazarus menu item in the Tools menu. moment, it has been mentioned that there will not be a version of Next Time: We will convert some component code from Delphi the IDE for the alternate platforms. (VCL) to Free Pascal (LCL), making sure that it runs correctly I created a very simple application in Delphi and saved it on to on OSX as well.

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 21 / 2135 DEVELOPERS 4 Writing Delphi Components II: Custom Properties and Windows Controls by Marco Cantù starter expert DELPHI 3-7 2005..10 Win32 Note: It’s important to name fields, access methods, and properties in a manner consistent with the standards defined by This article is the second of a series introducing a very relevant CodeGear and originally published in the Component Writer’s features of Delphi's architecture, namely writing your own Guide. The basic guidelines are: Use meaningful names for custom components. The first article of this introductory series properties, add an f to the names of fields that correspond to provided an overview of the Delphi Component Wizard and properties, and name access methods as Get or Set plus the showed a first very simple component. Our second component, property name (as in SetStatus and SetColor). covered here, will add some extra properties and events. A Graphical Component with Custom As usual, the Create constructor calls the inherited version of the Properties: The LED constructor (an important step to remember), and then sets the values I’ve specified as property defaults: To show you a more usable graphical component, I’ve built yet another LED component. (LED is an acronym for Light- constructor TCntLed . Create ( Owner : TComponent); Emitting Diode, a solid-state electronic light that’s typically begin used for indicating binary conditions such as the send/receive inherited Create ( Owner ); status of a modem.) Instead of calling it TYALC (for Yet // set default values fColor := clRed ; fStatus := lsOn ; Another LED Component), I’ve called it TCntLed, using the Cnt Width := 20 ; Height := 20 ; prefix after my name. end; The two Set methods follow the standard form: If the new value Here is the declaration of this simple component class. As you is really different from the current one, change the value and can see, there are only two custom properties, and Status: update the . Otherwise, do nothing: procedure TCntLed. SetStatus ( Value : TCntLedStatus); type beg TCntLedStatus = ( lsOn , lsOff ); if Value <> fStatus then begin fStatus := Value ; Invalidate; TCntLed = class (TGraphicControl) end ; private end; fStatus : TCntLedStatus; fColor : TColor ; procedure TCntLed . SetColor ( Value : TColor ); protected begin procedure SetStatus ( Value : TCntLedStatus); if Value <> fColor then begin procedure SetColor ( Value : TColor ); fColor := Value ; Invalidate; public end ; constructor Create ( Owner : TComponent); override ; end; procedure Paint ; override ; published The Paint method is a little more complex than the property property Status : TCntLedStatus methods. First it draws a background circle, which I use as a read fStatus write SetStatus default lsOn; property Color : TColor border, and then an inner circle if the LED is on. To make sure read fColor write SetColor default clRed ; the LED has the correct appearance (they’re almost always property Width default 20 ; round), I check the width and height properties to determine the property Height default 20 ; actual diameter of the LED (I use the smaller of the two values). property OnClick ; property OnDblClick; In a future example, I’ll show you how to use code to impose a end ; relationship between the width and the height of a component. Here’s the Paint method: For the Status property, I’ve defined an enumerated data type (TCntLedStatus), which is more understandable and flexible than a Boolean data type. By convention, you should use the initial letter procedure TCntLed .; Paint var Radius, XCenter , YCenter : Integer ; of the component and property name (ls for LED Status) to build begin the names of the enumerated values (for example, lsOn). // get the minimum between width and height If you examine the property declarations, you notice that I’ve if Height > Width then Radius := Width div 22 - applied the read and write directives to specify how to set or else Radius := Height div 22 - ;

retrieve the property’s current value. For these directives, you can XCenter := Width div 2 ; // get the center specify either a local field of the class, a function (to retrieve the YCenter := Height div 2 ; property), or a procedure that accepts a single parameter of the Canvas . Brush . Color := clDkGray ; // LED border color (fixed) same type (to set the property). Canvas . Ellipse ( In the declaration above, I’ve supplied private variables for the XCenter - Radius , YCenter - Radius , XCenter + Radius , YCenter + Radius ); Status and Color property read directives, and I’ve specified if fStatus = lsOn then begin // led surface procedures for the corresponding write directives. I used Canvas . Brush . Color := fColor ; procedures to set the property values so that I can update the user Radius := Radius - 3 ; interface when the property value changes. Canvas . Ellipse ( XCenter - Radius , YCenter - Radius , XCenter + Radius , YCenter + Radius ); end ; At the end of each property declaration, I’ve provided a default end; value. As you might have guessed, this implies that I’m going to set those values in the component’s constructor, which means I’ll need Instead, I’ve decided to show a similar but different to override it. I’ve declared an overridden version of the Create case—combining several TDdhLed components into a constructor for just this reason. TDdhSemaphore component.

Finally, you’ll notice that I’m overriding the Paint method, A Custom Windows Control: The Fonts Combo specifying default values for some inherited properties, and that Box Many applications have a toolbar with a combo box you I’m publishing several inherited event properties. The new Paint can use to select a font. If you often use such a customized method will allow us to take control of the appearance of the combo box, why not turn it into a component? Doing so will component, the new default property values represent additional probably take less than a minute. work that I’ll need to perform in the constructor, and publishing the inherited events gives us the opportunity to customize the component’s behavior.

Page 22 / 2136 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Writing Delphi Components II (continuation)

To begin, start the Component Wizard, either by choosing Notice that besides giving a new value to the component’s Component ? New Component, or by selecting File ? New ? Style property in the Create method, you redefine this property Other to open the Object Repository and then choosing the by setting a value with the default keyword. You have to do both component in the New page. In the Component Wizard, I've operations because adding the default keyword to a property created a component which inherit from TComboBox. and is declaration has no direct effect on the property’s initial value. Why called TCntFontCombo. specify a property’s default value then? Because properties that The Component Wizard will generate the following source code: have a value equal to the default are not streamed with the form definition (and they don’t appear in the textual description of the unit CntFontCombo; form, the DFM file). The default keyword tells the streaming code interface uses that the component initialization code will set the value of that Windows , Messages , SysUtils , Classes , Graphics , property. Controls, Forms , Dialogs , StdCtrls ; The other redefined property, Items, is set as a property that should type not be saved to the DFM file at all, regardless of the actual value. TCntFontCombo = class (TComboBox) This behavior is obtained with the stored directive followed by the private {Private declarations } protected {Protected declarations } value False. The component and its window will be created again public {Public declarations } when the program starts, so it doesn’t make sense to save in the published {Published declarations } DFM file information that will be discarded later (to be replaced end ; with the new list of fonts). procedure Register; implementation The third property, ChangeFormFont, is not inherited but introduced by the component. It is used to determine whether the procedure Register; current font selection in the combo box should specify the font of begin the form hosting the component. Again, this property is declared RegisterComponents(' Cnt ', [ TCntFontCombo]); end; with a default value, which is set in the constructor. The end. ChangeFormFont property is used in the code of the CreateWnd method, shown earlier, to set up the initial selection of the combo This example doesn’t include much code. You need only copy all depending on the font of the form hosting the component. This is the system fonts to the Items property of the combo box at startup. generally the component’s Owner, although I could also have To do so, you might try to override the Create method in the class walked the Parent tree looking for a form component. This code declaration, adding the statement Items := Screen.Fonts. However, isn’t perfect, but the Assigned and is tests provide some extra this is not the correct approach. The problem is, you cannot access safety. the combo box’s Items property before the window handle of the The ChangeFormFont property and the same if test play a key role component is available; the component cannot have a window in the Changed method, which in the base class triggers the handle until its Parent property is set; and that property isn’t set in OnChange event. By overriding this method, you provide a default the constructor, but later. behavior (which can be disabled by toggling the value of the For this reason, instead of assigning the new strings in the Create property) but also allow the execution of the OnChange event, so constructor, you must perform this operation in the CreateWnd that users of this class can fully customize its behavior. The final procedure, which is called to create the window control after the method, SetChangeFormFont, has been modified to refresh the component is constructed, its Parent property is set, and its window form’s font in case the property is being turned on. The complete handle is available. Again, you execute the default behavior, and code is as follows: then you can write your custom code. I could have skipped the Create constructor and written all the code in CreateWnd, but I procedure TCntFontCombo.; Change decided to use both startup methods to demonstrate the difference begin/ assign the font to the owner form if FChangeFormFont and Assigned ( Owner ) between them. Here is the declaration of the component class: and (Owner is TForm ) then TForm ( Owner ). Font . Name := Text ; inherited; type end; TCntFontCombo = class (TComboBox) private procedure TCntFontCombo. SetChangeFormFont(const Value: FChangeFormFont: Boolean ; Boolean); procedure SetChangeFormFont(const Value : Boolean ); begin public FChangeFormFont := Value ; constructor Create ( AOwner : TComponent); override ; if FChangeFormFont then Change; // refresh font procedure CreateWnd; override ; end; procedure Change ; override ; published property Style default csDropDownList; Temporarily Conclusion property Items stored False ; We have now seen some more about components, although these property ChangeFormFont: Boolean examples are not terribly useful, they should help you get started. read FChangeFormFont write SetChangeFormFont In the next issue we'll go ahead and cover a few more of the many default True ; end ; advanced features of components writing in Delphi. Author And here is the source code of its two methods executed at Marco Cantù is the author of several best-selling startup: Delphi books, including the Mastering Delphi series and the recent Delphi 2009 Handbook. He's also an constructor TCntFontCombo. Create ( AOwner : TComponent); begin active user and developer in the Web 2.0 world and inherited Create ( AOwner ); social web, like . You can reach him on Style := csDropDownList; FChangeFormFont := True ; www.marcocantu.com, blog.marcocantu.com, and end; twitter.com/marcocantu or by email at procedure TCntFontCombo. CreateWnd; [email protected]. begin inherited CreateWnd; Items . Assign ( Screen . Fonts ); // grab the default font of the owner form if FChangeFormFont and Assigned ( Owner ) and (Owner is TForm) then ItemIndex := Items . IndexOf (( Owner as TForm ). Font . Name ); end;

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 23 / 2137 DEVELOPERS 4 My Top Five Delphi 2010 New Features door Pawe³ G³owacki

starter expert DELPHI 2010 Delphi 2010, C++Builder 2010 and Delphi Prism 2010 have been just released. I have put together my own top five new features introduced in Delphi 2010. I'm so excited! The new version of Delphi is now available. Delphi 2010 contains plenty of new features in all areas of the product, including installation, help system, IDE, compiler, VCL and database development. My top five new Delphi 2010 feature list is very subjective and I'm sure every Delphi developer may have a different view on this matter, but here we go… Figure 2: Press F6 to display new IDE “Insight” dialog for easy keyboard access to anything.

There are a number of new usability features in the debugger. It is now much easier to debug a multithreaded application and the debugger now allows for stepping and debugging within selected threads. You can selectively "freeze" and "thaw" threads so that debugging activity can be isolated to a particular thread or threads. When a thread is frozen, it will not actually run and no debug events will occur in the context of that thread. You can access this functionality in the Thread Status view by using one of the four new context menu items: "Freeze", "Freeze All Other Threads", Figure 1: Splash screen "Thaw" and "Thaw All Threads". You can also set a breakpoint for

5. IDE Usability It is all about the productivity of a Delphi . If you are like me, you spend a big part of your day inside the IDE – Integrated Development Environment. I still wonder if there are any limits for creative ideas related to developer tools productivity. Delphi has an excellent tradition here. invented the IDE by putting together three formerly separate entities – code editor, compiler and debugger. Delphi 1 pioneered Rapid Application Development, introducing the concept of a component - an object instance that can be manipulated visually at design-time. Some of the capabilities introduced in Delphi 1, like live data at design time, are still unavailable in other IDEs.

I expect one of the biggest productivity wins is with using the brand new “IDE Figure 3: Source code formatter options Insight”. Just press F6 and it does not matter where you are in the IDE, you are presented with the list of a selected thread. What is even more intriguing is support for so possible commands available in a given context. For example the called “debug visualizers”. To make debugging programs much list of options will be different when you are in the code editor and easier, custom data viewers/data visualizers in the debugger different when you are in the forms designer. You can also start provide a way to view data other than using the standard output typing the name of the thing that you need and the IDE Insight from the evaluators. The Open Tools API supports the dialog will do incremental filtering as you type. As you can see in development of custom visualizers for data types. There are Figure 2, it is also possible to use pattern matching if you include sample visualizers for several data types in RAD Studio 2010, “*” character in the pattern. including the TDateTime, TDate, and TTime types and the std::string and std::wstring instances for C++. Another very much anticipated feature is the code formatter for Delphi and C++ source files. You can format either the whole file or just a selection of code in the code editor. This will be a very useful feature when you are maintaining source code formatting standards across different projects in your organization or maybe you have inherited some source code and you are just used to different formatting. Select a block of code and hit Ctrl+D and your selection will be instantly formatted according to the preferences set in the Code Formatter Options. You can see the code formatter options in Figure 3

Page 24 / 2138 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 My Top Five Delphi 2010 New Features (continuation 1)

Consider Figure 3, with the Delphi code has a breakpoint set at There is plenty of other IDE usability improvements, both big line 36. and small, like the new “Search” bar which is very similar to the procedure TForm21. Button1Click( Sender : TObject ); Firefox web browser, improved “Find in Files” dialog, var draggable bookmarks and breakpoints, an improved “Use Unit” SL : TStringList; dt : TDateTime; begin dialog where you can specify if you want to add a given unit to dt := Now ; SL := TStringList.; Create “interface” or “implementation” section of a unit, a new try “Reopen Menu Properties” dialog, an option to disable code SL . Add ( TimeToStr( dt )); folding in the editor and a number of new Open Tools API for SL . Add ('Delphi' ); SL . Add ('C++Builder'); customizing the IDE, including possibility to embed custom tabs ListBox1 . Items . Assign ( SL ); // <-- set a breakpoint here inside the IDE, and many more. finally SL . Free ; 4. Native Direct2D support end ; RAD Studio 2010 provides new “Direct2D.pas” unit where you end; can find a brand new “TDirect2DCanvas” class and helper Figure 4: Consider this breakpoint classes like “TDirect2DFont”, “TDirect2DPen” and “TDirect2DBrush”. But, what is Direct2D? It is a new Windows The Local Variables view in Figure 4 shows both visualizers in 7 graphics API that provides high performance and high quality action. “dt” variable, which internally is just a float, is displayed rendering for 2-D geometry, bitmaps, and text. Applications that as human readable date/time value. The “SL” variable has a use Direct2D for graphics can deliver much higher visual quality magnifying glass icon next to it, and the context menu “Show than can be easily achieved using GDI. Direct2D uses per- Strings”. When clicked you can actually see strings stored inside primitive anti-aliasing to deliver smoother-looking curves and the “SL” string list. lines in rendered content. There is also full support for transparency and alpha-blending when rendering 2-D primitives. Why is Direct2D so mighty? Because it is implemented in native code and Delphi provides native VCL wrappers for programming with Direct2D. Kenny Kerr in his “Introducing Direct2D” MSDN Magazine article (May 2009) says that “if you want to develop high-performance and high-quality commercial applications, you'll still look to C++ and native code to deliver that power.” Delphi developers could not agree more with this statement . The “TDirect2DCanvas” class gives Delphi and C++Builder programmers familiar “TCanvas” abstraction for doing Direct2D programming. Sweet! 3. Custom Attributes and new RTTI Delphi 2010 adds custom attributes to the Delphi language. This feature has been available in the past for the Delphi for .NET compiler, and is now available for native Delphi programming. Custom attributes make it possible to add arbitrary custom metadata information to your code. You can apply custom attributes to types, methods, arguments and even function results. Figure 5: Data visualizers make clearer and debugging easier If you want to define a custom attribute, you just need to derive and faster a new class from “TCustomAttribute” type. By convention names for custom attributes do not start with canonical Delphi RAD Studio 2010 makes it possible to author your own “T”. Custom attributes can have constructors like other Delphi visualizers for any custom type using new Open Tools API. You classes, however you can only pass simple types to attributes can verify which visualizers are installed in the new “Registered constructors. Visualizers” tab in the “Options” dialog as shown in Figure 6. Why would I want to use custom attributes? What are they good for? That's a good question. Let's imagine a custom Object-Relational Mapping solution where you want to map Delphi classes to database table names and object properties to column names. With custom attributes you can just mark your class and methods with custom attributes and store mappings as part of a class declaration. You could also use attributes to keep URLs to help topics in a web-based documentation system. Figure 6 shows the definition of “DocAttribute” that has “URL: string” property. Note that “TCustomAttribute” class is defined in the “system” unit.

Figure 6: An example of registered debugger data visualizers

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 25 / 2139 DEVELOPERS 4 My Top Five Delphi 2010 New Features (continuation 2)

unit uAttributes; uses RTTI , uClasses , uAttributes; interface {$R *.dfm} type DocAttribute = class (TCustomAttribute) procedure TForm2. Button1Click( Sender : TObject ); private var FURL : string ; ctx : TRttiContext; public t : TRttiType; constructor Create ( URL : string ); m : TRttiMethod; property URL : string read FURL write FURL ; a : TCustomAttribute; end ; begin ListBox1 . Clear ; implementation ctx := TRttiContext.; Create {DocAttribute } try t := ctx . GetType ( TMySuperClass); constructor DocAttribute. Create ( URL : string ); for a in t . GetAttributes do begin if a is DocAttribute then FURL := URL ; ListBox1. Items .( Add Format end; ('Type = %s; Attribute = %s, URL = %s', [TMySuperClass. ClassName, a . ClassName, end. DocAttribute( a ). URL ])); Figure 7: The definition of “DocAttribute” and class of type for m in t . GetMethods do TCustomerAttribute for a in m . GetAttributes do if a is DocAttribute then ListBox1.. Items Add Figure 8 shows a hypothetical definition of “TMySuperClass” ((Format 'Type = %s; Method = %s; Attribute = %s, URL = %s', decorated with custom documentation attributes. [TMySuperClass. ClassName, m . Name , uses uAttributes; a. ClassName, DocAttribute( a ). URL ])); type finally ctx . Free ; [Doc ('http://www.xyz.com/docs/23456')] // I'm skipping end ; "...Attribute" here! end; TMySuperClass = class public Figure 10: Querying custom attributes in code [DocAttribute('http://www.xyz.com/docs/12345')] procedure DoSomething; end ; Figure 8: TMySuperClass and DocAttribute use OK. So, what next? How do I query for attributes in code? Another great new feature of Delphi 2010 is support for new generation RTTI with capabilities similar to .NET/Java Reflection. There is brand new “rtti.pas” unit that provides types and methods for inspecting types. As you can see in Figure 8 (upper right corner), the starting point for using RTTI in code is creating an instance of “TRttiContext” class.

2. Touch, Multitouch and Gesturing Do you own iPhone? There is something natural in touching the screen and expecting something to happen. Touch is perceived as a natural evolution of human interactions with a computer. Delphi 2010 introduces support for touch interfaces at the level of the VCL library and this means that touch is supported not only on Windows 7, but also on all other versions of Windows supported by Delphi 2010. “TControl” class introduces “OnGesture” event and “DoGesture” virtual method that can be overridden in descendant classes. The VCL contains 34 built-in simple gestures and 5 interactive gestures. If you want to do more low level coding, you can intercept Windows WM_TOUCH Figure 11: How Zorro would define a custom gesture message, but it is easier to just implement event handlers for You just need to drop the “TGestureManager” component on a gestures you are interested in. Delphi 2010 also makes it possible form, connect it via the Form's “GestureManager” property and to define your own gestures, like my “Zorro” gesture in Figure you are up and running. Figure 12 (next page) shows the 11, and also embed in a Delphi application custom gesture editor “GestureManager” property. to let the end-users define their gestures.

Figure 9: Attributes listing When you click on the button you get the result

Page 26 / 2140 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 My Top Five Delphi 2010 New Features (continuation 3)

Figure 14: New DataSnap WebBroker Application Wizard

In the case of WebBroker-based application you can only use Figure 12: Setting Gestures in the Object Inspector. HTTP transport. Hosting DataSnap servers inside a web server It is probably the most elegant solution to use “TActionList” or has the advantage of starting server instances on demand. “TActionManager” component and hook individual gestures to That's a completely new dimension to DataSnap. It is such a “Action.Execute” event handlers. pleasure to observe how this technology has evolved with every For simple gestures you do not need to have touch-enabled new release of Delphi. Delphi 2007 introduced a completely hardware. You can imitate gestures with a mouse. rewritten new implementation of the dbExpress database driver architecture, in pure Delphi code. Then, Delphi 2009 provided 1. Datasnap 2010 brand new support for DataSnap client/server architecture New DataSnap 2010 features are my absolute number one. I was through extending dbExpress. hoping to see HTTP support in the new version of Delphi, but DataSnap connectivity is implemented as a special dbExpress there is much more. First of all there are two new DataSnap driver that unlike a normal driver, does not talk to a database, but wizards. One to create a standalone DataSnap server application rather knows how to communicate with DataSnap servers. packaged as “VCL Forms Application”, “Console Application” Delphi 2010 adds support for HTTP communication between or “Service Application”, supporting TCP and/or HTTP DataSnap clients and servers. There is also new support for communication as shown in Figure 13. server callbacks and passing data as JSON. Another interesting new feature is support for exposing DataSnap server methods as REST interfaces. Finally, it is now very easy to process a communication stream between client and server via implementing a custom filters. Delphi 2010 comes with compression filter out of the box.

Summary Recently released Embarcadero RAD Studio 2010 contains many new features including IDE usability improvements, support for touch, new Delphi language features and DataSnap 2010 architecture for component-based development of multitier systems. In this article, I have selected my personal top five, but there is much more in Delphi 2010, C++Builder 2010 and Delphi Prism 2010 then described here.

Try it for yourself! http://www.embarcadero.com/products/rad-studio

[email protected] Figure 13: New DataSnap Server Wizard or visit his blog on The second wizard let you create DataSnap Server WebBroker http://blogs.embarcadero.com/pawelglowacki application as shown in Figure 13. How cool is that?

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 27 / 2141 DEVELOPERS 4 Fast Graphic deformation by using Scanlines by Peter Bijlsma The SrcRect and DestRect rectangles (type TRect) have a Sometimes it's necessary to manipulate picture height of Ns (number of scanlines) and a width of Ls (Length of representations, e.g. to correct the perspective. Programs like scanlines). Next, the scanlinepointers of an area to be manipulated Photoshop have that functionality: buildings who are leaning must be copied to a dynamic array of type pPixArray, called towards each other can be set straight in no time. How can we ScanlinSel: accomplish such a deliberate deformation? We know, either by SetLength( ScanlinSel, Ns ); own experience or by reading articles or books about for I := 0 to Ns -1 do ScanlinSel[ I ] := OBM. Scanline[ I ]; Now we can reach each pixel as for instance ScanlinSel[Y][X].R programming, that routines manipulating images on pixel- points to the Red byte of pixel number X in row number Y of the level are very slow. Older Pascallers (like me) will remember OBM involved. But as we will see, in most cases we don't need the Putpixel procedure and our, sometimes desperate, attempts access to the separate Red, Blue or Green components. to learn enough machine language to make our routines faster In the following sections I'll describe procedures to deform the by using Inline code. Nowadays we do not have only faster selected area (and consequently the adjacent areas). For this “machines”, but also the programming possibilities developed. purpose we use another bitmap (VirtBM) in which the Delphi gave us a powerful property to bitmaps: Scanlines. This scanlinepointers of the manipulated areas are stored temporarily. article will describe the use of scanlines in connection with a program called “Deform!”. Linear Distortion With Linear Distortion I mean that the pixels in the original Scanlines bitmap copy OBM are stretched or compressed only in the X and The Bitmap.Scanline property is a the Y directions. The selected area is leading and the adjacent pointer to a horizontal row of pixels areas are changed synchronously to warrant smooth transitions in an image. As this property is read- between the various areas. See figure 2 for the process. The first only, we must make a copy of the image (at left) is the original image, in the next image the mouse scanlinepointers in order to be able cursor is used to draw a rectangle: the selected area. In the third to control the pixels in these rows (or image the rectangle is deformed by grabbing the sides with the lines) ourselves. In this copying- mouse cursor and moving them to other positions. The last process we can also enhance the image at right shows us the result. “granularity” of the pointers, so that we can address not only the separate pixels in a line, but also the Red, Blue and Green components of these pixels. This is done by defining a new type in the header of our program:

type TPixCol = record //sequence is Blue, Green, Red in scanlines Figure 2 Linear Distortion Process B : byte ; G : byte ; R : byte ; end ; Each area (OBM[0] through OBM[8]) is in this process TPixArray = array [0..5000 ] of TPixCol ; //5000 lines is enough deformed in the X and the Y direction. This is done in the for our use procedure LinearDistort, which puts the result in VirtBM. After pPixArray = ^TPixArray; copying VirtBM back to the original bitmap (this happens nine times), the process is completed. Now we see the need to store a Suppose we select an area of our image in Image1 (we'll call this copy of the original in OBM first: because the new (deformed) “main image”) by drawing a rectangle around the part we want to areas can overlap the original areas. The procedure LinearDistort manipulate. We copy this area into a new bitmap, OBM[0], needs the number of selected scanlines, the length of the selected which then contains a copy of the original pixels of the selected scanlines, the number of new scanlines in VirtBM and the length part of our image. By doing the same for the adjacent areas we of the new scanlines as parameters. obtain 9 bitmaps, see figure 1: The procedure is as follows: procedure TForm1. LinearDistort( NmbSelSLs, LenSelSLs, NmbVirtSLs, LenVirtSLs: Integer ); var Ysel , Yvirt , J , CyW : Integer ; CyF , Fry , Xfact , Yfact: Single ;{sub-procedure FillXVirt is incorporated here:} procedure FillXvirt; //stretch-shrink horizontal lines, see later begin || end begin VirtBM . Width := LenVirtSLs; VirtBM . Height := NmbVirtSLs; SetLength( ScanlinVirt, NmbVirtSLs); for J := 0 to NmbVirtSLs-1 do ScanlinVirt[ J ] := VirtBM. ScanLine [ J ]; Yfact := NmbVirtSLs/ NmbSelSLs; //factor to stretch-shrink vertically Xfact := LenVirtSLs/ LenSelSLs; //factor to stretch-shrink horizontally Yvirt := 0 ; CyF := 0.5 ; Figure 1: Selected area and adjacent areas in main image CyW := Trunc ( Yfact ); Fry := Frac ( Yfact ); copied to OBM bitmaps for Ysel := 0 to NmbSelSLs-1 do begin if CyW >0 then for J := 1 to CyW do begin The bitmap copies are stored using the CopyRect FillXvirt; inc ( Yvirt ); procedure: end ; CyF := CyF + Fry ; for I := 08 to do begin if CyF >= 1 then begin SrcRect [ I ] := Rect{corner coordinates of area}; FillXvirt; inc ( Yvirt ); DestRect := Rect (00 , , Ls [ I ], Ns [ I ]); CyF := CyF - 1 ; OBM [ I ]. Height := Ns [ I ]; end ; OBM [ I ]. Width := Ls [ I ]; end ; OBM [ I ]. Canvas . CopyRect ( DestRect , Image1 . Canvas , SrcRect [ I ]); end; end;

Page 28 / 2142 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Fast Graphic deformation by using Scanlines (continuation 2)

In the next part of the procedure the Start point array (SPar) and The pixel positions are calculated in the sub-procedure End point array (EPar) are filled. The lengths of these arrays are PlotPixel both equal to the longest side. The algorithm starts always with procedure PlotPixel; the longest side and compresses the other side in a similar way as begin we did for Linear Distortion. This is done by storing in ScanlinImg[ Ye ][ Xe ] := ScanlinVirt[ I ][ Xb ]; subsequent array values of the shortest side equal Y values where if Ye +1 < Image1 . Picture . Height - 2 then ScanlinImg[ Ye +1 ][ Xe ] := ScanlinVirt[ I ][ Xb ]; // avoid necessary. Because the shrink-factor is always equal to or smaller empty pixel positions than one, no CyW counter is needed: if abs ( ALin )>0.9 then begin if Ye +3 < Image1 . Picture . Height - 2 then begin NmbVirtSLs := max ( BegLo . Y - BegHi . Y , EndLo . Y - EndHi . Y ) + 1 ; ScanlinImg[ Ye +2 ][ Xe ] := ScanlinVirt[ I ][ Xb ]; SetLength(, SPar NmbVirtSLs); ScanlinImg[ Ye +3 ][ Xe ] := ScanlinVirt[ I ][ Xb ]; SetLength(, EPar NmbVirtSLs); end ; if NmbVirtSLs = BegLo .- Y BegHi .+ Y 1 then begin // begin of shape end ; is longest inc ( Xe ); Fry := Frac (( EndLo . Y - EndHi . Y +1 )/( BegLo . Y - BegHi . Y +1 )); if Xe > Image1 . Picture . Width - 1 then Xe := CyF := 0.5 ; I := 0 ; Image1. Picture . Width - 1 ; if Fry = 0 then Fry := 1 ; // heights are equal Ye := round ( ALin * Xe + BLin ); Ye := EndHi . Y ; Xe := EndHi . X ; if Ye > Image1 . Picture . Height - 1 then Ye := for Yb := BegHi . Y to BegLo . Y do begin Image1. Picture . Height - 1 ; SPar [ I ]. Y := Yb ; if Ye < 0 then Ye := 0 ; if ABeg =1e9 then SPar [ I ]. X := BegHi . X end; else SPar [ I ]. X := round (( Yb - BBeg )/ ABeg ); EPar [ I ]. Y := Ye ; To avoid too many complicated calculations, I did not give any EPar [ I ]. X := Xe ; CyF := CyF + Fry ; thoughts about anti-aliasing or the like. However, plotting the if CyF >= 1 then begin virtual scanlines could result in “empty” places, as each X position inc ( Ye ); has only one Y position. This is illustrated in figure 4: if AEnd =1e9 then Xe := EndHi . X else Xe := round (( Ye - BEnd )/ AEnd ); CyF := CyF - 1 end ; inc ( I ); end ; end else begin // end of shape is longest Fry := Frac (( BegLo . Y - BegHi . Y +1 )/( EndLo . Y - EndHi . Y +1 )); CyF := 0.5 ; I := 0 ; if Fry = 0 then Fry := 1 ; Yb := BegHi . Y ; Xb := BegHi . X ; for Ye := EndHi . Y to EndLo . Y do begin SPar [ I ]. Y := Yb ; SPar [ I ]. X := Xb ; EPar [ I ]. Y := Ye ; if AEnd =1e9 then EPar [ I ]. X := EndHi . X Figure 4: Empty pixel positions appear when plotting else EPar [ I ]. X := round (( Ye - BEnd )/ AEnd ); virtual scanlines CyF := CyF + Fry ; This problem is solved simply by plotting two (Ye and Ye + 1) if CyF >= 1 then begin inc ( Yb ); pixels for each X position. After all, if the additional pixel is if ABeg =1e9 then Xb := BegHi . X superfluous, the next line will overwrite this position else Xb := round (( Yb - BBeg )/ ABeg ); automatically. For very steep lines even more Y values are CyF := CyF - 1 end ; plotted for the same X. inc ( I ); end ; A short note about the huge gain in speed when scanlines are end; used as opposed to direct pixel addressing. Replace the code of The final part of DynamicDistort calculates the pixel positions of the “for Xb”-loop into: the virtual scanlines in “real” coordinates. Use is made of the //Image1.Canvas.Pen.Mode := pmCopy; must be set before formula Y = A * X + B, where the coefficients A and B must be For Xb := 0 to NmbOrgPix-1 do begin calculated for each virtual scanline. Next, the calculated pixel PixCol := ScanlinVirt[ I ][ Xb ]. R + ScanlinVirt[ I ][ Xb ]. G positions are assigned to the real scanline pointers of the shl 8 + ScanlinVirt[ I ][ Xb ]. B shl 16 ; Image1 . Canvas . Pen . Color := PixCol ; if CxW > 0 then for ScanlinImg array, which holds a copy of the BitmapImg scanlines J := 1 to CxW do begin of the main picture in Image1. Image1 . Canvas . Pixels [ Xe , Ye ] := PixCol ; I NmbVirtSLs for I := 0 to NmbVirtSLs-1 do begin if < -1 then Image1. Canvas . Pixels [ Xe , Ye +1 ] := PixCol ; NmbNewPix := EPar [ I ]. X - Spar [ I ]. X + 1 ; // different for each line inc ( Xe ); if SPar [ I ]. X = EPar [ I ]. X then begin Ye := round ( ALin * Xe + BLin ); ALin := 1e9 ; BLin := 0 ; end end ; else begin CxF := CxF + Frx ; ALin := ( SPar [ I ]. Y - EPar [ I ]. Y )/( SPar [ I ]. X - EPar [ I ]. X ); if CxF >=1 then begin BLin := SPar [ I ]. Y - ALin * SPar [ I ]. X ; Image1 . Canvas . Pixels [ Xe , Ye ] := PixCol ; end ; if I < NmbVirtSLs-1 then CxW := Trunc ( NmbNewPix/ NmbOrgPix); Image1. Canvas . Pixels [ Xe , Ye +1 ] := PixCol ; Frx := Frac ( NmbNewPix/ NmbOrgPix); inc ( Xe ); CxF := 0.5 ; Ye := round ( ALin * Xe + BLin ); Xe := SPar [ I ]. X ; CxF := CxF - 1 ; Ye := round ( ALin * Xe + BLin ); end ; if Ye > Image1 . Picture . Height - 1 then Ye := end; Image1. Picture . Height - 1 ; if Ye < 0 then Ye := 0 ; for Xb := 0 to NmbOrgPix-1 do begin In this procedure the correct colours are directly assigned to the if CxW > 0 then for J := 1 to CxW do PlotPixel; CxF := CxF + Frx ; pixels of Image1. Although this direct approach seems more if CxF >=1 then begin efficient, the routine is annoyingly slow. Try this example just to PlotPixel; learn that one should use scanlines instead! CxF := CxF - 1 ; end ; end ; Summarized, the code to change the content of all nine areas (see end; figure 1) in a random way is:

Page 30 / 2144 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Fast Graphic deformation by using Scanlines (continuation 1)

In this procedure first the scanlinepointers to VirtBM are copied Dynamic Distortion to the array ScanlinVirt. Like ScanlinSel, ScanlinVirt is a Where in linear distortion the sides of the selected area could dynamic array of type pPixArray. To stretch or shrink the only be moved in the X and/or the Y direction to reshape the pixelarrays in OBM (copy of the original, array ScanlinSel area, for dynamic distortion the corners of the selected area can points to these pixels) to the deformed ones in VirtBM (with be moved in any direction. This means that one side of the area pointers ScanlinVirt) the proportion-factors must be calculated can be stretched while the other (opposite) side can be first. If for instance the height of the bitmap in VirtBM is a compressed. Although the resulting area can now have an odd quarter bigger than the original in OBM and the width is a three shape, the adjacent areas must follow the selection to warrant quarters of the original, factors Yfact and Xfact become 1.25 smooth transitions, see figure 3: and 0.75 respectively. The truncated whole number (1 in this case for Y) is stored in CyW and the fraction (0.25) in Fry. For The first image (at left) is the original image, in the next image each Y value in the selected area the procedure determines the mouse cursor is used to draw a rectangle: the selected area. whether and how often Ysel must be copied to the new pointer In the third image the rectangle is deformed by grabbing the Yvirt. If counter CyW is greater than zero, CyW new lines are corners with the mouse cursor and moving them to other generated, while counter CyF generates a new line when the positions. The last image at right shows us the result. sum of the fractions during the loop add up to at least one. In our example this means that each time after four loops an additional line is generated. To obtain a better distribution I've preset counter CyF to 0.5.

The new lines are generated in sub-procedure FillXvirt. This procedure takes care that the length (X direction) of the new lines are calculated using the factor Xfact. The same algorithm is used as for the Y direction described above, but Figure 3 Dynamic Distortion Process The random shapes of the areas make the calculations of the now a random number deformed pixel positions rather complicated. I decided to tackle between 0 and 1 is used as this problem in various steps: preset for CxF to avoid loss of information in the event of 1. Copy the selected area and the eight adjacent areas in very thin vertical lines: OBM[0..8], see figure 1, as in linear distortion. 2. After reshaping the selected area to the desired form, call procedure FillXvirt; //stretch-shrink horizontal lines var Xvirt , Xsel , I , CxW : Integer ; for each area the procedure LinearDistort, but stretched only CxF , Frx : Single ; in the Y direction to the height of the longest side. This is begin done to obtain the required number of scanlines for the Xvirt := 0 ; CxF := random ; actual dynamic distortion process. CxW := Trunc ( Xfact ); Frx := Frac ( Xfact ); for Xsel := 0 to LenSelSLs-1 do begin 3. Call for each area the procedure DynamicDistort, using the if CxW >0 then for I := 1 to CxW do begin corner points of the shape as parameters. Calculate the ScanlinVirt[ Yvirt ][ Xvirt ] := ScanlinSel[ Ysel ][ Xsel ]; position of each pixel in a virtual scanline which starts from inc ( Xvirt ); a point on the left side of the modified shape and ends at a end ; CxF := CxF + Frx ; point at the right side of the shape. The start and end points if CxF >= 1 then begin have different Y positions and the lines have different ScanlinVirt[ Yvirt ][ Xvirt ] := ScanlinSel[ Ysel ][ Xsel ]; lengths. As the number of scanlines is fixed to the longest inc ( Xvirt ); side, some values on the other (shorter) side can be the CxF := CxF - 1 ; end ; same. end ; 4. Map the calculated pixels of the virtual scanlines to the end; original bitmap of the main image. The pointers to ScanlinSel are now copied to the pointers of The DynamicDistort procedure starts with calculating the desired ScanlinVirt dependent upon the size of the new bitmap VirtBM. begin and end points of the virtual scanlines. By using the formula After looping through LinearDistort, VirtBM contains the X = (Y-B)/A an X position is calculated for each Y position on the deformed bitmap of one area, which can subsequently be left and the right side of the modified shape. These points are transferred to the main image through the Canvas.Draw stored in arrays SPar (start points) and EPar (end points), forming procedure. Summarized, the code to change the content of all two lines being the left and right side of the shape. Coefficients A nine areas (see figure 1) in a linear way is: and B can be calculated from the corner coordinates which are for J := 08 to do begin given to the procedure as parameters: SetLength( ScanlinSel, Ns [ J ]); procedure TForm1. DynamicDistort( BegLo , BegHi , EndLo , if (Lsv [ J ]>0 ) and (Nsv [ J ]>0 ) then begin EndHi: TPoint ; NmbOrgPix: Integer ); for I := 0 to Ns [ J ]-1 do ScanlinSel[ I ] := OBM[ J ]. ScanLine [ I ]; Special care must be taken when a line is exactly vertical: LinearDistort( Ns [ J ], Ls [ J ], Nsv [ J ], Lsv [ J ]); //result in VirtBM if BegHi . X = BegLo . X then begin ABeg := 1e9 ; BBeg := 0 ; Image1 . Canvas . Draw ( SPoint [ J ]. X , SPoint [ J ]. Y , VirtBM ); end end ; else begin end; ABeg := ( BegHi . Y - BegLo . Y )/( BegHi . X - BegLo . X ); BBeg := BegHi . Y - ABeg * BegHi . X ; Where Ns and Ls are the number and length of the original end; if EndHi . X = EndLo . X then begin AEnd := 1e9 ; BEnd := 0 ; scanlines, Nsv and Lsv are the number and length of the new end (deformed) scanlines and SPoint (of type TPoint) is on the main else begin AEnd := ( EndHi . Y - EndLo . Y )/( EndHi . X - EndLo . X ); image the upper left-hand corner where the deformed bitmap BEnd := EndHi . Y - AEnd * EndHi . X ; should be placed.

October 2009 BLAISE PASCAL MAGAZINE 8 Page 29 / 2143 COMPONENTS DEVELOPERS 4 Fast Graphic deformation by using Scanlines (continuation 3)

SetLength( ScanlinImg, Image1 . Picture . Height ); out, this is an easy way to reduce your X-megapixel high- for I := 0 to Image1 . Picture . Height - 1 do resolution photographs to an acceptable size for use on the ScanlinImg[ I ] := BitmapImg. ScanLine [ I ]; for J := 08 to do begin SetLength( ScanlinSel, Ns [ J ]); internet. The procedure takes care that the image fits best on your if Nsv [ J ]>0 then begin working area: for I := 0 to Ns [ J ]-1 do ScanlinSel[ I ] := procedure TForm1. BtScreenFitClick( Sender : TObject ); OBM [ J ]. ScanLine [ I ]; var I , PH , PW , CH , CW : Integer ; LinearDistort( Ns [ J ], Ls [ J ], Nsv [ J ], Ls [ J ]); Aspect : single ; // first stretch to correct height begin SetLength( ScanlinSel, Nsv [ J ]); UndoBM.( Assign BitmapImg); //save original DynamicDistort( CornerLftlo[ J ], CornerLfthi[ J ], PH := Image1 . Picture . Height ; CornerRgtlo[ J ], CornerRgthi[0 ], Ls [ J ]); PW := Image1 . Picture . Width ; end ; CH := Image1 . Height ; Image1. Picture . Bitmap := BitmapImg; CW := Image1 . Width ; end; if (PW <=0 ) or (CW <=0 ) then exit ; Aspect := PH / PW ; if Aspect > CH / CW then CW := Trunc ( CH / Aspect ) else For Ns, Ls and Nsv see the section Linear Distortion. The Corner- CH := Trunc ( CW * Aspect ); variables are of type TPoint and refer to the four corners of the SetLength( ScanlinSel, PH ); distorted area. The actual code, however, is slightly different. The for I := 01 to PH - do ScanlinSel[ I ] := complete source code (belonging to the program “Deform!”) can, BitmapImg. ScanLine [ I ]; LinearDistort( PH , PW , CH , CW ); as usual, be downloaded from the website. This brings us to: BitmapImg.(); Assign VirtBM Image1 . Picture . Bitmap := BitmapImg; The Program “Deform!” end; The program “Deform!” utilizes the procedures as described in The Distortion buttons are grouped together. After clicking the previous paragraphs. The program can be used to deform one of these, an area can be selected by holding down the left photographic or other images. Sometimes for a good reason, mouse button and dragging the cursor over the image. Upon such as the straightening of objects or correcting the perspective, “Button Up” the area is fixed. The program contains but also just for fun. See figure 5. obviously CursorButtonDown, Move and Up procedures, but I will not describe them here to save space. I only tell that, as the mouse routines are shared by all distortion modes, Booleans are used to control the process.

LOAD IMAGE After “Distort Linear” has been clicked, the area set can be deformed by grabbing (mouse cursor and left button) the four Fit To Screen sides of the area and drag them to the desired positions. On

DISTORT clicking “Go” the LinearDistort procedure is called nine times LINEAIR DISTORT (once for each sub-area, see figure 1) causing the image to INNER AREA DISTORT ALL reshape according to figure 2. MIRROR R MIRROR L When “Distort Inner Area” has been clicked, a special use CROP of the DynamicDistort procedure is made. The area is now GO! UNDO divided into four equal pieces. Only the centre point can be moved and after clicking “Go” the four areas are deformed by SAVE IMAGE calling LinearDistort followed by DynamicDistort four times, SAVE AS ICON see figure 6: CLOSE PROGRAM The first image (at left) is the original image, in the next image the mouse cursor is used to draw a rectangle: the selected area. In the third image the rectangle is deformed by grabbing the centre point with the mouse cursor (plus left button) and moving it to another position. This process is called “Warp” in other programs. The last image at right shows us the result after clicking “Go”. The part of the image outside the selected area is not affected, so in this mode not the whole picture is deformed. Figure 5 “Deform!” can change your images

All buttons are located at the left-hand side, which enables the bitmap image in Image1 (at right) to follow the size of the window when it is resized by the user. As I admire the lady on the example image very much, I use a black Figure 6 Dynamic Distortion Process for a single point bar to make her unrecog- nizable. The user can load either a JPG or a BMP image by clicking “Load Image”. Be careful with the “Fit to Screen” button: this is not a zoom function, but it changes the actual number of pixels. See for instance what happens when you load a picture, drag the right side of the window as far as possible to the left, click “Fit to Screen”, maximize the window and click “Fit to Screen” again. The image will be barely recognizable. The “Fit to Screen” process makes use of the LinearDistort procedure to resize, so complete rows and columns of pixels are thrown away by reducing the size. However, as you will find

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 31 / 2145 DEVELOPERS 4 Fast Graphic deformation by using Scanlines (continuation 4)

When “Distort All” has been clicked, the area set can be deformed Conclusion by grabbing (mouse cursor and left button) the four corner points May be after clicking “Go” you didn't get the result you'd of the area and drag them to the desired positions. After clicking expected. No problem, after clicking “Undo” the former image is “Go” the LinearDistort and DynamicDistort procedures are called put back on the screen. But be careful: there is only one undo nine times (once for each sub-area) and the image is reshaped level! Of course you can utilize several distortion modes after according to figure 3. each other. This may result in a picture like in figure 8: When the final result is satisfactory, you can save the image (as When “MirrorR(ight)” or “MirrorL(eft)” has been clicked, the JPG or BPM) by clicking “Save Image”. As a special feature I selection area is split by a vertical division line in the centre. See added a “Save as Icon” possibility. This button can be used to figure 7, second image (as this gentleman doesn't sing as good as make your own icons without using an icon-editor. The icon the lady of figure 5, I didn't use the black bar this time): attached to this program is made with this procedure. Before using, crop your image to obtain an approximately square area. However, don't set your expectations too high: as an icon has an area of only 32 x 32 pixels, hi-res pictures or photographs can hardly be used for this process. Making a program like this is like eating peanuts: once you've started it's not easy to stop. You always think of another nice useful or funny feature to add. Be my guest, download the source code and add anything you like. In the “Distort Inner Area” for instance two points can be used instead of only one point, or even four points. Anyway, have fun playing, changing or just using this program.

See you next time...

Figure 7 The Mirror process MirrorR causes the right side of the selection to be mirrored to the left side (third image) and MirrrorL does the opposite (fourth image). So this mode can be used to make faces (or objects) symmetrical. The code is rather simple: begin SetLength( ScanlinSel, Ns [0 ]); for I := 0 to Ns [ 01 ]- do ScanlinSel[ I ] := OBM[0 ]. ScanLine [ I ]; for I := 0 to Ns [ 01 ]- do for J := 0 to (Ls [ 02 ]- ) shr 1 do Figure 8 A possible final result if MRight then ScanlinSel[ I ][ J ] := ScanlinSel[][[]--] I ls01 J else ScanlinSel[ I ][ ls [01 ]- J - ] := ScanlinSel[ I ][ J ]; Peter Bijlsma Image1 . Canvas . Draw ( Sel [3 ]. X , Sel [3 ]. Y , OBM [0 ]); was born in the Netherlands in 1946. He studied electronics end; and took a course in Algol. In 1982 he became the proud owner of an Apple II computer, and he programmed in Basic OBM[0] contains, as usual, a copy of the original selected area and 6502 assembly language. He learned other languages and Sel[3] (TPoint) is the upper left-hand corner of the selected (Pascal, ) by self-study. area. He worked as a Technical Communication specialist, writing technical manuals and acting as an instructor for military command & control systems. Later he wrote software in The last mode is “Crop”. If after several distortions you want to order to covert XML-based text into websites, CD-ROMs with save the created image, the edges may be deformed in an PDF files, and 'old-fashioned' manuals. He is now retired. undesirable way. These edges can be cut off by selecting the [email protected] “good” area after “Crop” has been selected. Clicking “Go” causes that the new main image will be just the selected area: Image1.Picture.Bitmap := OBM[0];

Page 32 / 2146 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Wide Information Bus (Introduction) by Fikret Hasovic starter expert DELPHI 3-7 2005..10 Win32 All of the pc's and servers on this image are all nodes in the Publish/subscribe type of information transfer has become a publish/subscribe world. hot subject lately, and its not without reason. However some of the nodes also act as kbmMW application servers, and some of the other nodes also act as kbmMW clients. The great thing about publish/subscribe is that its a loosely Its easy to compare publish and subscribe communication with a coupled event oriented setup compared to the traditional news agency publishing one or more magazines (e.g. Dr Dobbs request/response type of setup where clients starts a request Journal (DDJ), ComputerWorld (CW), PCWorld (PCW) etc.) and servers reply with a response. Those setups often do not and having some customers who subscribe for one, some or all allow for any 'out of order' server transmission to the client, or of the magazines. if it does, it does so in a relatively limited way requiring hard The publishers publish each magazine under a specific name, coding each situation for each client. which in the publish/subscribe (from now on called p/s) world would be called the subject. Customers would choose which Each publisher or subscriber of information is connected to a subjects to subscribe on and each time a publication was ready virtual bus which we call the WIB (Wide Information Bus). and sent out, the customer would receive it.

Why is it named like that? The subject 'Information Bus' because it is a virtual media of information In the computerized p/s world, the subject is a loosely formatted transportation, and 'Wide' because the types of data transported string build of one or more parts separated by '.'. on it can consist of any of kbmMW's already well known data The subject is used as an advanced addressing mechanism types. Thus a wide range of data types are available from simple surpassing simple IP numbers, used by nodes to know if they values over objects and arrays to streams which for example should receive a message or not published by another node. could contain video, sound or images, and datasets. Since the message in theory flows all over the WIB, all nodes All applications attached to a WIB can act both as servers and connected to it can choose to receive the message. I.e. one clients or rather as publishers and subscribers. Hence we published message can be received by many subscribers. generally don't distinguish between servers and clients when in a In practice there are several built in techniques to limit the flow typical publish/subscribe setup, but rather about nodes. to only nodes who have expressed their wish to receive messages with those specific subjects. A node is simply an application that is able to interact as an information publisher or subscriber, or both and that are attached The subject is loosely formatted because the number of parts and to the WIB. the contents of the parts are not defined by the p/s protocol as Thus any node can be generating or consuming information. such except for the first part, and thus can be freely defined by The nodes are connected to a virtual bus which we call the WIB the developer. (Wide Information Bus). The first part generally must be one of the following texts: The WIB can span all from a single physical segment on a local MSG, REQ, RES, SUB, USB, CAC, THR, SRV LAN, over multiple segments on an Intranet to the world wide We will first concentrate about MSG. Later the others will be Internet. explained. A sample publish/subscribe setup with the WIB spanning two Subjects starting with MSG identifies unsolicited asynchronous Ethernet LAN's messages. Using the MSG type subject we will try to build a subject which the newpaper agency can publish DDJ under. The subject to publish messages around DDJ could be 'MSG.DDJ'. Clients would be able to subscribe for 'MSG.DDJ' and receive all messages related WIB WIDE INFORMATION BUS to DDJ. However what if another newspaper agency have a journal which is named DDJ (Danish Deliveries Journal)? Then there would be a potential conflict if the two news agencies both publish under the same subject. Hence a refinement is needed of the subject. A news agency part should be added.

Lets say the news agency that publish Dr. Dobbs Journal is named CMP Media LLC, and the Danish Deliveries Journal is published by Berlingske, we could add a part which identifies the publisher. Eg. the subject for WIB WIDE INFORMATION BUS DrDobbs Journal would be: 'MSG.CMP.DDJ' and for Danish Deliveries would be 'MSG.BERLINGSKE.DDJ'. Notice the hierarchical layout of the subject, and that the subject is not case sensitive (all will be Figure 1:Wide information Bus Priciple handled as uppercase).

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 33 / 2147 DEVELOPERS 4 Wide Information Bus (continuation 1)

Lets also say that customers doesn't subscribe forever, but only Broadcast messaging for specific issues on a month basis. We could of course just Broadcast messages have the advantage that multiple nodes are subscribe for all DrDobbs Journal issues, and throw out the ones able to subscribe for and receive the same messages from other we don't want after inspecting the magazine itself, but it would nodes without the need to resend the message to each receiving be better if we didn't receive the issues we aren't interested in. node. Hence yet a refinement of the subject is needed. Thus only one single message travels on the physical network. We add an issue number: 'MSG.CMP.DDJ.yyyy.nn' where yyyy is the year the issue is published, and nn is a number from 1 to 12 Publisher Subscriber Subscriber identifying the issue that particular year. Then customers can choose to subscribe for DrDobbs Journal issue 4 year 2003 by subscribing for the subject: 'MSG.CMP.DDJ.2003.04'. What about customers who want to subscribe for all of 2003? Well then the client suddenly need to accept anything in the place of the issue part. That's where wildcards come handy. A customer can subscribe on 'MSG.CMP.DDJ.2003.>' to receive all packages regarding DDJ from CMP in 2003 when they are Figure 2: WIB published. This simplifies lots of situations, and generally lower bandwidth The > means, that the remaining part of the subject is not taken requirements. into consideration when kbmMW needs to figure out if a node Each node have a local list of subscriptions which it uses to subscribes for something or not. choose which of the incoming messages it would like to keep If the node want to subscribe for any DDJ, regardless from and process. Its voluntary if the node would like to publish its which newspaper agency, but only for 2003 and issue 12, the list of subscriptions to other nodes. node needs to subscribe like this: 'MSG.*.DDJ.2003.12' Due to the typical configuration of Ethernet routers and The * means, that specific part of the subject is not to be taken switches, broadcasting only works for nodes attached to one into consideration. The * has to replace a complete part, and its single Ethernet segment. not allowed to do like this: 'MSG.C*.DDJ '. In other words the * If there are multiple segments, or switches/routers in between must be considered a placeholder for a complete part. the segments, a gateway is needed. The gateway is an It's valid to have multiple * in a subscription on a subject. Its application which subscribes for messages on one segment and however not allowed to have more than one > (and wouldn't be transport those messages via a point to point transport (typically very sensible to have more anyway). TCP/IP) to a gateway on the other segment where the messages A node can subscribe for multiple subjects at any given time. are republished, hence stretching the WIB over two or more There is no technical limit to the number of subjects subscribed segments. on and the length of each, but since there may arrive thousand The gateway can easily be created by having a server with a messages/second which kbmMW needs to filter according to the registered service which a client component in the other end can subject, its good practice to keep the number of subscriptions as send a traditional message to containing the complete messaging low as possible (less than 100/node) and to limit the number of message. The service would then simply publish the received subject parts to less than 20. A special negate operator '!' also message on the local LAN. exists. Its purpose is for a subscriber to say that it definitely If a gateway is created its usually a good idea for each node to don't want to receive a specific subject. announce its subscriptions to let the gateway know what to listen I.e. the node could subscribe for MSG.*.DDJ.*.* which means it for on the other segment. This ensures that only traffic which is would receive all messages related to DDJ regardless of year or really interesting for nodes on both segments will be passing the issue. But lets say that the subscriber of some reason definitely gateway. do not want anything from year 2001. In this case the negate subject can be useful. Hub/Spoke messaging Thus the node would have these two subscriptions: Where the broadcast type of messaging may be impractical over !MSG.*.DDJ.2001.* multiple physical Ethernet segments (anyway using UDP as the MSG.*.DDJ.*.* transport layer), Hub/Spoke messaging often is the answer. Since the negate subscription is first, it will overrule the next more general subscription. There is of course no point in adding negate subscriptions for subjects which are not otherwise subscribed for, as the node will Publisher or Publisher or Publisher or never receive messages it does not actively want to receive by Subscriber Subscriber Subscriber setting its subscriptions accordingly. Its good practice to arrange the subject parts in such way that kbmMW is able to determine if a subject match subscriptions as soon as possible. kbmMW starts from the left when evaluating the subject parts and from the top of the subscription list iterating downwards until match or all subscriptions have been evaluated. Spoke Spoke kbmMW use a very fast hashing based algorithm for detecting subjects which a subscription has been made for but nonetheless Spoke its good practice to follow these rules of thumbs. The subject parts should generally only contain US/UK letters HUB with gateway and digits. Using local charactersets can have side effects if the capablilities messages are received by computers not setup the same way.

Messaging topologies kbmMW bundles support for UDP broadcast based messaging, TCPIP hub/spoke and UDP/TCPIP peer to peer messaging. Other types of messaging topologies can be supported by kbmMW as well. One could for example create a messaging Figure 3: HUB with gateway capablilities email transport utilizing standard emails for moving messages.

Page 34 / 2148 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Wide Information Bus (continuation 2)

The hub/spoke setup differs from the broadcast setup in that one have to designate a specific node as a hub to which other nodes About the author: connect versus the broadcast setup where all nodes were equally Fikret Hasovic attached to the WIB. Started working with Delphi in 1995 (at University, department for mathematics and computer science). The hub itself usually is directly attached to the WIB, thus able to First commercial work done in 1997, using Delphi, interact with other nodes on the WIB. Paradox and InterBase. 2001 joined USAID CRSP (Comunity Reintegration and Stabilization) Project

(Parsons Delaware Inc), developing a complete IT Since a hub/spoke setup requires that a message is sent multiple system solution using Delphi and InterBase 6.0. times to multiple subscribing nodes, a hub/spoke setup is not as In mid 2002 joined USAID TAMP (Tax Administration bandwidth efficient as the traditional broadcast messaging setup. Modernization) Project (Development Alternatives, To lessen the bandwidth load, spokes must inform the hub about Inc.), working as Senior Programmer and Computer what subjects they subscribe for. On a broadcast setup, this is Systems Engineer on design and development of Tax optional unless a filtering gateway is in place. system software for Bosnia and Herzegovina. The System is using n-tier concepts (AstaIO and then The spoke provides this information by announcing its migrated to kbmMW), client applications using Delphi subscriptions: (and Kylix) and kbmMW Application Servers (Delphi spoketransport.AnnounceSubscriptions; and Kylix based) connecting to Firebird 1.5.2 CS on linux. Peer to peer messaging One can target a message to a specific node, identified by its IP Also worked for USAID TARA (Tax Administration address, by specifying that IP address as the target argument in the Reform Activity) Project (Bearing Point, Inc). SendMessage method. Published an article about Firebird in Bosnian IT Publisher Subscriber Subscriber magazine INFO (www.info.ba), and wrote a Delphi 2005 article for the same magazine. Editor of Firebird Database Community news site: http://www.fyracle.org/shownews.php.

Figure 4: Sendmessage Targeting a message allows the message to cross Ethernet segments without having a messaging gateway, provided the switch, router or hub allow UDP packages to cross. Using the peer to peer setup, it's a true peer to peer setup Interested in working with where any node can communicate with any other node using the UDP messaging transport. The node targeted should of course Delphi and Flash still be subscribing for the subjects that the sender, choose to send. and or Adobe Flex? As usual any messages send to the node, for which the node does take a look at not have a matching subscription for, will be ignored. http://www.components4developers.com The WIB node Chose: Products Video To create a publishing or subscribing node, all what's needed is kbmMW integration with Adobe Flex, Flash and AIR. to add a TkbmMWxxxyyyMessagingTransport where xxx identifies the type of transport and the yyy if its a client or server transport. Why the distinction of a client or server transport? There are two reasons: - One reason is that the messaging transports also support the traditional request/response setups using kbmMW clients and servers. Hence the messaging server transport can be directly connected to a TkbmMWServer and operate simultaneously as a true asynchronous messaging transport and as a synchronized request/response transport. - Another reason is in case of the hub/spoke messaging transport setup. The hub will always be a server transport, and the spoke always a client transport. Thus if your publishing node also contains a kbmMW application server, you would usually put a server messaging transport on that node. And if you have nodes which act as clients to an application server, and thus operate according to the request/response principle, you would put a client messaging transport on the node. Its perfectly legal to create a setup of nodes who all operate 100% on the publish/subscribe bases without any requirements for an application server. In that case you don't have to add any TkbmMWServer components in any node, and can choose to use COMPONENTS just client transports on all nodes, except for those who act as DEVELOPERS hub nodes. 4 October 2009 BLAISE PASCAL MAGAZINE 8 Page 35 / 2149 Freehand Drawing - Introduction by David Dirkse

Pictured are 3 * 3 pixels. This article describes a Delphi-7 program for freehand From center (x,y) a code drawing. (0..7) points to the next pixel. Pictured below is an example: (reduced size) A freehand drawing can be defined by a list of these codes, given the coördinates of the starting point.

The code requires 3 bits for each step. This is far from ideal, because multiples of 3 bits do not fit bytes or words. A 4 bit code would be better. The extra 4th bit provides an extra possibility, see figure:

Figure1: The draw program in action Figure3: The extra 4th bit provides an extra possibility The drawing is generated by mouse-movements over a paintbox, Two successive codes of “0” may be combined to one code of “8” connecting the (x,y) coördinates by lines. , two codes of “1” to one code of “9” etcetera. A ColorPicker component is added to the form as well as an A 4 bits -movement- code I call a “stroke” for the moment. ArrayButton, to allow selection of pen-color and pen-width. (see earlier articles or visit my website) The list of strokes Drawing is not too difficult, but we want to store the drawing as At the start of a drawing, memory space is reserved for the storage well to be repainted later. of maximal 5000 strokes. This is accomplished by the statement getmem( P , number_of_bytes) which reserves number_of_bytes The program allows for storage of 9 drawings. bytes on the heap. (note: the heap is memory space outside the To verify this storage, bitbuttons “clear” and “repaint” are added. program area and is managed by the ) P is a “Clear” erases the paintbox and “repaint” draws all recorded pointer to this space. The strokes are stored in an array of words. drawings again. Type TA = array[0..strokewords] of word; The “backspace” button removes only the last added drawing. PA = ^TA; Type PA points to the start of an array of (strokewords + 1) words. The elements in this array are now addresable by statement like Coding a drawing var p : PA; I choosed to code a drawing by means of a step-by-step route ...... description. See figure below: P^[ index] := ...... p^[0] contains the number of strokes in the array. See figure , showing the data format.

Figure2: Step by step route Figure4: The list of strokes

Page 36 / 2150 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4 Freehand Drawing - Introduction (continuation)

To define the complete drawing, also the start coördinates must be For two adjacent points (px1,py1)..(px2,py2) the stroke code remembered together with the pen-width and pen-color. must be calculated. This is done in array “props” , saving this data for drawings 1..9. An interim variable called “dir” is used. But this data could as well be saved on the heap. Dir is reset to zero and then increased by Array “buffer” contains the pointers to the stroke arrays for each – 2 if px2 > px1 ...... binary 00000010 drawing. – 3 if px2 < px1 00000011 – 8 if py2 > py1 00001000 Generating the stroke list – 12 if py2 < py1 00001100 This is less simple then expected for the following reason: when the mouse pointer moves slowly over the screen, the Array “dir2stroke” translates the “dir” code into the stroke code. generated (x,y) coördinates will constitute adjacent pixels. However, for faster mouse movements the generated (x,y) points Housekeeping will have empty spaces between them which must be filled by the Windows has granted us memory space and keeps this space stroke codes. reserved far after we have closed our drawing application. It is our responsibility the free the memory space for use by We look at the program source code: others. Drawing starts by a mouse-down event in paintbox1. At “formcreate” the 9 pointers in he buffer are set to “nil” , no Funtion “requestbufferspace” is called to reserve space for the space is reserved yet. strokes. If reservation was successfull, “true” is returned. Then a At “formdestroy” the statement freemem(pointer) returns the flag “drawing” is set true, clearing the way for coming mouse- reserved memory space to Windows. move events. Possibly, not all pace was needed for our drawing. So, following The starting point is stored in array props, together with the a mouse-up event at the end of the drawing, the statement selected pen-color and pen-width. (x,y) coördinates are stored in variables (x1,y1) for start and (x2,y2) for the end of a line. reAllocMem(p,((p^[0]+1) shr 1)+2) BufNr is the number of the current drawing. (x1,y1) and (x2,y2) are outside procedures so they can be returns unused memory space to the operating system and does addressed by all procedures in unit1. not affect the data stored already. The general format is reallocmem(pointer, bytesize) . The line (x1,y1) ----> (x2,y2) is painted on the screen and function “recordstrokes” is called to encode the strokes. The expression for the bytesize : (p^[0]+1) shr 1)+2 evolved by Converting a line into strokes p^[0] : the number of strokes stored “Recordstrokes” translates a line into a sequence of strokes valued (P^[0]+1) shr 1 : the number of bytes needed {rounded 0..7 (not 0..15). upwards} For each stroke generated, procedure “savestroke” is called to add +2 : bytes needed for p^[0] itself. this stroke to the list. Savestroke looks at the previously stored stroke and in case of equality the new stroke is not stored but the Please refer to the program listing for more details. old one is increased by 8. David Dirkse To encode a line , it must be analysed point by point. Born 1945 in Amsterdam, David joined Control Data In this process it is convenient to distinguish “horizontally”- and Corporation in 1968, after studying electrical “vertically”- oriented lines, see figure: engineering. As a hardware engineer, he was responsible for the installation and maintenance of mainframes at scientific data centers in the Netherlands. With the decline of CDC around 1990, he studied mathematics and became a math teacher. His hobbies are programming, in particular educational software, math algorithms, and puzzle solving. http://home.hccnet.nl/david.dirkse

Figure 5: Horizontally”- and “vertically”- oriented lines In “horizontally” oriented lines, where dx > dy is true , dx is the number of steps and for each step the y-value changes by an amount of dy/dx.

In case of vertical orientation, dy is the step count and for each step, X changes by an amount of dx/dy. Note, that in the program at first dx = (x2 – x1) , dy = (y2 – y1) but later dx and dy are converted to the step values.(-1 or +1 , dx/dy or dy/dx)

October 2009 BLAISE PASCAL MAGAZINE 8 COMPONENTS Page 37 / 2151 DEVELOPERS 4 FastReport announcement: there is a new version that has a significant number improvements FastReport 4.8 released! http://fast-report.com/en/news/4485.html ! + added support of Embarcadero Rad Studio 2010 (Delphi/C++Builder) ! + added TfrxMailExport.OnSendMail event ! + [enterprise] added Windows Authentification mode ! + adedd checksum calculating for 25 interleaved barcode ! * [enterprise] improved CGI for IIS/Apache server ! * changed PDF export: added full unicode support, improved performance, decreased memory requirements old PDF export engine saved in file frxExportPDF_old.pas + added TfrxDBDataset.BCDToCurrency property + added TfrxReportOptions.HiddenPassword property to set password silently from code + added TfrxADOConnection.OnAfterDisconnect event + added TfrxDesigner.MemoParentFont property + added new TfrxDesignerRestriction: drDontEditReportScript and drDontEditInternalDatasets + added TfrxGroupHeader.ShowChildIfDrillDown property + added confirmation reading for TfrxMailExport + added TimeOut field to TfrxMailExport form + added ability to use keeping (KeepTogether / KeepChild / KeepHeader) in multi-column report + added ability to split big bands(biggest than page height) by default - changed inheritance mechanism, correct inherits of linked objects (fixups) - fixed bug with Mirror Mrgins in RTF, HTML, XLS, XML, OpenOffice exports - fixed bug when cross tab cut the text in corner, when corner height greater than column height - improved WatchForm TListBox changet to TCheckListBox - improved AddFrom method - copy outline - Improved functional of vertical bands, shows memos placed on H-band which doesn't across VBand, also calculate expression inside it and call events (like in FR2) - Improved unsorted mode in crosstab(join same columns correctly) - Improved converter from Report Builder - Improved TfrxDesigner.OnInsertObject, should call when drag&drop field from data tree - improved DrillDownd mechanism, should work correct with master-detail- subtetail nesting - fixed bug with DownThenAcross in Cross Tab - fixed several bugs under CodeGear RAD Studio (Delphi/C++Builder) 2009 - fixed bug with emf in ODT export - fixed bug with outline when build several composite reports in double pass mode - fixed bug when group doesn't fit on the whole page - fixed "Page" and "Line" variables inside vertical bands - fixed bug with using KeepHeader in some cases - fixed bug with displacement of subreport when use PrintOnParent property in some cases - fixed small memory leak in subreports - fixed problem with PageFooter and ReportSymmary when use PrintOnPreviousPage property - fixed bug when designer shows commented functions in object inspector - fixed bug when designer place function in commented text block - fixed bug when Engine try to split non-stretcheable view and gone to endless loop - fixed bug with HTML tags in memo when use shot text and WordWrap - [enterprise] fixed bug with variables lost on refresh/export - fixed bug whih PDF,ODT export in Delphi4 and CBuilder4 - fixed bug with some codepage which use two bytes for special symbols (Japanese ans Chinese codepages) - fixed bug when engine delete first space from text in split Memo - fixed bug in multi-column page when band overlap stretched PageHeader http://www.fast-report.com- fixed bug with using ReprintOnNewPage FastReport announcement: there is a new version that has a significant number improvements

1.2 .Net + added Functions in the "Data" window + added new report objects - CellularTextObject, ZipCodeObject added + report's Email settings (see Report|Options... menu, "Email" tab) + added multi-frame TIFF export added RC4 128-bit encryption in PDF + export added "Visible" flag in the highlight editor. Now the highlight + condition may hide the object + added TextObject's AutoShrink, AutoShrinkMinSize properties added + DataBand's RowCount property added reportPage. ManualBuild event added + PictureObject.Angle property added AfterData event to all report + objects added CommandTimeout property to all connections added export + of watermarks in HTML format added export of underlined TextObject + (Underlines = true) in PDF format added Swedish, Chinese + (Traditional), Czech, Turkish, Spanish localizations + added new demo reports in the "Report Objects" category added new demo + projects in the Demos folder * POSSIBLE BREAKING CHANGE! changes in the business objects engine. See details here: http://www.fast-report.com /en/forum/index.php?showtopic=5695 * improved performance (loading and running reports with lot of objects) * you can use Anchor property of report objects when printing hierarchical bands * changed default extension of resulting file in Excel(XML) export from *.xls to *.xml * changes in Excel(XML) export - added export of numeric values * changes in Matrix object * improvements in hierarchical reports (header/footers, totals) - fixed bug in VB.Net report language - fixed bug in Viewer.exe (exception if window is too small) - fixed bug with selecting Report in the ReportTree in VS design-mode - fixed bug when using WebReport with MasterPage - fixed bug with RTL in HTML export and WebReport - fixed bug with RTL in RichText(rtf) export - fixed bug in MS Chart (border width is not scaled properly when printing) - fixed bug with preview window's "Search" dialog - fixed bug with Nullable column type - fixed bug in PDF export when exporting complex fills - fixed bug with export different frame styles in XML and RichText formats - fixed bug when editing prepared report - fixed printing of CellularTextObject - fixed bug with dialogue form - fixed bug with Entity Framework in ASP.NET mode - fixed bug in PageSetup dialog in preview - fixed bug with rendering side-by-side Matrix objects - fixed bug in Label wizard - fixed bug with send email via MAPI

Page 40 / 2154 COMPONENTS October 2009 BLAISE PASCAL MAGAZINE 8 DEVELOPERS 4