Recent

Author Topic: Text orientation in TMemo?  (Read 19513 times)

hukka

  • New Member
  • *
  • Posts: 32
    • Github
Re: Text orientation in TMemo?
« Reply #15 on: February 16, 2024, 12:07:18 pm »
If you have a normal TMemo you can just paint the memo to a Bitmap, rotate it and display the bitmap/timage at the correct location.

Note that this will look ugly and possibly unreadable if the font is rendered with any sort of subpixel antialiasing such as ClearType on Windows.

CM630

  • Hero Member
  • *****
  • Posts: 1191
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Text orientation in TMemo?
« Reply #16 on: February 16, 2024, 09:22:03 pm »

I would not waste any time on this. TAChart now has editing tools (https://wiki.lazarus.freepascal.org/TAChart_documentation#Chart_element_tools), and I would simply show an InputBox after double(?) clicking on the title (see charteditor demo in the TAChart demo folder).

Something seems wrong with the Axis click tool.
The left axis seems okay, but when I click on the label of the bottom axis, I get ahtAxisStart instead of ahtTitle (snippet attached).
Lazarus 3.0.

..
Something like this (if you use Windows):...

Thanks, I tried it. I prefer some multiplatforms solution. I did some reading, but I have not found a multiplatform solution, yet.
And indeed, for some reason the rotated text seems somehouw ugly  :o
« Last Edit: February 16, 2024, 09:53:30 pm by CM630 »
Лазар 4,0RC1 32 bit (sometimes 64 bit); FPC3,2,2

wp

  • Hero Member
  • *****
  • Posts: 12456
Re: Text orientation in TMemo?
« Reply #17 on: February 17, 2024, 04:05:25 pm »
Something seems wrong with the Axis click tool.
The left axis seems okay, but when I click on the label of the bottom axis, I get ahtAxisStart instead of ahtTitle (snippet attached).
You are right, I just wonder why the ChartEditorDemo is working correctly... Anyway, the issue should be fixed now in main; and there is also an extended version of your test project among the TAChart demos.

CM630

  • Hero Member
  • *****
  • Posts: 1191
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Text orientation in TMemo?
« Reply #18 on: April 07, 2024, 07:03:07 pm »
I have some issues with the AxisClickTool.
1. How am I to know which axis was clicked?
Axis.ID returns whatever it wants.
Shall I use if leftstr(Axis.DisplayName,6)  = 'Bottom' then ... or there is another solution?


2. ahtAxisStart and
ahtAxisEnd happen to be too wide. Is this ajdustible?

3. Axis.GetLabeledAxisRect.Left seems to return the position of the plot area.
I definitely need this value, but is this expected behaviour? It does not sound like a property of the axis?


Лазар 4,0RC1 32 bit (sometimes 64 bit); FPC3,2,2

rvk

  • Hero Member
  • *****
  • Posts: 6570
Re: Text orientation in TMemo?
« Reply #19 on: April 08, 2024, 07:38:20 am »
1. How am I to know which axis was clicked?
Axis.ID returns whatever it wants.
Shall I use if leftstr(Axis.DisplayName,6)  = 'Bottom' then ... or there is another solution?
The TAxisClickTool.OnClick has a parameter Axis: TChartAxis. So you can just test that, can't you?
Code: Pascal  [Select][+][-]
  1. if Axis = ASender.Chart.HorAxis then ShowMessage('Horizontal axis');


2. ahtAxisStart and
ahtAxisEnd happen to be too wide. Is this ajdustible?

3. Axis.GetLabeledAxisRect.Left seems to return the position of the plot area.
I definitely need this value, but is this expected behaviour? It does not sound like a property of the axis?

In TChartAxis.GetHitTestInfoAt() you have the code below.
So you can see the start and end is defined by 1/4 at the left and 1/4 at the right and 2/4 at the center.
It doesn't seem to be adjustable (without modifying the code).

Code: Pascal  [Select][+][-]
  1.     end else begin
  2.       dist := abs(R.Right - R.Left) div 4;
  3.       p := abs(APoint.X - R.Left);
  4.       if p < dist then
  5.         loc := -1
  6.       else if p > 3 * dist then
  7.         loc := +1
  8.       else
  9.         loc := 0;
  10.     end;
  11.     if IsFlipped then
  12.       loc := -loc;
  13.     case loc of
  14.       -1: if (ahtAxisStart in ATest) then Include(Result, ahtAxisStart);
  15.        0: if (ahtAxisCenter in ATest) then Include(Result, ahtAxisCenter);
  16.       +1: if (ahtAxisEnd in ATest) then Include(Result, ahtAxisEnd);
  17.     end;

3. Axis.GetLabeledAxisRect.Left seems to return the position of the plot area.
I definitely need this value, but is this expected behaviour? It does not sound like a property of the axis?

I think Axis.GetLabeledAxisRect is only used when Axis.AtDataOnly is set to true.
(https://forum.lazarus.freepascal.org/index.php/topic,35606.msg235654.html#msg235654)

Maybe you can explain why you need this value, as you don't actually know what the value is supposed to return  ;)

Code: Pascal  [Select][+][-]
  1. function TChartAxis.GetLabeledAxisRect: TRect;
  2. begin
  3.   Result := FHelper.FClipRect^; //FAxisRect;
  4.   if FAtDataOnly then
  5.   begin
  6.     if IsVertical then
  7.     begin
  8.       Result.Bottom := FHelper.GraphToImage(FHelper.MinForMarks);
  9.       Result.Top := FHelper.GraphToImage(FHelper.MaxForMarks);
  10.     end else
  11.     begin
  12.       Result.Left := FHelper.GraphToImage(FHelper.MinForMarks);
  13.       Result.Right := FHelper.GraphToImage(FHelper.MaxForMarks);
  14.     end;
  15.   end;
  16. end;

CM630

  • Hero Member
  • *****
  • Posts: 1191
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Text orientation in TMemo?
« Reply #20 on: April 08, 2024, 11:37:33 am »
I need to draw a TText (txtExtents) over the scale so the user will be able to set a value for the extents.
So I need to know where to place the text box.
With GetLabeledAxisRect I get the rightmost position for the left axis and the top position of the bottom axis.
But if I am not using it properly, it might not work in some cases.

This seems to work, but I am not sure if it will do it always:
Code: Pascal  [Select][+][-]
  1. ...
  2.   txtExtents.Alignment := taRightJustify;
  3.   if (ahtAxisEnd in aHit) and Axises.AxisYVisible then
  4.         begin
  5.           txtExtents.Width := Axis.GetLabeledAxisRect.Left - Axis.TickLength - 1;
  6.           txtExtents.Left := 0;
  7.           txtExtents.Top := Chart.Top;                              
  8.  
  9. ...
  10.  
  11.       txtExtents.Width := 40;
  12.       txtExtents.Alignment := taLeftJustify;
  13.       if (ahtAxisStart in aHit) and Axises.AxisXVisible then
  14.         begin
  15.           txtExtents.Top:= Axis.GetLabeledAxisRect.Bottom + Axis.TickLength + 1;
  16.           txtExtents.Left:=Chart.Margins.Left + 75;
Лазар 4,0RC1 32 bit (sometimes 64 bit); FPC3,2,2

wp

  • Hero Member
  • *****
  • Posts: 12456
Re: Text orientation in TMemo?
« Reply #21 on: April 08, 2024, 01:05:54 pm »
The attachment gives an impression of edit controls for chart axis minimum and maximum. They are added to the bottom of the panel to which the chart belongs; in my case it was enough to place them right in the corners of the panel and align them so that they adjust their position when the chart size changes. If you want to position the edits close to the border of the plot area you can use the ClipRect property of the Chart (which returns pixel coordinates) or CurrentExtent and convert to pixels (Chart.GraphToImage).

I would not place the edits into the chart to sit right over the labels because it's quite some effort to determine the position of the axis labels.

CM630

  • Hero Member
  • *****
  • Posts: 1191
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Text orientation in TMemo?
« Reply #22 on: April 08, 2024, 07:50:10 pm »
...
Code: Pascal  [Select][+][-]
  1. if Axis = ASender.Chart.HorAxis then ShowMessage('Horizontal axis');
...
Yes, that works!


If you want to position the edits close to the border of the plot area you can use the ClipRect property of the Chart (which returns pixel coordinates) or CurrentExtent and convert to pixels (Chart.GraphToImage).
txtExtents.Width := Axis.GetLabeledAxisRect.Left - Axis.TickLength - 1;
   and
txtExtents.Top:= Axis.GetLabeledAxisRect.Bottom + Axis.TickLength + 1;
give me the position that I need. But does Axis.GetLabeledAxisRect return what it is expected to do?
If it does, maybe there is no benefit in using ClipRect etc?

The attachment gives an impression of edit controls for chart axis minimum and maximum.
Yes, that is it.

They are added to the bottom of the panel to which the chart belongs; in my case it was enough to place them right in the corners of the panel and align them so that they adjust their position when the chart size changes.
Having edits always will result in a waste of screen space, and it does not fit in the „standard“.

I would not place the edits into the chart to sit right over the labels because it's quite some effort to determine the position of the axis labels.

There is actually one and only edit, which is visible only when editing. And it is placed over the endmost position of the scale.
In the perfect case it should be placed over the endmost indication value of the scale, when the endmost value is clicked.
Maybe it might be solved with a custom scale, which will force values displayed in the beginning and the end of the scale. Still I am not sure if it will look good.
« Last Edit: April 08, 2024, 07:54:10 pm by CM630 »
Лазар 4,0RC1 32 bit (sometimes 64 bit); FPC3,2,2

wp

  • Hero Member
  • *****
  • Posts: 12456
Re: Text orientation in TMemo?
« Reply #23 on: April 08, 2024, 08:00:59 pm »
But does Axis.GetLabeledAxisRect return what it is expected to do?
To be honest, I don't know. In particular, when there are several axes at the same side of the chart, its hard to tell whether it covers the entire side of the chart or only the part of that specific axis; I would have to make an experiement. But in case of a single axis it should work. The same applies to ClipRect as well, BTW.

CM630

  • Hero Member
  • *****
  • Posts: 1191
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Text orientation in TMemo?
« Reply #24 on: April 17, 2024, 04:00:30 pm »
For some reason sometimes TDataPointDragTool.Series does not work (it returns nil instead of the pointed series) when there is an enabled TAxisClickTool.
Unfortunately, I did not succeed in creating a simple snippet, in which the issue is reproduced.
Лазар 4,0RC1 32 bit (sometimes 64 bit); FPC3,2,2

wp

  • Hero Member
  • *****
  • Posts: 12456
Re: Text orientation in TMemo?
« Reply #25 on: April 17, 2024, 05:51:25 pm »
Is this when the datapoint is very close to the axis or the axis grid? What is the order of the two tools in the ChartTools list? When the axis click tool is first and the clicked datapoint is close to or on a grid line, the axis tool will catch the click, which then will not be propagated to the drag tool. So, from this point-of-view use the ChartTool editor to move the drag tool before the axis click tool. But on the other hand, when the first data points are on the axis you cannot click on the axis any more in this configuration to display a range editor for the axis range. If something like this is likely to happen you should assign different Shift combinations to the tools or add a toolbar or similar so that only one of them can be active.

CM630

  • Hero Member
  • *****
  • Posts: 1191
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Text orientation in TMemo?
« Reply #26 on: April 18, 2024, 08:41:53 am »
I reproduced it and found a solution that solves the dragging issue, it does not seem to affect the AxisClick behaviour.
A sample code is attached, with the same code, as shown below.
It is as you proposed. If ctMainAxisClick.Toolset:=ctMain; is before ctMainDataPointDrag.Toolset:=ctMain; I cannot drag,
but when I reversed the order of these two lines, I can drag.
But if you run the app, you might also notice, that Label2 changes its caption when clicking/dragging on places which are too far from the axises. Maybe this behaviour is not okay?

Code: Pascal  [Select][+][-]
  1.  
  2.   Chart1.Toolset := ctMain;
  3.   ctMainAxisClick.Toolset:=ctMain;
  4.   ctMainDataPointDrag.Toolset:=ctMain;  
  5.  




The full code of the snippet:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3.  
  4. {$mode objfpc}{$H+}
  5.  
  6.  
  7. interface
  8.  
  9.  
  10. uses
  11.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, TAGraph,
  12.   TATools, TASeries, TADrawUtils, TACustomSeries, Types, TAChartAxis, TASources, TACustomSource,TAChartUtils;
  13.  
  14.  
  15. type
  16.  
  17.  
  18.   TFloatPoint = Record
  19.     X: Double;
  20.     Y: Double;
  21.   end;
  22.  
  23.  
  24.   TFloatPointArray = array of TFloatPoint;
  25.   { TForm1 }
  26.  
  27.  
  28.   TForm1 = class(TForm)
  29.     Chart1: TChart;
  30.     Chart1LineSeries1: TLineSeries;
  31.     Label1: TLabel;
  32.     Label2: TLabel;
  33.     Label3: TLabel;
  34.  
  35.  
  36.     ctMain: TChartToolset;
  37.     ctMainDataPointDrag: TDataPointDragTool;
  38.     ctMainAxisClick: TAxisClickTool;
  39.     procedure ctMainAxisClickToolOnClick(ASender: TChartTool; Axis: TChartAxis; AHitInfo: TChartAxisHitTests);
  40.     procedure ctMainDataPointDragAfterMouseMove(ATool: TChartTool; APoint: TPoint);
  41.     procedure ctMainDataPointDragTool1DragStart(ASender: TDataPointDragTool; var AGraphPoint: TDoublePoint);
  42.     procedure FormCreate(Sender: TObject);
  43.   private
  44.  
  45.  
  46.   public
  47.  
  48.  
  49.   end;
  50.  
  51.  
  52. var
  53.   Form1: TForm1;
  54.  
  55.  
  56. implementation
  57.  
  58.  
  59. {$R *.lfm}
  60.  
  61.  
  62. { TForm1 }
  63.  
  64.  
  65. function GenSin (Frequency: Extended; Amplitude: Extended; SamPerSec:single; Offset: Extended=0; Duration: integer= 1000;PhaseShift:single=0): TFloatPointArray;
  66. var
  67.   i: integer;
  68.   SampleCount: integer;
  69.   dt: double;
  70.   debY: double;
  71. begin
  72.   SampleCount:=trunc(SamPerSec*Duration/1000)+1;
  73.   SetLength(Result,SampleCount);
  74.   dt:=1/SamPerSec;
  75.   for i:= 0 to SampleCount-1 do
  76.   begin
  77.     Result[i].X:=i/SamPerSec ;
  78.     debY:=sin(i*2*pi*Frequency/SamPerSec+(PhaseShift*2*pi/360))*Amplitude+Offset;
  79.     Result[i].Y:=sin(i*2*pi*Frequency/SamPerSec+(PhaseShift*2*pi/360))*Amplitude+Offset;
  80.   end;
  81. end;
  82.  
  83.  
  84. procedure TForm1.FormCreate(Sender: TObject);
  85. var
  86.   LSeriesArray: array of TLineSeries;
  87.   i: integer;
  88.   sin1: TFloatPointArray;
  89. begin
  90.   ctMain:=TChartToolset.Create (Chart1);
  91.  
  92.  
  93.   ctMainAxisClick := TAxisClickTool.Create(ctMain);
  94.   ctMainAxisClick.Shift := [ssLeft];
  95.   ctMainAxisClick.Enabled := True;
  96.   ctMainAxisClick.OnClick := @ctMainAxisClickToolOnCLick;
  97.  
  98.  
  99.   ctMainDataPointDrag:=TDataPointDragTool.Create(ctMain);
  100.   ctMainDataPointDrag.Shift:=[ssLeft];
  101.   ctMainDataPointDrag.Enabled:=True;
  102.   ctMainDataPointDrag.OnDragStart := @ctMainDataPointDragTool1DragStart;
  103.   ctMainDataPointDrag.OnAfterMouseMove:=@ctMainDataPointDragAfterMouseMove;
  104.  
  105.  
  106.   Chart1.Toolset := ctMain;
  107.   ctMainAxisClick.Toolset:=ctMain;
  108.   ctMainDataPointDrag.Toolset:=ctMain;
  109.  
  110.  
  111.   sin1 := GenSin(50,5,1000,0,1000);
  112.   for i:=0 to Length(sin1) do
  113.     Chart1LineSeries1.AddXY(sin1[i].x,sin1[i].y);
  114.  
  115.  
  116.   SetLength (LSeriesArray ,10);
  117.   for i:=0 to 9 do
  118.   begin
  119.     LSeriesArray[i] := TLineSeries.Create(self);
  120.     Chart1.AddSeries(LSeriesArray[i]);
  121.     LSeriesArray[i].Pointer.Visible := true;
  122.     LSeriesArray[i].AddXY(i/10,i);
  123.   end;
  124. end;
  125.  
  126.  
  127. procedure TForm1.ctMainDataPointDragAfterMouseMove(ATool: TChartTool; APoint: TPoint);
  128. begin
  129.   if ctMainDataPointDrag.Series = nil then Label3.Caption := 'nil' else Label3.Caption := IntToStr( ctMainDataPointDrag.Series.Index);
  130.   Label1.Caption := {ChartToolset1DataPointDragTool1.Series.Name + '; ' +}  IntToStr(APoint.X) + '; ' + IntToStr(APoint.y)  ;
  131. end;
  132.  
  133.  
  134. procedure TForm1.ctMainAxisClickToolOnCLick(ASender: TChartTool; Axis: TChartAxis; AHitInfo: TChartAxisHitTests);
  135. begin
  136.   Label2.Caption := Axis.DisplayName;
  137. end;
  138.  
  139.  
  140. procedure TForm1.ctMainDataPointDragTool1DragStart(ASender: TDataPointDragTool; var AGraphPoint: TDoublePoint);
  141. begin
  142.   if ctMainDataPointDrag.Series = nil then exit; //Checks if a dot is dragger, to prevent crashing
  143.   if ctMainDataPointDrag.Series = Chart1LineSeries1 then       ASender.Handled;; //Prevent dragging the main curve
  144. end;
  145.  
  146.  
  147. end.
« Last Edit: April 18, 2024, 09:04:10 am by CM630 »
Лазар 4,0RC1 32 bit (sometimes 64 bit); FPC3,2,2

wp

  • Hero Member
  • *****
  • Posts: 12456
Re: Text orientation in TMemo?
« Reply #27 on: April 18, 2024, 10:27:54 am »
you might also notice, that Label2 changes its caption when clicking/dragging on places which are too far from the axises.
Well, a reaction on such clicks is expected when you click on one of the grid lines associated with an axis. You can hide the axis grid, and the click will no longer be assigned to this axis. But I see that it is not always an option to turn off the axis grid, and therefore I just committed a change to the chart axis in which a new property EnabledHitTests (of type TChartHitTests = set of (ahtTitle, ahtLine, ahtLabels, ahtGrid, ahtAxisStart, ahtAxisCenter, ahtAxisEnd) ) is available. When you here remove an element, a click on the corresponding part of the axis will no longer be registered as an axis-click.

In your code:
Code: Pascal  [Select][+][-]
  1. // Note: TAChart from Laz/main 02d8ea0bde or newer required!)
  2.   Chart1.BottomAxis.EnabledHitTests := Chart1.BottomAxis.EnabledHitTests - [ahtGrid];
  3.   Chart1.LeftAxis.EnabledHitTests := Chart1.LeftAxis.EnabledHitTests - [ahtGrid];  

 

TinyPortal © 2005-2018