Difference between revisions of "Custom Drawn Interface"

From Free Pascal wiki
(Undo revision 57079 by Ggeldenhuys (talk))
m (Fixed syntax highlighting)
 
(22 intermediate revisions by 8 users not shown)
Line 1: Line 1:
 
{{Custom_Drawn_Interface}}
 
{{Custom_Drawn_Interface}}
 +
{{Warning|THIS INFORMATION IS EXTREMELY DATED AND NEEDS UPDATING as of 2015}}
 +
 
__TOC__
 
__TOC__
 
{{Other Interfaces}}
 
{{Other Interfaces}}
 +
 
==Introduction==
 
==Introduction==
 
LCL-CustomDrawn-Android has the following features:
 
LCL-CustomDrawn-Android has the following features:
Line 11: Line 14:
  
 
==FAQ==
 
==FAQ==
 
===LCL-CustomDrawn versus a native interfaces for Android/iPhone===
 
 
Anyone who says that a native LCL-Android interface is nearly feasable clearly has never used the Android API. I, Felipe Monteiro de Carvalho, actually started LCL-Android and it lived for a time in Lazarus 0.9.31 until I deleted it in favor of LCL-CustomDrawn-Android. The Android API does not match the LCL at all and it is not fit for a native LCL interface. It doesn't even properly support setting the X, Y, width, height position of components, controls do not match what the LCL offers, the API is in Java, etc. LCL-CustomDrawn fixes all those issues by implementing everything in a powerful Pascal framework and interfacing with Java via JNI. It has automatic layout adjustment for the DPI, it makes changes to adapt the form as much as possible to the Android way of being, with the form ocupying the entire display width and the height being scrollable if larger then the display. It automatically adjusts the form when the display orientation changes on a rotation, it supports GPS, accelerometer, SMS sending, etc, etc. In general, it is the full power of the LCL with a lot more of unique features on your Android device.
 
 
And in general, I, Felipe Monteiro de Carvalho, started the LCL-CustomDrawn interface because several things convinced me that it is the future of Lazarus. Each native interface takes aproximately 5 years of a lot of work to get ready for production use in large projects. That's a huge, immense amount of work, and platforms die all the time. So by the time you finished, it will soon be obsolete and when it gets obsolete, all your work is flushed down the toiled. After seing Microsoft drop Windows CE without any reason after years and years that I worked on LCL-WinCE, see Apple drop Carbon, see Nokia drop both Symbian and Meego, I am convinced that the big corporations that make the calls are unreliable and will drop their platforms in an eye blink when a big shot director has a new favorite toy framework. So there is no point in wasting 5 years to write an interface which will die. In LCL-CustomDrawn nothing is wasted, because 99% of the code is common amount all backends, 99% of  bugs fixed in LCL-CustomDrawn are fixed forever and it only goes forward, gets better, faster and more reliable. No effort is wasted anymore and I can very easily debug smartphone applications in my desktop, get a 100% reliable LCL across platforms and at the same time have power features like the ones developed for our Android support: layout auto-adjustment, GPS support, accelerometer support, etc.
 
 
===Comparison of LCL-CustomDrawn and LCL-fpGUI===
 
 
Note: People which disagree with this comparison are free to create their own comparison at another page.
 
 
{| BORDER="1" CELLSPACING="0"
 
!COLSPAN="1" STYLE="background:#ffdead;"|'''Item'''
 
!COLSPAN="1" STYLE="background:#ffdead;"|'''LCL-fpGUI'''
 
!COLSPAN="1" STYLE="background:#ffdead;"|'''LCL-CustomDrawn'''
 
|--
 
|Native handles||fpGUI uses 1 native window for each control||LCL-CustomDrawn uses 1 native window for each form in X11, Cocoa and Windows and 1 native surface for all forms in Android
 
|--
 
|Canvas implementation||fpGUI can use native Canvas routines from each platform, or a 100% object pascal implemented 2D graphics engine with full anti-aliasing and sub-pixel accuracy.||LCL-CustomDrawn has a define to choose between native and non-native (via PasFreeType) text metrics/rendering and everything else from canvas drawing is implemented by TRawImage+TLazIntfImage+TLazCanvas. Being non-native means a faster and more reliable result.
 
|--
 
|Text implementation||fpGUI can use native text routines from each platform, or use the FreeType library to do vector or bitmap based text rendering. All text is always anti-aliased. If the vector text engine is used, then outlined text, gradient text, rotated text and text following any graphics path is possible.||LCL-CustomDrawn can either use the native text of the platform or use LazFreeType which is a powerful pure Pascal descendent from the original FreeType written in Pascal which can render text with anti-aliasing from the truetype fonts of the platform.
 
|--
 
|Supported platforms||Windows, Windows CE, X11 (Linux and others)||Windows, Cocoa (Mac OS X), X11 (Linux and others) and Android
 
|--
 
|Level of indirection||fpGUI acts as an unnecessary intermediary layer between the LCL and the platform, which makes the development harder. It is also not part of the Lazarus code base, uses a different version control system and has different versions which would need to be synchronized.||There are no intermediaries, the LCL talks directly to each platform and everything is in our single SVN repository and shares the same version
 
|--
 
|Adaptation for platforms without native sub-windows||fpGUI would need extensive changes to work in platforms which do not have native sub-controls, for example Android, linux framebuffer, OpenGL||LCL-CustomDrawn is designed from the start to work on very limited platforms, for example the Linux Framebuffer, an Android SurfaceView or OpenGL
 
|--
 
|LCL Adaptation||fpGUI is a separate unrelated framework. Its controls and Canvas APIs do not necessary match what is required by the LCL||LCL-CustomDrawn is designed to perfectly implement all features from the LCL and perfectly paint it's Canvas drawing routines like LCL-Win32, LCL-Gtk2 and LCL-Qt do
 
|--
 
|How to port the LCL to a new platform using this widgetset?||fpGUI would need to be ported to the new platform.||You can port LCL-CustomDrawn directly to new platforms by implementing a new backend which contains support for form, application and and other parts
 
|--
 
|Maintenance||LCL-fpGUI was abandoned by its creator and currently has no maintainers||A growing team works on LCL-CustomDrawn and companies are building products around it
 
|}
 
 
More comments on why developing LCL-CustomDrawn instead of LCL-fpGUI: Just to start with, it is the correct architecture. There is no need for an intermediary API which complicates the architecture and makes debugging and porting harder. We can do everything directly without it and greatly simplify our code. Also, by eating our own dog food we ensure that our platform is more strongly tested and has a higher quality. Each feature in LCL-CustomDrawn is implemented using other more basic features. For example TButton, TPageControl and all other visual controls are implemented with TCanvas, so it guarantees that our Canvas drawing is in excellent shape. Drawing in LCL-CustomDrawn is executed via LCL classes: TRawImage, TLazIntfImage and TLazCanvas. If there is an intermediary API then porting the LCL means first porting the intermediary API and debugging it and then debug the combined package. LCL porters should not need to learn unrelated frameworks to port the LCL.
 
 
On top of that, LCL-CustomDrawn is designed from the start to be portable to even the most spartan and problematic of platforms. It requires from the platform only a raster surface in any pixel format and also input events. From that onwards we can implement everything else non-natively. There are non-native implementations of Forms, WinControls, standard controls, TCanvas drawing, dialogs and even text can be provided if necessary. Each backend can select its mix of non-native / native elements, although they should never attempt to implement TWinControl natively. fpGUI on the other hand would need a large rewrite to be able to support this level of portability.
 
  
 
