Difference between revisions of "BidiMode"

From Free Pascal wiki
Jump to navigationJump to search
m (Fixed syntax highlighting)
 
(20 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 
Some languages (Arabic, Hebrew, Farsi ...) write the characters from the right to the left, and adequate support for this must be implemented on Lazarus.
 
Some languages (Arabic, Hebrew, Farsi ...) write the characters from the right to the left, and adequate support for this must be implemented on Lazarus.
 
   
 
   
====BidiMode====  
+
====BidiMode====
  bdLeftToRight
+
BidiMode can have these settings:
  bdRightToLeft
+
<syntaxhighlight lang="pascal">
  bdRightToLeftNoAlign
+
bdLeftToRight
  bdRightToLeftReadingOnly
+
bdRightToLeft
 +
bdRightToLeftNoAlign
 +
bdRightToLeftReadingOnly
 +
</syntaxhighlight>
  
 
=====bdLeftToRight=====  
 
=====bdLeftToRight=====  
Default of BidiMode, mean read and order is normal "Left To Right"
+
Default of BidiMode, which means read and order is normal "Left To Right"
 +
 
 
=====bdRightToLeft=====
 
=====bdRightToLeft=====
 
Makes a control Right To Left reading text and right alignment depend a kind of the control,
 
Makes a control Right To Left reading text and right alignment depend a kind of the control,
  
In Delphi if there is Alignment property effect by reverse taLeft to taRight and vise versa, but in Lazarus we will reverse the alignment with FlipControls function, that make more consistency with Anchors and Align properties.
+
In Delphi if there is Alignment property effect by reverse taLeft to taRight and vise versa, but in Lazarus we will reverse the alignment with FlipControls function, which is more consistent with Anchors and Align properties.
Also bdRightToLeft take a Scrollbar at the Left and if there is a Cells or Menus must ordered from the Right.
+
Also bdRightToLeft takes a Scrollbar at the left and if there is a cell or menus they must ordered from the right.
  
 
   For Example
 
   For Example
Line 21: Line 25:
 
     Menu3, Menu2, Menu1
 
     Menu3, Menu2, Menu1
  
That mean not just a Right Alignment it is Right To Left Order.
+
That means not just Right Alignment; it is Right To Left Order.
 
bdRightToLeft must effect the text reading as depend on the OS if it is supported, the sentence words take as like Cells
 
bdRightToLeft must effect the text reading as depend on the OS if it is supported, the sentence words take as like Cells
  
Line 28: Line 32:
 
   in bdRightToLeft:  
 
   in bdRightToLeft:  
 
     Word3 Word2 Word1
 
     Word3 Word2 Word1
We are reading the Word1 first then Word2, We read from the Right to Left, but Draw Text is more complicated than normal Cells, in fact the function that Draw the text care about English/Latin words and draw it Left To Right, so if we mixed both languages in the same sentence the draw function drawing continual English words by Left To Right order to make it more readable, but a symbols like as ? or ! considered as Right To Left characters.
 
  
For testing purpose i used English word with a symbol to test Right To Left text reading
+
We are reading the Word1 first then Word2, We read from the Right to Left, but Draw Text is more complicated than normal Cells; in fact the function that draws the text cares about English/Latin words and draws it Left To Right, so if we mixed both languages in the same sentence, the draw function draws continual English words in Left To Right order to make it  readable, but symbols like ? or ! are considered as Right To Left characters.
 +
 
 +
For testing purpose I used English word with a symbol to test Right To Left text reading
  
Like as ''Word?''
+
E.g. ''Word?''
  
For special states or in fact for more compatibly with Delphi there is another values
+
For special states or for more compatibility with Delphi there are other values (possible? used? handy?)
  
 
=====bdRightToLeftNoAlign=====
 
=====bdRightToLeftNoAlign=====
It is right to left but except Alignment property not reversed,  
+
It is Right to Left but not reversed (except the Alignment property),  
 
but in Lazarus worked when use FlipControls
 
but in Lazarus worked when use FlipControls
  
 
=====bdRightToLeftReadingOnly=====
 
=====bdRightToLeftReadingOnly=====
It is right to left text reading only, scrollbar and alignment is not take effect.
+
It is Right to Left text reading only; scrollbar and alignment do not take effect (''??? remain left to right???'').
  
 
===ParentBidiMode===
 
===ParentBidiMode===
  
If it is True the control inherit BidiMode value from the parent.
+
If this is True the control inherits the BidiMode value from its parent.
  
 
===BidiMode for developers===
 
===BidiMode for developers===
When you build you own controls and try make your control support the right to left or BidiMode, you must not access the BiDiMode property directly, you must use
+
When you build you own controls and try to make your control support Right to Left or BidiMode, you must not access the BiDiMode property directly. Instead you must use
  
  function UseRightToLeftAlignment: Boolean; virtual;
+
<syntaxhighlight lang="pascal">
  function UseRightToLeftReading: Boolean; virtual;
+
function UseRightToLeftAlignment: Boolean; virtual;
  function UseRightToLeftScrollBar: Boolean;
+
function UseRightToLeftReading: Boolean; virtual;
  function IsRightToLeft: Boolean;
+
function UseRightToLeftScrollBar: Boolean;
 +
function IsRightToLeft: Boolean;
 +
</syntaxhighlight>
  
Because some controls not need to make effect to the alignment for example TButton it always is centered , or TMainMenu it always take Right align if it Right To left.
+
Because some controls do not need to make changes to the alignment - for example TButton it always is centered, or TMainMenu which always is right aligned if it is Right to Left.
  
  
Not just reading the words and cells, it is every thing depend on the order (positions), for application there is a Menus and Controls that placed on the form it must have position from the right.
+
Not just reading the words and cells, everything depends on the order (positions). For an application there is a Menus and Controls that when placed on the form must have positions starting from the right. It is like looking at a LeftToRight Form in a mirror. The flow of the Form must be from Right To Left.
  
 
[[Image:BidiMode_Sample_1.png|Sample 1]]
 
[[Image:BidiMode_Sample_1.png|Sample 1]]
Line 64: Line 71:
 
==Add BidiMode support to LCL components==
 
==Add BidiMode support to LCL components==
  
Most of OS now support RightToLeft but there is controls not supported yet or there is controls make by native language like as (TLabel, TGrid).
+
Most OSes now support RightToLeft but there are controls that are not supported yet or there is controls made by native language (''custom drawn?'') such as (TLabel, TGrid).
so we have 3 kinds of control
+
So we have 3 kinds of control:
 +
 
 +
# Standard Controls: it is easy to enable RTL support: just add some flag to switch it to RightToLeft (TEdit, TList, TComboBox, TCheckBox).
 +
# Standard Controls not supported by the OS: There is no idea just waiting the OS developers to implement it to support (TListView, TTreeView), or use native controls that already support it.
 +
# Native Controls: hard work is needed to make it Support RightToLeft, or we must add new controls that already have this features (TLabel, TGrid).
 +
 
 +
=== Add BidiMode property to TControl===
 +
 
 +
''TBidiMode is already declared in Classes''
 +
<syntaxhighlight lang="pascal">property BiDiMode: TBiDiMode read FBiDiMode write SetBiDiMode stored IsBiDiModeStored;
 +
property ParentBiDiMode: Boolean read FParentBiDiMode write SetParentBiDiMode default True;</syntaxhighlight>
 +
 
 +
BidiMode must not be stored if ParentBidiMode = True
 +
<syntaxhighlight lang="pascal">
 +
function TControl.IsBiDiModeStored: Boolean;
 +
begin
 +
  Result := not ParentBiDiMode;
 +
end;</syntaxhighlight>
 +
 
 +
'''Override BidiMode functions'''
 +
 
 +
<syntaxhighlight lang="pascal">
 +
function IsRightToLeft:Boolean; override;
 +
function UseRightToLeftAlignment: Boolean; override;
 +
function UseRightToLeftReading: Boolean; override;
 +
function UseRightToLeftScrollBar: Boolean; override;</syntaxhighlight>
 +
 
 +
''BiDiMode property is public and must published in every control need to RightToLeft''
 +
 
 +
===Bidi Controls Road Map ===
 +
 
 +
GTK2 You must build LCL with
 +
OPT=-dGTK2 OPT=-dGTK_2_8
 +
 
  
# Standard Controls: it easy to make it just add some flag to switch it to RightToLeft (TEdit, TList, TComboBox, TCheckBox).
+
{| class="wikitable"
# Standard Controls not supported in OS: There is no idea just waiting the OS developers to implement it to support (TListView, TTreeView), or use native controls already support it.
+
! Component !! win32 !! gtk2 !! carbon !! qt !! wince !! cocoa
# Native Controls: more hard work for make it Support RightToLeft, or we must add new control already have this features (TLabel, TGrid).
+
|----
 +
|TForm
 +
|class="working"|Working
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TLabel
 +
|class="working"|Working
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TButton
 +
|class="working"|Working
 +
|class="partial"|Partially Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TEdit  
 +
|class="working"|Working
 +
|class="partial"|Partially Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TListBox
 +
|class="working"|Working
 +
|class="partial"|Partially Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TComboBox  
 +
|class="working"|Working
 +
|class="partial"|Partially Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TCheckBox  
 +
|class="working"|Working
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TStaticText
 +
|class="working"|Working
 +
|class="partial"|Partially Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TGroupBox
 +
|class="working"|Working
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TRadioButton
 +
|class="working"|Working
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|Menus
 +
|class="working"|Working
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TBitBtn
 +
|class="partial"|Partially Implemented
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TSpeedBtn
 +
|class="working"|Working
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TRadioGroup
 +
|class="working"|Working
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TCheckGroup
 +
|class="working"|Working
 +
|class="working"|Working
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|----
 +
|TGrid  
 +
|class="working"|Working
 +
|class="partial"|Partially Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|class="not"|Not Implemented
 +
|}
  
Make application Right to Left order have 4 phases
+
===Functions and Utils useful for multi language application===
  
=== Phase 1: Add BidiMode property to TControl===
+
  '''TControl.FlipControls; virtual'''
 +
  Change Right to Left and Left to Right in this properties (Left, Align, Anchors and Alignment)
  
''TBidiMode already declaired in Classes''
+
==How to test RightToLeft reading==
<delphi>
+
Create a new form, then add a TButton or TEdit. Set the caption to '''OK?'''. You must add '''?''' or '''!''' or '''.''' to the last word without a space. Now set the BidiMode to bdRightToLeft, and you should see the ? in the left of word if it works.
  property BiDiMode: TBiDiMode read FBiDiMode write SetBiDiMode stored IsBiDiModeStored;
 
  property ParentBiDiMode: Boolean read FParentBiDiMode write SetParentBiDiMode default True;
 
</delphi>
 
  
BidiMode must not stored if ParentBidiMode = True
+
=BiDi support of the widgetsets=
<delphi>
 
  function TControl.IsBiDiModeStored: Boolean;
 
  begin
 
    Result := not ParentBiDiMode;
 
  end;
 
</delphi>
 
  
'''Add virtual functions'''
+
==Carbon==
<delphi>
 
  function IsRightToLeft:Boolean; virtual;
 
  function UseRightToLeftAlignment: Boolean; virtual;
 
  function UseRightToLeftReading: Boolean; virtual;
 
  function UseRightToLeftScrollBar: Boolean; virtual;
 
</delphi>
 
  ''BiDiMode property in public and must published in every control need to RightToLeft''
 
  
===Phase 2: Modify Controls===
+
Write me.
  
Add RightToLeft to Standard controls,
+
==fpGui==
  
''done here for Win32''
+
Write me.
  
  TForm {done}
+
==Gtk1==
  TLabel {done} Alignment reversed when bdRightToLeft
 
  TButton {done}
 
  TEdit {done}
 
  TListBox {done}
 
  TComboBox {done}
 
  TCheckBox {done}
 
  TStaticText {done}
 
  TGroupBox {done}
 
  TRadioButton {done} (in Win32 need RecreateWnd in SetBidiMode)
 
  TMenu/TMenuItem {done} [http://support.microsoft.com/kb/253308 there is a bug in windows] 
 
    With Menus in Lazarus Win32 the developers force to make it OWNERDRAW, We want to modify DrawMenuItem functions {done}.
 
  TScrollbar {not supported by Win32} Delphi emulate it by change the position with virtual position.
 
  
 +
Has almost no BiDi support. Is deprecated by Lazarus anyway, so no new development at all.
  
'''In progress''' 
+
==Gtk2==
  TApplication {done} Changing the BidiMode will fire ParentBidiModeChanged and FlipChildren (see AutoFlipControls) to all TComponent and TControls owned by Application.
 
  Also FlipChildrens will reverse the Anchors as like Align property.
 
  Application.AutoFlipControls:Boolean; {Done}
 
  it is useful when changing the language from "Left To Right" language like as English to Arabic and vise versa.
 
  TBitBtn {} Layout glyph will reversed between Right and Left
 
  TSpeedBtn {} Layout glyph will reversed
 
  TRadioGroup {It use ChildSizing more complex code for me and sensitive area}
 
  TCheckGroup
 
  TGrid {}
 
 
 
Delphi use CanvasOrientation for mirror the control and maked RightToLeft, i hate use this because it flip the shadow and images (like as the Check) it is make the control ugly.
 
  
===Phase 4: Functions and Utils useful for multi language application===
+
In TMemo, TEdit, TComboBox the popup menu contains the two sub menus ''Input Methods'' and ''Insert Unicode Control character''. Gtk2 uses for text rendering the '''Pango''' library, which has excellent Unicode support.
  
  FlipControls; virtual;
+
==Qt==
  Change Right to Left and Left to Right in this properties (Left, Align, Anchors and Alignment)
 
  ''if We compare with Delphi(TM) Anchors and Alignment was excepted''
 
  
  Need funtion to detect language is RightToLeft.
+
Write me.
  
==How to test RightToLeft reading==
+
==Windows==
Create new form, then add TButton or TEdit set the caption to '''OK?''' you must add '''?''' or '''!''' or '''.''' to the last word with out space, now set the BidiMode to bdRightToLeft, you will see the ? in the left of word.
 
  
 +
In Windows 7 you can switch in TMemo, TEdit, TComboBox the base direction with Left-{{keypress|Ctrl}}+Right-{{keypress|Shift}} to RTL (right to left) and Right-{{keypress|Ctrl}}+Left-{{keypress|Shift}} to LTR (left to right).
 +
This also works in the IDE for most things, like in the Property Editor and the Strings Editor Dialog.
  
==References==
+
=References=
  
http://www.unicode.org/reports/tr9/
+
* [http://www.unicode.org/reports/tr9/ Unicode Bidirectional Algorithm]
 +
* [http://www.catch22.net/book/export/html/14 Design and Implementation of a Win32 Text Editor]
  
[http://www.catch22.net/book/export/html/14 Design and Implementation of a Win32 Text Editor]
+
[[Category:Localization]]
 +
[[Category:Lazarus]]
 +
[[Category:LCL]]
 +
[[Category:Lazarus internals]]

Latest revision as of 02:27, 7 February 2020

Some languages (Arabic, Hebrew, Farsi ...) write the characters from the right to the left, and adequate support for this must be implemented on Lazarus.

BidiMode

BidiMode can have these settings:

bdLeftToRight
bdRightToLeft
bdRightToLeftNoAlign
bdRightToLeftReadingOnly
bdLeftToRight

Default of BidiMode, which means read and order is normal "Left To Right"

bdRightToLeft

Makes a control Right To Left reading text and right alignment depend a kind of the control,

In Delphi if there is Alignment property effect by reverse taLeft to taRight and vise versa, but in Lazarus we will reverse the alignment with FlipControls function, which is more consistent with Anchors and Align properties. Also bdRightToLeft takes a Scrollbar at the left and if there is a cell or menus they must ordered from the right.

 For Example
 in bdLeftToRight:
   Menu1, Menu2, Menu2
 in bdRightToLeft: 
   Menu3, Menu2, Menu1

That means not just Right Alignment; it is Right To Left Order. bdRightToLeft must effect the text reading as depend on the OS if it is supported, the sentence words take as like Cells

 in bdLeftToRight:
   Word1 Word2 Word2
 in bdRightToLeft: 
   Word3 Word2 Word1

We are reading the Word1 first then Word2, We read from the Right to Left, but Draw Text is more complicated than normal Cells; in fact the function that draws the text cares about English/Latin words and draws it Left To Right, so if we mixed both languages in the same sentence, the draw function draws continual English words in Left To Right order to make it readable, but symbols like ? or ! are considered as Right To Left characters.

For testing purpose I used English word with a symbol to test Right To Left text reading

E.g. Word?

For special states or for more compatibility with Delphi there are other values (possible? used? handy?)

bdRightToLeftNoAlign

It is Right to Left but not reversed (except the Alignment property), but in Lazarus worked when use FlipControls

bdRightToLeftReadingOnly

It is Right to Left text reading only; scrollbar and alignment do not take effect (??? remain left to right???).

ParentBidiMode

If this is True the control inherits the BidiMode value from its parent.

BidiMode for developers

When you build you own controls and try to make your control support Right to Left or BidiMode, you must not access the BiDiMode property directly. Instead you must use

function UseRightToLeftAlignment: Boolean; virtual;
function UseRightToLeftReading: Boolean; virtual;
function UseRightToLeftScrollBar: Boolean;
function IsRightToLeft: Boolean;

Because some controls do not need to make changes to the alignment - for example TButton it always is centered, or TMainMenu which always is right aligned if it is Right to Left.


Not just reading the words and cells, everything depends on the order (positions). For an application there is a Menus and Controls that when placed on the form must have positions starting from the right. It is like looking at a LeftToRight Form in a mirror. The flow of the Form must be from Right To Left.

Sample 1

Add BidiMode support to LCL components

Most OSes now support RightToLeft but there are controls that are not supported yet or there is controls made by native language (custom drawn?) such as (TLabel, TGrid). So we have 3 kinds of control:

  1. Standard Controls: it is easy to enable RTL support: just add some flag to switch it to RightToLeft (TEdit, TList, TComboBox, TCheckBox).
  2. Standard Controls not supported by the OS: There is no idea just waiting the OS developers to implement it to support (TListView, TTreeView), or use native controls that already support it.
  3. Native Controls: hard work is needed to make it Support RightToLeft, or we must add new controls that already have this features (TLabel, TGrid).

Add BidiMode property to TControl

TBidiMode is already declared in Classes

property BiDiMode: TBiDiMode read FBiDiMode write SetBiDiMode stored IsBiDiModeStored;
property ParentBiDiMode: Boolean read FParentBiDiMode write SetParentBiDiMode default True;

BidiMode must not be stored if ParentBidiMode = True

function TControl.IsBiDiModeStored: Boolean;
begin
  Result := not ParentBiDiMode;
end;

Override BidiMode functions

function IsRightToLeft:Boolean; override;
function UseRightToLeftAlignment: Boolean; override;
function UseRightToLeftReading: Boolean; override;
function UseRightToLeftScrollBar: Boolean; override;

BiDiMode property is public and must published in every control need to RightToLeft

Bidi Controls Road Map

GTK2 You must build LCL with OPT=-dGTK2 OPT=-dGTK_2_8


Component win32 gtk2 carbon qt wince cocoa
TForm Working Working Not Implemented Not Implemented Not Implemented Not Implemented
TLabel Working Working Not Implemented Not Implemented Not Implemented Not Implemented
TButton Working Partially Implemented Not Implemented Not Implemented Not Implemented Not Implemented
TEdit Working Partially Implemented Not Implemented Not Implemented Not Implemented Not Implemented
TListBox Working Partially Implemented Not Implemented Not Implemented Not Implemented Not Implemented
TComboBox Working Partially Implemented Not Implemented Not Implemented Not Implemented Not Implemented
TCheckBox Working Working Not Implemented Not Implemented Not Implemented Not Implemented
TStaticText Working Partially Implemented Not Implemented Not Implemented Not Implemented Not Implemented
TGroupBox Working Working Not Implemented Not Implemented Not Implemented Not Implemented
TRadioButton Working Working Not Implemented Not Implemented Not Implemented Not Implemented
Menus Working Working Not Implemented Not Implemented Not Implemented Not Implemented
TBitBtn Partially Implemented Working Not Implemented Not Implemented Not Implemented Not Implemented
TSpeedBtn Working Working Not Implemented Not Implemented Not Implemented Not Implemented
TRadioGroup Working Working Not Implemented Not Implemented Not Implemented Not Implemented
TCheckGroup Working Working Not Implemented Not Implemented Not Implemented Not Implemented
TGrid Working Partially Implemented Not Implemented Not Implemented Not Implemented Not Implemented

Functions and Utils useful for multi language application

 TControl.FlipControls; virtual
 Change Right to Left and Left to Right in this properties (Left, Align, Anchors and Alignment)

How to test RightToLeft reading

Create a new form, then add a TButton or TEdit. Set the caption to OK?. You must add ? or ! or . to the last word without a space. Now set the BidiMode to bdRightToLeft, and you should see the ? in the left of word if it works.

BiDi support of the widgetsets

Carbon

Write me.

fpGui

Write me.

Gtk1

Has almost no BiDi support. Is deprecated by Lazarus anyway, so no new development at all.

Gtk2

In TMemo, TEdit, TComboBox the popup menu contains the two sub menus Input Methods and Insert Unicode Control character. Gtk2 uses for text rendering the Pango library, which has excellent Unicode support.

Qt

Write me.

Windows

In Windows 7 you can switch in TMemo, TEdit, TComboBox the base direction with Left-Ctrl+Right- Shift to RTL (right to left) and Right-Ctrl+Left- Shift to LTR (left to right). This also works in the IDE for most things, like in the Property Editor and the Strings Editor Dialog.

References