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