Recent

Author Topic: TSynEditMarkupCtrlMouseLink for Ctrl+Alt  (Read 19707 times)

Pascal

  • Hero Member
  • *****
  • Posts: 932
TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« on: August 02, 2016, 01:54:24 pm »
Martin,

i need a TSynEditMarkupCtrlMouseLink for Ctrl+Alt (for cobol cross reference, like Ctrl-I in lazarus). It's not easy to add it to a subclass of TCustomSynEdit!
What about a base class TSynEditMarkupMouseLink. TCustomSynEdit then can scan all markups for beeing a
TSynEditMarkupMouseLink and doing the stuff it does today with TSynEditMarkupCtrlMouseLink.
So i can add a subclass of TSynEditMarkupMouseLink to the markups an it gets automatically handled
by TCustomSynEdit.

Code: Pascal  [Select][+][-]
  1. TCustomSynEdit(SynEdit).IsLinkable(NewY, NewX1, NewX2)
and
Code: Pascal  [Select][+][-]
  1. (emShowCtrlMouseLinks in TCustomSynEdit(SynEdit).MouseOptions)
have to be put into events which have to be set to the appropriate functions after creation.

What do you think about this?
« Last Edit: August 02, 2016, 01:56:03 pm by Pascal »
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9869
  • Debugger - SynEdit - and more
    • wiki
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #1 on: August 02, 2016, 02:30:01 pm »
You should be able to use the TSynEditMarkupMouseLink as it is.

But if you want to add your own subclass, see ide/SourceSynEditor.pas
SynEdit.MarkupManager is public (at least in trunk), so not sure why you need a subclass of TCustomSynEdit?

*IF* you do a subclass: Why do you need IsLinkable? Add your own event, in your TSynEditMarkupMouseLink subclass.

------------
But first of all: What you can do WITHOUT subclassing anything.

You can use
Code: Pascal  [Select][+][-]
  1.     property OnClickLink : TMouseEvent
  2.     property OnMouseLink: TSynMouseLinkEvent
  3.  
to decide what to link, and where to link too.

You can use MouseAcitons to configure what shift-key-mouse-button combo  should trigger.

1) add synedit to form, then in ObjectInspector:
2) set SynEdit.MouseAction.emUseMouseActions
3) set SynEdit.MouseAction.emShowControlMouseLink
4) Right click / pop up menu, the SynEdit in the form designe, and select "Reset mouse actions"
5) You may need to deselect the SynEdit (select another component, or the form), and select SYnEdit again. (Not sure, shouldnt be needed, but I just tested, and it was needed)

Now In ObInsp, go to
  SynEdit.MouseTextActions (should have 8 items)
click the [...]
In the window that appears, choose "Source Link", and edit the "shift" property

For more info:
http://wiki.lazarus.freepascal.org/IDE_Window:_EditorMouseOptionsAdvanced

----------------------------------
If you want to add your own, because you need TWO mouse link handlers:

Well the behaviour should be entirely in the markup class, SynEdit should not have any special code for it. That is just because it never was entirely moved....

As I said you can get the IsLink/OnLink in your class. So all you need is to get notified when the mouse buttons are used.