===Diagram of the Custom Drawn Interface===
 
===Diagram of the Custom Drawn Interface===
Line 92: Line 57:
  
 
TCanvas will be fully non-native in this widgetset and based on [[Developing_with_Graphics#Working_with_TLazIntfImage.2C_TRawImage_and_TLazCanvas|LazCanvas]]. All drawings to visual controls and on the OnPaint event of controls of the form are naturally double-buffered because the entire drawing of the form is first performed on an off-screen buffer and then copied in 1 operation to the form native canvas. In reality there is only 1 TLazCanvas for the entire form, but sub-controls will think they are on a separate canvas because the property BaseWindowOrg sets an internal start position of the canvas and also because all drawings will be clipped to reflect the size and shape of the sub-control.
 
TCanvas will be fully non-native in this widgetset and based on [[Developing_with_Graphics#Working_with_TLazIntfImage.2C_TRawImage_and_TLazCanvas|LazCanvas]]. All drawings to visual controls and on the OnPaint event of controls of the form are naturally double-buffered because the entire drawing of the form is first performed on an off-screen buffer and then copied in 1 operation to the form native canvas. In reality there is only 1 TLazCanvas for the entire form, but sub-controls will think they are on a separate canvas because the property BaseWindowOrg sets an internal start position of the canvas and also because all drawings will be clipped to reflect the size and shape of the sub-control.
 +
 +
===Getting the TLazCanvas object inside TCanvas===
 +
 +
This works only in the LCL-CustomDrawn interface:
 +
 +
<syntaxhighlight lang="pascal">
 +
uses lazcanvas, lclintf;
 +
 +
var
 +
  MyLazCanvas: TLazCanvas:
 +
begin
 +
  if nctLazCanvas in LCLIntf.GetAvailableNativeCanvasTypes(MyCanvas.Handle) then
 +
  begin
 +
    MyLazCanvas := TLazCanvas(LCLIntf.GetNativeCanvas(MyCanvas.Handle, nctLazCanvas));
 +
    // do something here with TLazCanvas
 +
  end;
 +
</syntaxhighlight>
 +
 +
===Drawing optimization roadmap===
 +
 +
====Optimizations already done====
 +
*Give 1 bitmap to each control and buffer the control images and only redraw them if invalidated. This greatly helps in large forms when invalidating only 1 control.
 +
*Don't draw controls which are completely covered by other ones. Commits:
 +
**http://svn.freepascal.org/cgi-bin/viewvc.cgi?view=rev&root=lazarus&revision=36437
 +
**http://svn.freepascal.org/cgi-bin/viewvc.cgi?view=rev&root=lazarus&revision=36455
 +
*Change the control bitmaps to use the native format (with ifdefs for ARGB32 for alpha blending support). This was implemented together with the next optimization:
 +
*Optimize the case of drawing a bitmap to a canvas, when the pixel formats match and the clip rect is inexistent or rectangular. The magnifier full painting went from 630ms to 477ms for me.
 +
**http://svn.freepascal.org/cgi-bin/viewvc.cgi?view=rev&root=lazarus&revision=36576
 +
**http://svn.freepascal.org/cgi-bin/viewvc.cgi?view=rev&root=lazarus&revision=36578
 +
*Optimize rectangle area filling if the clip rect is inexistent or rectangular. Decreased the drawing of a fullscreen form in X11 with 4 buttons from 95ms to 33ms for me
 +
**http://svn.freepascal.org/cgi-bin/viewvc.cgi?view=rev&root=lazarus&revision=36580
 +
 +
====Optimizations to be done====
 +
*Buffer the native bitmap of the form instead of generating it on each operation
 +
*Reuse the buffered native bitmap contents if they don't change
 +
*Support invalidating only a rectangle instead of the entire control
  
 
==Font rendering==
 
==Font rendering==
Line 129: Line 130:
  
 
[[Image:Lazclock_customdrawn.png]]
 
[[Image:Lazclock_customdrawn.png]]
 +
 +
[[Image:lcl_android_30_mar.png]]
 +
[[Image:vpr-android.png]]
  
 
==See Also==
 
==See Also==
 
*[[Lazarus Custom Drawn Controls]]
 
*[[Lazarus Custom Drawn Controls]]
 +
 +
[[Category:Custom Drawn]]

Latest revision as of 06:28, 8 February 2020

English (en) русский (ru)

Warning-icon.png

Warning: THIS INFORMATION IS EXTREMELY DATED AND NEEDS UPDATING as of 2015

Other Interfaces

Platform specific Tips

Interface Development Articles

Introduction

LCL-CustomDrawn-Android has the following features:

  • Backends for X11, Android and Windows and a partially working one for Cocoa, more can be added in the future
  • Painting is done completely inside Lazarus without any interference from the native libraries except for text drawing. This assures a complete perfection of the executed drawings in all platforms and a uniform level of supported features
  • Only 1 native window is utilized for each form, in the Android backend at the moment this is 1 native window for the entire application
  • Utilizes the Lazarus Custom Drawn Controls for implementing the LCL standard controls
  • Utilizes as it's painting engine the lcl parts: TLazIntfImage, TRawImage, lazcanvas and lazregions

FAQ

Diagram of the Custom Drawn Interface

customdrawn diagram.png

Legend:

  • Blue - New elements implemented as part of the LCL-CustomDrawn project
  • Yellow - Pre-existing LCL elements
  • Gray - System APIs

The LCL-CustomDrawn Backends

LCL-CustomDrawn needs backends to implement the most basic parts of the widgetset. Each backend should implement the following minimal parts:

  • TWidgetSet.Run, ProcessMessages, etc
  • TForm
  • TWinControl with all events
  • TTrayIcon

LCL-CustomDrawn-Android

This backend is working. See this page Custom Drawn Interface/Android

And also Android Programming

LCL-CustomDrawn-X11

This backend is working. See Custom Drawn Interface/X11

LCL-CustomDrawn-Cocoa

This backend is working.

LCL-CustomDrawn-Windows

This backend is working.

LCL-CustomDrawn-iPhone

This is planned, but not yet started.

Canvas

TCanvas will be fully non-native in this widgetset and based on LazCanvas. All drawings to visual controls and on the OnPaint event of controls of the form are naturally double-buffered because the entire drawing of the form is first performed on an off-screen buffer and then copied in 1 operation to the form native canvas. In reality there is only 1 TLazCanvas for the entire form, but sub-controls will think they are on a separate canvas because the property BaseWindowOrg sets an internal start position of the canvas and also because all drawings will be clipped to reflect the size and shape of the sub-control.

Getting the TLazCanvas object inside TCanvas

This works only in the LCL-CustomDrawn interface:

uses lazcanvas, lclintf;

var
  MyLazCanvas: TLazCanvas:
begin
  if nctLazCanvas in LCLIntf.GetAvailableNativeCanvasTypes(MyCanvas.Handle) then
  begin
    MyLazCanvas := TLazCanvas(LCLIntf.GetNativeCanvas(MyCanvas.Handle, nctLazCanvas));
    // do something here with TLazCanvas
  end;

Drawing optimization roadmap

Optimizations already done

Optimizations to be done

  • Buffer the native bitmap of the form instead of generating it on each operation
  • Reuse the buffered native bitmap contents if they don't change
  • Support invalidating only a rectangle instead of the entire control

Font rendering

When the define CD_UseNativeText is activated, LCL-CustomDrawn will use the native text rendering of the platform as provided by the backend. If it isn't activated, then it will use LazFreeType to render the text. The define is automatically activated for some backends if convenient when using them.

Message and Common Dialogs

Message and Common Dialogs might be native if this is considered very convenient for the backend. If not, they will be non-native. At the moment the Android backend has native message boxes.

Windowed visual controls

All Windowed visual controls (TButton, TPageControl, etc) will be based in the Lazarus Custom Drawn Controls

Conditional defines accepted by LCL-CustomDrawn

One easy way to set a conditional define for the LCL-CustomDrawn is to define it in the file lcl/interfaces/customdrawn/customdrawndefines.inc

Here are defines which affect the functionality offered by this interface:

  • CD_UseNativeText - Activates using native text instead of PasFreeType. This define will be automatically set if convenient for a particular backend, don't set it manually unless you know what you are doing.

And here debug information defines:

  • VerboseCDPaintProfiler - Adds profiling information to indicate how fast the paint event is processed
  • VerboseCDWinAPI - Extended verbose information for LCLIntf calls, except those which are covered by one of these defines instead:
    • VerboseCDText - Verbose info for text winapi calls
    • VerboseCDDrawing - Verbose info for Canvas and drawing operations
    • VerboseCDBitmap - Verbose info for Bitmap and rawimage creation and handling
  • VerboseCDForms - Extended verbose information for TWSCustomForm methods and about the non-native form from customdrawnproc (when utilized)
  • VerboseCDEvents - Extended verbose information for native events (for example mouse click, key input, etc). This excludes the paint event
  • VerboseCDPaintEvent - Debug info for the paint event
  • VerboseCDApplication - Verbose info for App routines from the Widgetset object
  • VerboseCDMessages - Verbose info for messages from the operating system (Paint, keyboard, mouse)

Screenshots

Lazclock customdrawn.png

lcl android 30 mar.png vpr-android.png

See Also