Making a split screen editor using Tk Text Widgets 
Author Message
 Making a split screen editor using Tk Text Widgets

In the past I wrote a simple file viewer/editor based upon the Text
widget. I've decided to add a few enhancements, the main one being the
ability to split the view into two (ie one file two text widgets).

I'm still at the thinking about it stage but it occurs to me that I
need a scheme whereby all key & mouse events on one text widget are
captured and sent to the other widget after some massaging. Oh the joy
of bind and bindtags...

I was hoping that the first rule of programming may come to my aid viz
"never write what you can plagarise  someone else"  - you can then
blame them for the bugs...

Can anyone point me towards some code that does this

Much obliged
Julian H J Loaring
//////////////////

One more dried frog pill won't hurt, they're not at all {*filter*}ive



Sun, 17 Sep 2000 03:00:00 GMT  
 Making a split screen editor using Tk Text Widgets


: In the past I wrote a simple file viewer/editor based upon the Text
: widget. I've decided to add a few enhancements, the main one being the
: ability to split the view into two (ie one file two text widgets).
:
: I'm still at the thinking about it stage but it occurs to me that I
: need a scheme whereby all key & mouse events on one text widget are
: captured and sent to the other widget after some massaging. Oh the joy
: of bind and bindtags...

I have been thinking on something similar - a text editor/IDE with
multiple-file/multiple-window support.  The problem is, what happens if
someone wants to edit the same file in multiple windows?  

I could (1) Just not let them do that or (2) setup a binding for on/off
focus for the text widget (or the window), and if the widget/window has a
file that's edited elsewheres, update the elsewheres.  This isn't entirely
perfect, but it's the best I can think of (aside from trying to 'tee' the
keyboard *AND* mouse bindings to edit two windows).

******************************************************************************
           Steve McAndrewSmith          HTTP:  www.niftytech.com/~stevemc

------------------------------------------------------------------------------
"Good health" is merely the slowest rate at which one can die.
******************************************************************************



Sun, 17 Sep 2000 03:00:00 GMT  
 Making a split screen editor using Tk Text Widgets


Quote:

> In the past I wrote a simple file viewer/editor based upon the Text
> widget. I've decided to add a few enhancements, the main one being the
> ability to split the view into two (ie one file two text widgets).

> I'm still at the thinking about it stage but it occurs to me that I
> need a scheme whereby all key & mouse events on one text widget are
> captured and sent to the other widget after some massaging. Oh the joy
> of bind and bindtags...

> I was hoping that the first rule of programming may come to my aid viz
> "never write what you can plagarise  someone else"  - you can then
> blame them for the bugs...

> Can anyone point me towards some code that does this

Here ya go... whipped this up in 5 minutes or so with no bindings (well,
except for the escape key). It could be optimized a bit, but I think you
get the drift. The gist of it is, override the text widget procs, and
whatever happens in one widget is done in the other. Though as you'll
see if you read the code, I get kind of clever with scrolling type
actions (xview, yview and see).

Plagerize away, though a kindly mention in the comments might be nice
:-)

I'm not {*filter*}ed to Tcl. I'm really not. I have everything under
control. I can quit writing tcl code any time I want. I just don't want
to quit right now. ;-)

------------------------ cut here --------------------------------
# two text widgets...
text .view1 -width 40 -height 10 -wrap none \
        -xscrollcommand ".hsb1 set" -yscrollcommand ".vsb1 set"
text .view2 -width 40 -height 10 -wrap none \
        -xscrollcommand ".hsb2 set" -yscrollcommand ".vsb2 set"

# two vertical scrollbars
scrollbar .vsb1 -orient vertical -command ".view1 yview"
scrollbar .vsb2 -orient vertical -command ".view2 yview"

# and two horizontal scrollbars
scrollbar .hsb1 -orient horizontal -command ".view1 xview"
scrollbar .hsb2 -orient horizontal -command ".view2 xview"

