//------------------------------------------------------------------------------
// emPanel.h
//
// Copyright (C) 2004-2008,2010-2012,2014-2017 Oliver Hamann.
//
// Homepage: http://eaglemode.sourceforge.net/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
// more details.
//
// You should have received a copy of the GNU General Public License version 3
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#ifndef emPanel_h
#define emPanel_h

#ifndef emWindow_h
#include <emCore/emWindow.h>
#endif


//==============================================================================
//================================== emPanel ===================================
//==============================================================================

class emPanel : public emEngine {

public:

        // emPanel is the base class for all our panels. An emPanel is a
        // rectangular piece of a user interface which can be zoomed and
        // scrolled in an emView. Each panel can have child panels that are
        // making up more details. Child panels are always clipped by their
        // ancestors. That means, a panel can never be seen outside its parent.
        //
        // You should also read the comments on the class emView. A panel is
        // always a member of a tree of panels that is owned by a view. There is
        // no possibility to show a panel in multiple views. In addition, panels
        // could be created and destroyed very dynamically while the user
        // navigates around. Therefore, when talking about the classic
        // model-view concept, an emPanel should not be classified like a model.
        // It belongs the view. Practically this means that a panel object
        // should not contain any extensive model data. See class emModel for a
        // better place.
        //
        // Each panel has its own coordinate system. The origin is in the
        // upper-left corner of the panel, the X axis points to the right and
        // the Y-axis points to the bottom. The width of the panel is always 1.0
        // and the height depends on the layout.
        //
        // Note that an emView can have such a deep tree of panels, that the
        // precision of the data type "double" is not sufficient for converting
        // coordinates to a far ancestor or descendant panel. It is even not
        // always possible to calculate the view coordinates of a panel.
        // Therefore the view coordinates got with GetViewedX() and so on are
        // valid only if the panel is actually viewed (IsViewed()==true).
        //
        // There are many more topics around emPanel. Just sit back and read the
        // comments on all the methods.
        //
        // *********************************************************************
        // IMPORTANT HINT FOR THE ADVANCED PROGRAMMER: You should never create a
        // path of many panels where every panel has IsOpaque()==false and
        // GetCanvasColor().IsOpaque()==false simultaneously, because it would
        // mean that the view must paint all the panels on that path when the
        // last is viewed, and this could make the overall painting too slow.
        // *********************************************************************

        class ParentArgClass {
        public:
                // This is just a small helper class for the first argument of
                // the constructor of emPanel. It helps to avoid having multiple
                // versions of the panel constructor.
                ParentArgClass(emPanel & panel);
                ParentArgClass(emPanel * panel);
                ParentArgClass(emView & view);
                ParentArgClass(emView * view);
                emRootContext & GetRootContext() const;
                emView & GetView() const;
                emPanel * GetPanel() const;
        private:
                emView * View;
                emPanel * Panel;
        };

        typedef const ParentArgClass & ParentArg;
                // Type of the first argument of the constructor of emPanel.

        emPanel(ParentArg parent, const emString & name);
                // Construct a panel. Note that if this is not a root panel, the
                // panel will be initially hidden by being placed outside its
                // parent panel (call Layout to make visible).
                // Arguments:
                //   parent - The parent for this panel. This can be a parent
                //            panel or a view. If it is a view, this panel will
                //            be the root panel of that view. Otherwise it will
                //            be the last child of the parent panel. Note that
                //            the type ParentArg can be cast implicitly from:
                //            emPanel&, emPanel*, emView& and emView*. But the
                //            pointer must never be NULL.
                //   name   - The name for this panel. There must not be any
                //            sister panel with the same name.

        virtual ~emPanel();
                // Destruct this panel. Any child panels are deleted.

        void LinkCrossPtr(emCrossPtrPrivate & crossPtr);
                // This means emCrossPtr<emPanel> is possible.

        const emString & GetName() const;
                // Get the name of this panel.

        emString GetIdentity() const;
        static emString EncodeIdentity(const emArray<emString> & names);
        static emArray<emString> DecodeIdentity(const char * identity);
                // The identity of a panel consists of all the panel names on
                // the path from the root panel down to the identified panel.
                // They are delimited by colons, while colons and backslashes in
                // the names are quoted by backslashes.

        virtual emString GetTitle() const;
                // Get the title of this panel. Normally, the title of the
                // active panel is shown as the title of the view. The default
                // implementation of this method asks the parent panel. See
                // also: InvalidateTitle()

        virtual emString GetIconFileName() const;
                // Get the file name of an icon for this panel. For example,
                // this is used in bookmarks. The returned string can be the
                // name of a file in the default icon directory, or an absolute
                // file path. An empty string means to have no icon. The default
                // implementation of this method asks the parent panel.

        emView & GetView() const;
                // Get the view.

        emContext & GetViewContext() const;
                // Get the context of the view, this is just like GetView()
                // because emView is an emContext. (Yes, this method is
                // unnecessary)

