Wednesday, November 19, 2008

New TPen properties

1. What is a Pen?

You know we are using pens when we draw a line or a shape border on a graphic canvas. A Pen defines how our lines will look. It can be thick or thin, dotted or solid, color or black. So lets review what properties a pen can have?

First of all pens can be cosmetic and geometric. Cosmetic pens are always 1 pixel wide, while geometric pens can have any width. But width of geometric pens are defined in world units and thus depends on transforms (scaling, rotation, shear, reflection) applied to canvas. Operations with cosmetic pens are faster.

The next pen property is pattern. Different libraries suggest different sets of default patterns (dot, dash, dash dot, dash dot dot, etc). Some of them don't contain any predefined pattern but allow to set a custom pattern. All libraries allow to set a solid pen pattern (usually default pattern) and some of then an empty pattern (invisible :) ).

The next usual pen property is color. Every library allows to set any custom pen color.

Geometric pens usually allow to set the style of end caps and the style of the joins between lines. The end cap can be: Round, Square and Flat. Look at the picture - they are placed in this order. When end caps are round - last points are drawn round, when end caps are square - last points are drawn square. When end caps are flat - last points are not drawn at all.
The join style can be: Round, Bevel and Miter. Look at the picture - they area placed in the same order.
Lazarus is using different libraries and each of them has a different pen implementation. For example Carbon does not supports cosmetic pens. And gtk does not support flat end caps for geometric pens (a similar style exists - GDK_CAP_NOT_LAST but it behaves as GDK_BUTT for geometric pens).

2. What was added and how it behaves

Before 0.9.27 pens were the same in Delphi and Lazarus. Pens were (and are) implemented through TPen class and had the following properties: Color, Style, Width (which cannot be less than 1). In order to create a widgetset object, TPen used a call to the CreatePenIndirect winapi compatibility function.

Thus I looked at how winapi works with all those end caps, join styles, cosmetic/geomtric and found another function which can create all what I need - ExtCreatePen. So the first thing I've done was inclusion of ExtCreatePen into LCL. I tried different pens by assigning that function result to Canvas.Pen.Handle. ExtCreatePen allows to choose whether your pen be cosmetic or geomtric, set a predefined line style or use custom dashes, set a solid color or even any brush to draw a line, set end cap style and join style. Don't expect full winapi compatibility from LCL, if you try to use this function directly. Only solid colors are supported - thus you need to pass BS_SOLID for the brush style and hatch = 0.

Another winapi compatibility function I touched was GetObject. It returns a description for the given GDI object. I've extended it to return correct TLogPen if a pen was created by CreatePenIndirect and TExtLogPen if a pen was created by ExtCreatePen.

Next I touched the TPen class itself. I've added TPenEndCap, TPenJoinStlye enumerations and TPen.EndCap, TPen.JoinStyle properties. Also I've added TPen.Cosmetic property since TPen.Width cannot be less than 1 (in other case I would use Pen.Width = 0 as cosmetic). So if you set TPen.Width = 1 and TPen.Cosmetic = True - you'll get your cosmetic pen (this is set by default for newly created pens). In all other cases pens are geometric. Pen is always geometric if Pen.Width > 1 even if Pen.Cosmetic = True. I've also added TPen.SetPattern method to set user defined patterns. If Pen.Style = psPattern lines will be drawn with dashes defined in the pattern array (first number means dash length, second space length and so forth).

3. Limitations

As I wrote before, Carbon does not support cosmetic pens and Gtk has its own point of view about Flat end caps :) But is this all you need to keep in mind?

When I wrote my test application and launched it on Mac OS X I've found that anti aliasing is not always a good friend :) My dashes were invisible and the pen looked almost solid for all styles when its width was equal to one. To eliminate this defects I've added TCanvas.Antialiasing property and now we can control it (only on Carbon and Qt though).

4. Conclusion

Almost all pen capabilities you can find in different libraries are now present in the LCL TPen class. If you missed ExtCreatePen or GetObject winapi functions - you can use them now too. If you don't understand something or just need more info then read msdn (ExtCreatePen), Qt help (QPen class reference) and Gtk reference manual (Graphics Contexts). If you want to look at TPen extensions yourself then launch our "Pen and Brush" example (I was inspired by a Qt Basic Drawing example when wrote it).

Tuesday, November 18, 2008

Compressed HTML help (CHM) in Freepascal