grid .view1 -sticky nsew -row 0 -column 0
grid .vsb1  -sticky ns   -row 0 -column 1
grid .hsb1  -sticky ew   -row 1 -column 0
grid .view2 -sticky nsew -row 2 -column 0
grid .vsb2  -sticky ns   -row 2 -column 1
grid .hsb2  -sticky ew   -row 3 -column 0

# just for fun, set a binding on <Esc> to move between the two windows
# it makes playing around with this demo a little easier...
bind .view1 <Escape> {focus .view2}
bind .view2 <Escape> {focus .view1}

# here's the interesting part: redefining each widget's proc to send
# actions to the other.

rename .view1 _.view1_
rename .view2 _.view2_

proc .view1 {args} {
    # first, let the original widget do its thing
    set result [eval _.view1_ $args]

    # now, request the other widget to do the very same thing. Only,
    # we'll get a little clever and *not* replicate scrolling commands
    # in the other window so you can truly have two different views
    # into the text
    set cmd [lindex $args 0]
    if {$cmd != "see" && $cmd != "xview" && $cmd != "yview"} {
        eval _.view2_ $args
    }
    return $result

Quote:
}

proc .view2 {args} {
    # first, let the original widget do its thing
    set result [eval _.view2_ $args]

    # now, request the other widget to do the very same thing. Only,
    # we'll get a little clever and *not* replicate scrolling commands
    # in the other window so you can truly have two different views
    # into the text
    set cmd [lindex $args 0]
    if {$cmd != "see" && $cmd != "xview" && $cmd != "yview"} {
        eval _.view1_ $args
    }

    return $result

Quote:
}

# let's go ahead and add some data in the widgets so we have a starting
# point. We'll insert one long line, then insert a whole bunch of short
# lines, just to prove the scrollbars work...
.view1 insert insert "[info commands]\n"
.view1 insert insert [join [info commands] "\n"]

------------------------ cut here --------------------------------

As a postscript, for anyone foolish enough to read down this far... it
should be real easy to write a proc, say "newView" which takes two
arguments; a "master" text widget, and the name of a new text widget to
be created. The proc could do all the dirty work of making the widget
procs and synchronizing things. Probably in less than 100 lines of code.

Or... using the same technique, add a new text widget command -- split
-- to split a window. The widget could then be responsible for splitting
itself; ie: .text split horizontal or .text split vertical.

Hmmmm...

I _swear_ I'm not {*filter*}ed to tcl. And, no, I really don't have as much
spare time as it seems.

--
Bryan Oakley, self appointed deity of overriding text widget procs



Sun, 17 Sep 2000 03:00:00 GMT  
 Making a split screen editor using Tk Text Widgets

Quote:

> I have been thinking on something similar - a text editor/IDE with
> multiple-file/multiple-window support.  The problem is, what happens if
> someone wants to edit the same file in multiple windows?

It can be done. See my previous post. Typing in either window updated
both windows simultaneously.

Quote:

> I could (1) Just not let them do that or (2) setup a binding for on/off
> focus for the text widget (or the window), and if the widget/window has a
> file that's edited elsewheres, update the elsewheres.  This isn't entirely
> perfect, but it's the best I can think of (aside from trying to 'tee' the
> keyboard *AND* mouse bindings to edit two windows).

In effect, that's what I did. But instead of duplicating bindings which
can be tricky and error prone, I just took advantage of the ability to
rewrite the widget proc(s) to send the invoked widget commands to more
than one widget. Works great (IMO). The guts of the code was only a
couple dozen lines of very straight forward code and is, I think, fairly
foolproof.

--
Bryan Oakley
ChannelPoint, Inc.



Sun, 17 Sep 2000 03:00:00 GMT  
 Making a split screen editor using Tk Text Widgets

Bryan,

A nice demo.  In additition to the see, xview and yview commands which you
don't want replicated, you need to add the scan command so that middle
mouse button dragging still leaves the other window in tact.  In addition,
the selection process needs work.  If you select in one window, it appears
in the other.  I block the tag add|remove sel commands from being
replicated and this leaves the highlighting in the proper window.  The
delete selection needs to be converted to a delete range since the other
view doesn't have a selection defined.  What else should we watch out for?