        emRootContext & GetRootContext() const;
                // Get the root context (don't confuse with root panel).

        emWindow * GetWindow() const;
        emScreen * GetScreen() const;
                // These are short cuts for GetView().GetWindow() and
                // GetView().GetScreen().

        emPanel * GetParent() const;
                // Get the parent panel. Returns NULL if this is the root panel.

        emPanel * GetChild(const char * name) const;
                // Search a child panel by name. Returns NULL if there is no
                // such panel.

        emPanel * GetFirstChild() const;
        emPanel * GetLastChild() const;
                // Get the first or last child panel. The first child panel is
                // painted at first, and the last one is painted at last (first
                // means bottom, last means top). Returns NULL if this panel has
                // no children.

        emPanel * GetPrev() const;
        emPanel * GetNext() const;
                // Get the previous or next panel within the list of the
                // parent's list of children. It is painted before or after this
                // panel, respectively. Returns NULL if this is the first or
                // last child panel, respectively.

        void BeFirst();
        void BeLast();
        void BePrevOf(emPanel * sister);
        void BeNextOf(emPanel * sister);
                // Move this panel within the stacking order.

        void SortChildren(
                int(*compare)(emPanel * c1, emPanel * c2, void * context),
                void * context=NULL
        );
                // Sort all child panels.
                // Arguments:
                //   compare - A function for comparing two child panels. The
                //             result is:
                //               < 0   -  c1 is "less" than c2
                //               > 0   -  c1 is "greater" than c2
                //               == 0  -  c1 is "equal" to c2 (no change in
                //                        the order)
                //   context - Any pointer to be forwarded to the compare
                //             function.

        void DeleteAllChildren();
                // Delete all child panels.

        virtual void Layout(double layoutX, double layoutY,
                            double layoutWidth, double layoutHeight,
                            emColor canvasColor=0);
                // Move and/or resize this panel, and set the canvas color.
                // IMPORTANT: For best performance, please set the canvas color
                // whenever possible. It accelerates the paint algorithms, and
                // it helps the view to choose a better supreme viewed panel.
                // Arguments:
                //   layoutX, layoutX          - Position of this panel (upper-
                //                               left corner) in the coordinate
                //                               system of the parent panel. But
                //                               for the root panel, this is
                //                               ignored.
                //   layoutWidth, layoutHeight - Size of this panel in the
                //                               coordinate system of the parent
                //                               panel. But for the root panel,
                //                               only the quotient is of
                //                               interest.
                //   canvasColor               - Color of the canvas when this
                //                               panel is painted. Please study
                //                               the class emPainter for
                //                               understanding this argument.

        double GetLayoutX() const;
        double GetLayoutY() const;
        double GetLayoutWidth() const;
        double GetLayoutHeight() const;
                // Get the upper-left corner and size of this panel, in the
                // coordinate system of the parent panel.

        emColor GetCanvasColor() const;
                // Get the canvas color, non-opaque if unspecified.

        double GetWidth() const; // Always 1.0
        double GetHeight() const;
                // Get the size of this panel in its own coordinate system. The
                // width is always 1.0, and therefore the height is equal to
                // LayoutHeight/LayoutWidth.

        double GetTallness() const;
                // Get the height/width ratio of this panel. This is equal to
                // GetHeight() here. In classic computer graphics, the
                // reciprocal value is called "aspect ratio". But with emPanel
                // and emView it seems to be more practical working with
                // height/width ratios instead of width/height ratios. Let's
                // call it "tallness".

        virtual void GetSubstanceRect(double * pX, double * pY,
                                      double * pW, double * pH,
                                      double * pR) const;
                // Get the substance rectangle of this panel. This should
                // surround everything except empty margins and shadows. It is
                // used by emView to paint the focus rectangle, and it is used
                // to filter mouse and touch events (the panel will not get such
                // events outside of the rectangle). The returned rectangle is
                // in the coordinate system of this panel. It can have round
                // corners (*pR is set to the radius). The default
                // implementation returns the whole panel rectangle with zero
                // radius.

        bool IsPointInSubstanceRect(double x, double y) const;
                // Ask if a point lies within the substance rectangle. The point
                // must be given in the coordinate system of this panel.

        virtual void GetEssenceRect(double * pX, double * pY,
                                    double * pW, double * pH) const;
                // Get the essence rectangle of this panel. When the panel is to
                // be shown full-sized in the view, this rectangular part of the
                // panel is actually shown full-sized. The returned rectangle is
                // in the coordinate system of this panel. The default
                // implementation calls GetSubstanceRect(...).

        bool IsViewed() const;
        bool IsInViewedPath() const;
                // A panel is viewed if it is painted to the view. And a panel
                // is in viewed path if itself or a descendant is viewed. There
                // is always exactly one viewed panel within the whole tree of
                // panels, whose parent is not viewed (or which does not have a
                // parent). It is called the supreme viewed panel. The viewed
                // panels are making up a tree.