What are CHM files?

CHM files are html archives that are compressed using the LZX compression algorithm.

The Idea

In early 2000 something, there was a discussion about Lazarus and making the help system better. Many different ideas were thrown around but the one that caught my eye was CHM, to me it made sense.

So I began to search for a way to make Lazarus help available as CHM files. The Freepascal documentation: the Run Time Library(RTL), Free Component Library(FCL) and the Lazarus Documentation Lazarus Component Library(LCL) were and are, all available in html format either to download as a zip file or from a website for browsing. This was good because CHM's are just html files in a special archive so in theory it's easy to make CHM's from the existing HTML files.

A bunch of History

I used the MS HTML Help Workshop to make some CHM's from the existing html files. This worked just fine but already I was seeing a problem: CHM readers only exist for Windows.

I found a library, libchm, which was capable of reading and decompressing CHM files. I started working with that and in not too long I was able to extract any file from within a CHM file and display it. This was wonderful but still it was not a perfect solution since Lazarus, if it provided a CHM help system, would rely on an uncommon library.

So I searched using google for an explanation of the CHM file format and found a very detailed specification. http://www.speakeasy.org/~russotto/chm/
The real work began. I converted the LZX decompression code in chmlib from C to Pascal. At first it did not work, but with the help of Micha Nelissen I corrected the mistakes from the conversion and that was finished.

Next came the part which required actual understanding of the innermost workings of a CHM archive. This is when I realized that reading CHM files was not just one file to understand but many. I'll explain: We already know that a CHM file is an archive that contains compressed HTML documents, but how do we know which HTLM documents are included and where they are, or how big they are? CHM's have a document index which uses a tree structure to store information about the directory and files within. After some time I was able to read this structure and see a list of all files and directories in CHM's. Subsequently I realized that a CHM has files stored within it that are added when it is made, which contain information about the Table of Contents, Index, which file is the “Home page” of the CHM and many other disinteresting but important things. Understanding a CHM involves understanding these internal files of a chm.

The specification I referred to above had all the information I needed about reading a CHM's contents but not how to understand these other internal files. Google to the rescue. I found another website http://www.nongnu.org/chmspec/latest/ that had information about the internal files! Not much later I was able to open, extract, and show correctly chm files. All without any external library dependencies.

I was very pleased but the CHMs made by the MS HTML Workshop did not have a very helpful Table of Contents or Index. Additionally there was some discomfort on the part of Lazarus developers that the documentation could only be compiled on Windows PC's since many of the Lazarus developers only used Linux.

This is why several months later, I began work on a CHM compiler! During a two week period I converted more C code to Pascal so a LZX compressor existed for pascal, and wrote from scratch several units to write CHM files.

Now it is possible to write and read CHM's files. The code is included with Freepascal in the packages/chm folder. Also fpdoc the Freepascal documentation tool incorporates the ability to write CHM files.

A program was made (LHelp) and a package made for Lazarus to integrate CHM help. It did not gain popularity however. Why? I'm not sure but it could be because people didn't know it was there. It required setting up in the Lazarus which may have been too compilicated for some. But regardless two years go by.

Recent Progress

I had recently been distracted away from Lazarus development by life and not paying much attention to it's progress. Then an email on the mailinglist caught my eye. A Freepascal dev, Marco van de Voort, was working on integration CHM help into the FP ide. I immediately started reading the logs to find out what interest had been shown in CHM's.

So in the last few weeks I implemented something I had wanted to but as yet, not been motivated to do: I implemented creating and reading the search index CHM's can contain.

What does this mean? This means that now it is possible to author searchable CHM files in any os/platform that FreePascal supports and also read them, all with Pascal code and with no external library requirements.

In the not too distant future, Lazarus may by default use these CHM files to display help when you need it.

Tuesday, September 30, 2008

Lazarus cross platform and cross widget set example

Today I read a news item on the Lazarus site about a SI_Browser, a simple DICOM viewer. I didn't know what DICOM was, but google led me to the wikipedia article about it.

At the bottom of the site, I found a familiar link about the MRIcron DICOM viewer. I knew MRIcron is built using Lazarus; Chris Rorden, the developer, has made and paid several successful bounties to support MRIcron and Lazarus.

