View Issue Details

IDProjectCategoryView StatusLast Update
0027547LazarusTAChartpublic2015-03-12 16:33
ReporterValdas JankūnasAssigned ToZeljan Rikalo 
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
PlatformOSLinux 64 bit; KDE 4.14.2OS Version
Product Version1.5 (SVN)Product Buildr47935 
Target Version1.4RC2Fixed in Version1.5 (SVN) 
Summary0027547: [Qt, rotated text] Wrong position of Tile of left TChartAxis
Description- Start project,
- Drop TCart on form,
- Chart -> left_axis -> title -> Caption := "some text"
- Chart -> left_axis -> title -> visible := TRUE

Result (see attached screenshot): text of left axis is not at center.

But if Chart -> left_axis -> title -> font -> orientation := 0 then text appears at center (but horizontal of course);

Tested same SVN version on WinXP - text is at center of axis.
TagsNo tags attached.
Fixed in Revision48299,48300
LazTarget1.4
WidgetsetQT
Attached Files
  • tchart_axis_title.png (196,903 bytes)
    tchart_axis_title.png (196,903 bytes)
  • textalignment_textlayout.zip (2,598 bytes)
  • current_qt.png (34,155 bytes)
    current_qt.png (34,155 bytes)
  • qt_with_patch.png (33,639 bytes)
    qt_with_patch.png (33,639 bytes)
  • qt-drawtext.patch (2,123 bytes)
    Index: qtwinapi.inc
    ===================================================================
    --- qtwinapi.inc	(Revision 48278)
    +++ qtwinapi.inc	(Arbeitskopie)
    @@ -1303,48 +1303,6 @@
       B: Boolean;
       S: String;
       i: Integer;
    -
    -  procedure CalculateOffsetWithAngle(const AFontAngle: Integer;
    -    var TextLeft,TextTop: Integer);
    -  var
    -    OffsX, OffsY: integer;
    -    Angle: Integer;
    -    Size: TSize;
    -  begin
    -    OffsX := R.Right - R.Left;
    -    OffsY := R.Bottom - R.Top;
    -    Size.cX := OffsX;
    -    Size.cy := OffsY;
    -    Angle := AFontAngle div 10;
    -    if Angle < 0 then
    -      Angle := 360 + Angle;
    -
    -    if Angle <= 90 then
    -    begin
    -      OffsX := 0;
    -      OffsY := Trunc(Size.cx * sin(Angle * Pi / 180));
    -    end else
    -    if Angle <= 180 then
    -    begin
    -      OffsX := Trunc(Size.cx * -cos(Angle * Pi / 180));
    -      OffsY := Trunc(Size.cx * sin(Angle * Pi / 180) +
    -         Size.cy * cos((180 - Angle) * Pi / 180));
    -    end else
    -    if Angle <= 270 then
    -    begin
    -      OffsX := Trunc(Size.cx * -cos(Angle * Pi / 180) +
    -        Size.cy * sin((Angle - 180) * Pi / 180));
    -      OffsY := Trunc(Size.cy * sin((270 - Angle) * Pi / 180));
    -    end else
    -    if Angle <= 360 then
    -    begin
    -      OffsX := Trunc(Size.cy * sin((360 - Angle) * Pi / 180));
    -      OffsY := 0;
    -    end;
    -    TextTop := OffsY;
    -    TextLeft := OffsX;
    -  end;
    -
     begin
       {$ifdef VerboseQtWinAPI}
         WriteLn('[WinAPI DrawText] DC: ', dbghex(DC), ' Str: ', string(Str),
    @@ -1410,17 +1368,7 @@
         Exit;
       end;
     
    -  // if our Font.Orientation <> 0 we must recalculate X,Y offset
    -  // also it works only with DT_TOP DT_LEFT. Qt can handle multiline
    -  // text in this case too.
       Pt := Point(0, 0);
    -  if (QtDC.Font.Angle <> 0) and
    -    (Flags and DT_VCENTER = 0) and (Flags and DT_CENTER = 0) and
    -    (Flags and DT_RIGHT = 0) and (Flags and  DT_BOTTOM = 0) then
    -  begin
    -    Pt := Point(ARect.Left, ARect.Top);
    -    CalculateOffsetWithAngle(QtDC.font.Angle, Pt.X, Pt.Y);
    -  end;
     
       // we cannot fit into rectangle, so use DT_SINGLELINE.See #17329.
       // http://msdn.microsoft.com/en-us/library/dd162498%28v=VS.85%29.aspx
    
    qt-drawtext.patch (2,123 bytes)

Activities

Valdas Jankūnas

2015-02-26 18:33

reporter  

tchart_axis_title.png (196,903 bytes)
tchart_axis_title.png (196,903 bytes)

wp

2015-02-27 00:56

developer   ~0081469

In Lazarus, fonts are initialized with a default size 0. This works fine for many widget sets such as Windows or gtk, but qt seems to be a candidate where the size seems to require the correct value to work correctly.

As a work-around set the size of the rotated font to a reasonable value (10, presumably), and the axis title will be centered correctly.

In the meantime, I'll investigate if or how this issue can be avoided.

wp

2015-02-27 01:01

developer   ~0081470

Tested with Laz 1.5/qt in Mint 32-bit in a VM and confirm the issue (it does not occur with gtk). As written in the previous note, the title is correctly centered if the labelfont size is a non-zero value.

wp

2015-03-10 00:28

developer  

textalignment_textlayout.zip (2,598 bytes)

wp

2015-03-10 00:29

developer  

wp

2015-03-10 00:30

developer  

wp

2015-03-10 00:35

developer   ~0081786

Last edited: 2015-03-10 00:38

View 2 revisions

Strange... I can no longer confirm that the title is correctly centered if the font has a non-zero size.

Anyway, I investigated a bit further into this issue.

TAChart draws the axis title with TextAlignment taLeftJustify and TextLayout tlTop. To get the text centered vertically it moves the drawing rectangle down by half the text width such that the anchor point is at the correct position. From the screenshot of the OP I would guess that the text anchor should be where the title ends. With "anchor" I mean the top/left position of the text.

I uploaded a test program which paints text on a paintbox with all combinations of TextAlignment and TextLayout. I must confess that there are some surprises in this output which would require some further corrections of anchor points. But let's focus on the top/left corner of the rectangle which corresponds to the combination laLeftJustify/tlLayout used by TAChart.

See the attached screenshots for windows and qt.

On both Windows and qt, non-rotated text (combobox 0°) has its upper left corner at this point (only Win screenshot uploaded).

Switching to 90° rotates the text out of the rectangle in Windows, but again the anchor point is at the left/top corner of the rectangle.

In qt, on the other hand, the rotated text stays within the rectangle, the text ends in the upper left corner. Moreover qt is not consistent because the other TextAlignments move the text out of the box.

In total, the qt output is offset with respect to the Windows output for the rotated font. No idea whether the qt or windows point of view is correct, but they absolutely must be consistent.

wp

2015-03-10 00:37

developer  

Zeljan Rikalo

2015-03-10 21:55

developer  

current_qt.png (34,155 bytes)
current_qt.png (34,155 bytes)

Zeljan Rikalo

2015-03-10 21:56

developer  

qt_with_patch.png (33,639 bytes)
qt_with_patch.png (33,639 bytes)

Zeljan Rikalo

2015-03-10 21:59

developer   ~0081815

Last edited: 2015-03-10 22:45

View 2 revisions

Pls look at the provided screenshoots. I've used fillRect() with opacity to show cliprect (yellow) and textrect (red),
Textrect comes from TAChart, so there's no 1st text rect for top left text. Text rect is TAChart rect. IMO this is TAChart bug.
Second screenshoot shows how it looks with one liner patch. Win7 prints it up because it uses Abs(calculatedOffset) for rotated text, but it does not matter too much. Point is that 1st text rect (topleft "ABC") from tachart is not correct.
EDIT: now I see it's paintbox, so TAChart doesn't have anything to do with that.

wp

2015-03-10 23:04

developer   ~0081819

I was not concerned about clipping in this code (clipping is turned off), only on positioning of the text with respect to the points defined by TextAlignment and TextLayout.

Did you look at my code? The texts are painted like this:

  Paintbox1.Canvas.TextRect(R, x, y, 'ABC', txtstyle);

txtstyle defines text alignment and layout, and turns clipping off (--> no cliprect involved; if clipping is on the rotated texts disappear except for topleft, in contrast to win where only the upper row disappears because it is outside the cliprect). R is the YELLOW (!) rectangle, x,y defines the top left corner - TextRect ignore this parameter only for the top/left arrangement (you can see this if you change x/y by means of the spin controls).
 
I do not see how your argument relates to my code.

Could you upload your modified version of the demo? How did you paint the red boxes?

Zeljan Rikalo

2015-03-11 17:28

developer   ~0081838

No, your code is ok. See "EDIT" in my comment. I didn't even look into your code but in widgetset code, so all the time I though that example contains TAChart, but finally when I looked into your code I've found plain TPaintBox (after I wrote my comments). :)