        double GetViewedPixelTallness() const;
                // Same as GetView().GetCurrentPixelTallness()

        double GetViewedX() const;
        double GetViewedY() const;
        double GetViewedWidth() const;
        double GetViewedHeight() const;
                // Get the upper-left corner and size of this panel, in the
                // coordinate system of the view (which should be the coordinate
                // system of the screen, measured in pixels). Note the equation:
                // ViewedHeight / ViewedWidth * ViewedPixelTallness == Height
                // CAUTION: These methods are valid only if IsViewed()==true.

        double GetClipX1() const;
        double GetClipY1() const;
        double GetClipX2() const;
        double GetClipY2() const;
                // Get the upper-left and lower-right corners of the clipping
                // rectangle, in the coordinate system of the view. This
                // clipping respects the ancestor panels and the view, bot not
                // any overlapping panels like descendants, sisters and aunts.
                // CAUTION: These methods are valid only if IsViewed()==true.

        double PanelToViewX(double panelX) const;
        double PanelToViewY(double panelY) const;
        double ViewToPanelX(double viewX) const;
        double ViewToPanelY(double viewY) const;
                // Transform panel coordinates to view coordinates and vice
                // versa.
                // CAUTION: These methods are valid only if IsViewed()==true.

        double PanelToViewDeltaX(double panelDeltaX) const;
        double PanelToViewDeltaY(double panelDeltaY) const;
        double ViewToPanelDeltaX(double viewDeltaX) const;
        double ViewToPanelDeltaY(double viewDeltaY) const;
                // Transform panel deltas (widths and heights) to view deltas
                // and vice versa.
                // CAUTION: These methods are valid only if IsViewed()==true.

        enum ViewConditionType {
                VCT_AREA,
                VCT_WIDTH,
                VCT_HEIGHT,
                VCT_MIN_EXT,
                VCT_MAX_EXT
        };
        double GetViewCondition(ViewConditionType vcType=VCT_AREA) const;
                // This can be used to decide whether the panel should show a
                // detail or not (through painting or through existence of a
                // child panel). The larger the panel is shown, the larger is
                // the result of the method. The result should be compared
                // against a threshold value, and if the threshold is less or
                // equal, the detail should be shown. In particular, this method
                // works as follows: If IsInViewedPath()==false, the result is
                // always zero (=> don't show any details). Otherwise, if
                // IsViewed()==false, the view has zoomed into a child panel and
                // therefore the result is very very large (=> keep details,
                // don't destroy child panels). Otherwise, the panel is a viewed
                // one and the result is calculated from the viewed size
                // depending on the argument vcType:
                //   VCT_AREA:    GetViewedWidth() * GetViewedHeight()
                //   VCT_WIDTH:   GetViewedWidth()
                //   VCT_HEIGHT:  GetViewedHeight()
                //   VCT_MIN_EXT: emMin(GetViewedWidth(), GetViewedHeight())
                //   VCT_MAX_EXT: emMax(GetViewedWidth(), GetViewedHeight())
                // vcType should be chosen so that the threshold value can be
                // independent from the height/width ratio of this panel.
                // Therefore, please consider, in the coordinate system of this
                // panel, how the size of the detail is depending on the height
                // (GetHeight()) of this panel. For example, if the detail has a
                // fixed layout without any dependency on GetHeight(), say
                // VCT_WIDTH. The default of VCT_AREA assumes that the layout
                // scales the detail in one extend by GetHeight(), which is
                // often the case.

        double GetAutoExpansionThresholdValue() const;
        ViewConditionType GetAutoExpansionThresholdType() const;
        virtual void SetAutoExpansionThreshold(
                double thresholdValue, ViewConditionType vcType=VCT_AREA
        );
                // Threshold value and type for the auto-expansion mechanism
                // (see AutoExpand()). The default should be okay for normal
                // cases.

        bool IsAutoExpanded() const;
                // Whether this panel is currently auto-expanded (see
                // AutoExpand()).

        virtual void SetEnableSwitch(bool enableSwitch);
        bool GetEnableSwitch() const;
        bool IsEnabled() const;
                // Set/get the enable switch and get the enable state. A panel
                // is enabled if itself and all its ancestor panels have the
                // enable switch set to true. Thereby it is possible to disable
                // a whole sub-tree by setting the enable switch of its root to
                // false. The enable state has no influence on the arguments to
                // the Input method. Programmers of derived panel classes should
                // care about the enable state in methods like Input and Paint
                // when it is appropriate.

        virtual void SetFocusable(bool focusable);
        bool IsFocusable() const;
                // Whether this panel can be focused. The default is true. The
                // root panel must always be focusable. Thus, it has no effect
                // to call SetFocusable(false) on the root panel.