The actual reason I write this post, is the installation page of MRIcron. MRIcron is a Lazarus application that really shows the strength of Lazarus cross platfrom and widget set support. Chris offers MRIcron in 8 differenent flavours:
  • Windows (WinAPI widgetset)
  • Linux
    • 32-bit (QT widgetset)
    • 32-bit (GTK1 widgetset)
    • 32-bit (GTK2 widgetset)
    • 64-bit (GTK1 widgetset)
    • 64-bit (GTK2 widgetset)
  • Macintosh OSX
    • OSX 10.4 or later (Universal binary, Carbon widgetset)
    • OSX 10.3 or earlier (PowerPC, GTK1 widgetset)

Chris, thanks for showing the power of Lazarus.

Thursday, September 25, 2008

Lazarus 0.9.26 tagged

Today I tagged the 0.9.26 version of Lazarus. In the coming week we will do the release building, some testing and preparing the announcement.

Lazarus svn trunk now contains version 0.9.27 and there is a new fixes_0_9_26 branch with 0.9.26.1.

Thursday, August 21, 2008

SVN and the bug tracker: a powerful team

This morning an issue was reported that using the win32 widget set,"RadioButton changes its state (becomes checked) when selected with Tab key". I could reproduce the issue easily and I remember that I had seen some code in the win32callback.inc file that sets the radiobuttons explictly using the BM_SETCHECK message. In Lazarus, I used Find in files searching in the lcl\interfaces\win32 directory, I found the piece of code rapidly, the WM_SETFOCUS handler around line 2084. The next step was to use svn annotate on the file, which returns the file with a note in which revision the lastest change has been made and by who. Then the patch and the log message are just a mouse click away:
moved checking of radiobutton to wm_setfocus, so keyboard action is handled too (issue 1171)
Now, resolving this report is easy. Either closing it as won't fix: it is as designed or revert the change of revision 8017. The hard part is to decide what is the best behavior.

Without using SVN or bugtracker, all this would depend on people's memory. I would not have remembered it after almost 3 years. The most important lesson for me, is that it showed how vital it is to put the issue number in the svn log message, otherwise you loose the track from change in source to bug report.

Wednesday, August 20, 2008

Lazarus 0.9.26 release preparation

The list of open issues for Lazarus 0.9.26 is getting smaller by the day. Most are fixed. Some are re-targeted to 0.9.28, if we estimate it takes too long fix them now. Some are re-targeted to 1.0.0, if closer inspection turns out the bug is not a regression.

Some issue are in the status feedback. This means that the Lazarus developers are waiting for information from the issue reporters to be able to fix the issue or for confirmation that the bug already has been fixed in the meantime. I'd like to ask people who have submitted bug to check their reports and give the necessary feedback.

Translators are requested to check the translations for new or modified strings, so we can release Lazarus with up to date translations.

Monday, August 18, 2008

FPC 2.2.2 released

FPC 2.2.2 has been released. In the coming time we will focus on fixing the regressions in Lazarus 0.9.25 and release 0.9.26. There are still about 15 issues to be fixed.

If you don't want to have nasty surprises, when Lazarus 0.9.26 is released, grab one of the snapshots and test it.

Wednesday, June 25, 2008

Amazing features in 0.9.26

I don't remeber any release which excited me so much like the not yet finished 0.9.26. The reason is that many great features which were once a distant dream are now ready from becoming reality. I will describe some of them bellow.

* Windows Unicode support, even in Windows 9x. This is a very strong feature, which will take Lazarus much closer to having full Unicode support in all our supported platforms, something indispensable for any modern GUI Library. This allows us to show in the same application Russian, Portuguese and Chinese, for example, regardless of the Windows locale. Having Windows 9x support with the help of some testers puts us ahead of many other GUI Toolkits that dropped Windows 9x. Extended information for users can be found here.

* Native Mac OS X version with the Carbon widgetset. Yes, no more X11, no more Gtk under Mac OS X. A native IDE instead, which can be launched form the Dock and integrates nicely into the system. Copy+Paste, Debugging, everything works in the new Mac IDE. I expect this to boost Lazarus popularity under Mac OS X. In the long term a Cocoa interface is being developed, but the Carbon IDE should be more the enough in the next 1-2 years.

* TIcon.Handle finally working. This is also a long awaited feature, and should help removing some necessary ifdefs when using TTrayIcon, which needs TIcon.Handle to work.

