March 28, 2024, 09:04:22 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Visual position V Actual position

Started by Andy, September 25, 2020, 10:27:28 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andy

September 25, 2020, 10:27:28 PM Last Edit: September 25, 2020, 10:50:47 PM by Andy
Well this one surprised me.

When I added in the command to set the tabs on loading a file into a rich edit control everything looked nice and neat.

SENDMESSAGE(rHandle,EM_SETSEL,0,0+1)
CONTROLCMD w1,1,@RTGETSELTEXT,ClipText
CONTROLCMD w1,1,@RTREPLACESEL,CLipText
SENDMESSAGE(rHandle,EM_SETTABSTOPS,1,&Tabss)  '<-- Tabss is set to 3

But there are problems with that...

It is only a visual effect, it does not change the character positions.

Let me explain, here is the code I use to find out what position I am on in the rich edit:

ppos = GETCARETPOSITION w1,AcrossX,DownY
AcrossX --
AcrossX = AcrossX / 8
AcrossX ++
EditPos = CONTROLCMD(w1,1,@RTCHARFROMLINE,cLine-1)
EditPos = (EditPos + AcrossX) - 1

W1 is my window.
1 is the rich edit control.
cLine is the current line number.

EditPos is the position where I am, i.e. position

Now if we take one simple line (with tabs in it)

<TAB><TAB>IF<TAB>ENDIF

And we set the tab spacing to 3...

On screen when we move across the line the EditPos variable returns this:

<TAB> no 1 (position zero  - 0 to 2)
<TAB> no 2 (position three - 3 to 5)
IF        (The "I" is shown as position 6)

However, when I use the GETLINE function to get the line text, it gives me what's really there:

<TAB><TAB>IF<TAB>ENDIF

10 characters (let's ignore the CHR$(13) and CHR$(10) at the end of the line).

The problem:

On screen the EditPos variable says the "I" in the word "IF" starts at 6, the GETLINE function says it starts at 3.

The GETLINE function:

CONTROLCMD(w1,1,@RTGETLINE,cLine-1,line$,512) '<-- line$ contains the line

So how can I calculate the position difference?

And here's the punch line!


You would think the <TAB> between the words IF and ENDIF would space 3 on screen, but visually it does not, it only places 1 space between them, even worse, depending on how you have typed the line and what's on it you can even end up with a tab creating two spaces.

So I believe it has something to do with multiples of 3? (as tabs in this case are set to 3).

Try typing the above line in your IWB editor and it does exactly as my program does.

By the way, I'm using

SETFONT w1, "Courier New",10,400,0,1

for my rich edit control.

This is a serious problem for me, it means:

1. I can't use Clint's fast load code to load a file as tabs are not replaced.
2. I can't auto complete key words when typing as the edit position is wrong.

I need a way of translating the EditPos value to the actual position in the line of text.

I need a smart person on this please!

Thanks,
Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

September 26, 2020, 05:57:43 AM #1 Last Edit: September 26, 2020, 06:00:08 AM by Andy
Solved.

Well I knew an adjustment of some sort was needed to the edit position on screen, but how?

Here is the code:


ppos = GETCARETPOSITION w1,AcrossX,DownY
AcrossX --
AcrossX = AcrossX / 8
AcrossX ++
EditPos = CONTROLCMD(w1,1,@RTCHARFROMLINE,cLine-1)
EditPos = (EditPos + AcrossX) - 1

IF PrevEditPos <> EditPos
  IF cLine = StoreLine
   INT varStart2,varEnd2
   CONTROLCMD w1,1,@RTGETSELECTION,varStart2,varEnd2
   IF varStart2 <> Offset
   AdjustPos = EditPos - varStart2
   ELSE
   AdjustPos = 0
   ENDIF
   EditPos = EditPos - AdjustPos
  ENDIF
  IF cLine <> StoreLine and varStart2 = Offset
 EditPos = Offset
  ENDIF
  PrevEditPos = EditPos
ENDIF

Code explained:

This code is in my fast timer.

cLine is the current line you are on now.
StoreLine was the previous line you were on.
PrevEditPos was the position you were on.

If you have changed position but still on the same line as before, get the caret position (where the cursor is).

CONTROLCMD w1,1,@RTGETSELECTION,varStart2,varEnd2

If the caret position is not the first character on the line (Offset) and different to the visual edit position (EditPos) then we have to adjust EditPos.

IF varStart2 <> Offset
  AdjustPos = EditPos - varStart2
ELSE
  AdjustPos = 0
ENDIF
 EditPos = EditPos - AdjustPos '<---- Adjust EditPos

If you've moved to another line and on it's first character:

IF cLine <> StoreLine and varStart2 = Offset
  EditPos = Offset
ENDIF

And that's it, even got my auto complete working again.

The above code fixes the actual edit position rather than giving the visual position which is wrong for what I need here, and I won't forget this one for a while!

8)

Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

aurelCB

Andy 
Dont get me wrong ,and maybe i have no right about that.,
You need some sort of tokenizer to skip chars like empty ,whitespace(blank),tab,cret.lfeed
so skip chr(9) -> tab and never select this chars...
so..do i have right or i am just guesing ?  :)