        emPanel * GetFocusableParent() const;
        emPanel * GetFocusableFirstChild() const;
        emPanel * GetFocusableLastChild() const;
        emPanel * GetFocusablePrev() const;
        emPanel * GetFocusableNext() const;
                // Like GetParent, GetFirstChild and so on, but these methods
                // behave like if all non-focusable panels would have been
                // removed from the panel tree. At such a thought removal, the
                // children of a removed panel are given to the parent of the
                // removed panel. It is allowed to call the methods on
                // non-focusable panels. They are just additional possible start
                // points for the search.

        bool IsActive() const;
        bool IsInActivePath() const;
                // There is always exactly one panel, which is called the active
                // panel. The application behind the view usually shows the
                // title and the control panel for the active panel, and the
                // view normally paints a highlight around it. And it can be the
                // focused panel (see IsFocused()). A panel cannot be active if
                // it is not focusable (see SetFocusable()). A panel is in
                // active path if itself or any descendant is the active panel.

        bool IsActivatedAdherent() const;
                // Ask whether this panel is activated adherent. "Adherent"
                // usually means that the activation has been made by the user.
                // An adherent activation is not so easy to change by zooming
                // and scrolling like a non-adherent activation.

        void Activate(bool adherent=true);
                // Make this the active panel, or if this panel is not
                // focusable, make the nearest focusable ancestor active.

        bool IsFocused() const;
        bool IsInFocusedPath() const;
                // When the view is focused, the active panel is even the
                // focused panel. Otherwise there is no focused panel. A panel
                // is in focused path if itself or any descendant is the focused
                // panel.

        bool IsViewFocused() const;
                // Ask whether the view has the input focus.

        void Focus(bool adherent=true);
                // Make this the focused panel, or if this panel is not
                // focusable, make the nearest focusable ancestor focused. This
                // is like calling Activate() and GetView().Focus().

        double GetUpdatePriority() const;
                // Get the priority for updating this panel. For example, this
                // could be used when working with emPriSchedAgent. The result
                // is in the range of 0.0 (minimum priority) to 1.0 (maximum
                // priority).

        emUInt64 GetMemoryLimit() const;
                // Get the maximum number of memory bytes this panel is allowed
                // to allocate, including all descendant panels and all mostly
                // non-shared referred models, but not including any descendant
                // panels which are also supporting this blurred concept.
                // Mainly, this method has been invented for panels which are
                // showing file contents, because files or their models often
                // can have any size, and we have to make sure that the overall
                // process does not consume too much memory.

        emUInt64 GetInputClockMS() const;
                // Get the time of the currently handled input event and input
                // state, or the current time if all events are handled. The
                // time is measured in milliseconds and starts anywhere, but it
                // should never overflow.

        virtual double GetTouchEventPriority(double touchX, double touchY) const;
                // Get the priority of this panel for receiving touch events.
                // This is used by certain view input filters to decide whether
                // to eat touch events for their purpose. Remember the
                // possibility of an emSubViewPanel. Currently, following
                // priorities are defined:
                //  0.0 - No touch event processing.
                //  1.0 - Set focus by touches.
                //  2.0 - Emulate mouse functions by touches.
                //  3.0 - Emulate mouse functions, and zoom/scroll by touches.
                // The default implementation returns 0.0 when not focusable, or
                // 1.0 when focusable, according to the default implementation
                // of the Input method.
                // Arguments:
                //   touchX, touchY - Position of a first touch in view
                //                    coordinates.

        typedef int AutoplayHandlingFlags;
        enum {
                APH_ITEM               = (1<<0),
                APH_DIRECTORY          = (1<<1),
                APH_CUTOFF             = (1<<2),
                APH_CUTOFF_AT_SUBITEMS = (1<<3)
        };
        virtual void SetAutoplayHandling(AutoplayHandlingFlags flags);
        AutoplayHandlingFlags GetAutoplayHandling() const;
                // How this panel shall be handled by an autoplay function:
                //  APH_ITEM               - This panel is worth to be shown or
                //                           played by autoplay. This flag is set
                //                           by default, but it is ignored if
                //                           the panel is not focusable.
                //  APH_DIRECTORY          - Autoplay shall enter or leave this
                //                           sub-tree only when acting recursively.
                //                           This flag is ignored if the panel is
                //                           not focusable.
                //  APH_CUTOFF             - Autoplay shall never enter or leave
                //                           this sub-tree. If APH_ITEM is also
                //                           set, the panel may be shown as part
                //                           of the upper tree.
                //  APH_CUTOFF_AT_SUBITEMS - Force any sub-items to act like
                //                           APH_CUTOFF.

        virtual bool IsContentReady(bool * pReadying=NULL) const;
                // Ask if this panel has created all its child panels and if it
                // is ready for showing or playback. If not, *pReadying is set
                // to whether the panel will be ready later. Otherwise the panel
                // may not be ready because it is not viewed completely or large
                // enough. This method may be polled by autoplay. It should only
                // be called through a low-priority engine. The default
                // implementation returns IsAutoExpanded() and readying false.

