1 //------------------------------------------------------------------------------
2 // emPanel.h
3 //
4 // Copyright (C) 2004-2008,2010-2012,2014-2017 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #ifndef emPanel_h
22 #define emPanel_h
23
24 #ifndef emWindow_h
25 #include <emCore/emWindow.h>
26 #endif
27
28
29 //==============================================================================
30 //================================== emPanel ===================================
31 //==============================================================================
32
33 class emPanel : public emEngine {
34
35 public:
36
37 // emPanel is the base class for all our panels. An emPanel is a
38 // rectangular piece of a user interface which can be zoomed and
39 // scrolled in an emView. Each panel can have child panels that are
40 // making up more details. Child panels are always clipped by their
41 // ancestors. That means, a panel can never be seen outside its parent.
42 //
43 // You should also read the comments on the class emView. A panel is
44 // always a member of a tree of panels that is owned by a view. There is
45 // no possibility to show a panel in multiple views. In addition, panels
46 // could be created and destroyed very dynamically while the user
47 // navigates around. Therefore, when talking about the classic
48 // model-view concept, an emPanel should not be classified like a model.
49 // It belongs the view. Practically this means that a panel object
50 // should not contain any extensive model data. See class emModel for a
51 // better place.
52 //
53 // Each panel has its own coordinate system. The origin is in the
54 // upper-left corner of the panel, the X axis points to the right and
55 // the Y-axis points to the bottom. The width of the panel is always 1.0
56 // and the height depends on the layout.
57 //
58 // Note that an emView can have such a deep tree of panels, that the
59 // precision of the data type "double" is not sufficient for converting
60 // coordinates to a far ancestor or descendant panel. It is even not
61 // always possible to calculate the view coordinates of a panel.
62 // Therefore the view coordinates got with GetViewedX() and so on are
63 // valid only if the panel is actually viewed (IsViewed()==true).
64 //
65 // There are many more topics around emPanel. Just sit back and read the
66 // comments on all the methods.
67 //
68 // *********************************************************************
69 // IMPORTANT HINT FOR THE ADVANCED PROGRAMMER: You should never create a
70 // path of many panels where every panel has IsOpaque()==false and
71 // GetCanvasColor().IsOpaque()==false simultaneously, because it would
72 // mean that the view must paint all the panels on that path when the
73 // last is viewed, and this could make the overall painting too slow.
74 // *********************************************************************
75
76 class ParentArgClass {
77 public:
78 // This is just a small helper class for the first argument of
79 // the constructor of emPanel. It helps to avoid having multiple
80 // versions of the panel constructor.
81 ParentArgClass(emPanel & panel);
82 ParentArgClass(emPanel * panel);
83 ParentArgClass(emView & view);
84 ParentArgClass(emView * view);
85 emRootContext & GetRootContext() const;
86 emView & GetView() const;
87 emPanel * GetPanel() const;
88 private:
89 emView * View;
90 emPanel * Panel;
91 };
92
93 typedef const ParentArgClass & ParentArg;
94 // Type of the first argument of the constructor of emPanel.
95
96 emPanel(ParentArg parent, const emString & name);
97 // Construct a panel. Note that if this is not a root panel, the
98 // panel will be initially hidden by being placed outside its
99 // parent panel (call Layout to make visible).
100 // Arguments:
101 // parent - The parent for this panel. This can be a parent
102 // panel or a view. If it is a view, this panel will
103 // be the root panel of that view. Otherwise it will
104 // be the last child of the parent panel. Note that
105 // the type ParentArg can be cast implicitly from:
106 // emPanel&, emPanel*, emView& and emView*. But the
107 // pointer must never be NULL.
108 // name - The name for this panel. There must not be any
109 // sister panel with the same name.
110
111 virtual ~emPanel();
112 // Destruct this panel. Any child panels are deleted.
113
114 void LinkCrossPtr(emCrossPtrPrivate & crossPtr);
115 // This means emCrossPtr<emPanel> is possible.
116
117 const emString & GetName() const;
118 // Get the name of this panel.
119
120 emString GetIdentity() const;
121 static emString EncodeIdentity(const emArray<emString> & names);
122 static emArray<emString> DecodeIdentity(const char * identity);
123 // The identity of a panel consists of all the panel names on
124 // the path from the root panel down to the identified panel.
125 // They are delimited by colons, while colons and backslashes in
126 // the names are quoted by backslashes.
127
128 virtual emString GetTitle() const;
129 // Get the title of this panel. Normally, the title of the
130 // active panel is shown as the title of the view. The default
131 // implementation of this method asks the parent panel. See
132 // also: InvalidateTitle()
133
134 virtual emString GetIconFileName() const;
135 // Get the file name of an icon for this panel. For example,
136 // this is used in bookmarks. The returned string can be the
137 // name of a file in the default icon directory, or an absolute
138 // file path. An empty string means to have no icon. The default
139 // implementation of this method asks the parent panel.
140
141 emView & GetView() const;
142 // Get the view.
143
144 emContext & GetViewContext() const;
145 // Get the context of the view, this is just like GetView()
146 // because emView is an emContext. (Yes, this method is
147 // unnecessary)
148
149 emRootContext & GetRootContext() const;
150 // Get the root context (don't confuse with root panel).
151
152 emWindow * GetWindow() const;
153 emScreen * GetScreen() const;
154 // These are short cuts for GetView().GetWindow() and
155 // GetView().GetScreen().
156
157 emPanel * GetParent() const;
158 // Get the parent panel. Returns NULL if this is the root panel.
159
160 emPanel * GetChild(const char * name) const;
161 // Search a child panel by name. Returns NULL if there is no
162 // such panel.
163
164 emPanel * GetFirstChild() const;
165 emPanel * GetLastChild() const;
166 // Get the first or last child panel. The first child panel is
167 // painted at first, and the last one is painted at last (first
168 // means bottom, last means top). Returns NULL if this panel has
169 // no children.
170
171 emPanel * GetPrev() const;
172 emPanel * GetNext() const;
173 // Get the previous or next panel within the list of the
174 // parent's list of children. It is painted before or after this
175 // panel, respectively. Returns NULL if this is the first or
176 // last child panel, respectively.
177
178 void BeFirst();
179 void BeLast();
180 void BePrevOf(emPanel * sister);
181 void BeNextOf(emPanel * sister);
182 // Move this panel within the stacking order.
183
184 void SortChildren(
185 int(*compare)(emPanel * c1, emPanel * c2, void * context),
186 void * context=NULL
187 );
188 // Sort all child panels.
189 // Arguments:
190 // compare - A function for comparing two child panels. The
191 // result is:
192 // < 0 - c1 is "less" than c2
193 // > 0 - c1 is "greater" than c2
194 // == 0 - c1 is "equal" to c2 (no change in
195 // the order)
196 // context - Any pointer to be forwarded to the compare
197 // function.
198
199 void DeleteAllChildren();
200 // Delete all child panels.
201
202 virtual void Layout(double layoutX, double layoutY,
203 double layoutWidth, double layoutHeight,
204 emColor canvasColor=0);
205 // Move and/or resize this panel, and set the canvas color.
206 // IMPORTANT: For best performance, please set the canvas color
207 // whenever possible. It accelerates the paint algorithms, and
208 // it helps the view to choose a better supreme viewed panel.
209 // Arguments:
210 // layoutX, layoutX - Position of this panel (upper-
211 // left corner) in the coordinate
212 // system of the parent panel. But
213 // for the root panel, this is
214 // ignored.
215 // layoutWidth, layoutHeight - Size of this panel in the
216 // coordinate system of the parent
217 // panel. But for the root panel,
218 // only the quotient is of
219 // interest.
220 // canvasColor - Color of the canvas when this
221 // panel is painted. Please study
222 // the class emPainter for
223 // understanding this argument.
224
225 double GetLayoutX() const;
226 double GetLayoutY() const;
227 double GetLayoutWidth() const;
228 double GetLayoutHeight() const;
229 // Get the upper-left corner and size of this panel, in the
230 // coordinate system of the parent panel.
231
232 emColor GetCanvasColor() const;
233 // Get the canvas color, non-opaque if unspecified.
234
235 double GetWidth() const; // Always 1.0
236 double GetHeight() const;
237 // Get the size of this panel in its own coordinate system. The
238 // width is always 1.0, and therefore the height is equal to
239 // LayoutHeight/LayoutWidth.
240
241 double GetTallness() const;
242 // Get the height/width ratio of this panel. This is equal to
243 // GetHeight() here. In classic computer graphics, the
244 // reciprocal value is called "aspect ratio". But with emPanel
245 // and emView it seems to be more practical working with
246 // height/width ratios instead of width/height ratios. Let's
247 // call it "tallness".
248
249 virtual void GetSubstanceRect(double * pX, double * pY,
250 double * pW, double * pH,
251 double * pR) const;
252 // Get the substance rectangle of this panel. This should
253 // surround everything except empty margins and shadows. It is
254 // used by emView to paint the focus rectangle, and it is used
255 // to filter mouse and touch events (the panel will not get such
256 // events outside of the rectangle). The returned rectangle is
257 // in the coordinate system of this panel. It can have round
258 // corners (*pR is set to the radius). The default
259 // implementation returns the whole panel rectangle with zero
260 // radius.
261
262 bool IsPointInSubstanceRect(double x, double y) const;
263 // Ask if a point lies within the substance rectangle. The point
264 // must be given in the coordinate system of this panel.
265
266 virtual void GetEssenceRect(double * pX, double * pY,
267 double * pW, double * pH) const;
268 // Get the essence rectangle of this panel. When the panel is to
269 // be shown full-sized in the view, this rectangular part of the
270 // panel is actually shown full-sized. The returned rectangle is
271 // in the coordinate system of this panel. The default
272 // implementation calls GetSubstanceRect(...).
273
274 bool IsViewed() const;
275 bool IsInViewedPath() const;
276 // A panel is viewed if it is painted to the view. And a panel
277 // is in viewed path if itself or a descendant is viewed. There
278 // is always exactly one viewed panel within the whole tree of
279 // panels, whose parent is not viewed (or which does not have a
280 // parent). It is called the supreme viewed panel. The viewed
281 // panels are making up a tree.
282
283 double GetViewedPixelTallness() const;
284 // Same as GetView().GetCurrentPixelTallness()
285
286 double GetViewedX() const;
287 double GetViewedY() const;
288 double GetViewedWidth() const;
289 double GetViewedHeight() const;
290 // Get the upper-left corner and size of this panel, in the
291 // coordinate system of the view (which should be the coordinate
292 // system of the screen, measured in pixels). Note the equation:
293 // ViewedHeight / ViewedWidth * ViewedPixelTallness == Height
294 // CAUTION: These methods are valid only if IsViewed()==true.
295
296 double GetClipX1() const;
297 double GetClipY1() const;
298 double GetClipX2() const;
299 double GetClipY2() const;
300 // Get the upper-left and lower-right corners of the clipping
301 // rectangle, in the coordinate system of the view. This
302 // clipping respects the ancestor panels and the view, bot not
303 // any overlapping panels like descendants, sisters and aunts.
304 // CAUTION: These methods are valid only if IsViewed()==true.
305
306 double PanelToViewX(double panelX) const;
307 double PanelToViewY(double panelY) const;
308 double ViewToPanelX(double viewX) const;
309 double ViewToPanelY(double viewY) const;
310 // Transform panel coordinates to view coordinates and vice
311 // versa.
312 // CAUTION: These methods are valid only if IsViewed()==true.
313
314 double PanelToViewDeltaX(double panelDeltaX) const;
315 double PanelToViewDeltaY(double panelDeltaY) const;
316 double ViewToPanelDeltaX(double viewDeltaX) const;
317 double ViewToPanelDeltaY(double viewDeltaY) const;
318 // Transform panel deltas (widths and heights) to view deltas
319 // and vice versa.
320 // CAUTION: These methods are valid only if IsViewed()==true.
321
322 enum ViewConditionType {
323 VCT_AREA,
324 VCT_WIDTH,
325 VCT_HEIGHT,
326 VCT_MIN_EXT,
327 VCT_MAX_EXT
328 };
329 double GetViewCondition(ViewConditionType vcType=VCT_AREA) const;
330 // This can be used to decide whether the panel should show a
331 // detail or not (through painting or through existence of a
332 // child panel). The larger the panel is shown, the larger is
333 // the result of the method. The result should be compared
334 // against a threshold value, and if the threshold is less or
335 // equal, the detail should be shown. In particular, this method
336 // works as follows: If IsInViewedPath()==false, the result is
337 // always zero (=> don't show any details). Otherwise, if
338 // IsViewed()==false, the view has zoomed into a child panel and
339 // therefore the result is very very large (=> keep details,
340 // don't destroy child panels). Otherwise, the panel is a viewed
341 // one and the result is calculated from the viewed size
342 // depending on the argument vcType:
343 // VCT_AREA: GetViewedWidth() * GetViewedHeight()
344 // VCT_WIDTH: GetViewedWidth()
345 // VCT_HEIGHT: GetViewedHeight()
346 // VCT_MIN_EXT: emMin(GetViewedWidth(), GetViewedHeight())
347 // VCT_MAX_EXT: emMax(GetViewedWidth(), GetViewedHeight())
348 // vcType should be chosen so that the threshold value can be
349 // independent from the height/width ratio of this panel.
350 // Therefore, please consider, in the coordinate system of this
351 // panel, how the size of the detail is depending on the height
352 // (GetHeight()) of this panel. For example, if the detail has a
353 // fixed layout without any dependency on GetHeight(), say
354 // VCT_WIDTH. The default of VCT_AREA assumes that the layout
355 // scales the detail in one extend by GetHeight(), which is
356 // often the case.
357
358 double GetAutoExpansionThresholdValue() const;
359 ViewConditionType GetAutoExpansionThresholdType() const;
360 virtual void SetAutoExpansionThreshold(
361 double thresholdValue, ViewConditionType vcType=VCT_AREA
362 );
363 // Threshold value and type for the auto-expansion mechanism
364 // (see AutoExpand()). The default should be okay for normal
365 // cases.
366
367 bool IsAutoExpanded() const;
368 // Whether this panel is currently auto-expanded (see
369 // AutoExpand()).
370
371 virtual void SetEnableSwitch(bool enableSwitch);
372 bool GetEnableSwitch() const;
373 bool IsEnabled() const;
374 // Set/get the enable switch and get the enable state. A panel
375 // is enabled if itself and all its ancestor panels have the
376 // enable switch set to true. Thereby it is possible to disable
377 // a whole sub-tree by setting the enable switch of its root to
378 // false. The enable state has no influence on the arguments to
379 // the Input method. Programmers of derived panel classes should
380 // care about the enable state in methods like Input and Paint
381 // when it is appropriate.
382
383 virtual void SetFocusable(bool focusable);
384 bool IsFocusable() const;
385 // Whether this panel can be focused. The default is true. The
386 // root panel must always be focusable. Thus, it has no effect
387 // to call SetFocusable(false) on the root panel.
388
389 emPanel * GetFocusableParent() const;
390 emPanel * GetFocusableFirstChild() const;
391 emPanel * GetFocusableLastChild() const;
392 emPanel * GetFocusablePrev() const;
393 emPanel * GetFocusableNext() const;
394 // Like GetParent, GetFirstChild and so on, but these methods
395 // behave like if all non-focusable panels would have been
396 // removed from the panel tree. At such a thought removal, the
397 // children of a removed panel are given to the parent of the
398 // removed panel. It is allowed to call the methods on
399 // non-focusable panels. They are just additional possible start
400 // points for the search.
401
402 bool IsActive() const;
403 bool IsInActivePath() const;
404 // There is always exactly one panel, which is called the active
405 // panel. The application behind the view usually shows the
406 // title and the control panel for the active panel, and the
407 // view normally paints a highlight around it. And it can be the
408 // focused panel (see IsFocused()). A panel cannot be active if
409 // it is not focusable (see SetFocusable()). A panel is in
410 // active path if itself or any descendant is the active panel.
411
412 bool IsActivatedAdherent() const;
413 // Ask whether this panel is activated adherent. "Adherent"
414 // usually means that the activation has been made by the user.
415 // An adherent activation is not so easy to change by zooming
416 // and scrolling like a non-adherent activation.
417
418 void Activate(bool adherent=true);
419 // Make this the active panel, or if this panel is not
420 // focusable, make the nearest focusable ancestor active.
421
422 bool IsFocused() const;
423 bool IsInFocusedPath() const;
424 // When the view is focused, the active panel is even the
425 // focused panel. Otherwise there is no focused panel. A panel
426 // is in focused path if itself or any descendant is the focused
427 // panel.
428
429 bool IsViewFocused() const;
430 // Ask whether the view has the input focus.
431
432 void Focus(bool adherent=true);
433 // Make this the focused panel, or if this panel is not
434 // focusable, make the nearest focusable ancestor focused. This
435 // is like calling Activate() and GetView().Focus().
436
437 double GetUpdatePriority() const;
438 // Get the priority for updating this panel. For example, this
439 // could be used when working with emPriSchedAgent. The result
440 // is in the range of 0.0 (minimum priority) to 1.0 (maximum
441 // priority).
442
443 emUInt64 GetMemoryLimit() const;
444 // Get the maximum number of memory bytes this panel is allowed
445 // to allocate, including all descendant panels and all mostly
446 // non-shared referred models, but not including any descendant
447 // panels which are also supporting this blurred concept.
448 // Mainly, this method has been invented for panels which are
449 // showing file contents, because files or their models often
450 // can have any size, and we have to make sure that the overall
451 // process does not consume too much memory.
452
453 emUInt64 GetInputClockMS() const;
454 // Get the time of the currently handled input event and input
455 // state, or the current time if all events are handled. The
456 // time is measured in milliseconds and starts anywhere, but it
457 // should never overflow.
458
459 virtual double GetTouchEventPriority(double touchX, double touchY) const;
460 // Get the priority of this panel for receiving touch events.
461 // This is used by certain view input filters to decide whether
462 // to eat touch events for their purpose. Remember the
463 // possibility of an emSubViewPanel. Currently, following
464 // priorities are defined:
465 // 0.0 - No touch event processing.
466 // 1.0 - Set focus by touches.
467 // 2.0 - Emulate mouse functions by touches.
468 // 3.0 - Emulate mouse functions, and zoom/scroll by touches.
469 // The default implementation returns 0.0 when not focusable, or
470 // 1.0 when focusable, according to the default implementation
471 // of the Input method.
472 // Arguments:
473 // touchX, touchY - Position of a first touch in view
474 // coordinates.
475
476 typedef int AutoplayHandlingFlags;
477 enum {
478 APH_ITEM = (1<<0),
479 APH_DIRECTORY = (1<<1),
480 APH_CUTOFF = (1<<2),
481 APH_CUTOFF_AT_SUBITEMS = (1<<3)
482 };
483 virtual void SetAutoplayHandling(AutoplayHandlingFlags flags);
484 AutoplayHandlingFlags GetAutoplayHandling() const;
485 // How this panel shall be handled by an autoplay function:
486 // APH_ITEM - This panel is worth to be shown or
487 // played by autoplay. This flag is set
488 // by default, but it is ignored if
489 // the panel is not focusable.
490 // APH_DIRECTORY - Autoplay shall enter or leave this
491 // sub-tree only when acting recursively.
492 // This flag is ignored if the panel is
493 // not focusable.
494 // APH_CUTOFF - Autoplay shall never enter or leave
495 // this sub-tree. If APH_ITEM is also
496 // set, the panel may be shown as part
497 // of the upper tree.
498 // APH_CUTOFF_AT_SUBITEMS - Force any sub-items to act like
499 // APH_CUTOFF.
500
501 virtual bool IsContentReady(bool * pReadying=NULL) const;
502 // Ask if this panel has created all its child panels and if it
503 // is ready for showing or playback. If not, *pReadying is set
504 // to whether the panel will be ready later. Otherwise the panel
505 // may not be ready because it is not viewed completely or large
506 // enough. This method may be polled by autoplay. It should only
507 // be called through a low-priority engine. The default
508 // implementation returns IsAutoExpanded() and readying false.
509
510 virtual bool GetPlaybackState(bool * pPlaying, double * pPos=NULL) const;
511 // Get the playback state of this panel.
512 // Arguments:
513 // pPlaying - Pointer for returning whether playpack is active.
514 // pPos - Optional pointer for returning the playback
515 // position in the range of 0.0 to 1.0.
516 // If *pPlaying is set to false, *pPos==0.0 means
517 // stopped by user or never started, and *Pos==1.0
518 // means stopped by playing to the end, and
519 // 0.0<*pPos<1.0 means paused by user at that
520 // position.
521 // Returns:
522 // Whether this panel supports playback. The default
523 // implementation returns false.
524
525 virtual bool SetPlaybackState(bool playing, double pos=-1.0);
526 // Set the playback state of this panel.
527 // Arguments:
528 // playing - Whether playpack shall be active or not.
529 // pos - Desired playback position in the range of 0.0 to
530 // 1.0. -1.0 means not to change the position.
531 // Returns:
532 // Whether this panel supports playback. The default
533 // implementation returns false.
534
535 protected:
536
537 virtual bool Cycle();
538 // emPanel has been derived from emEngine for convenience. This
539 // default implementation does nothing and returns false.
540
541 typedef emUInt16 NoticeFlags;
542 enum {
543 NF_CHILD_LIST_CHANGED = (1<<0),
544 NF_LAYOUT_CHANGED = (1<<1),
545 NF_VIEWING_CHANGED = (1<<2),
546 NF_ENABLE_CHANGED = (1<<3),
547 NF_ACTIVE_CHANGED = (1<<4),
548 NF_FOCUS_CHANGED = (1<<5),
549 NF_VIEW_FOCUS_CHANGED = (1<<6),
550 NF_UPDATE_PRIORITY_CHANGED = (1<<7),
551 NF_MEMORY_LIMIT_CHANGED = (1<<8),
552 NF_SOUGHT_NAME_CHANGED = (1<<9)
553 };
554 virtual void Notice(NoticeFlags flags);
555 // Called some time after this panel has possibly changed in
556 // some states. Each flag in the argument indicates a certain
557 // state which may have changed:
558 // NF_CHILD_LIST_CHANGED - List of children
559 // NF_LAYOUT_CHANGED - GetLayout...(), GetHeight(),
560 // GetCanvasColor()
561 // NF_VIEWING_CHANGED - IsViewed(), IsInViewedPath(),
562 // GetViewed...(), GetClip...(),
563 // GetViewCondition(...)
564 // NF_ENABLE_CHANGED - IsEnabled()
565 // NF_ACTIVE_CHANGED - IsActive(), IsInActivePath()
566 // NF_FOCUS_CHANGED - IsFocused(), IsInFocusedPath()
567 // NF_VIEW_FOCUS_CHANGED - IsViewFocused()
568 // NF_UPDATE_PRIORITY_CHANGED - GetUpdatePriority()
569 // NF_MEMORY_LIMIT_CHANGED - GetMemoryLimit()
570 // NF_SOUGHT_NAME_CHANGED - GetSoughtName()
571 // The default implementation does nothing.
572
573 virtual void Input(emInputEvent & event, const emInputState & state,
574 double mx, double my);
575 // Process input form keyboard, mouse, and touch. This method is
576 // called on every panel whenever there is a change in the input
577 // state or when there is an input event. The order of callings
578 // is from children to parents and from top to bottom (=last to
579 // first). The default implementation does this: First, if it is
580 // a mouse or touch event and if this panel is focusable, the
581 // focus is set to this panel and the event is eaten. And
582 // secondly, if this is the active panel, certain keyboard
583 // events are processed and eaten for switching the focus to
584 // another panel. Also see the methods GetInputClockMS and
585 // GetTouchEventPriority.
586 // Arguments:
587 // event - An input event. This is non-empty only if:
588 // * It is a mouse button event, and the mouse
589 // position lies within the substance rectangles of
590 // the panel and of all of its ancestors, and the
591 // event has not been eaten by a descendant panel
592 // or by an overlapping panel in front or by a view
593 // input filter.
594 // * It is a touch event, and the first touch
595 // position lies within the substance rectangles of
596 // the panel and of all of its ancestors, and the
597 // event has not been eaten by a descendant panel
598 // or by an overlapping panel in front or by a view
599 // input filter. Normally, touch events are
600 // converted to mouse events by a view input
601 // filter.
602 // * It is a keyboard key event, and this panel is in
603 // focused path, and the event has not been eaten
604 // by a descendant panel or by a view input filter.
605 // The event can be eaten by calling event.Eat(). The
606 // event reference is non-const only for that. Please
607 // do not modify the event in any other way.
608 // state - The current input state. The values of
609 // state.GetMouseX/Y are from the coordinate system
610 // of the view (thus, they are in pixels).
611 // mx, my - Position of the mouse in the coordinate system of
612 // this panel. Valid only if IsInViewedPath().
613
614 virtual emCursor GetCursor() const;
615 // Get the mouse cursor to be shown for this panel. The default
616 // implementation asks the parent panel. See also:
617 // InvalidateCursor()
618
619 virtual bool IsOpaque() const;
620 // Whether this panel is completely opaque by its painting or by
621 // its child panels. If true, the background may not be
622 // initialized when the panel is painted. It even helps the view
623 // to choose a better supreme viewed panel. The default
624 // implementation returns false. See also: InvalidatePainting()
625
626 virtual void Paint(const emPainter & painter, emColor canvasColor) const;
627 // Paint this panel. The default implementation does nothing.
628 // Note that for a single painting of the whole panel, this
629 // method may be called multiple times with different clipping
630 // rectangles in order to optimize cache usage.
631 //
632 // ***************** CAUTION: MULTI-THREADING ******************
633 // * In order to improve the graphics performance on *
634 // * multi-core CPUs, Paint may be called by multiple threads *
635 // * in parallel, but in a way that there is always at most *
636 // * one thread at a time in user code, outside any call to *
637 // * emPainter. There is a shared mutex which is entered *
638 // * before a thread calls an emPanel::Paint. It is left only *
639 // * while the thread is in a call to a method of emPainter *
640 // * and re-entered before such a call returns. *
641 // * Please prepare your code for this. Ideally, do not modify *
642 // * any shared data in an implementation of Paint. *
643 // *************************************************************
644 //
645 // Arguments:
646 // painter - A painter for painting the panel to the
647 // screen. Origin and scaling of this painter
648 // are prepared for having the coordinate system
649 // of the panel.
650 // canvasColor - Please study emPainter for understanding this
651 // parameter. Normally this is equal to
652 // GetCanvasColor(), but if this panel is the
653 // supreme viewed panel, it could be a different
654 // color.
655 // See also: InvalidatePainting()
656
657 virtual void AutoExpand();
658 // Create child panels by auto-expansion. Often it is a good
659 // idea to dynamically create and delete the children of a panel
660 // depending on the view condition, instead of wasting resources
661 // by having the child panels always existent. For solving
662 // dynamic creation and deletion, AutoExpand could be overloaded
663 // to create the child panels in it. The default implementation
664 // does nothing. AutoExpand is called when the view condition
665 // reaches a threshold value. As soon as the view condition
666 // falls below again, the child panels are deleted through
667 // calling AutoShrink(). See also:
668 // SetAutoExpansionThreshold(...), AutoShrink(),
669 // InvalidateAutoExpansion().
670
671 virtual void AutoShrink();
672 // Delete child panels by auto-shrinking. The default
673 // implementation deletes exactly those child panels that have
674 // been created within a call to AutoExpand (yes, there is some
675 // internal magic for knowing whether a panel has bee created
676 // inside or outside AutoExpand). So there is no need to
677 // overload this method except if you want to do something like
678 // setting panel pointer variables to NULL.
679
680 virtual void LayoutChildren();
681 // Lay out the child panels of this panel. The default
682 // implementation does nothing. It is not a must to do the
683 // layout herein, but it is a good idea. The method is called
684 // after there was a change in the list of child panels (like
685 // NF_CHILD_LIST_CHANGED) or in the layout of this panel (like
686 // NF_LAYOUT_CHANGED), but only if there is at least one child
687 // panel. See also: InvalidateChildrenLayout()
688
689 virtual emPanel * CreateControlPanel(ParentArg parent,
690 const emString & name);
691 // Create a control panel for this content panel. If this panel
692 // is in a content view, and if it is the active panel, then
693 // this method may be called by the view to create a control
694 // panel. The default implementation asks the parent of this
695 // panel. A result of NULL means to have no control panel.
696 // Remember that the control panel is normally created in
697 // another view and therefore in another view context than this
698 // content panel. But it is okay to have links (pointers,
699 // references) from a control panel to the content view context
700 // or to its models. That means, per definition, the content
701 // view context always has to live longer than the panels of the
702 // control view. Hint: If a panel does not want to leave its
703 // control panel to its descendants, it could check IsActive()
704 // to see whether the control panel would be for itself or for a
705 // descendant. See also: InvalidateControlPanel()
706
707 const char * GetSoughtName() const;
708 // While the view is seeking for a child of this panel, this
709 // method returns the name of the sought child panel. Otherwise
710 // it returns NULL.
711
712 virtual bool IsHopeForSeeking() const;
713 // While the view is seeking for a still non-existent child of
714 // this panel, this method is called by the view on every time
715 // slice for asking whether there is any hope that the desired
716 // child panel will ever be created. If this returns false
717 // continuously for at least 10 time slices, the seeking is
718 // given up. Thus, the implementation can temporarily say false
719 // even if there is hope. This often simplifies the
720 // implementation regarding pending notices and signals. The
721 // default implementation always returns false. Hint: While the
722 // view is seeking for a child panel, the parent panel is shown
723 // full-sized and its memory limit is set to a maximum. Thereby
724 // it is often not needed to care about the seek problem when
725 // programming a panel.
726
727 void InvalidateTitle();
728 // Indicate a change in the results of GetTitle(). After calling
729 // this, showings of the title will be updated.
730
731 void InvalidateCursor();
732 // Indicate a change in the results of GetCursor(). After
733 // calling this, showings of the cursor will be updated.
734
735 void InvalidatePainting();
736 void InvalidatePainting(double x, double y, double w, double h);
737 // Indicate a change in the results of IsOpaque() and Paint().
738 // After calling this, the panel will be re-painted if it is
739 // shown. The second version of the method allows to invalidate
740 // just a rectangular area instead of the whole panel.
741 // Arguments:
742 // x,y,w,h - Upper-left corner and size of the rectangle, in
743 // the coordinate system of this panel.
744
745 void InvalidateAutoExpansion();
746 // Indicate a change in the results of AutoExpand(). After
747 // calling this, and if in expanded state, AutoShrink() and
748 // AutoExpand() will be called again.
749
750 void InvalidateChildrenLayout();
751 // Indicate a change in the results of LayoutChildren(). After
752 // calling this, LayoutChildren() will be called again, but only
753 // if there is at least one child.
754
755 void InvalidateControlPanel();
756 // Indicate a change in the results of CreateControlPanel().
757 // After calling this, the control panel will be re-created, but
758 // only if it is shown.
759
760 // - - - - - - - - - - Depreciated methods - - - - - - - - - - - - - - -
761 // The following virtual non-const methods have been replaced by const
762 // methods (see above). The old versions still exist here with the
763 // "final" keyword added, so that old overridings will fail to compile.
764 // If you run into this, please adapt your overridings by adding
765 // "const". Besides, please read the new comments about multi-threading
766 // in Paint more above.
767 public:
768 virtual emString GetTitle() final;
769 virtual emString GetIconFileName() final;
770 virtual void GetSubstanceRect(double * pX, double * pY,
771 double * pW, double * pH,
772 double * pR) final;
773 virtual void GetEssenceRect(double * pX, double * pY,
774 double * pW, double * pH) final;
775 virtual double GetTouchEventPriority(double touchX, double touchY) final;
776 protected:
777 virtual emCursor GetCursor() final;
778 virtual bool IsOpaque() final;
779 virtual void Paint(const emPainter & painter, emColor canvasColor) final;
780 virtual bool IsHopeForSeeking() final;
781 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
782
783 private:
784
785 friend class emView;
786 friend class ParentArgClass;
787
788 void AddPendingNotice(NoticeFlags flags);
789 void HandleNotice();
790 void UpdateChildrenViewing();
791 void AvlInsertChild(emPanel * child);
792 void AvlRemoveChild(emPanel * child);
793
794 emView & View;
795 emCrossPtrList CrossPtrList;
796 emString Name;
797 emAvlNode AvlNode;
798 emAvlTree AvlTree;
799 emPanel * Parent;
800 emPanel * FirstChild;
801 emPanel * LastChild;
802 emPanel * Prev;
803 emPanel * Next;
804 emView::PanelRingNode NoticeNode;
805 double LayoutX, LayoutY, LayoutWidth, LayoutHeight;
806 double ViewedX, ViewedY, ViewedWidth, ViewedHeight;
807 double ClipX1, ClipY1, ClipX2, ClipY2;
808 double AEThresholdValue;
809 emColor CanvasColor;
810 NoticeFlags PendingNoticeFlags;
811 unsigned Viewed : 1;
812 unsigned InViewedPath : 1;
813 unsigned EnableSwitch : 1;
814 unsigned Enabled : 1;
815 unsigned Focusable : 1;
816 unsigned Active : 1;
817 unsigned InActivePath : 1;
818 unsigned PendingInput : 1;
819 unsigned ChildrenLayoutInvalid : 1;
820 unsigned AEInvalid : 1;
821 unsigned AEDecisionInvalid : 1;
822 unsigned AECalling : 1;
823 unsigned AEExpanded : 1;
824 unsigned CreatedByAE : 1;
825 unsigned AEThresholdType : 3;
826 unsigned AutoplayHandling : 4;
827 };
828
ParentArgClass(emPanel & panel)829 inline emPanel::ParentArgClass::ParentArgClass(emPanel & panel)
830 : View(&panel.View),Panel(&panel)
831 {
832 }
833
ParentArgClass(emPanel * panel)834 inline emPanel::ParentArgClass::ParentArgClass(emPanel * panel)
835 : View(&panel->View),Panel(panel)
836 {
837 }
838
ParentArgClass(emView & view)839 inline emPanel::ParentArgClass::ParentArgClass(emView & view)
840 : View(&view),Panel(NULL)
841 {
842 }
843
ParentArgClass(emView * view)844 inline emPanel::ParentArgClass::ParentArgClass(emView * view)
845 : View(view),Panel(NULL)
846 {
847 }
848
GetRootContext()849 inline emRootContext & emPanel::ParentArgClass::GetRootContext() const
850 {
851 return View->GetRootContext();
852 }
853
GetView()854 inline emView & emPanel::ParentArgClass::GetView() const
855 {
856 return *View;
857 }
858
GetPanel()859 inline emPanel * emPanel::ParentArgClass::GetPanel() const
860 {
861 return Panel;
862 }
863
LinkCrossPtr(emCrossPtrPrivate & crossPtr)864 inline void emPanel::LinkCrossPtr(emCrossPtrPrivate & crossPtr)
865 {
866 CrossPtrList.LinkCrossPtr(crossPtr);
867 }
868
GetName()869 inline const emString & emPanel::GetName() const
870 {
871 return Name;
872 }
873
GetView()874 inline emView & emPanel::GetView() const
875 {
876 return View;
877 }
878
GetViewContext()879 inline emContext & emPanel::GetViewContext() const
880 {
881 return View;
882 }
883
GetRootContext()884 inline emRootContext & emPanel::GetRootContext() const
885 {
886 return View.GetRootContext();
887 }
888
GetWindow()889 inline emWindow * emPanel::GetWindow() const
890 {
891 return View.GetWindow();
892 }
893
GetScreen()894 inline emScreen * emPanel::GetScreen() const
895 {
896 return View.GetScreen();
897 }
898
GetParent()899 inline emPanel * emPanel::GetParent() const
900 {
901 return Parent;
902 }
903
GetFirstChild()904 inline emPanel * emPanel::GetFirstChild() const
905 {
906 return FirstChild;
907 }
908
GetLastChild()909 inline emPanel * emPanel::GetLastChild() const
910 {
911 return LastChild;
912 }
913
GetPrev()914 inline emPanel * emPanel::GetPrev() const
915 {
916 return Prev;
917 }
918
GetNext()919 inline emPanel * emPanel::GetNext() const
920 {
921 return Next;
922 }
923
GetLayoutX()924 inline double emPanel::GetLayoutX() const
925 {
926 return LayoutX;
927 }
928
GetLayoutY()929 inline double emPanel::GetLayoutY() const
930 {
931 return LayoutY;
932 }
933
GetLayoutWidth()934 inline double emPanel::GetLayoutWidth() const
935 {
936 return LayoutWidth;
937 }
938
GetLayoutHeight()939 inline double emPanel::GetLayoutHeight() const
940 {
941 return LayoutHeight;
942 }
943
GetCanvasColor()944 inline emColor emPanel::GetCanvasColor() const
945 {
946 return CanvasColor;
947 }
948
GetWidth()949 inline double emPanel::GetWidth() const
950 {
951 return 1.0;
952 }
953
GetHeight()954 inline double emPanel::GetHeight() const
955 {
956 return LayoutHeight/LayoutWidth;
957 }
958
GetTallness()959 inline double emPanel::GetTallness() const
960 {
961 return LayoutHeight/LayoutWidth;
962 }
963
IsViewed()964 inline bool emPanel::IsViewed() const
965 {
966 return Viewed;
967 }
968
IsInViewedPath()969 inline bool emPanel::IsInViewedPath() const
970 {
971 return InViewedPath;
972 }
973
GetViewedPixelTallness()974 inline double emPanel::GetViewedPixelTallness() const
975 {
976 return View.CurrentPixelTallness;
977 }
978
GetViewedX()979 inline double emPanel::GetViewedX() const
980 {
981 return ViewedX;
982 }
983
GetViewedY()984 inline double emPanel::GetViewedY() const
985 {
986 return ViewedY;
987 }
988
GetViewedWidth()989 inline double emPanel::GetViewedWidth() const
990 {
991 return ViewedWidth;
992 }
993
GetViewedHeight()994 inline double emPanel::GetViewedHeight() const
995 {
996 return ViewedHeight;
997 }
998
GetClipX1()999 inline double emPanel::GetClipX1() const
1000 {
1001 return ClipX1;
1002 }
1003
GetClipY1()1004 inline double emPanel::GetClipY1() const
1005 {
1006 return ClipY1;
1007 }
1008
GetClipX2()1009 inline double emPanel::GetClipX2() const
1010 {
1011 return ClipX2;
1012 }
1013
GetClipY2()1014 inline double emPanel::GetClipY2() const
1015 {
1016 return ClipY2;
1017 }
1018
PanelToViewX(double panelX)1019 inline double emPanel::PanelToViewX(double panelX) const
1020 {
1021 return panelX*ViewedWidth+ViewedX;
1022 }
1023
PanelToViewY(double panelY)1024 inline double emPanel::PanelToViewY(double panelY) const
1025 {
1026 return panelY*ViewedWidth/View.CurrentPixelTallness+ViewedY;
1027 }
1028
ViewToPanelX(double viewX)1029 inline double emPanel::ViewToPanelX(double viewX) const
1030 {
1031 return (viewX-ViewedX)/ViewedWidth;
1032 }
1033
ViewToPanelY(double viewY)1034 inline double emPanel::ViewToPanelY(double viewY) const
1035 {
1036 return (viewY-ViewedY)*View.CurrentPixelTallness/ViewedWidth;
1037 }
1038
PanelToViewDeltaX(double panelDeltaX)1039 inline double emPanel::PanelToViewDeltaX(double panelDeltaX) const
1040 {
1041 return panelDeltaX*ViewedWidth;
1042 }
1043
PanelToViewDeltaY(double panelDeltaY)1044 inline double emPanel::PanelToViewDeltaY(double panelDeltaY) const
1045 {
1046 return panelDeltaY*ViewedWidth/View.CurrentPixelTallness;
1047 }
1048
ViewToPanelDeltaX(double viewDeltaX)1049 inline double emPanel::ViewToPanelDeltaX(double viewDeltaX) const
1050 {
1051 return viewDeltaX/ViewedWidth;
1052 }
1053
ViewToPanelDeltaY(double viewDeltaY)1054 inline double emPanel::ViewToPanelDeltaY(double viewDeltaY) const
1055 {
1056 return viewDeltaY*View.CurrentPixelTallness/ViewedWidth;
1057 }
1058
GetAutoExpansionThresholdValue()1059 inline double emPanel::GetAutoExpansionThresholdValue() const
1060 {
1061 return AEThresholdValue;
1062 }
1063
GetAutoExpansionThresholdType()1064 inline emPanel::ViewConditionType emPanel::GetAutoExpansionThresholdType() const
1065 {
1066 return (ViewConditionType)AEThresholdType;
1067 }
1068
IsAutoExpanded()1069 inline bool emPanel::IsAutoExpanded() const
1070 {
1071 return AEExpanded;
1072 }
1073
GetEnableSwitch()1074 inline bool emPanel::GetEnableSwitch() const
1075 {
1076 return EnableSwitch;
1077 }
1078
IsEnabled()1079 inline bool emPanel::IsEnabled() const
1080 {
1081 return Enabled;
1082 }
1083
IsFocusable()1084 inline bool emPanel::IsFocusable() const
1085 {
1086 return Focusable;
1087 }
1088
IsActive()1089 inline bool emPanel::IsActive() const
1090 {
1091 return Active;
1092 }
1093
IsInActivePath()1094 inline bool emPanel::IsInActivePath() const
1095 {
1096 return InActivePath;
1097 }
1098
IsActivatedAdherent()1099 inline bool emPanel::IsActivatedAdherent() const
1100 {
1101 return Active && View.IsActivationAdherent();
1102 }
1103
IsFocused()1104 inline bool emPanel::IsFocused() const
1105 {
1106 return Active && View.IsFocused();
1107 }
1108
IsInFocusedPath()1109 inline bool emPanel::IsInFocusedPath() const
1110 {
1111 return InActivePath && View.IsFocused();
1112 }
1113
IsViewFocused()1114 inline bool emPanel::IsViewFocused() const
1115 {
1116 return View.IsFocused();
1117 }
1118
GetInputClockMS()1119 inline emUInt64 emPanel::GetInputClockMS() const
1120 {
1121 return View.GetInputClockMS();
1122 }
1123
GetAutoplayHandling()1124 inline emPanel::AutoplayHandlingFlags emPanel::GetAutoplayHandling() const
1125 {
1126 return AutoplayHandling;
1127 }
1128
InvalidateChildrenLayout()1129 inline void emPanel::InvalidateChildrenLayout()
1130 {
1131 ChildrenLayoutInvalid=1;
1132 if (!NoticeNode.Next) View.AddToNoticeList(&NoticeNode);
1133 }
1134
AddPendingNotice(NoticeFlags flags)1135 inline void emPanel::AddPendingNotice(NoticeFlags flags)
1136 {
1137 PendingNoticeFlags|=flags;
1138 if (!NoticeNode.Next) View.AddToNoticeList(&NoticeNode);
1139 }
1140
1141
1142 #endif
1143