# Bryan Oakley's linked text widget demo with selection fixed
# two text widgets...
text .view1 -width 40 -height 10 -wrap none \
        -xscrollcommand ".hsb1 set" -yscrollcommand ".vsb1 set"
text .view2 -width 40 -height 10 -wrap none \
        -xscrollcommand ".hsb2 set" -yscrollcommand ".vsb2 set"

# two vertical scrollbars
scrollbar .vsb1 -orient vertical -command ".view1 yview"
scrollbar .vsb2 -orient vertical -command ".view2 yview"

# and two horizontal scrollbars
scrollbar .hsb1 -orient horizontal -command ".view1 xview"
scrollbar .hsb2 -orient horizontal -command ".view2 xview"

grid .view1 -sticky nsew -row 0 -column 0
grid .vsb1  -sticky ns   -row 0 -column 1
grid .hsb1  -sticky ew   -row 1 -column 0
grid .view2 -sticky nsew -row 2 -column 0
grid .vsb2  -sticky ns   -row 2 -column 1
grid .hsb2  -sticky ew   -row 3 -column 0

# just for fun, set a binding on <Esc> to move between the two windows
# it makes playing around with this demo a little easier...
bind .view1 <Escape> {focus .view2}
bind .view2 <Escape> {focus .view1}

# here's the interesting part: redefining each widget's proc to send
# actions to the other.

rename .view1 _.view1_
rename .view2 _.view2_

proc .view1 {args} {
    #-----------------------------------------------
    # keep track of the select range in case this
    # command deletes it.
    #-----------------------------------------------
    set selrange [ _.view1_ tag ranges sel ]

    # let the original widget do its thing
    set result [eval _.view1_ $args]

    # now, request the other widget to do the very same thing. Only,
    # we'll get a little clever and *not* replicate scrolling commands
    # in the other window so you can truly have two different views
    # into the text

    #-----------------------------------------------------
    # don't pass on selection commands to the other view
    #-----------------------------------------------------
    if { [ regexp "tag (add|remove) sel" $args ] } { return $result }

    #--------------------------------------------------------------
    # if we delete the selection, turn that into a delete range
    # in the other view, since the other view won't have a
    # a selection
    #--------------------------------------------------------------
    if { $args == "delete sel.first sel.last" } {
      eval _.view2_ delete $selrange
      return $result
    }

    set cmd [lindex $args 0]
    if {$cmd != "see" && $cmd != "xview" && $cmd != "yview" && $cmd !=
"scan" } {
        eval _.view2_ $args
    }
    return $result

Quote:
}

proc .view2 {args} {
    #-----------------------------------------------
    # keep track of the select range in case this
    # command deletes it.
    #-----------------------------------------------
    set selrange [ _.view2_ tag ranges sel ]

    # let the original widget do its thing
    set result [eval _.view2_ $args]

    # now, request the other widget to do the very same thing. Only,
    # we'll get a little clever and *not* replicate scrolling commands
    # in the other window so you can truly have two different views
    # into the text

    #-----------------------------------------------------
    # don't pass on selection commands to the other view
    #-----------------------------------------------------
    if { [ regexp "tag (add|remove) sel" $args ] } { return $result }

    #--------------------------------------------------------------
    # if we delete the selection, turn that into a delete range
    # in the other view, since the other view won't have a
    # a selection
    #--------------------------------------------------------------
    if { $args == "delete sel.first sel.last" } {
      eval _.view1_ delete $selrange
      return $result
    }

    set cmd [lindex $args 0]
    if {$cmd != "see" && $cmd != "xview" && $cmd != "yview" && $cmd !=
"scan" } {
        eval _.view1_ $args
    }

    return $result

Quote:
}

# let's go ahead and add some data in the widgets so we have a starting
# point. We'll insert one long line, then insert a whole bunch of short
# lines, just to prove the scrollbars work...
.view1 insert insert "[info commands]\n"
.view1 insert insert [join [info commands] "\n"]