        virtual bool GetPlaybackState(bool * pPlaying, double * pPos=NULL) const;
                // Get the playback state of this panel.
                // Arguments:
                //   pPlaying - Pointer for returning whether playpack is active.
                //   pPos     - Optional pointer for returning the playback
                //              position in the range of 0.0 to 1.0.
                //              If *pPlaying is set to false, *pPos==0.0 means
                //              stopped by user or never started, and *Pos==1.0
                //              means stopped by playing to the end, and
                //              0.0<*pPos<1.0 means paused by user at that
                //              position.
                // Returns:
                //   Whether this panel supports playback. The default
                //   implementation returns false.

        virtual bool SetPlaybackState(bool playing, double pos=-1.0);
                // Set the playback state of this panel.
                // Arguments:
                //   playing - Whether playpack shall be active or not.
                //   pos     - Desired playback position in the range of 0.0 to
                //             1.0. -1.0 means not to change the position.
                // Returns:
                //   Whether this panel supports playback. The default
                //   implementation returns false.

protected:

        virtual bool Cycle();
                // emPanel has been derived from emEngine for convenience. This
                // default implementation does nothing and returns false.

        typedef emUInt16 NoticeFlags;
        enum {
                NF_CHILD_LIST_CHANGED       = (1<<0),
                NF_LAYOUT_CHANGED           = (1<<1),
                NF_VIEWING_CHANGED          = (1<<2),
                NF_ENABLE_CHANGED           = (1<<3),
                NF_ACTIVE_CHANGED           = (1<<4),
                NF_FOCUS_CHANGED            = (1<<5),
                NF_VIEW_FOCUS_CHANGED       = (1<<6),
                NF_UPDATE_PRIORITY_CHANGED  = (1<<7),
                NF_MEMORY_LIMIT_CHANGED     = (1<<8),
                NF_SOUGHT_NAME_CHANGED      = (1<<9)
        };
        virtual void Notice(NoticeFlags flags);
                // Called some time after this panel has possibly changed in
                // some states. Each flag in the argument indicates a certain
                // state which may have changed:
                //   NF_CHILD_LIST_CHANGED      - List of children
                //   NF_LAYOUT_CHANGED          - GetLayout...(), GetHeight(),
                //                                GetCanvasColor()
                //   NF_VIEWING_CHANGED         - IsViewed(), IsInViewedPath(),
                //                                GetViewed...(), GetClip...(),
                //                                GetViewCondition(...)
                //   NF_ENABLE_CHANGED          - IsEnabled()
                //   NF_ACTIVE_CHANGED          - IsActive(), IsInActivePath()
                //   NF_FOCUS_CHANGED           - IsFocused(), IsInFocusedPath()
                //   NF_VIEW_FOCUS_CHANGED      - IsViewFocused()
                //   NF_UPDATE_PRIORITY_CHANGED - GetUpdatePriority()
                //   NF_MEMORY_LIMIT_CHANGED    - GetMemoryLimit()
                //   NF_SOUGHT_NAME_CHANGED     - GetSoughtName()
                // The default implementation does nothing.

        virtual void Input(emInputEvent & event, const emInputState & state,
                           double mx, double my);
                // Process input form keyboard, mouse, and touch. This method is
                // called on every panel whenever there is a change in the input
                // state or when there is an input event. The order of callings
                // is from children to parents and from top to bottom (=last to
                // first). The default implementation does this: First, if it is
                // a mouse or touch event and if this panel is focusable, the
                // focus is set to this panel and the event is eaten. And
                // secondly, if this is the active panel, certain keyboard
                // events are processed and eaten for switching the focus to
                // another panel. Also see the methods GetInputClockMS and
                // GetTouchEventPriority.
                // Arguments:
                //   event  - An input event. This is non-empty only if:
                //            * It is a mouse button event, and the mouse
                //              position lies within the substance rectangles of
                //              the panel and of all of its ancestors, and the
                //              event has not been eaten by a descendant panel
                //              or by an overlapping panel in front or by a view
                //              input filter.
                //            * It is a touch event, and the first touch
                //              position lies within the substance rectangles of
                //              the panel and of all of its ancestors, and the
                //              event has not been eaten by a descendant panel
                //              or by an overlapping panel in front or by a view
                //              input filter. Normally, touch events are
                //              converted to mouse events by a view input
                //              filter.
                //            * It is a keyboard key event, and this panel is in
                //              focused path, and the event has not been eaten
                //              by a descendant panel or by a view input filter.
                //            The event can be eaten by calling event.Eat(). The
                //            event reference is non-const only for that. Please
                //            do not modify the event in any other way.
                //   state  - The current input state. The values of
                //            state.GetMouseX/Y are from the coordinate system
                //            of the view (thus, they are in pixels).
                //   mx, my - Position of the mouse in the coordinate system of
                //            this panel. Valid only if IsInViewedPath().

        virtual emCursor GetCursor() const;
                // Get the mouse cursor to be shown for this panel. The default
                // implementation asks the parent panel. See also:
                // InvalidateCursor()