Zeljan Rikalo

2015-03-11 17:30

developer   ~0081839

If you wan't to fix it look into TQtWidgetSet.DrawText() where we calculate offset for rotated text.

wp

2015-03-12 12:06

developer   ~0081866

The TQtWidgetSet.DrawText contains some calculations for the top/left case which make sure that the rotated text never leaves the rectangle specified by DrawRect. If I remove this calculation (see in the attached patch) then qt behaves like win (except for multiline text, which stays correctly aligned in rotated qt), and the title is correctly centered in TAChart.

It is disturbing, however, that gtk2 seems to contain the same calculations and shows the same rotated text offset as qt (before the patch), but the chart axis title is nevertheless correctly centered. Therefore, I fear the "true" bug is somewhere else.

I also think that this calculation must be there for some reason and I fear some side-effects in other components or user applications...

wp

2015-03-12 12:06

developer  

qt-drawtext.patch (2,123 bytes)
Index: qtwinapi.inc
===================================================================
--- qtwinapi.inc	(Revision 48278)
+++ qtwinapi.inc	(Arbeitskopie)
@@ -1303,48 +1303,6 @@
   B: Boolean;
   S: String;
   i: Integer;
-
-  procedure CalculateOffsetWithAngle(const AFontAngle: Integer;
-    var TextLeft,TextTop: Integer);
-  var
-    OffsX, OffsY: integer;
-    Angle: Integer;
-    Size: TSize;
-  begin
-    OffsX := R.Right - R.Left;
-    OffsY := R.Bottom - R.Top;
-    Size.cX := OffsX;
-    Size.cy := OffsY;
-    Angle := AFontAngle div 10;
-    if Angle < 0 then
-      Angle := 360 + Angle;
-
-    if Angle <= 90 then
-    begin
-      OffsX := 0;
-      OffsY := Trunc(Size.cx * sin(Angle * Pi / 180));
-    end else
-    if Angle <= 180 then
-    begin
-      OffsX := Trunc(Size.cx * -cos(Angle * Pi / 180));
-      OffsY := Trunc(Size.cx * sin(Angle * Pi / 180) +
-         Size.cy * cos((180 - Angle) * Pi / 180));
-    end else
-    if Angle <= 270 then
-    begin
-      OffsX := Trunc(Size.cx * -cos(Angle * Pi / 180) +
-        Size.cy * sin((Angle - 180) * Pi / 180));
-      OffsY := Trunc(Size.cy * sin((270 - Angle) * Pi / 180));
-    end else
-    if Angle <= 360 then
-    begin
-      OffsX := Trunc(Size.cy * sin((360 - Angle) * Pi / 180));
-      OffsY := 0;
-    end;
-    TextTop := OffsY;
-    TextLeft := OffsX;
-  end;
-
 begin
   {$ifdef VerboseQtWinAPI}
     WriteLn('[WinAPI DrawText] DC: ', dbghex(DC), ' Str: ', string(Str),
@@ -1410,17 +1368,7 @@
     Exit;
   end;
 
-  // if our Font.Orientation <> 0 we must recalculate X,Y offset
-  // also it works only with DT_TOP DT_LEFT. Qt can handle multiline
-  // text in this case too.
   Pt := Point(0, 0);
-  if (QtDC.Font.Angle <> 0) and
-    (Flags and DT_VCENTER = 0) and (Flags and DT_CENTER = 0) and
-    (Flags and DT_RIGHT = 0) and (Flags and  DT_BOTTOM = 0) then
-  begin
-    Pt := Point(ARect.Left, ARect.Top);
-    CalculateOffsetWithAngle(QtDC.font.Angle, Pt.X, Pt.Y);
-  end;
 
   // we cannot fit into rectangle, so use DT_SINGLELINE.See #17329.
   // http://msdn.microsoft.com/en-us/library/dd162498%28v=VS.85%29.aspx
qt-drawtext.patch (2,123 bytes)

Zeljan Rikalo

2015-03-12 16:20

developer   ~0081877

Please test and close if ok. Gtk2 and Qt are fixed.

Valdas Jankūnas

2015-03-12 16:33

reporter   ~0081879

Thanks.

Issue History

Date Modified Username Field Change
2015-02-26 18:33 Valdas Jankūnas New Issue
2015-02-26 18:33 Valdas Jankūnas File Added: tchart_axis_title.png
2015-02-27 00:51 wp Assigned To => wp
2015-02-27 00:51 wp Status new => assigned
2015-02-27 00:56 wp Note Added: 0081469
2015-02-27 01:01 wp Note Added: 0081470
2015-02-27 08:59 Zeljan Rikalo Assigned To wp => Zeljan Rikalo
2015-03-10 00:28 wp File Added: textalignment_textlayout.zip
2015-03-10 00:29 wp File Added: textalignment_textlayout_win.png
2015-03-10 00:30 wp File Added: textalignment_textlayout_qt.png
2015-03-10 00:35 wp Note Added: 0081786
2015-03-10 00:37 wp File Added: textalignment_textlayout_win_not_rotated.png
2015-03-10 00:38 wp Note Edited: 0081786 View Revisions
2015-03-10 21:55 Zeljan Rikalo File Added: current_qt.png
2015-03-10 21:56 Zeljan Rikalo File Added: qt_with_patch.png
2015-03-10 21:59 Zeljan Rikalo LazTarget => -
2015-03-10 21:59 Zeljan Rikalo Note Added: 0081815
2015-03-10 21:59 Zeljan Rikalo Status assigned => feedback
2015-03-10 22:45 Zeljan Rikalo Note Edited: 0081815 View Revisions
2015-03-10 23:04 wp Note Added: 0081819
2015-03-11 17:28 Zeljan Rikalo Note Added: 0081838
2015-03-11 17:30 Zeljan Rikalo Note Added: 0081839
2015-03-12 12:06 wp Note Added: 0081866
2015-03-12 12:06 wp File Added: qt-drawtext.patch
2015-03-12 16:20 Zeljan Rikalo Fixed in Revision => 48299,48300
2015-03-12 16:20 Zeljan Rikalo LazTarget - => 1.4
2015-03-12 16:20 Zeljan Rikalo Note Added: 0081877
2015-03-12 16:20 Zeljan Rikalo Status feedback => resolved
2015-03-12 16:20 Zeljan Rikalo Fixed in Version => 1.5 (SVN)
2015-03-12 16:20 Zeljan Rikalo Resolution open => fixed
2015-03-12 16:20 Zeljan Rikalo Target Version => 1.4RC2
2015-03-12 16:33 Valdas Jankūnas Note Added: 0081879
2015-03-12 16:33 Valdas Jankūnas Status resolved => closed