--
Peter Bird                Nortel Advanced Technology
Advanced Design Methods   P.O.Box 3511, Station C
(613) 763-5071            Ottawa, Ont., Canada K1Y 4H7



Mon, 18 Sep 2000 03:00:00 GMT  
 Making a split screen editor using Tk Text Widgets

Quote:

> Bryan,

> A nice demo.  

Thank you. Tcl is fun -- stuff like that is so easy to throw together

Quote:
> In additition to the see, xview and yview commands which you
> don't want replicated, you need to add the scan command so that middle
> mouse button dragging still leaves the other window in tact.

Good point. I forgot about that one.

Quote:
>  In addition,
> the selection process needs work.  If you select in one window, it appears
> in the other.  I block the tag add|remove sel commands from being
> replicated and this leaves the highlighting in the proper window.  The
> delete selection needs to be converted to a delete range since the other
> view doesn't have a selection defined.  

Yup, you are right, I think (without actually thinking too hard ;-)

Quote:
> What else should we watch out for?

I guess the setting of the marks named "insert" and "current". Also,
embedded windows would have to be dealt with. I'm not sure if you can
embed the same window in two different text widgets (never tried it).
Maybe the same goes for embedded images; maybe not. Searching should be
dealt with specially -- no reason to run the search command twice.

Where you change the delete selection command could probably be
generalized a bit more. Perhaps for any command the indicies ought to be
converted to an absolute address before sending to the other window. So,
"sel.first" should be converted to whatever "sel.first" really is, using
[_.view1_ index sel.first]. Same with "current" and "insert". This would
be fairly easy to do, and work for for all sorts of weird cases, like if
someone attempted ".widget delete sel.first current" or some such
nonsense.

As always, to truly do it "right" is a bit more difficult than to do it
quickly. But it would be an interesting exercise to see if it could be
made bullet proof (maybe with an exception that embedded windows can't
be dealt with).

--
Bryan Oakley
ChannelPoint, Inc.



Mon, 18 Sep 2000 03:00:00 GMT  
 Making a split screen editor using Tk Text Widgets

On Wed, 01 Apr 1998 13:14:45 -0700, Bryan Oakley

Quote:


>> I have been thinking on something similar - a text editor/IDE with
>> multiple-file/multiple-window support.  The problem is, what happens if
>> someone wants to edit the same file in multiple windows?

>It can be done. See my previous post. Typing in either window updated
>both windows simultaneously.

>> I could (1) Just not let them do that or (2) setup a binding for on/off
>> focus for the text widget (or the window), and if the widget/window has a
>> file that's edited elsewheres, update the elsewheres.  This isn't entirely
>> perfect, but it's the best I can think of (aside from trying to 'tee' the
>> keyboard *AND* mouse bindings to edit two windows).

>In effect, that's what I did. But instead of duplicating bindings which
>can be tricky and error prone, I just took advantage of the ability to
>rewrite the widget proc(s) to send the invoked widget commands to more
>than one widget. Works great (IMO). The guts of the code was only a
>couple dozen lines of very straight forward code and is, I think, fairly
>foolproof.

Many thanks for this.  The one gothca I have found (there is always
one) is that the selection mechanism doesn't behave - the 'other
window' gets the selection not the one the user is interacting with.  

I fixed this up by checking for tag commands involving the 'sel' tag
and delete commands involving 'sel.first' and 'sel.last' ranges. I
basically substitute a dummy tag 'selClone' which looks the same as
'sel' and then regsub 'selClone' for 'sel' - the 'other' widget gets
the substituted command, the current widget gets the real selection
commands.  I will post the code once it's tidied up.

Much obliged
Julian H J Loaring
//////////////////

One more dried frog pill won't hurt, they're not at all {*filter*}ive



Mon, 18 Sep 2000 03:00:00 GMT  
 Making a split screen editor using Tk Text Widgets