        virtual bool IsOpaque() const;
                // Whether this panel is completely opaque by its painting or by
                // its child panels. If true, the background may not be
                // initialized when the panel is painted. It even helps the view
                // to choose a better supreme viewed panel. The default
                // implementation returns false. See also: InvalidatePainting()

        virtual void Paint(const emPainter & painter, emColor canvasColor) const;
                // Paint this panel. The default implementation does nothing.
                // Note that for a single painting of the whole panel, this
                // method may be called multiple times with different clipping
                // rectangles in order to optimize cache usage.
                //
                // ***************** CAUTION: MULTI-THREADING ******************
                // * In order to improve the graphics performance on           *
                // * multi-core CPUs, Paint may be called by multiple threads  *
                // * in parallel, but in a way that there is always at most    *
                // * one thread at a time in user code, outside any call to    *
                // * emPainter. There is a shared mutex which is entered       *
                // * before a thread calls an emPanel::Paint. It is left only  *
                // * while the thread is in a call to a method of emPainter    *
                // * and re-entered before such a call returns.                *
                // * Please prepare your code for this. Ideally, do not modify *
                // * any shared data in an implementation of Paint.            *
                // *************************************************************
                //
                // Arguments:
                //   painter     - A painter for painting the panel to the
                //                 screen. Origin and scaling of this painter
                //                 are prepared for having the coordinate system
                //                 of the panel.
                //   canvasColor - Please study emPainter for understanding this
                //                 parameter. Normally this is equal to
                //                 GetCanvasColor(), but if this panel is the
                //                 supreme viewed panel, it could be a different
                //                 color.
                // See also: InvalidatePainting()

        virtual void AutoExpand();
                // Create child panels by auto-expansion. Often it is a good
                // idea to dynamically create and delete the children of a panel
                // depending on the view condition, instead of wasting resources
                // by having the child panels always existent. For solving
                // dynamic creation and deletion, AutoExpand could be overloaded
                // to create the child panels in it. The default implementation
                // does nothing. AutoExpand is called when the view condition
                // reaches a threshold value. As soon as the view condition
                // falls below again, the child panels are deleted through
                // calling AutoShrink(). See also:
                // SetAutoExpansionThreshold(...), AutoShrink(),
                // InvalidateAutoExpansion().

        virtual void AutoShrink();
                // Delete child panels by auto-shrinking. The default
                // implementation deletes exactly those child panels that have
                // been created within a call to AutoExpand (yes, there is some
                // internal magic for knowing whether a panel has bee created
                // inside or outside AutoExpand). So there is no need to
                // overload this method except if you want to do something like
                // setting panel pointer variables to NULL.

        virtual void LayoutChildren();
                // Lay out the child panels of this panel. The default
                // implementation does nothing. It is not a must to do the
                // layout herein, but it is a good idea. The method is called
                // after there was a change in the list of child panels (like
                // NF_CHILD_LIST_CHANGED) or in the layout of this panel (like
                // NF_LAYOUT_CHANGED), but only if there is at least one child
                // panel. See also: InvalidateChildrenLayout()

        virtual emPanel * CreateControlPanel(ParentArg parent,
                                             const emString & name);
                // Create a control panel for this content panel. If this panel
                // is in a content view, and if it is the active panel, then
                // this method may be called by the view to create a control
                // panel. The default implementation asks the parent of this
                // panel. A result of NULL means to have no control panel.
                // Remember that the control panel is normally created in
                // another view and therefore in another view context than this
                // content panel. But it is okay to have links (pointers,
                // references) from a control panel to the content view context
                // or to its models. That means, per definition, the content
                // view context always has to live longer than the panels of the
                // control view. Hint: If a panel does not want to leave its
                // control panel to its descendants, it could check IsActive()
                // to see whether the control panel would be for itself or for a
                // descendant. See also: InvalidateControlPanel()

        const char * GetSoughtName() const;
                // While the view is seeking for a child of this panel, this
                // method returns the name of the sought child panel. Otherwise
                // it returns NULL.

        virtual bool IsHopeForSeeking() const;
                // While the view is seeking for a still non-existent child of
                // this panel, this method is called by the view on every time
                // slice for asking whether there is any hope that the desired
                // child panel will ever be created. If this returns false
                // continuously for at least 10 time slices, the seeking is
                // given up. Thus, the implementation can temporarily say false
                // even if there is hope. This often simplifies the
                // implementation regarding pending notices and signals. The
                // default implementation always returns false. Hint: While the
                // view is seeking for a child panel, the parent panel is shown
                // full-sized and its memory limit is set to a maximum. Thereby
                // it is often not needed to care about the seek problem when
                // programming a panel.

        void InvalidateTitle();
                // Indicate a change in the results of GetTitle(). After calling
                // this, showings of the title will be updated.

        void InvalidateCursor();
                // Indicate a change in the results of GetCursor(). After
                // calling this, showings of the cursor will be updated.

