|
1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // The text cursor |
|
15 // |
|
16 // |
|
17 |
|
18 #include <e32std.h> |
|
19 #include <graphics/wscursor.h> |
|
20 #include "server.h" |
|
21 #include "tcursor.h" |
|
22 #include "windowgroup.h" |
|
23 #include "wstop.h" |
|
24 #include "panics.h" |
|
25 #include "EVENT.H" |
|
26 #include "graphics/windowserverconstants.h" |
|
27 |
|
28 static const TInt64 KFlashRate(500000); // duration cursor is ON or OFF |
|
29 |
|
30 void RWsTextCursor::ConstructL(CWsWindowGroup *aGroupWin) |
|
31 { |
|
32 iInternalFlags = 0; |
|
33 iGroupWin=aGroupWin; |
|
34 iCustomTextCursor = NULL; |
|
35 } |
|
36 |
|
37 void RWsTextCursor::Close() |
|
38 { |
|
39 iDrawRegion.Close(); |
|
40 Cancel(); |
|
41 } |
|
42 |
|
43 void RWsTextCursor::SetL(const TWsWinCmdSetTextCursor &aSet, TBool aClipped) |
|
44 { |
|
45 if (aSet.cursor.iType < TTextCursor::ETypeFirst || |
|
46 (aSet.cursor.iType > TTextCursor::ETypeLast && |
|
47 aSet.cursor.iType <= TTextCursor::ETypeLastBasic) || |
|
48 (aSet.cursor.iFlags&static_cast<TUint>(ETextCursorPrivateFlags))) |
|
49 { |
|
50 Cancel(); |
|
51 iGroupWin->OwnerPanic(EWservPanicInvalidTextCursor); |
|
52 } |
|
53 else |
|
54 { |
|
55 CWsClientWindow* win = NULL; |
|
56 iGroupWin->WsOwner()->HandleToClientWindow(aSet.window, &win); |
|
57 |
|
58 // Check window is a child of the group window |
|
59 CWsWindowBase* searchWin = NULL; |
|
60 for(searchWin=win; searchWin->WinType()!=EWinTypeGroup; searchWin=searchWin->BaseParent()) |
|
61 {} |
|
62 if (iGroupWin != searchWin) |
|
63 { |
|
64 Cancel(); |
|
65 iGroupWin->OwnerPanic(EWservPanicWindow); |
|
66 } |
|
67 |
|
68 TPoint pos(aSet.pos.iX, aSet.pos.iY-aSet.cursor.iAscent); |
|
69 TSize size(aSet.cursor.iWidth, aSet.cursor.iHeight); |
|
70 TUint flags = aSet.cursor.iFlags; |
|
71 TInt type = aSet.cursor.iType; |
|
72 TRect clipRect = iClipRect; |
|
73 TRgb color = aSet.cursor.iColor; |
|
74 CWsCustomTextCursor* customTextCursor = iCustomTextCursor; |
|
75 TBool changed = EFalse; |
|
76 |
|
77 TPoint clipOrigo; |
|
78 TSize clipSize; |
|
79 |
|
80 if (type > TTextCursor::ETypeLastBasic) |
|
81 { |
|
82 changed = ETrue; |
|
83 |
|
84 customTextCursor = CWsClient::FindCustomTextCursor(type); |
|
85 if (!customTextCursor) |
|
86 { |
|
87 Cancel(); |
|
88 iGroupWin->OwnerPanic(EWservPanicNoCustomTextCursor); |
|
89 return; |
|
90 } |
|
91 |
|
92 if( !customTextCursor->HasSpriteMember() ) |
|
93 { |
|
94 iGroupWin->OwnerPanic(EWservPanicNoSpriteMember); |
|
95 return; |
|
96 } |
|
97 |
|
98 TInt yAdjust=0; |
|
99 switch (customTextCursor->Alignment()) |
|
100 { |
|
101 case RWsSession::ECustomTextCursorAlignTop: |
|
102 break; |
|
103 case RWsSession::ECustomTextCursorAlignBaseline: |
|
104 yAdjust = aSet.cursor.iAscent-1; |
|
105 break; |
|
106 case RWsSession::ECustomTextCursorAlignBottom: |
|
107 yAdjust = aSet.cursor.iHeight-1; |
|
108 break; |
|
109 default: |
|
110 Cancel(); |
|
111 iGroupWin->OwnerPanic(EWservPanicCustomTextCursorAlign); |
|
112 return; |
|
113 } |
|
114 pos.iY += yAdjust; |
|
115 // Start with a clipping rect to be the whole window |
|
116 // relative cursor pos and shrink down to what we want |
|
117 clipOrigo = -pos; |
|
118 clipSize = win->Size(); |
|
119 if (flags & TTextCursor::EFlagClipHorizontal) |
|
120 { |
|
121 clipOrigo.iX = 0; |
|
122 clipSize.iWidth = size.iWidth; |
|
123 } |
|
124 if (flags & TTextCursor::EFlagClipVertical) |
|
125 { |
|
126 clipOrigo.iY = -yAdjust; |
|
127 clipSize.iHeight = aSet.cursor.iHeight; |
|
128 } |
|
129 } |
|
130 else |
|
131 { |
|
132 customTextCursor = NULL; |
|
133 } |
|
134 |
|
135 if (aClipped) |
|
136 { |
|
137 flags|=ETextCursorFlagClipped; |
|
138 clipRect=aSet.rect; |
|
139 } |
|
140 |
|
141 if (pos != iPos || size != iSize || iType != type || |
|
142 flags != iFlags || clipRect != iClipRect || color != iColor || |
|
143 customTextCursor != iCustomTextCursor || win != iWin) |
|
144 { |
|
145 // There is a change in the cursor. |
|
146 changed = ETrue; |
|
147 } |
|
148 |
|
149 if (iInternalFlags&EHasFocus && changed) |
|
150 { |
|
151 if ((win != iWin && !iCustomTextCursor) || (customTextCursor && !iCustomTextCursor)) |
|
152 ReleaseNode(); |
|
153 TCursorSprite::Hide(); |
|
154 } |
|
155 |
|
156 UpdateAttributes(pos, size, type, flags, clipRect, color, customTextCursor, win); |
|
157 |
|
158 if (customTextCursor && iInternalFlags&EHasFocus) |
|
159 { |
|
160 customTextCursor->CompleteL(win, !(flags&TTextCursor::EFlagNoFlash), flags & (TTextCursor::EFlagClipHorizontal | TTextCursor::EFlagClipVertical), clipOrigo, clipSize); |
|
161 customTextCursor->SetPositionNoRedraw(pos); |
|
162 } |
|
163 |
|
164 if (iInternalFlags&EHasFocus && changed) |
|
165 { |
|
166 TCursorSprite::SetCurrentCursor(this, win); |
|
167 } |
|
168 } |
|
169 } |
|
170 void RWsTextCursor::UpdateAttributes(TPoint aPos, TSize aSize, TInt aType, TUint aFlags, TRect aClipRect, TRgb aColor, CWsCustomTextCursor* aCustomTextCursor, CWsClientWindow* aWin) |
|
171 { |
|
172 if (aPos != iPos || aSize != iSize) |
|
173 { |
|
174 iPos = aPos; |
|
175 iSize = aSize; |
|
176 WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen); |
|
177 MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver(); |
|
178 if (windowTreeObserver && iInternalFlags&EHasFocus && iInternalFlags&EActiveNode) |
|
179 windowTreeObserver->NodeExtentChanged(*this, RectRelativeToScreen()); |
|
180 } |
|
181 |
|
182 if (aType != iType) |
|
183 { |
|
184 iType = aType; |
|
185 NotifyObserver(MWsWindowTreeObserver::ECursorType); |
|
186 } |
|
187 |
|
188 if (aClipRect != iClipRect) |
|
189 { |
|
190 iClipRect = aClipRect; // must update clip rect before sending clip rect set/unset notification |
|
191 if ((aFlags&ETextCursorFlagClipped) && (iFlags&ETextCursorFlagClipped)) |
|
192 NotifyObserver(MWsWindowTreeObserver::ECursorClipRect); // clip rect changed |
|
193 } |
|
194 |
|
195 if (aFlags != iFlags) |
|
196 { |
|
197 TBool sendFlagChanged = EFalse; |
|
198 if ((aFlags&ETextCursorFlagClipped) != (iFlags&ETextCursorFlagClipped)) |
|
199 { |
|
200 if (iInternalFlags&EHasFocus && iInternalFlags&EActiveNode) |
|
201 { |
|
202 // We can't send flag changed till iFlags has been updated, as otherwise plugins responding to |
|
203 // the flag changed notification by calling ClipRect() may get the wrong rect |
|
204 sendFlagChanged = ETrue; |
|
205 } |
|
206 } |
|
207 const TBool userFlagsChanged((aFlags&ETextCursorUserFlags) != (iFlags&ETextCursorUserFlags)); |
|
208 iFlags = aFlags; |
|
209 if (userFlagsChanged) |
|
210 NotifyObserver(MWsWindowTreeObserver::ECursorFlags); |
|
211 if (sendFlagChanged) |
|
212 { |
|
213 WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen); |
|
214 MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver(); |
|
215 if (windowTreeObserver) |
|
216 windowTreeObserver->FlagChanged(*this, MWsWindowTreeObserver::ECursorClipRectSet, !!(iFlags&ETextCursorFlagClipped)); // clip rect set/unset |
|
217 } |
|
218 } |
|
219 |
|
220 if (aColor != iColor) |
|
221 { |
|
222 iColor = aColor; |
|
223 NotifyObserver(MWsWindowTreeObserver::ECursorColor); |
|
224 } |
|
225 iCustomTextCursor = aCustomTextCursor; |
|
226 iWin = aWin; |
|
227 } |
|
228 |
|
229 void RWsTextCursor::NotifyObserver(MWsWindowTreeObserver::TAttributes aAttribute) const |
|
230 { |
|
231 if (iInternalFlags&EHasFocus && iInternalFlags&EActiveNode) |
|
232 { |
|
233 WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen); |
|
234 MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver(); |
|
235 if (windowTreeObserver) |
|
236 windowTreeObserver->AttributeChanged(*this, aAttribute); |
|
237 } |
|
238 } |
|
239 |
|
240 void RWsTextCursor::CreateNode() |
|
241 { |
|
242 WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen); |
|
243 MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver(); |
|
244 if (windowTreeObserver && !(iInternalFlags&EActiveNode)) |
|
245 { |
|
246 iInternalFlags |= EActiveNode; |
|
247 windowTreeObserver->NodeCreated(*this, iWin); |
|
248 windowTreeObserver->NodeExtentChanged(*this, RectRelativeToScreen()); |
|
249 if (iFlags&ETextCursorFlagClipped) |
|
250 windowTreeObserver->FlagChanged(*this, MWsWindowTreeObserver::ECursorClipRectSet, ETrue); |
|
251 windowTreeObserver->NodeActivated(*this); |
|
252 } |
|
253 } |
|
254 |
|
255 void RWsTextCursor::ReleaseNode() |
|
256 { |
|
257 if (iInternalFlags&EActiveNode) |
|
258 { |
|
259 WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen); |
|
260 MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver(); |
|
261 if (windowTreeObserver) |
|
262 { |
|
263 windowTreeObserver->NodeReleased(*this); |
|
264 iInternalFlags &= ~EActiveNode; |
|
265 } |
|
266 } |
|
267 } |
|
268 |
|
269 void RWsTextCursor::SendState(MWsWindowTreeObserver& aWindowTreeObserver) const |
|
270 { |
|
271 if (iInternalFlags & EActiveNode) |
|
272 { |
|
273 aWindowTreeObserver.NodeCreated(*this, iWin); |
|
274 aWindowTreeObserver.NodeExtentChanged(*this, RectRelativeToScreen()); |
|
275 if (iFlags&ETextCursorFlagClipped) |
|
276 aWindowTreeObserver.FlagChanged(*this, MWsWindowTreeObserver::ECursorClipRectSet, ETrue); |
|
277 aWindowTreeObserver.NodeActivated(*this); |
|
278 } |
|
279 } |
|
280 |
|
281 void RWsTextCursor::Cancel() |
|
282 { |
|
283 if (iType!=TTextCursor::ETypeNone) |
|
284 { |
|
285 if (iInternalFlags&EHasFocus) |
|
286 TCursorSprite::SetFocus(NULL); |
|
287 iType=TTextCursor::ETypeNone; |
|
288 iWin=NULL; |
|
289 } |
|
290 } |
|
291 |
|
292 void RWsTextCursor::Disable() |
|
293 { |
|
294 if (iWin) |
|
295 { |
|
296 TCursorSprite::Hide(); |
|
297 } |
|
298 } |
|
299 |
|
300 void RWsTextCursor::Enable() |
|
301 { |
|
302 if (iWin) |
|
303 { |
|
304 TCursorSprite::Reveal(); |
|
305 } |
|
306 } |
|
307 |
|
308 void RWsTextCursor::LostFocus() |
|
309 { |
|
310 TCursorSprite::SetFocus(NULL); |
|
311 iInternalFlags &= ~EHasFocus; |
|
312 } |
|
313 |
|
314 void RWsTextCursor::ReceivedFocus() |
|
315 { |
|
316 iInternalFlags |= EHasFocus; |
|
317 if (iType!=TTextCursor::ETypeNone && iWin) |
|
318 { |
|
319 TCursorSprite::SetFocus(this,iWin); |
|
320 if (iCustomTextCursor) |
|
321 { |
|
322 iCustomTextCursor->SetPositionNoRedraw(iPos); |
|
323 } |
|
324 } |
|
325 } |
|
326 |
|
327 TRect RWsTextCursor::RectRelativeToScreen() const |
|
328 { |
|
329 TRect rect; |
|
330 rect.iTl=iPos+iWin->Origin(); |
|
331 rect.iBr=rect.iTl+iSize; |
|
332 return(rect); |
|
333 } |
|
334 |
|
335 TRect RWsTextCursor::RectRelativeToWindow() const |
|
336 { |
|
337 TRect rect; |
|
338 rect.iTl=iPos; |
|
339 rect.iBr=rect.iTl+iSize; |
|
340 return rect; |
|
341 } |
|
342 |
|
343 void RWsTextCursor::doDraw(const TRegion& aRegion) |
|
344 { |
|
345 TRegionFix<1> fallbackClipRegion; |
|
346 const TRegion *clipRegion= &aRegion; |
|
347 if (aRegion.CheckError()) |
|
348 { |
|
349 fallbackClipRegion.AddRect(iWin->AbsRect()); |
|
350 clipRegion= &fallbackClipRegion; |
|
351 } |
|
352 |
|
353 if(!clipRegion->IsEmpty()) |
|
354 { |
|
355 MWsTextCursor::TTextCursorInfo renderStageCursorInfo( |
|
356 RectRelativeToWindow(), |
|
357 *clipRegion, |
|
358 iType, static_cast<MWsWindow *>(Win()), iColor |
|
359 ); |
|
360 |
|
361 MWsTextCursor* textCursor = iWin->Screen()->RenderStageTextCursor(); |
|
362 |
|
363 textCursor->DrawTextCursor(renderStageCursorInfo); |
|
364 |
|
365 TWindowServerEvent::NotifyScreenDrawingEvent(clipRegion); |
|
366 } |
|
367 } |
|
368 |
|
369 void RWsTextCursor::Draw(const TRegion& aRegion) |
|
370 { |
|
371 iDrawRegion.Copy(iWin->VisibleRegion()); |
|
372 if (iFlags&ETextCursorFlagClipped) |
|
373 { |
|
374 TRect rect(iClipRect); |
|
375 rect.Move(iWin->Origin()); |
|
376 iDrawRegion.ClipRect(rect); |
|
377 } |
|
378 |
|
379 // Need to clip against a possible recent screen size change. |
|
380 iDrawRegion.ClipRect(iWin->Screen()->SizeInPixels()); |
|
381 |
|
382 RWsRegion tmpRegion; |
|
383 tmpRegion.Intersection(iDrawRegion, aRegion); |
|
384 if (tmpRegion.CheckError()) |
|
385 doDraw(iDrawRegion); |
|
386 else |
|
387 { |
|
388 if (!tmpRegion.IsEmpty()) |
|
389 { |
|
390 doDraw(tmpRegion); |
|
391 } |
|
392 } |
|
393 tmpRegion.Close(); |
|
394 } |
|
395 |
|
396 void RWsTextCursor::WindowDisconnected(CWsWindow *aWindow) |
|
397 { |
|
398 if (iWin==aWindow) |
|
399 Cancel(); |
|
400 } |
|
401 |
|
402 TBool RWsTextCursor::IsStandardCursorActive() |
|
403 { |
|
404 return TCursorSprite::IsStandardCursorActive(); |
|
405 } |
|
406 |
|
407 TBool RWsTextCursor::IsFlashing() const |
|
408 { |
|
409 return !(iFlags&TTextCursor::EFlagNoFlash); |
|
410 } |
|
411 |
|
412 void RWsTextCursor::ScheduleReDrawNow() |
|
413 { |
|
414 if (!iGroupWin->Screen()->ChangeTracking()) |
|
415 iGroupWin->Screen()->ScheduleAnimation(ETextCursor, RectRelativeToScreen(), 0, 0, 0, iWin); |
|
416 } |
|
417 |
|
418 /** @see MWsWindowTreeNode */ |
|
419 MWsWindowTreeNode::TType RWsTextCursor::NodeType() const |
|
420 { |
|
421 return MWsWindowTreeNode::EWinTreeNodeStandardTextCursor; |
|
422 } |
|
423 |
|
424 /** @see MWsWindowTreeNode */ |
|
425 const MWsWindow* RWsTextCursor::Window() const |
|
426 { |
|
427 return NULL; |
|
428 } |
|
429 |
|
430 /** @see MWsWindowTreeNode */ |
|
431 const MWsSprite* RWsTextCursor::Sprite() const |
|
432 { |
|
433 return NULL; |
|
434 } |
|
435 |
|
436 /** @see MWsWindowTreeNode */ |
|
437 const MWsStandardTextCursor* RWsTextCursor::StandardTextCursor() const |
|
438 { |
|
439 return this; |
|
440 } |
|
441 |
|
442 /** @see MWsWindowTreeNode */ |
|
443 const MWsWindowGroup* RWsTextCursor::WindowGroup() const |
|
444 { |
|
445 return static_cast<MWsWindowGroup*>(iGroupWin); |
|
446 } |
|
447 |
|
448 /** @see MWsWindowTreeNode */ |
|
449 const MWsWindowTreeNode* RWsTextCursor::ParentNode() const |
|
450 { |
|
451 return iWin; |
|
452 } |
|
453 |
|
454 /** @see MWsStandardTextCursor */ |
|
455 TInt RWsTextCursor::Type() const |
|
456 { |
|
457 return iType; |
|
458 } |
|
459 |
|
460 /** @see MWsStandardTextCursor */ |
|
461 TRect RWsTextCursor::Rect() const |
|
462 { |
|
463 return RectRelativeToScreen(); |
|
464 } |
|
465 |
|
466 /** @see MWsStandardTextCursor */ |
|
467 TRect RWsTextCursor::ClipRect() const |
|
468 { |
|
469 if (iFlags&ETextCursorFlagClipped) |
|
470 { |
|
471 TRect clipRectRelativeToScreen(iClipRect); |
|
472 clipRectRelativeToScreen.Move(iWin->Origin()); |
|
473 return clipRectRelativeToScreen; |
|
474 } |
|
475 else |
|
476 { |
|
477 return Rect(); |
|
478 } |
|
479 } |
|
480 |
|
481 /** @see MWsStandardTextCursor */ |
|
482 TUint RWsTextCursor::Flags() const |
|
483 { |
|
484 return iFlags&ETextCursorUserFlags; |
|
485 } |
|
486 |
|
487 /** @see MWsStandardTextCursor */ |
|
488 TRgb RWsTextCursor::Color() const |
|
489 { |
|
490 return iColor; |
|
491 } |
|
492 |
|
493 /** @see MWsStandardTextCursor */ |
|
494 TTimeIntervalMicroSeconds32 RWsTextCursor::FlashInterval() const |
|
495 { |
|
496 return iFlags&TTextCursor::EFlagNoFlash ? 0 : KFlashRate; |
|
497 } |
|
498 |
|
499 TFlashState RWsTextCursor::CurrentCursorFlashState() const |
|
500 { |
|
501 if (IsFlashing()) |
|
502 { |
|
503 return (CWsTop::CurrentFocusScreen()->Now().DateTime().MicroSecond()<KFlashRate)?EFlashOn:EFlashOff; |
|
504 } |
|
505 else |
|
506 { |
|
507 return EFlashOn; |
|
508 } |
|
509 } |
|
510 |
|
511 |
|
512 // Cursor sprite handling |
|
513 |
|
514 TBool TCursorSprite::iHidden=ETrue; |
|
515 RWsTextCursor *TCursorSprite::iCurrentCursor=NULL; |
|
516 |
|
517 // |
|
518 |
|
519 // Hide / Reveal text cursors. |
|
520 void TCursorSprite::Hide() |
|
521 { |
|
522 if (!iHidden && iCurrentCursor) |
|
523 { |
|
524 iHidden=ETrue; |
|
525 if (iCurrentCursor->iCustomTextCursor) |
|
526 { |
|
527 iCurrentCursor->iCustomTextCursor->Deactivate(); |
|
528 } |
|
529 else |
|
530 { |
|
531 iCurrentCursor->ScheduleReDrawNow(); |
|
532 } |
|
533 } |
|
534 } |
|
535 |
|
536 void TCursorSprite::Reveal() |
|
537 { |
|
538 if(iHidden && iCurrentCursor) |
|
539 { |
|
540 iHidden=EFalse; |
|
541 if (iCurrentCursor->iCustomTextCursor) |
|
542 { |
|
543 iCurrentCursor->iCustomTextCursor->Activate(); |
|
544 } |
|
545 else |
|
546 { |
|
547 iCurrentCursor->ScheduleReDrawNow(); |
|
548 } |
|
549 } |
|
550 } |
|
551 |
|
552 void TCursorSprite::SetFocus(RWsTextCursor* aFocus,CWsClientWindow* aWin/*=NULL*/) |
|
553 { |
|
554 if (iCurrentCursor!=aFocus) |
|
555 { |
|
556 if (iCurrentCursor) |
|
557 iCurrentCursor->ReleaseNode(); |
|
558 Hide(); |
|
559 SetCurrentCursor(aFocus, aWin); |
|
560 } |
|
561 } |
|
562 |
|
563 void TCursorSprite::SetCurrentCursor(RWsTextCursor* aFocus, CWsClientWindow* aWin) |
|
564 { |
|
565 if (aFocus && !aFocus->iCustomTextCursor) |
|
566 aFocus->CreateNode(); |
|
567 iCurrentCursor = aFocus; |
|
568 if (aWin && iCurrentCursor && iCurrentCursor->iCustomTextCursor) |
|
569 { |
|
570 iCurrentCursor->iCustomTextCursor->SetWindow(aWin); |
|
571 } |
|
572 Reveal(); |
|
573 } |
|
574 |
|
575 TBool TCursorSprite::IsStandardCursorActive() |
|
576 { |
|
577 return iCurrentCursor && !iCurrentCursor->iCustomTextCursor && !iHidden; |
|
578 } |
|
579 |