* A much better Windows CE interface. Lazarus 0.9.24 was the first release supporting Windows CE, but many bugs were present at the time, making it somewhat problematic to develop real applications. In Lazarus 0.9.25 we have made a great work polishing the Windows CE interface, and this new release will push it to a new level, making it ready for the development of high quality applications. For some screenshots and extended information of the work being done, take a look here

* Tons of bugfixes

The final feature, which would make Lazarus finally ready for 1.0 (just my opinion! I know others disagree) is unfortunately not in this list. It would be the retirement of the Gtk 1 widgetset, and the move to a fully unicode and modern Linux Toolkit. I have worked a lot in the Gtk 2 widgetset, trying to get it to a development level where it could substitute Gtk 1, but I got really frustrated, partly because of the low quality of the mixed gtk1/gtk2 interface code, but also because Gtk just doesn't help. Having worked with the Windows API, Qt, fpGUI, Cocoa and Gtk, I am absolutely sure that Gtk is the worse GUI toolkit I have ever seen. Yes, even worse then direct Windows API, because at least the Windows API works!

The final shot in Gtk 2 for me was the fact that the Qt 4 interface, which I started 2 years ago just to learn how the LCL worked inside, managed to become much more reliable then the Gtk 2 interface which was already being developed a long time before, and without the support of most core developers! (Paul is the only core developer doing heavy development in Qt). Unfortunately Qt is not LGPL, and we expect to support the development of proprietary applications without the need to buy licenses, so Qt cannot substitute Gtk =/ At the moment I believe that fpGUI is the widgetset with the highest changes to substitute Gtk 1. The highest obstacles are the lack of developers and fpGUI being still under development, which makes it's API not so stable, but I really believe this path may have a great future.

A small comparison of the development difficulty in each widgetset:
Implementing TTrayIcon under Windows API: 4 hours
Implementing TTrayIcon under Qt: 3 hours
Implementing TTrayIcon under Gtk 2: 2 *weeks*

Concluding, I had originally planned for 2 posts, 1 about the great new stuff in 0.9.26 and 1 ranting about Gtk, but I managed to cover both topics here =D In conclusion I think we are reaching a new milestone, a new development level, but our official Linux interface (gtk 1) is unfortunately limited and we have no good enough substitute yet.

Thursday, June 19, 2008

FPC 2.2.2 RC1 released

The first release candidate of FPC 2.2.2 has been released. The Lazarus team is waiting for the release of FPC 2.2.2, because it needs it for the Unicode support for the win32 widget set. We intend to release Lazarus 0.9.26 soon after FPC 2.2.2 has been released.

People who want to test this release candidate with Lazarus, can download a Lazarus snapshot. The last week have replaced all fpc 2.2.0 based snapshots with fpc 2.2.2rc1 based snapshots.

Don't wait too long with testing, because 30 June will start the code freeze in preparation of the RC2. Hopefully this is the final release candidate for FPC 2.2.2, so we can have a FPC release before the end of July. Another release candidate will delay the release about a month. So test well, and report any regressions before the end of June.

Wednesday, May 14, 2008

New 0.9.26 features. Part 2. ImageList effects

I think that almost nobody knows that internally the LCL TCustomImageList contains an array of 32 bit (rgb + alpha) data. In this array the imagelist stores images in the best quality. When it is needed the imagelist use this array to create a widget set imagelist (at this moment this is only the case for the win32 widget set) with the best possible quality. Any time we can access the 32 bit image data and we can do any manipulation with it. If you ever worked with image data you should know that 32 bit data is one the easiest formats for manipulations.

But what manipulations do applications (controls) usually need? The most often used manipulation is the transform from multi-color to gray image. It is used for example in menus and bitbtns (a button with an image). The next two often used manipulations are image highlighting and shadowing, which are also used in menus and buttons.

So I added TCustomImageList.Draw(... ADrawEffect: TGraphicsDrawEffect) and TCustomImageList.GetBitmap(... AEffect: TGraphicsDrawEffect).


At this picture you can see all effects currently supported by the imagelist. And this is the description:
  1. Normal - no effect. You get an original image without any transform.
  2. Disabled - gray image. Red = Green = Blue. We get every component value by the following formula: (Red + Green + Blue) / 3.
  3. Highlighted - a bit shining image. To achieve shining we alphablend the original image with white.
  4. Shadowed - opposite of highlighted. To achieve shadowing we alphablend the original image with black.
  5. 1Bit - this effect is used for drawing bitbtn glyphs in windows applications with no theme support. Windows just cannot draw gray images - they can use only 3 colors on a button: clBtnFace (transparent), clBtnShadow and clBtnHighlight. To support disabled bitmap drawing on such buttons we have added this special effect. We are using a special formula to achieve sharp edges in order to save all image details.