Quote:
> Many thanks for this.  The one gothca I have found (there is always
> one) is that the selection mechanism doesn't behave - the 'other
> window' gets the selection not the one the user is interacting with.

Yeah, one fix (I think) is to just reverse the order that the widgets
are updated. I should have had the "other" widget acted on first, and
then the "current" widget. I just tried that and it seems to work much
better. I shoulda thought of that the first time around. Though I don't
recall seeing the problem with the selection the old way either -- maybe
its an OS quirk? (I'm using NT)

This has the side benefit that both windows have a sel tag, so using the
index "sel.first" works in both windows so you don't have to do the
regsub. At least, it _seems_ to be that way in my test case. I don't
really have time to investigate it further, though.

Quote:

> I fixed this up by checking for tag commands involving the 'sel' tag
> and delete commands involving 'sel.first' and 'sel.last' ranges. I
> basically substitute a dummy tag 'selClone' which looks the same as
> 'sel' and then regsub 'selClone' for 'sel' - the 'other' widget gets
> the substituted command, the current widget gets the real selection
> commands.  I will post the code once it's tidied up.

I guess that could work too. Sounds a bit complicated, but hey,
duplicating widgets is a complex thing and maybe these contortions are
necessary. I suggest you try my way too -- reversing the order that the
real widget commands are called -- to see if it works right. Its much
cleaner and won't clash with any other tags (what if somebody wants
their own tag named "selClone"?).  

--
Bryan Oakley
ChannelPoint, Inc.



Mon, 18 Sep 2000 03:00:00 GMT  
 Making a split screen editor using Tk Text Widgets

: > I could (1) Just not let them do that or (2) setup a binding for on/off
: > focus for the text widget (or the window), and if the widget/window has a
: > file that's edited elsewheres, update the elsewheres.  This isn't entirely
: > perfect, but it's the best I can think of (aside from trying to 'tee' the
: > keyboard *AND* mouse bindings to edit two windows).
:
: In effect, that's what I did. But instead of duplicating bindings which
: can be tricky and error prone, I just took advantage of the ability to
: rewrite the widget proc(s) to send the invoked widget commands to more
: than one widget. Works great (IMO). The guts of the code was only a
: couple dozen lines of very straight forward code and is, I think, fairly
: foolproof.

That's neat!  Aside from the fact that it's short, elegant, and completely
functional, it never occured to me that Tk would do all of it's own widget
updates by calling the widgets themselves (although I've had experience to
the contrary - widget/namespace problems, for example).

Definitly using that code (actually, I'll probobly write a nice generic
version for linking multiple widgets).

Thanks.

******************************************************************************
           Steve McAndrewSmith          HTTP:  www.niftytech.com/~stevemc

------------------------------------------------------------------------------
Bumper Sticker:
  Warning: Dates in Calendar are closer than they appear.
******************************************************************************



Tue, 19 Sep 2000 03:00:00 GMT  
 Making a split screen editor using Tk Text Widgets

Quote:

> That's neat!  Aside from the fact that it's short, elegant, and completely
> functional, it never occured to me that Tk would do all of it's own widget
> updates by calling the widgets themselves (although I've had experience to
> the contrary - widget/namespace problems, for example).

> Definitly using that code (actually, I'll probobly write a nice generic
> version for linking multiple widgets).

Great! When  you do, make it public so others can use it.

Quote:

> Thanks.

You are welcome.

--
Bryan Oakley
ChannelPoint, Inc.



Tue, 19 Sep 2000 03:00:00 GMT  
 
 [ 10 post ] 

 Relevant Pages 

1. Tk multi-line text editor widget?

2. Text widgets as basic text editors?

3. Text widget --screen lines vs. text lines

4. Using a tk text widget for stdout

5. Some questions on elided text in the text widget (and a few other text widget questions)

6. Making VHDL look the same in different text editors

7. Splitting Text Widget ?

8. Splitting text widget

9. Shared text between Tk text widgets.

10. TIP #19: Add a Text Changed Flag to Tk's Text Widget

 

 
Powered by phpBB® Forum Software