    //------------------------------------------------------------------------------
    // emPanel.h
    //
    // Copyright (C) 2004-2008,2010-2011 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 casted 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.

            emUInt64 GetCreationNumber() const;
                    // This is a generic consecutive identification number for this
                    // panel. It is unique within the view. Whenever a panel is
                    // created, a private counter in the view is incremented by one,
                    // and the panel gets that number as its creation number.

            virtual emString GetTitle();
                    // 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()

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

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

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

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

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

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

            emPanel * GetFirstChild();
            emPanel * GetLastChild();
                    // 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();
            emPanel * GetNext();
                    // 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 GetEssenceRect(double * pX, double * pY,
                                        double * pW, double * pH);
                    // 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 returns the whole panel rectangle.

            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. It is called the supreme
                    // viewed panel. Thus, 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.

            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();
            emPanel * GetFocusableFirstChild();
            emPanel * GetFocusableLastChild();
            emPanel * GetFocusablePrev();
            emPanel * GetFocusableNext();
                    // 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 IsVisited() const;
            bool IsInVisitedPath() const;
                    // There is always exactly one viewed panel which is called the
                    // visited panel. It is the anchor for the view within the panel
                    // tree. That means, if the layout of any panel is modified, the
                    // visited panel keeps its position and size within the view. A
                    // panel is in visited path if itself or any descendant is
                    // visited.

            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.
                    //
                    // Why is there a difference between visited and active? Indeed,
                    // normally the active panel is even the visited panel. But the
                    // visited panel must be a viewed panel, and the active panel
                    // must be focusable. On the other hand, the supreme viewed
                    // panel is chosen for optimum performance and for avoiding
                    // over/under-flows of floating point numbers. So there can be
                    // one special case where the visited panel and the active panel
                    // are not the same: The visited panel is the supreme viewed
                    // panel, and it is not focusable, and the active panel is the
                    // nearest focusable ancestor of the visited panel.

            void Activate();
                    // Make this the active panel, or if this panel is not
                    // focusable, make the nearest focusable ancestor active. This
                    // method is a short cut for: GetView().VisitLazy(this,true)

            void ActivateLater();
                    // Mark this panel for being activated at the end of the current
                    // time slice. This gives time for other things to come first,
                    // especially layout updates which may unhide this panel. If
                    // this is called on multiple panels of the same view within the
                    // same time slice, the last call counts.

            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();
                    // 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);
                    // 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.

    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_VISIT_CHANGED            = (1<< 4),
                    NF_ACTIVE_CHANGED           = (1<< 5),
                    NF_FOCUS_CHANGED            = (1<< 6),
                    NF_VIEW_FOCUS_CHANGED       = (1<< 7),
                    NF_UPDATE_PRIORITY_CHANGED  = (1<< 8),
                    NF_MEMORY_LIMIT_CHANGED     = (1<< 9),
                    NF_SOUGHT_NAME_CHANGED      = (1<<10)
            };
            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_VISIT_CHANGED           - IsVisited(), IsInVisitedPath()
                    //   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 which has IsInViewedPath()==true
                    // 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 panel and all 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 panel and all 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.

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

            virtual bool IsOpaque();
                    // 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);
                    // 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.
                    // 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()

            void EnableAutoExpansion();
                    // Enable the auto-expansion mechanism. This must be called in
                    // the constructors of panel classes which overload the method
                    // AutoExpand().

            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: EnableAutoExpansion(),
                    // 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();
                    // 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.

    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;
            emUInt64 CreationNumber;
            emColor CanvasColor;
            NoticeFlags PendingNoticeFlags;
            unsigned Viewed : 1;
            unsigned InViewedPath : 1;
            unsigned EnableSwitch : 1;
            unsigned Enabled : 1;
            unsigned Focusable : 1;
            unsigned Visited : 1;
            unsigned InVisitedPath : 1;
            unsigned Active : 1;
            unsigned InActivePath : 1;
            unsigned PendingInput : 1;
            unsigned ChildrenLayoutInvalid : 1;
            unsigned AEEnabled : 1;
            unsigned AEDecisionInvalid : 1;
            unsigned AECalling : 1;
            unsigned AEExpanded : 1;
            unsigned CreatedByAE : 1;
            unsigned AEThresholdType : 3;
    };

    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 emUInt64 emPanel::GetCreationNumber() const
    {
            return CreationNumber;
    }

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

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

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

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

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

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

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

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

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

    inline emPanel * emPanel::GetNext()
    {
            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::GetEnableSwitch() const
    {
            return EnableSwitch;
    }

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

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

    inline bool emPanel::IsVisited() const
    {
            return Visited;
    }

    inline bool emPanel::IsInVisitedPath() const
    {
            return InVisitedPath;
    }

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

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

    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 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