        void InvalidatePainting();
        void InvalidatePainting(double x, double y, double w, double h);
                // Indicate a change in the results of IsOpaque() and Paint().
                // After calling this, the panel will be re-painted if it is
                // shown. The second version of the method allows to invalidate
                // just a rectangular area instead of the whole panel.
                // Arguments:
                //   x,y,w,h - Upper-left corner and size of the rectangle, in
                //             the coordinate system of this panel.

        void InvalidateAutoExpansion();
                // Indicate a change in the results of AutoExpand(). After
                // calling this, and if in expanded state, AutoShrink() and
                // AutoExpand() will be called again.

        void InvalidateChildrenLayout();
                // Indicate a change in the results of LayoutChildren(). After
                // calling this, LayoutChildren() will be called again, but only
                // if there is at least one child.

        void InvalidateControlPanel();
                // Indicate a change in the results of CreateControlPanel().
                // After calling this, the control panel will be re-created, but
                // only if it is shown.

        // - - - - - - - - - - Depreciated methods - - - - - - - - - - - - - - -
        // The following virtual non-const methods have been replaced by const
        // methods (see above). The old versions still exist here with the
        // "final" keyword added, so that old overridings will fail to compile.
        // If you run into this, please adapt your overridings by adding
        // "const". Besides, please read the new comments about multi-threading
        // in Paint more above.
public:
        virtual emString GetTitle() final;
        virtual emString GetIconFileName() final;
        virtual void GetSubstanceRect(double * pX, double * pY,
                                      double * pW, double * pH,
                                      double * pR) final;
        virtual void GetEssenceRect(double * pX, double * pY,
                                    double * pW, double * pH) final;
        virtual double GetTouchEventPriority(double touchX, double touchY) final;
protected:
        virtual emCursor GetCursor() final;
        virtual bool IsOpaque() final;
        virtual void Paint(const emPainter & painter, emColor canvasColor) final;
        virtual bool IsHopeForSeeking() final;
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

private:

        friend class emView;
        friend class ParentArgClass;

        void AddPendingNotice(NoticeFlags flags);
        void HandleNotice();
        void UpdateChildrenViewing();
        void AvlInsertChild(emPanel * child);
        void AvlRemoveChild(emPanel * child);

        emView & View;
        emCrossPtrList CrossPtrList;
        emString Name;
        emAvlNode AvlNode;
        emAvlTree AvlTree;
        emPanel * Parent;
        emPanel * FirstChild;
        emPanel * LastChild;
        emPanel * Prev;
        emPanel * Next;
        emView::PanelRingNode NoticeNode;
        double LayoutX, LayoutY, LayoutWidth, LayoutHeight;
        double ViewedX, ViewedY, ViewedWidth, ViewedHeight;
        double ClipX1, ClipY1, ClipX2, ClipY2;
        double AEThresholdValue;
        emColor CanvasColor;
        NoticeFlags PendingNoticeFlags;
        unsigned Viewed : 1;
        unsigned InViewedPath : 1;
        unsigned EnableSwitch : 1;
        unsigned Enabled : 1;
        unsigned Focusable : 1;
        unsigned Active : 1;
        unsigned InActivePath : 1;
        unsigned PendingInput : 1;
        unsigned ChildrenLayoutInvalid : 1;
        unsigned AEInvalid : 1;
        unsigned AEDecisionInvalid : 1;
        unsigned AECalling : 1;
        unsigned AEExpanded : 1;
        unsigned CreatedByAE : 1;
        unsigned AEThresholdType : 3;
        unsigned AutoplayHandling : 4;
};

inline emPanel::ParentArgClass::ParentArgClass(emPanel & panel)
        : View(&panel.View),Panel(&panel)
{
}

inline emPanel::ParentArgClass::ParentArgClass(emPanel * panel)
        : View(&panel->View),Panel(panel)
{
}

inline emPanel::ParentArgClass::ParentArgClass(emView & view)
        : View(&view),Panel(NULL)
{
}

inline emPanel::ParentArgClass::ParentArgClass(emView * view)
        : View(view),Panel(NULL)
{
}

inline emRootContext & emPanel::ParentArgClass::GetRootContext() const
{
        return View->GetRootContext();
}

inline emView & emPanel::ParentArgClass::GetView() const
{
        return *View;
}

inline emPanel * emPanel::ParentArgClass::GetPanel() const
{
        return Panel;
}

inline void emPanel::LinkCrossPtr(emCrossPtrPrivate & crossPtr)
{
        CrossPtrList.LinkCrossPtr(crossPtr);
}

inline const emString & emPanel::GetName() const
{
        return Name;
}

inline emView & emPanel::GetView() const
{
        return View;
}

inline emContext & emPanel::GetViewContext() const
{
        return View;
}

inline emRootContext & emPanel::GetRootContext() const
{
        return View.GetRootContext();
}

inline emWindow * emPanel::GetWindow() const
{
        return View.GetWindow();
}

inline emScreen * emPanel::GetScreen() const
{
        return View.GetScreen();
}