Use MouseActions as described. (Actually you do not need to, if you don't SynEdit uses an internal list, and you can still extend it, see below(

In your TSynEditMarkupMouseLink  subclass, you can hook
Code: Pascal  [Select][+][-]
  1.     procedure RegisterMouseActionSearchHandler(AHandlerProc: TSynEditMouseActionSearchProc);
  2.     procedure UnregisterMouseActionSearchHandler(AHandlerProc: TSynEditMouseActionSearchProc);
  3.     procedure RegisterMouseActionExecHandler(AHandlerProc: TSynEditMouseActionExecProc);
  4.  

And you can add a property with a new mouseaction (actually you need a list, even for just one). Make sure you use a unique command. Look how other classes do that.

The MouseAction is to trigger the link (direction set to "up")

In ActionSearchHandler you will check if it is matched, you can also check for mouse up/down.

« Last Edit: August 02, 2016, 02:32:03 pm by Martin_fr »

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #2 on: August 02, 2016, 03:02:21 pm »
The reason is i need both.

In TCustom SynEdit fMarkupCtrlMouse it used several times to call some functions of fMarkupCtrlMouse:

Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.KeyDown(var Key: Word; Shift: TShiftState);
  2.   ...
  3.   if assigned(fMarkupCtrlMouse) then
  4.     fMarkupCtrlMouse.UpdateCtrlState(Shift);
Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.KeyUp(var Key: Word; Shift: TShiftState);
  2.   ...
  3.   if assigned(fMarkupCtrlMouse) then
  4.     fMarkupCtrlMouse.UpdateCtrlState(Shift);
Code: Pascal  [Select][+][-]
  1. function TCustomSynEdit.DoHandleMouseAction(AnActionList: TSynEditMouseActions;
  2.   var AnInfo: TSynEditMouseActionInfo): Boolean;
  3.       ...
  4.       emcMouseLink:
  5.         begin
  6.           if assigned(fMarkupCtrlMouse) and fMarkupCtrlMouse.IsMouseOverLink and
  7.              assigned(FOnClickLink)
  8.           then begin
  9.             if AnAction.MoveCaret then
  10.               MoveCaret;
  11.             FOnClickLink(Self, SynMouseButtonBackMap[AnInfo.Button], AnInfo.Shift, AnInfo.MouseX, AnInfo.MouseY);
  12.           end
Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.UpdateCursor;
  2.   ...
  3.   if (FLastMousePoint.X >= FTextArea.Bounds.Left) and (FLastMousePoint.X <  FTextArea.Bounds.Right) and
  4.      (FLastMousePoint.Y >= FTextArea.Bounds.Top) and (FLastMousePoint.Y < FTextArea.Bounds.Bottom)
  5.   then begin
  6.     if Assigned(FMarkupCtrlMouse) and (FMarkupCtrlMouse.Cursor <> crDefault) then
  7.       Cursor := FMarkupCtrlMouse.Cursor
  8.  
Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.SetLastMouseCaret(const AValue: TPoint);
  2. begin
  3.   if (FLastMouseCaret.X=AValue.X) and (FLastMouseCaret.Y=AValue.Y) then exit;
  4.   FLastMouseCaret:=AValue;
  5.   if assigned(fMarkupCtrlMouse) then
  6.     fMarkupCtrlMouse.LastMouseCaret := AValue;
  7.   UpdateCursor;
  8. end;
  9.  
Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.SetMouseOptions(AValue: TSynEditorMouseOptions);
  2.   ...
  3.   if (emShowCtrlMouseLinks in ChangedOptions) then begin
  4.     if assigned(fMarkupCtrlMouse) then
  5.       fMarkupCtrlMouse.UpdateCtrlMouse;
  6.     UpdateCursor;
  7.   end;
  8.   StatusChanged([scOptions]);
  9. end;
  10.  

How can i make my subclass of TCustomSynEdit do the same for my additional MouseLinkMarkup?
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9869
  • Debugger - SynEdit - and more
    • wiki
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #3 on: August 02, 2016, 03:54:30 pm »
Ok.

Right you need key up/down
Code: Pascal  [Select][+][-]
  1.     procedure RegisterBeforeKeyDownHandler(AHandlerProc: TKeyEvent);
  2.  
Unfortunately a key-up handler is missing.

Feel free to add (same as key down), and provide a patch.

---------
Quote
DoHandleMouseAction
This you can get via the
Code: Pascal  [Select][+][-]
  1.         procedure RegisterMouseActionSearchHandler(AHandlerProc: TSynEditMouseActionSearchProc);
  2.         procedure RegisterMouseActionExecHandler(AHandlerProc: TSynEditMouseActionExecProc);

---
That leaves "UpdateCursor"
- calling it, when a change is needed
- setting the right cursor when it is called.

That one is tricky.

It also is currently breaking the published "cursor" property, because it ignores any user supplied value.

Sorry, I have no quick solution for that.

Probably need to reintroduce the Cursor property (override getter and setter). Then at least the default value can be set and would be respected.

Then you could just change that default by changing the Cursor property.

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #4 on: August 03, 2016, 12:00:32 pm »
That leaves "UpdateCursor"
- calling it, when a change is needed
- setting the right cursor when it is called.

That one is tricky.

It also is currently breaking the published "cursor" property, because it ignores any user supplied value.

Sorry, I have no quick solution for that.

Probably need to reintroduce the Cursor property (override getter and setter). Then at least the default value can be set and would be respected.

Then you could just change that default by changing the Cursor property.

What about adding a an event that gets called when assigned?
Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.UpdateCursor;
  2.   ...
  3.   if (FLastMousePoint.X >= FTextArea.Bounds.Left) and (FLastMousePoint.X <  FTextArea.Bounds.Right) and
  4.      (FLastMousePoint.Y >= FTextArea.Bounds.Top) and (FLastMousePoint.Y < FTextArea.Bounds.Bottom)
  5.   then begin
  6.     if Assigned(FMarkupCtrlMouse) and (FMarkupCtrlMouse.Cursor <> crDefault) then
  7.       Cursor := FMarkupCtrlMouse.Cursor
  8.     // new:
  9.     if Assigned(FOnUpdateCursor) then begin
  10.       tmp_cursor := FOnUpdateCursor;
  11.       if tmp_cursor <> Cursor then
  12.         Cursor := tmp_Cursor;
  13.     end;
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9869
  • Debugger - SynEdit - and more
    • wiki
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #5 on: August 03, 2016, 12:53:32 pm »
What about adding a an event that gets called when assigned?
Maybe...
But if so, it would need to be a list (register style). And it may need conflict resolution.... Also flags for hide cursor.
something maybe like
Code: Pascal  [Select][+][-]
  1.   procedure CursorRequestHandler(sender: TObject; var replacementCursor: TCursor; var flags: Tfooflags, info: Tinfo)
  2. // replacementCursor starts as crDefault (meaning the one specified by SynEdit), and can be changed by each handler)
  3. // Tfooflags = set of (noHide) // or maybe record type
  4. // TInfo = record wouldHide: boolean end; // record so it can be extended.
  5.  
maybe a changedBy, or ChangeReason or priority....

record types a arguments in events/handlers mean, that one can later add more fields, without breaking existing handlers.

And Cursor would need to be fixed first anyway (but that should be easy)

-----------------------------
While that needs to be addressed at some point, I just had another idea/question.

Ok, so you have 2 different links.
But still one module should do fine?

You can check inside the OnIsLink/OnLink event what kind of link it is, and act accordingly.

The only thing, you can archive with 2 markups, is different link color/style. But you can change the style in the OnLink event. That will be considerable less work.

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #6 on: August 03, 2016, 01:45:51 pm »
While that needs to be addressed at some point, I just had another idea/question.

Ok, so you have 2 different links.
But still one module should do fine?

You can check inside the OnIsLink/OnLink event what kind of link it is, and act accordingly.

The only thing, you can archive with 2 markups, is different link color/style. But you can change the style in the OnLink event. That will be considerable less work.

Yes, but then i have to get the modifier keys to decide which link type to check. And the Markup has to react on
both or even on all possible modifiers. I need Ctrl for navigate in in source and Ctr+Alt to build a cross-reference.
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9869
  • Debugger - SynEdit - and more
    • wiki
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #7 on: August 03, 2016, 02:24:42 pm »
Anyway ok to add a handler for update cursor.

Just need to think about the parameters.

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #8 on: August 04, 2016, 06:49:22 am »
Okay,

i've started to implement this. And i also refactored unit SynEditMarkupCtrlMouseLink to
have a more general parent class for TSynEditMarkupCtrlMouseLink: TSynEditMarkupMouseLink.
TSynEditMarkupMouseLink can be used for all Qualifiers to handle more than one link type with
one instance of the class while TSynEditMarkupCtrlMouseLink stays compatible to current trunk
version.
TSynEditMarkupMouseLink will register its handlers itself so that TCustomSynEdit becomes independet
of calls to fMarkupCtrlMouse.
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9869
  • Debugger - SynEdit - and more
    • wiki
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #9 on: August 04, 2016, 12:08:46 pm »
sounds good.

when done, please put on mantis/bugtracker

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #10 on: September 14, 2016, 01:07:58 pm »
Martin_fr,

i added first patch for adding BeforeKeyUpHandler: http://bugs.freepascal.org/view.php?id=30600
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #11 on: September 15, 2016, 01:46:57 am »
Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.KeyDown(var Key: Word; Shift: TShiftState);
  2.   ...
  3.   if assigned(fMarkupCtrlMouse) then
  4.     fMarkupCtrlMouse.UpdateCtrlState(Shift);
Okay.

Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.KeyUp(var Key: Word; Shift: TShiftState);
  2.   ...
  3.   if assigned(fMarkupCtrlMouse) then
  4.     fMarkupCtrlMouse.UpdateCtrlState(Shift);
Okay.

Code: Pascal  [Select][+][-]
  1. function TCustomSynEdit.DoHandleMouseAction(AnActionList: TSynEditMouseActions;
  2.   var AnInfo: TSynEditMouseActionInfo): Boolean;
  3.       ...
  4.       emcMouseLink:
  5.         begin
  6.           if assigned(fMarkupCtrlMouse) and fMarkupCtrlMouse.IsMouseOverLink and
  7.              assigned(FOnClickLink)
  8.           then begin
  9.             if AnAction.MoveCaret then
  10.               MoveCaret;
  11.             FOnClickLink(Self, SynMouseButtonBackMap[AnInfo.Button], AnInfo.Shift, AnInfo.MouseX, AnInfo.MouseY);
  12.           end
Okay.

Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.UpdateCursor;
  2.   ...
  3.   if (FLastMousePoint.X >= FTextArea.Bounds.Left) and (FLastMousePoint.X <  FTextArea.Bounds.Right) and
  4.      (FLastMousePoint.Y >= FTextArea.Bounds.Top) and (FLastMousePoint.Y < FTextArea.Bounds.Bottom)
  5.   then begin
  6.     if Assigned(FMarkupCtrlMouse) and (FMarkupCtrlMouse.Cursor <> crDefault) then
  7.       Cursor := FMarkupCtrlMouse.Cursor
  8.  
Left over for now.

Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.SetLastMouseCaret(const AValue: TPoint);
  2. begin
  3.   if (FLastMouseCaret.X=AValue.X) and (FLastMouseCaret.Y=AValue.Y) then exit;
  4.   FLastMouseCaret:=AValue;
  5.   if assigned(fMarkupCtrlMouse) then
  6.     fMarkupCtrlMouse.LastMouseCaret := AValue;
  7.   UpdateCursor;
  8. end;
  9.  
Code: Pascal  [Select][+][-]
  1. procedure TCustomSynEdit.SetMouseOptions(AValue: TSynEditorMouseOptions);
  2.   ...
  3.   if (emShowCtrlMouseLinks in ChangedOptions) then begin
  4.     if assigned(fMarkupCtrlMouse) then
  5.       fMarkupCtrlMouse.UpdateCtrlMouse;
  6.     UpdateCursor;
  7.   end;
  8.   StatusChanged([scOptions]);
  9. end;
  10.  
How to handle these?
New handler for LastMouseCaretChanged and MouseOptionsChanged?
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9869
  • Debugger - SynEdit - and more
    • wiki
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #12 on: September 15, 2016, 12:19:59 pm »
Quote
How to handle these?
New handler for LastMouseCaretChanged and MouseOptionsChanged?

For the time being, loop through all the markup and check the class.

Similar to MarkupByClass, but checking with "is TSynEditMarkupCtrlMouseLink" and not stopping at the first.


Pascal

  • Hero Member
  • *****
  • Posts: 932
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #13 on: September 19, 2016, 03:38:07 pm »
Is
Code: Pascal  [Select][+][-]
  1.   emcoMouseLinkShow           =  TSynEditorMouseCommandOpt(0);
  2.   emcoMouseLinkHide           =  TSynEditorMouseCommandOpt(1);
  3.  
realy needed?

I can't find any place where emcoMouseLinkHide is used!

I would like to use Option for all MouseActions which are used for TSynEditMarkupMouseLink like with emcSynEditCommand.

In my current implementation of TSynEditMarkupMouseLink i can add several MouseCommands on wich it should react. If the link
is clicked and no OnLinkClick event is assigned it will process the command specified in Option of the MouseAction (like emcSynEditCommand)
if it's other than 0.

I already can use this for my own MouseActionCommands but not for emcMouseLink as Option is used with above options.
laz trunk x64 - fpc trunk i386 (cross x64) - Windows 10 Pro x64 (21H2)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9869
  • Debugger - SynEdit - and more
    • wiki
Re: TSynEditMarkupCtrlMouseLink for Ctrl+Alt
« Reply #14 on: September 19, 2016, 04:18:05 pm »
"emcoMouseLinkShow" means the underline (or markup) will be shown.
"emcoMouseLinkHide" means the link will work, but is not visibly indicated.

It isnt used, because the Option value is (should be) either of the 2, and if it is not "emcoMouseLinkShow", then it must be the other.

user code, setting up a SynEdit may however use it.

------------------------------
The option property can be thought of as an enum. Only because every command has different options, it cant be enum. So it is integer, and for each command there are several (if any) constants.

"emcoMouseLinkShow"  = 0 // so it is the default

 

TinyPortal © 2005-2018