Discussion:
Selection Highlighting and Caret drawing with Quartz
(too old to reply)
Eyal Redler
2001-10-08 00:35:59 UTC
Permalink
Hi,

I need to draw a text selection highlight and a blinking insertion point
using Quartz (inside NSView).
This is the kind of stuff I know very well under classic but am completely
lost with Cocoa and Quartz.

1. In Classic the procedure was to set the highlight bit and call
InvertRect, without redrawing the text under the selection (and you could
do the same again to erase the highlight) I assume this is not the case
with Quartz. Right? My guess is that the proper way to do this is to get
the highlight color from somewhere and draw the selection over the text
with some transparency (if so, how transparent should it be? and where do
I get the highlight color from?
2. With the caret I have two additional questions
a. How do I trigger the blinking (NSTimer?) and where can I find the
value for the time interval?
b. How do I trigger the actual drawing (what is the equivalent to
InvalRect?)

I appreciate any pointers you could give me on this.

Eyal
Erik M. Buck
2001-10-08 02:22:01 UTC
Permalink
Post by Eyal Redler
1. In Classic the procedure was to set the highlight bit and call
InvertRect, without redrawing the text under the selection (and you could
do the same again to erase the highlight) I assume this is not the case
with Quartz. Right? My guess is that the proper way to do this is to get
the highlight color from somewhere and draw the selection over the text
with some transparency (if so, how transparent should it be? and where do
I get the highlight color from?
My first suggestion would be to user an NSTextView. You can use an
arbitrary text view (such as the window's field editor) to draw text in any
view. Attributed text is capable of drawing any kind of colored background
including highlight color. My second suggestion is that you take a long
look at what you are doing because I have never heard of a Cocoa application
that had to handle its own text selection/highlighting and insertion point
blinking or not. If you are trying to do these things yourself, you are
probably doing 99.5% too much work.
Post by Eyal Redler
2. With the caret I have two additional questions
a. How do I trigger the blinking (NSTimer?) and where can I find the
value for the time interval?
A timer would work fine. Any old NSTextView will give it to you for free.
Post by Eyal Redler
b. How do I trigger the actual drawing (what is the equivalent to
InvalRect?)
-setNeedsDisplayInRect:
Eyal Redler
2001-10-08 11:00:01 UTC
Permalink
Post by Erik M. Buck
Post by Eyal Redler
1. In Classic the procedure was to set the highlight bit and call
InvertRect, without redrawing the text under the selection (and you could
do the same again to erase the highlight) I assume this is not the case
with Quartz. Right? My guess is that the proper way to do this is to get
the highlight color from somewhere and draw the selection over the text
with some transparency (if so, how transparent should it be? and where do
I get the highlight color from?
My first suggestion would be to user an NSTextView. You can use an
arbitrary text view (such as the window's field editor) to draw text in any
view. Attributed text is capable of drawing any kind of colored background
including highlight color. My second suggestion is that you take a long
look at what you are doing because I have never heard of a Cocoa application
that had to handle its own text selection/highlighting and insertion point
blinking or not. If you are trying to do these things yourself, you are
probably doing 99.5% too much work.
Yes, but the Cocoa text system doesn't support Hebrew and Arabic... And
MLTE/ATSUI are simply too buggy to use.
I also looked into customising the text system, but I'm not sure it got all
the answers I need (for example I need to access multiple 'cmap's in the
font to get the full repertoire of the glyphs (not all mac hebrew glyphs are
supported by unicode))
I need to implement this myself...
It seems to me that it is really painful for Cocoa developers to imagine
that someone will not use all those wonderful things that are "for free".
Maybe it'll help if I said this is some sort of custom graphic.... Nothing
to do with text...
Post by Erik M. Buck
Post by Eyal Redler
2. With the caret I have two additional questions
a. How do I trigger the blinking (NSTimer?) and where can I find the
value for the time interval?
A timer would work fine. Any old NSTextView will give it to you for free.
Post by Eyal Redler
b. How do I trigger the actual drawing (what is the equivalent to
InvalRect?)
Thanks,

Eyal
Douglas Davidson
2001-10-08 15:53:10 UTC
Permalink
Post by Eyal Redler
1. In Classic the procedure was to set the highlight bit and call
InvertRect, without redrawing the text under the selection (and you
could do the same again to erase the highlight) I assume this is not
the case with Quartz. Right? My guess is that the proper way to do this
is to get the highlight color from somewhere and draw the selection
over the text with some transparency (if so, how transparent should it
be? and where do I get the highlight color from?
2. With the caret I have two additional questions
a. How do I trigger the blinking (NSTimer?) and where can I find
the value for the time interval?
b. How do I trigger the actual drawing (what is the equivalent to
InvalRect?)
For what it's worth, the default time interval for blinking the Cocoa
text system's insertion point caret is currently 0.56 seconds (I believe
that's a half-cycle time, not a full cycle). You would want to do
something like this to start the timer

timer = [[NSTimer timerWithTimeInterval:blinkTime target:someTarget
selector:@selector(blinkThatCaret:) userInfo:anythingYouWant
repeats:YES] retain];
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSModalPanelRunLoopMode];

and then something like this to stop it.

[timer invalidate];
[timer release];
timer = nil;

There are a few subtleties here--for example, you will notice that the
Cocoa text system keeps the caret drawn without blinking it while the
user is actually typing.

With regard to actually drawing the blinking caret, there are several
ways to do it, but probably the simplest is to give your view the
ability to draw with either the caret shown or not shown. When you flip
the switch, you then just tell your view setNeedsDisplayInRect:rect
where rect is some rectangle that contains the caret.

Highlighted text in the Cocoa text system is just a specific instance of
background color--in fact, it's configurable by setting the NSTextView's
selectedTextAttributes. The default is a control color, [NSColor
selectedTextBackgroundColor], whose actual color value may vary. When
we draw a region, we first fill in the background color, then draw the
text on top of it. Again, when we change the highlighted region, we
call setNeedsDisplayInRect: with some rect that contains the areas that
changed.

Douglas Davidson
Eyal Redler
2001-10-08 16:41:25 UTC
Permalink
Post by Douglas Davidson
Post by Eyal Redler
1. In Classic the procedure was to set the highlight bit and call
InvertRect, without redrawing the text under the selection (and you
could do the same again to erase the highlight) I assume this is not
the case with Quartz. Right? My guess is that the proper way to do this
is to get the highlight color from somewhere and draw the selection
over the text with some transparency (if so, how transparent should it
be? and where do I get the highlight color from?
2. With the caret I have two additional questions
a. How do I trigger the blinking (NSTimer?) and where can I find
the value for the time interval?
b. How do I trigger the actual drawing (what is the equivalent to
InvalRect?)
For what it's worth, the default time interval for blinking the Cocoa
text system's insertion point caret is currently 0.56 seconds (I believe
that's a half-cycle time, not a full cycle). You would want to do
something like this to start the timer
Isn't it user conrollable? It is in Classic (GetCaretTime() or something...)
Post by Douglas Davidson
With regard to actually drawing the blinking caret, there are several
ways to do it, but probably the simplest is to give your view the
ability to draw with either the caret shown or not shown. When you flip
the switch, you then just tell your view setNeedsDisplayInRect:rect
where rect is some rectangle that contains the caret.
So this means I need to be very optimed since the Caret drawing will trigger
a call to drawRect (and might effect neighboring characters) and I don't
wan't to de the whole refresh...
I guess I need to get out of the "Classic" way of thinking.
Post by Douglas Davidson
Highlighted text in the Cocoa text system is just a specific instance of
background color--in fact, it's configurable by setting the NSTextView's
selectedTextAttributes. The default is a control color, [NSColor
selectedTextBackgroundColor], whose actual color value may vary. When
we draw a region, we first fill in the background color, then draw the
text on top of it. Again, when we change the highlighted region, we
call setNeedsDisplayInRect: with some rect that contains the areas that
changed.
Thanks, that helped a lot.
I've got more questions though.

1. When I call setNeedsDisplayInRect, is the action immidiate? If I need to
do this from inside the mouse tracking code I need to somehow make this
appear fast for interaction.

2. Can I call setNeedsDisplayInRect a few times to accomulte the area that
needs update (like InvalRect) or should I calculate the total myself and
pass that?

Thanks,

Eyal
Erik M. Buck
2001-10-08 16:57:05 UTC
Permalink
Post by Eyal Redler
1. When I call setNeedsDisplayInRect, is the action immidiate? If I need to
do this from inside the mouse tracking code I need to somehow make this
appear fast for interaction.
2. Can I call setNeedsDisplayInRect a few times to accomulte the area that
needs update (like InvalRect) or should I calculate the total myself and
pass that?
-setNeedsDisplayInRect: accumulates rectangles. All of this is nicely
explained in the on-line documentation.
http://developer.apple.com/techpubs/macosx/Cocoa/Reference/ApplicationKit/Ob
jC_classic/Classes/NSView.html#//apple_ref/occ/instm/NSView/displayRect:

setNeedsDisplayInRect:
- (void)setNeedsDisplayInRect:(NSRect)invalidRect

Marks the region of the receiver within invalidRect as needing display,
increasing the receiver's existing invalid region to include it. A later
displayIfNeeded... method will then perform drawing only within the invalid
region. NSViews marked as needing display are automatically redisplayed on
each pass through the application's event loop. (View objects that need to
redisplay before the event loop comes around can of course immediately be
sent the appropriate display... method.)
See Also: - setNeedsDisplay: - needsDisplay
Andreas Monitzer
2001-10-08 17:03:02 UTC
Permalink
Post by Eyal Redler
So this means I need to be very optimed since the Caret drawing will
trigger
a call to drawRect (and might effect neighboring characters) and I don't
wan't to de the whole refresh...
You have to do that anyways, since resizing the window means constantly
redrawing it.

andy
--
The downside [of current processors] is that most modern boxes seem to be
best suited for running flight simulators - at least they sound like jet
engines. -- Seen on Slashdot
Douglas Davidson
2001-10-08 17:06:47 UTC
Permalink
Post by Eyal Redler
Post by Douglas Davidson
With regard to actually drawing the blinking caret, there are several
ways to do it, but probably the simplest is to give your view the
ability to draw with either the caret shown or not shown. When you
flip
the switch, you then just tell your view setNeedsDisplayInRect:rect
where rect is some rectangle that contains the caret.
So this means I need to be very optimed since the Caret drawing will
trigger
a call to drawRect (and might effect neighboring characters) and I don't
wan't to de the whole refresh...
I guess I need to get out of the "Classic" way of thinking.
There are more optimized ways of doing this, but I really would suggest
you try it this way first, and see whether the performance is
acceptable. Optimizing drawing is a good thing, but don't do it
prematurely, and you shouldn't hold on to performance preconceptions
that may not be applicable to current systems.
Post by Eyal Redler
Post by Douglas Davidson
Highlighted text in the Cocoa text system is just a specific instance
of
background color--in fact, it's configurable by setting the
NSTextView's
selectedTextAttributes. The default is a control color, [NSColor
selectedTextBackgroundColor], whose actual color value may vary. When
we draw a region, we first fill in the background color, then draw the
text on top of it. Again, when we change the highlighted region, we
call setNeedsDisplayInRect: with some rect that contains the areas that
changed.
Thanks, that helped a lot.
I've got more questions though.
1. When I call setNeedsDisplayInRect, is the action immidiate? If I
need to
do this from inside the mouse tracking code I need to somehow make this
appear fast for interaction.
2. Can I call setNeedsDisplayInRect a few times to accomulte the area
that
needs update (like InvalRect) or should I calculate the total myself and
pass that?
setNeedsDisplayInRect: will accumulate rects for you until the next
display happens. You should look at the NSView and NSWindow
documentation to get a full understanding of the whole Cocoa display
mechanism, but the general idea is that under most circumstances you
don't want immediate drawing; instead you usually accumulate dirty rects
and display once per event loop. Mostly this will just happen
automatically, and you don't need to worry about it. Yes, this is fast
enough for interaction; this is what Cocoa views like NSTextView do.

One minor caveat is that Cocoa usually just maintains an accumulated
rect that is the union of all the dirty rects sent to the view, not a
more general region. If you are constantly dirtying two widely
separated small regions at the same time, there may be some inefficiency
here. Again, though, you should not worry about this at all unless and
until you see it as a measurable performance problem in practice in your
application. Use QuartzDebug to see regions as they are redrawn.

Douglas Davidson
Andreas Monitzer
2001-10-08 17:27:11 UTC
Permalink
Post by Douglas Davidson
There are more optimized ways of doing this, but I really would suggest
you try it this way first, and see whether the performance is acceptable.
Optimizing drawing is a good thing, but don't do it prematurely, and
you shouldn't hold on to performance preconceptions that may not be
applicable to current systems.
Well, I guess this philosophy made Mac OS X so slow. Some (most?)
performance improvements are best designed at the beginning.

andy
--
"He was addicted to life. But we cured him"
Douglas Davidson
2001-10-08 17:37:22 UTC
Permalink
Post by Andreas Monitzer
Post by Douglas Davidson
There are more optimized ways of doing this, but I really would
suggest you try it this way first, and see whether the performance is
acceptable.
Optimizing drawing is a good thing, but don't do it prematurely, and
you shouldn't hold on to performance preconceptions that may not be
applicable to current systems.
Well, I guess this philosophy made Mac OS X so slow. Some (most?)
performance improvements are best designed at the beginning.
The topic under discussion was text highlighting and the insertion point
caret, not general system performance. If you feel that the drawing of
text highlighting and the blinking insertion point caret is too slow in
Cocoa on Mac OS X, you can talk directly to me about it.

Douglas Davidson
Andreas Monitzer
2001-10-08 18:00:09 UTC
Permalink
Post by Douglas Davidson
Post by Andreas Monitzer
Post by Douglas Davidson
There are more optimized ways of doing this, but I really would suggest
you try it this way first, and see whether the performance is
acceptable.
Optimizing drawing is a good thing, but don't do it prematurely, and
you shouldn't hold on to performance preconceptions that may not be
applicable to current systems.
Well, I guess this philosophy made Mac OS X so slow. Some (most?)
performance improvements are best designed at the beginning.
The topic under discussion was text highlighting and the insertion point
caret, not general system performance. If you feel that the drawing of
text highlighting and the blinking insertion point caret is too slow in
Cocoa on Mac OS X, you can talk directly to me about it.
No, the topic of this sub-discussion was to improve the redraw-performance
of the text display because the blinking caret forces the view to redraw
parts of itself regularly.

andy
--
Description forthcoming.
Andreas Monitzer
2001-10-08 18:28:04 UTC
Permalink
Post by Andreas Monitzer
Well, I guess this philosophy made Mac OS X so slow. Some (most?)
performance improvements are best designed at the beginning.
Hmm no... Premature optimization is generally regarded as a bad thing.
Make it work, then make it work good :-)
That depends on the type of optimization. Of course, you shouldn't use
assembly (when the only advantage is speed). But for instance, removing
the transparent window feature because no computer in the following ten
years can handle that in reasonable speed is a premature optimization that
can only happen before you write the whole graphics system around it (and
that's the main problem with window resizing and scrolling in Mac OS X
currently).

andy
--
God created the universe in 6 days because He didn't have to worry about
an installed base
Max Horn
2001-10-10 00:01:30 UTC
Permalink
Post by Andreas Monitzer
Post by Andreas Monitzer
Well, I guess this philosophy made Mac OS X so slow. Some (most?)
performance improvements are best designed at the beginning.
Hmm no... Premature optimization is generally regarded as a bad
thing. Make it work, then make it work good :-)
That depends on the type of optimization. Of course, you shouldn't
use assembly (when the only advantage is speed). But for instance,
removing the transparent window feature because no computer in the
following ten years
You're talking from ten years ago or what? :) It works quite well on
my 400 Mhz G4.
Post by Andreas Monitzer
can handle that in reasonable speed is a premature optimization that
can only happen before you write the whole graphics system around it
(and that's the main problem with window resizing and scrolling in
Mac OS X currently).
Windows don't have to be transparent on OS X. They *can* be.

You can even turn of the drop shadows of windows if you know how :)


Max
--
-----------------------------------------------
Max Horn
Software Developer

email: <mailto:***@quendi.de>
phone: (+49) 6151-494890
Andreas Monitzer
2001-10-10 00:08:13 UTC
Permalink
Post by Andreas Monitzer
Post by Andreas Monitzer
Well, I guess this philosophy made Mac OS X so slow. Some (most?)
performance improvements are best designed at the beginning.
Hmm no... Premature optimization is generally regarded as a bad thing.
Make it work, then make it work good :-)
That depends on the type of optimization. Of course, you shouldn't use
assembly (when the only advantage is speed). But for instance, removing
the transparent window feature because no computer in the following ten
years
You're talking from ten years ago or what? :) It works quite well on my
400 Mhz G4.
Doesn't work very well on my G3/300.
Post by Andreas Monitzer
can handle that in reasonable speed is a premature optimization that can
only happen before you write the whole graphics system around it (and
that's the main problem with window resizing and scrolling in Mac OS X
currently).
Windows don't have to be transparent on OS X. They *can* be.
But the mere possibility of transparent windows prevents much optimization
(like direct-to-screen drawing and 2D accelerator support).
You can even turn of the drop shadows of windows if you know how :)
Quartz does it automatically here when resizing windows, because it couldn'
t handle it (hey! that's optimization!).

andy
--
The downside [of current processors] is that most modern boxes seem to be
best suited for running flight simulators - at least they sound like jet
engines. -- Seen on Slashdot
Finlay Dobbie
2001-10-10 00:34:56 UTC
Permalink
Also, I think that transparent windows and drop shadows are actually
side effects of having such a powerful drawing and compositing engine.
Of course it adds more overhead, but solid dragging of windows is
definitely nicer and smoother on OS X than Windows :-)