inline emPanel * emPanel::GetParent() const
{
        return Parent;
}

inline emPanel * emPanel::GetFirstChild() const
{
        return FirstChild;
}

inline emPanel * emPanel::GetLastChild() const
{
        return LastChild;
}

inline emPanel * emPanel::GetPrev() const
{
        return Prev;
}

inline emPanel * emPanel::GetNext() const
{
        return Next;
}

inline double emPanel::GetLayoutX() const
{
        return LayoutX;
}

inline double emPanel::GetLayoutY() const
{
        return LayoutY;
}

inline double emPanel::GetLayoutWidth() const
{
        return LayoutWidth;
}

inline double emPanel::GetLayoutHeight() const
{
        return LayoutHeight;
}

inline emColor emPanel::GetCanvasColor() const
{
        return CanvasColor;
}

inline double emPanel::GetWidth() const
{
        return 1.0;
}

inline double emPanel::GetHeight() const
{
        return LayoutHeight/LayoutWidth;
}

inline double emPanel::GetTallness() const
{
        return LayoutHeight/LayoutWidth;
}

inline bool emPanel::IsViewed() const
{
        return Viewed;
}

inline bool emPanel::IsInViewedPath() const
{
        return InViewedPath;
}

inline double emPanel::GetViewedPixelTallness() const
{
        return View.CurrentPixelTallness;
}

inline double emPanel::GetViewedX() const
{
        return ViewedX;
}

inline double emPanel::GetViewedY() const
{
        return ViewedY;
}

inline double emPanel::GetViewedWidth() const
{
        return ViewedWidth;
}

inline double emPanel::GetViewedHeight() const
{
        return ViewedHeight;
}

inline double emPanel::GetClipX1() const
{
        return ClipX1;
}

inline double emPanel::GetClipY1() const
{
        return ClipY1;
}

inline double emPanel::GetClipX2() const
{
        return ClipX2;
}

inline double emPanel::GetClipY2() const
{
        return ClipY2;
}

inline double emPanel::PanelToViewX(double panelX) const
{
        return panelX*ViewedWidth+ViewedX;
}

inline double emPanel::PanelToViewY(double panelY) const
{
        return panelY*ViewedWidth/View.CurrentPixelTallness+ViewedY;
}

inline double emPanel::ViewToPanelX(double viewX) const
{
        return (viewX-ViewedX)/ViewedWidth;
}

inline double emPanel::ViewToPanelY(double viewY) const
{
        return (viewY-ViewedY)*View.CurrentPixelTallness/ViewedWidth;
}

inline double emPanel::PanelToViewDeltaX(double panelDeltaX) const
{
        return panelDeltaX*ViewedWidth;
}

inline double emPanel::PanelToViewDeltaY(double panelDeltaY) const
{
        return panelDeltaY*ViewedWidth/View.CurrentPixelTallness;
}

inline double emPanel::ViewToPanelDeltaX(double viewDeltaX) const
{
        return viewDeltaX/ViewedWidth;
}

inline double emPanel::ViewToPanelDeltaY(double viewDeltaY) const
{
        return viewDeltaY*View.CurrentPixelTallness/ViewedWidth;
}

inline double emPanel::GetAutoExpansionThresholdValue() const
{
        return AEThresholdValue;
}

inline emPanel::ViewConditionType emPanel::GetAutoExpansionThresholdType() const
{
        return (ViewConditionType)AEThresholdType;
}

inline bool emPanel::IsAutoExpanded() const
{
        return AEExpanded;
}

inline bool emPanel::GetEnableSwitch() const
{
        return EnableSwitch;
}

inline bool emPanel::IsEnabled() const
{
        return Enabled;
}

inline bool emPanel::IsFocusable() const
{
        return Focusable;
}

inline bool emPanel::IsActive() const
{
        return Active;
}

inline bool emPanel::IsInActivePath() const
{
        return InActivePath;
}

inline bool emPanel::IsActivatedAdherent() const
{
        return Active && View.IsActivationAdherent();
}

inline bool emPanel::IsFocused() const
{
        return Active && View.IsFocused();
}

inline bool emPanel::IsInFocusedPath() const
{
        return InActivePath && View.IsFocused();
}

inline bool emPanel::IsViewFocused() const
{
        return View.IsFocused();
}

inline emUInt64 emPanel::GetInputClockMS() const
{
        return View.GetInputClockMS();
}

inline emPanel::AutoplayHandlingFlags emPanel::GetAutoplayHandling() const
{
        return AutoplayHandling;
}

inline void emPanel::InvalidateChildrenLayout()
{
        ChildrenLayoutInvalid=1;
        if (!NoticeNode.Next) View.AddToNoticeList(&NoticeNode);
}

inline void emPanel::AddPendingNotice(NoticeFlags flags)
{
        PendingNoticeFlags|=flags;
        if (!NoticeNode.Next) View.AddToNoticeList(&NoticeNode);
}


#endif