Currently every bitbtn and menu use these methods to draw their glyphs. When you disable them , the gdeDisabled effect is used, when you move a mouse pointer over a control, gdeHighlight is used and when you press a control gdeShadowed is used.
Of course, these imagelist methods can be useful not only for menus and buttons - you can use them for your own controls and other needs too. And we hope you will do that. :-)

Sunday, February 10, 2008

GTK2 planned not before Lazarus 1.2?

Sometimes people ask: Why don't the Lazarus developers want to fix the gtk2 bug before Lazarus 1.0?

The Lazarus developers have limited resources, so in order to have Lazarus 1.0 sooner rather than later, some decisions were made to reduce the work load (scope) for Lazarus 1.0. Some of this is mentioned on the wiki.

Basically, this means we think that no new features are needed for Lazarus 1.0. That doesn't mean that there will be no new features until then, but that we won't delay the release of Lazarus 1.0 because of it.

The gtk2 interface could be regarded as a feature too, because in most cases the gtk1 interface works just fine or better (except it looks dated). I must admit it is getting more troublesome recently, because some distroes now ship with gtk2 only. Currently the gtk widgetset is more stable and has less bugs with Lazarus than gtk2. Until that situation has changed gtk1 will remain the default. As soon as gtk2 is better (i.e. less bugs and more stable) than gtk1, it will come the default. But this is no priority for the Lazarus team, it rather focuses on other bugs.

Fortunately Lazarus is open source and with your contributions you can steer the path of Lazarus. For example Andrew Haines and Ales Katona understood that and have contributed a lot of gtk2 patches, trying to improve the gtk2 widgetset, so that it become the default for Lazarus 1.0. If a couple of other people start helping, I have no doubt that Lazarus 1.0 will eventually be with gtk2.

New 0.9.26 features. Part 1. SendMessage and PostMessage

If you ever wrote some big application or component, I am sure you met the problem of postponed execution of some code. Delphi programmers usually used 2 solutions: timers and Windows message system abilities. This article is about message system approach. Note that Lazarus has a third solution: Application.QueueAsyncCall.

I suppose you already know something about the Windows message system. And you are familiar with SendMessage and PostMessage commands. They are used to deliver messages to controls. SendMessage sends message dirrectly to control window procedure. PostMessage adds message to the message queue, so control will get it only after processing all other pending messages.

Group of message numbers from 0 to WM_USER are used by Windows itself. So if you want to use message system in personal purpose you should use message numbers >= WM_USER.

Lets return to Lazarus where you want to indirectly perform some actions. Very usual task is when you need to destroy some control (your form for example) in event handler. Ofcource your application crash if you call Free in event handler - so you need to call Free somehow after event handler. But how? Call PostMessage in event handler and process posted message in message handler.

Delphi example:

const
MY_MESSAGE = WM_USER + 1; // <-- your message number
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject); // <-- some event handler
private
procedure MyMsgHandler(var Message: TMessage); message MY_MESSAGE; // <-- message handler
end;

...

procedure TForm1.Button1Click(Sender: TObject);
begin
... //code before
PostMessage(Handle, MY_MESSAGE, 1, 0); // <-- here you post message to message queue
... // code after
end;

procedure TForm1.MyMsgHandler(var Message: TMessage);
begin
Free;
end;

If you used similar constructions in Delphi, you should know that they did not work in Lazarus. In the win32 widgetset code all WM_USER messages were blocked for some reasons:
- other widgetsets had no support for PostMessage and SendMessage
- few WM_USER messages were used by Windows and cause errors in LCL

After releasing 0.9.24 we reevaluated our decision since gtk and qt supported PostMessage and SendMessage. Then an implementation for Carbon appeared. Of course it would be a joke to block messages under Windows when all other widgetsets (where messages are aliens) support them. Now you can use PostMessage and SendMessage with few limitations:
- use Message numbers >= LM_USER
- sending messages outside application does not work (you cannot send message to another application)

And the last - if you need example - look at lazarus\examples\messages.