-- Finlay
Post by Andreas Monitzer
That depends on the type of optimization. Of course, you shouldn't use
assembly (when the only advantage is speed). But for instance,
removing the transparent window feature because no computer in the
following ten years
You're talking from ten years ago or what? :) It works quite well on my
400 Mhz G4.
Post by Andreas Monitzer
can handle that in reasonable speed is a premature optimization that
can only happen before you write the whole graphics system around it
(and that's the main problem with window resizing and scrolling in Mac
OS X currently).
Windows don't have to be transparent on OS X. They *can* be.
You can even turn of the drop shadows of windows if you know how :)
Finlay Dobbie
2001-10-10 04:33:02 UTC
Permalink
Post by Andreas Monitzer
Post by Max Horn
Windows don't have to be transparent on OS X. They *can* be.
But the mere possibility of transparent windows prevents much
optimization (like direct-to-screen drawing and 2D accelerator support).
Not particularly. Direct-to-screen drawing is possible (but
difficult) -- the DVD player does it. The problem here is that
everything is heavily double-buffered so that things like solid window
dragging work properly. 2D accelerator support isn't possible because
most of quartz is vector and just different from what most current 2D
accelerators support.
Post by Andreas Monitzer
Post by Max Horn
You can even turn of the drop shadows of windows if you know how :)
Quartz does it automatically here when resizing windows, because it
couldn'
t handle it (hey! that's optimization!).
Doesn't turn them off here. The only time the OS turns them off is when
the windowserver applies affine transforms to windows or changes their
shape (i.e. Dock).

-- Finlay
Finlay Dobbie
2001-10-11 07:30:04 UTC
Permalink
Post by Erik M. Buck
My first suggestion would be to user an NSTextView. You can use an
arbitrary text view (such as the window's field editor) to draw text in
any
view. Attributed text is capable of drawing any kind of colored
background
including highlight color. My second suggestion is that you take a long
look at what you are doing because I have never heard of a Cocoa
application
that had to handle its own text selection/highlighting and insertion
point
blinking or not. If you are trying to do these things yourself, you are
probably doing 99.5% too much work.
For example OmniWeb?

-- Finlay
Finlay Dobbie
2001-10-11 07:32:59 UTC
Permalink
Post by Andreas Monitzer
Well, I guess this philosophy made Mac OS X so slow. Some (most?)
performance improvements are best designed at the beginning.
Hmm no... Premature optimization is generally regarded as a bad thing.
Make it work, then make it work good :-)

-- Finlay

Loading...