Andy

September 26, 2020, 11:38:45 PM #3 Last Edit: September 26, 2020, 11:48:36 PM by Andy
Aurel,

What you say sounds logical to me and common sense, however it's not what I found.

When we add in the command to set tabs, the rich edit control decides on the visual appearance and sets it based on the tab size we have told it.

This then plays havoc with the edit position values, or rather it adjusts the edit position to reflect what a human would expect.

Example:

Tabs set to 3.

<TAB>IF

<TAB> --- sel 0
IF --- sels 1 & 2

To me and you, the "I" in the word "IF" would be sel 1, however, because of setting tabs the position of "I" is moved on (here it is 3, but could be 2 or even 1).

As we don't have control of how many "spaces" a tab might be then we cannot calculate what "I" should be.

The sub routine below re-calculates the "visual position" and tells us the "actual position" in the line.

SUB GetSelPos()

'Get X / Y coordinates of the caret on screen.
ppos = GETCARETPOSITION w1,AcrossX,DownY

'Based on watching the value of AcrossX as I moved cursor position
'This formula might different for a different font / size?
'I'm using "Courier New", size 10.
AcrossX --
AcrossX = AcrossX / 8
AcrossX ++

'Get the first character position in the current line (Offset)
EditPos = CONTROLCMD(w1,1,@RTCHARFROMLINE,cLine-1)

'Now adjust EditPos with the value of AcrossX
EditPos = (EditPos + AcrossX) - 1

'Have we changed position ?
IF PrevEditPos <> EditPos '<---- Yes, where we were is not where we are now.

 INT varStart2,varEnd2

 'Where we think we are now...
 CONTROLCMD w1,1,@RTGETSELECTION,varStart2,varEnd2

 'As long as we are not on the first character of the line we need to adjust EditPos.
 IF varStart2 <> Offset
    AdjustPos = EditPos - varStart2 '<--- Find the difference.
 ELSE
    AdjustPos = 0
 ENDIF

 'Adjust EditPos
 EditPos = EditPos - AdjustPos

 'Has line changed? and are we on it's first character? 
 IF cLine <> StoreLine and varStart2 = Offset '<--- Yes
    EditPos = Offset '<--- Just reset EditPos to the line offset position.
 ENDIF

 'Update the Previous edit position.
 PrevEditPos = EditPos

 'Update screen coordinate display information if wanted by you.
 SETCONTROLTEXT(w1,PosEdit,ltrim$(str$(EditPos))) 'Rich edit pos (zero based)
 CONTROLCMD(w1,1,@RTGETLINE,cLine-1,line$,512)
 Offset = SendMessage(rHandle,EM_LINEINDEX,cLine-1,0)
 WordNumber = GetAllWordsOnLine(rHandle,cLine-1,line$,Offset)
ENDIF

CharPos = (EditPos - Offset) + 1 'Human position on line ( 1 based)
IF PrevCharPos <> CharPos
   PrevCharPos = CharPos
   SETCONTROLTEXT(w1,CharPosEdit,ltrim$(str$(CharPos)))
ENDIF

IF PrevWordNumber <> WordNumber  'Human word number ( 1 based)
   PrevWordNumber = WordNumber
   SETCONTROLTEXT(w1,WordNumberEdit,ltrim$(str$(WordNumber)))
ENDIF

RETURN
ENDSUB


I call this sub from a fast timer, which ensures I always know where I am in the rich edit control.

And I use EditPos for my auto complete of key words function as it has to replace the correct characters with a selected key word at the right position.

And that really is the best I can explain it, all I can say is it works - at least in my program.

Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

aurelCB

Wow Andy
i must say that all this looks to complex to me and i am nothing else
than more confused with all this things.
I don't know did i tell you i recently found one code in pureBasic and when i translated it to 
EBasic then not work...why i cannot exaplain to myself..also not work¸in oxygen compiler too
it looks crazy..
also there is very big difference in messages
like 
EM_SETSEL
and 
EM_EXSETSEL
the second cousing crush on my win7 32bit...
ufff

Andy

Aurel,

I don't use EM_EXSETSEL at all so I can't say why it crashes your program.

Regarding the visual position, if you think about it, we are getting the x / y coordinates of the cursor on screen.

Now that the rich edit has moved text across due to tabbing we move the mouse / cursor to the position we see the text at, and that's why we get the visual position and not the actual position of that text in the line itself.

Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

aurelCB

Andy
sorry but i don't get it this thing with visual x.y 
maybe i am too stupid for that things 
at moment i have this :
microEditSyntax.png

aurelCB

Andy
may i ask you ,is there a way to disable vertical scroll when i scan and hilite line by  line ?

Andy

Aurel,

Visual X / Y positions - NO you are not stupid at all! It took a good while for my two brain cells to work it out for me too. The X / Y positions we get are the actual positions on screen, not the position in the rich edit control.

To me and you on screen they would appear to be the same, they simply are not.

Disable vertical scrolling:

This works, create a global variable

INT Scanning = 0

Set it to 1 when scanning, then when finished set it back to zero.

I'm presuming you have sub classed your rich edit control? if so, then all you need to add in it is this -

SUB Rich_Edit_Handler(hwnd:int,uMsg:int,wParam:int,lParam:pointer),int

    SELECT uMsg
           case WM_VSCROLL
                IF Scanning = 1
                   'Here we stop the rich edit scolling by returning zero
                   return 0
                ELSE
                   'Here we let the rich edit do what it was programmed to so - scroll.
                   RETURN CallWindowProcA(GetPropA(hwnd,"edit_handler"),hwnd,uMsg,wParam,lParam)
                ENDIF


Or this -

SUB Rich_Edit_Handler(hwnd:int,uMsg:int,wParam:int,lParam:pointer),int

    SELECT uMsg
           case WM_VSCROLL
                IF Scanning = 1
                   'Here we stop the rich edit scolling by returning zero
                   return 0
                ENDIF

The rest I can look into for you if you can clarify what you are doing / meaning.

Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

aurelCB

QuoteDisable vertical scrolling:

This works, create a global variable

INT Scanning = 0

Set it to 1 when scanning, then when finished set it back to zero.

I'm presuming you have sub classed your rich edit control? if so, then all you need to add in it is this -

CodeSelect
SUB Rich_Edit_Handler(hwnd:int,uMsg:int,wParam:int,lParam:pointer),int

    SELECT uMsg
           case WM_VSCROLL
                IF Scanning = 1
                   'Here we stop the rich edit scolling by returning zero
                   return 0
                ELSE
                   'Here we let the rich edit do what it was programmed to so - scroll.
                   RETURN CallWindowProcA(GetPropA(hwnd,"edit_handler"),hwnd,uMsg,wParam,lParam)
                ENDIF
WOW ..thank you Andy ...i will hard time to figure this ...

and looks really simple... :)

Yes Richedit is subclassed ,image show o2 compiled program which original version is from one Purebasic 
example ,,,,so i think that must work in Ebasic or IWB.
I know how to translate o2 to IWB/EB but i am in same time busy with interpreter
but i will make EB version and post it here ..i hope that should work !

aurelCB

Andy 
I tried with wm_vscroll and not work, also scrolling still work.
But then i found one example from garrybeane - from powerbasic examples
(yes i have powerbasic10 too..)
and found that


QuoteSendMessage(hRich, WM_SETREDRAW, 0, 0) ' disable control redraw and disable vscroll too
IF LineCount > 0
  For Ln = 0 to LineCount
      HighlightLine(Ln)
  Next Ln
END IF
SendMessage(hRich, WM_SETREDRAW, -1, 0) 'enable redraw (-1) is true
and voila it works great...

aurelCB

and small update 
after operation with redraw we need to invalidate rect to unblock control
like this :


QuoteSendMessage(hRich, WM_SETREDRAW, 0, 0)
IF LineCount > 0
  For Ln = 0 to LineCount
      HighlightLine(Ln)
  Next Ln
END IF
SendMessage(hRich, WM_SETREDRAW, -1, 0)
InvalidateRect(hRich, 0, 0) : UpdateWindow hRich

Andy

Aurel,

Good man! well worked out.

I'm already doing this in a sub routine I call QuietMode (in my editor program release I miss spelt it as QuiteMode!)

Here it is:

SUB QuietMode(int Switch)
    IF Switch
      eventMask = SENDMESSAGE(rHandle,EM_SETEVENTMASK,0,mask)
      SENDMESSAGE(rHandle,WM_SETREDRAW,false,0)
    ENDIf
    IF !Switch
      SENDMESSAGE(rHandle,WM_SETREDRAW,TRUE,0)
      InvalidateRect(rHandle,0,true)
      SENDMESSAGE(rHandle,EM_SETEVENTMASK,TRUE,eventMask|ENM_CHANGE)
    ENDIF
ENDSUB


I use it mainly for when I am colouring text or setting sel selections to get say the line's text.

I use it like this:

QuietMode(1) '<---- On

  Do something like colour some text....

QuietMode(0) '<---- Off

And if you really want to speed things up even more try using Fletchie's conDraw functions like this:

conDrawOff(w1,1) '<---- Turns control updating off
QuietMode(1) '<---- On

  Do something like colour some text....

QuietMode(0) '<---- Off
conDrawOn(w1,1) '<---- Turns control updating back on again - important!

w1 is my window, 1 is the rich edit control.

Like I said Aurel, good man, well worked out!

Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

aurelCB

well i don't tested it yet in EB but in o2 compiler this operation is really fast

Andy

Aurel,

Yes it is, very fast.

In EBasic, you should also be able to use the conDrawOn / conDrawOff function that Fletchie wrote.

If you add in conDraw as well as WM_SETREDRAW then you are completely turning off all messages and notifications from the rich edit to the parent window.

It's these messages and notifications that slow you right down - turn them off and then WOW!

Andy.
 :)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.