michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkView_DEFINED michael@0: #define SkView_DEFINED michael@0: michael@0: #include "SkEventSink.h" michael@0: #include "SkRect.h" michael@0: #include "SkDOM.h" michael@0: #include "SkTDict.h" michael@0: #include "SkMatrix.h" michael@0: #include "SkMetaData.h" michael@0: michael@0: class SkCanvas; michael@0: class SkLayerView; michael@0: michael@0: /** \class SkView michael@0: michael@0: SkView is the base class for screen management. All widgets and controls inherit michael@0: from SkView. michael@0: */ michael@0: class SkView : public SkEventSink { michael@0: public: michael@0: enum Flag_Shift { michael@0: kVisible_Shift, michael@0: kEnabled_Shift, michael@0: kFocusable_Shift, michael@0: kFlexH_Shift, michael@0: kFlexV_Shift, michael@0: kNoClip_Shift, michael@0: michael@0: kFlagShiftCount michael@0: }; michael@0: enum Flag_Mask { michael@0: kVisible_Mask = 1 << kVisible_Shift, //!< set if the view is visible michael@0: kEnabled_Mask = 1 << kEnabled_Shift, //!< set if the view is enabled michael@0: kFocusable_Mask = 1 << kFocusable_Shift, //!< set if the view can receive focus michael@0: kFlexH_Mask = 1 << kFlexH_Shift, //!< set if the view's width is stretchable michael@0: kFlexV_Mask = 1 << kFlexV_Shift, //!< set if the view's height is stretchable michael@0: kNoClip_Mask = 1 << kNoClip_Shift, //!< set if the view is not clipped to its bounds michael@0: michael@0: kAllFlagMasks = (uint32_t)(0 - 1) >> (32 - kFlagShiftCount) michael@0: }; michael@0: michael@0: SkView(uint32_t flags = 0); michael@0: virtual ~SkView(); michael@0: michael@0: /** Return the flags associated with the view michael@0: */ michael@0: uint32_t getFlags() const { return fFlags; } michael@0: /** Set the flags associated with the view michael@0: */ michael@0: void setFlags(uint32_t flags); michael@0: michael@0: /** Helper that returns non-zero if the kVisible_Mask bit is set in the view's flags michael@0: */ michael@0: int isVisible() const { return fFlags & kVisible_Mask; } michael@0: int isEnabled() const { return fFlags & kEnabled_Mask; } michael@0: int isFocusable() const { return fFlags & kFocusable_Mask; } michael@0: int isClipToBounds() const { return !(fFlags & kNoClip_Mask); } michael@0: /** Helper to set/clear the view's kVisible_Mask flag */ michael@0: void setVisibleP(bool); michael@0: void setEnabledP(bool); michael@0: void setFocusableP(bool); michael@0: void setClipToBounds(bool); michael@0: michael@0: /** Return the view's width */ michael@0: SkScalar width() const { return fWidth; } michael@0: /** Return the view's height */ michael@0: SkScalar height() const { return fHeight; } michael@0: /** Set the view's width and height. These must both be >= 0. This does not affect the view's loc */ michael@0: void setSize(SkScalar width, SkScalar height); michael@0: void setSize(const SkPoint& size) { this->setSize(size.fX, size.fY); } michael@0: void setWidth(SkScalar width) { this->setSize(width, fHeight); } michael@0: void setHeight(SkScalar height) { this->setSize(fWidth, height); } michael@0: /** Return a rectangle set to [0, 0, width, height] */ michael@0: void getLocalBounds(SkRect* bounds) const; michael@0: michael@0: /** Loc - the view's offset with respect to its parent in its view hiearchy. michael@0: NOTE: For more complex transforms, use Local Matrix. The tranformations michael@0: are applied in the following order: michael@0: canvas->translate(fLoc.fX, fLoc.fY); michael@0: canvas->concat(fMatrix); michael@0: */ michael@0: /** Return the view's left edge */ michael@0: SkScalar locX() const { return fLoc.fX; } michael@0: /** Return the view's top edge */ michael@0: SkScalar locY() const { return fLoc.fY; } michael@0: /** Set the view's left and top edge. This does not affect the view's size */ michael@0: void setLoc(SkScalar x, SkScalar y); michael@0: void setLoc(const SkPoint& loc) { this->setLoc(loc.fX, loc.fY); } michael@0: void setLocX(SkScalar x) { this->setLoc(x, fLoc.fY); } michael@0: void setLocY(SkScalar y) { this->setLoc(fLoc.fX, y); } michael@0: michael@0: /** Local Matrix - matrix used to tranform the view with respect to its michael@0: parent in its view hiearchy. Use setLocalMatrix to apply matrix michael@0: transformations to the current view and in turn affect its children. michael@0: NOTE: For simple offsets, use Loc. The transformations are applied in michael@0: the following order: michael@0: canvas->translate(fLoc.fX, fLoc.fY); michael@0: canvas->concat(fMatrix); michael@0: */ michael@0: const SkMatrix& getLocalMatrix() const { return fMatrix; } michael@0: void setLocalMatrix(const SkMatrix& matrix); michael@0: michael@0: /** Offset (move) the view by the specified dx and dy. This does not affect the view's size */ michael@0: void offset(SkScalar dx, SkScalar dy); michael@0: michael@0: /** Call this to have the view draw into the specified canvas. */ michael@0: virtual void draw(SkCanvas* canvas); michael@0: michael@0: /** Call this to invalidate part of all of a view, requesting that the view's michael@0: draw method be called. The rectangle parameter specifies the part of the view michael@0: that should be redrawn. If it is null, it specifies the entire view bounds. michael@0: */ michael@0: void inval(SkRect* rectOrNull); michael@0: michael@0: // Focus management michael@0: michael@0: SkView* getFocusView() const; michael@0: bool hasFocus() const; michael@0: michael@0: enum FocusDirection { michael@0: kNext_FocusDirection, michael@0: kPrev_FocusDirection, michael@0: michael@0: kFocusDirectionCount michael@0: }; michael@0: bool acceptFocus(); michael@0: SkView* moveFocus(FocusDirection); michael@0: michael@0: // Click handling michael@0: michael@0: class Click { michael@0: public: michael@0: Click(SkView* target); michael@0: virtual ~Click(); michael@0: michael@0: const char* getType() const { return fType; } michael@0: bool isType(const char type[]) const; michael@0: void setType(const char type[]); // does NOT make a copy of the string michael@0: void copyType(const char type[]); // makes a copy of the string michael@0: michael@0: enum State { michael@0: kDown_State, michael@0: kMoved_State, michael@0: kUp_State michael@0: }; michael@0: SkPoint fOrig, fPrev, fCurr; michael@0: SkIPoint fIOrig, fIPrev, fICurr; michael@0: State fState; michael@0: void* fOwner; michael@0: unsigned fModifierKeys; michael@0: michael@0: SkMetaData fMeta; michael@0: private: michael@0: SkEventSinkID fTargetID; michael@0: char* fType; michael@0: bool fWeOwnTheType; michael@0: michael@0: void resetType(); michael@0: michael@0: friend class SkView; michael@0: }; michael@0: Click* findClickHandler(SkScalar x, SkScalar y, unsigned modifierKeys); michael@0: michael@0: static void DoClickDown(Click*, int x, int y, unsigned modi); michael@0: static void DoClickMoved(Click*, int x, int y, unsigned modi); michael@0: static void DoClickUp(Click*, int x, int y, unsigned modi); michael@0: michael@0: /** Send the event to the view's parent, and its parent etc. until one of them michael@0: returns true from its onEvent call. This view is returned. If no parent handles michael@0: the event, null is returned. michael@0: */ michael@0: SkView* sendEventToParents(const SkEvent&); michael@0: /** Send the query to the view's parent, and its parent etc. until one of them michael@0: returns true from its onQuery call. This view is returned. If no parent handles michael@0: the query, null is returned. michael@0: */ michael@0: SkView* sendQueryToParents(SkEvent*); michael@0: michael@0: // View hierarchy management michael@0: michael@0: /** Return the view's parent, or null if it has none. This does not affect the parent's reference count. */ michael@0: SkView* getParent() const { return fParent; } michael@0: SkView* attachChildToFront(SkView* child); michael@0: /** Attach the child view to this view, and increment the child's reference count. The child view is added michael@0: such that it will be drawn before all other child views. michael@0: The child view parameter is returned. michael@0: */ michael@0: SkView* attachChildToBack(SkView* child); michael@0: /** If the view has a parent, detach the view from its parent and decrement the view's reference count. michael@0: If the parent was the only owner of the view, this will cause the view to be deleted. michael@0: */ michael@0: void detachFromParent(); michael@0: /** Attach the child view to this view, and increment the child's reference count. The child view is added michael@0: such that it will be drawn after all other child views. michael@0: The child view parameter is returned. michael@0: */ michael@0: /** Detach all child views from this view. */ michael@0: void detachAllChildren(); michael@0: michael@0: /** Convert the specified point from global coordinates into view-local coordinates michael@0: * Return true on success; false on failure michael@0: */ michael@0: bool globalToLocal(SkPoint* pt) const { michael@0: if (NULL != pt) { michael@0: return this->globalToLocal(pt->fX, pt->fY, pt); michael@0: } michael@0: return true; // nothing to do so return true michael@0: } michael@0: /** Convert the specified x,y from global coordinates into view-local coordinates, returning michael@0: the answer in the local parameter. michael@0: */ michael@0: bool globalToLocal(SkScalar globalX, SkScalar globalY, SkPoint* local) const; michael@0: michael@0: /** \class F2BIter michael@0: michael@0: Iterator that will return each of this view's children, in michael@0: front-to-back order (the order used for clicking). The first michael@0: call to next() returns the front-most child view. When michael@0: next() returns null, there are no more child views. michael@0: */ michael@0: class F2BIter { michael@0: public: michael@0: F2BIter(const SkView* parent); michael@0: SkView* next(); michael@0: private: michael@0: SkView* fFirstChild, *fChild; michael@0: }; michael@0: michael@0: /** \class B2FIter michael@0: michael@0: Iterator that will return each of this view's children, in michael@0: back-to-front order (the order they are drawn). The first michael@0: call to next() returns the back-most child view. When michael@0: next() returns null, there are no more child views. michael@0: */ michael@0: class B2FIter { michael@0: public: michael@0: B2FIter(const SkView* parent); michael@0: SkView* next(); michael@0: private: michael@0: SkView* fFirstChild, *fChild; michael@0: }; michael@0: michael@0: /** \class Artist michael@0: michael@0: Install a subclass of this in a view (calling setArtist()), and then the michael@0: default implementation of that view's onDraw() will invoke this object michael@0: automatically. michael@0: */ michael@0: class Artist : public SkRefCnt { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(Artist) michael@0: michael@0: void draw(SkView*, SkCanvas*); michael@0: void inflate(const SkDOM&, const SkDOM::Node*); michael@0: protected: michael@0: virtual void onDraw(SkView*, SkCanvas*) = 0; michael@0: virtual void onInflate(const SkDOM&, const SkDOM::Node*); michael@0: private: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: /** Return the artist attached to this view (or null). The artist's reference michael@0: count is not affected. michael@0: */ michael@0: Artist* getArtist() const; michael@0: /** Attach the specified artist (or null) to the view, replacing any existing michael@0: artist. If the new artist is not null, its reference count is incremented. michael@0: The artist parameter is returned. michael@0: */ michael@0: Artist* setArtist(Artist* artist); michael@0: michael@0: /** \class Layout michael@0: michael@0: Install a subclass of this in a view (calling setLayout()), and then the michael@0: default implementation of that view's onLayoutChildren() will invoke michael@0: this object automatically. michael@0: */ michael@0: class Layout : public SkRefCnt { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(Layout) michael@0: michael@0: void layoutChildren(SkView* parent); michael@0: void inflate(const SkDOM&, const SkDOM::Node*); michael@0: protected: michael@0: virtual void onLayoutChildren(SkView* parent) = 0; michael@0: virtual void onInflate(const SkDOM&, const SkDOM::Node*); michael@0: private: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: /** Return the layout attached to this view (or null). The layout's reference michael@0: count is not affected. michael@0: */ michael@0: Layout* getLayout() const; michael@0: /** Attach the specified layout (or null) to the view, replacing any existing michael@0: layout. If the new layout is not null, its reference count is incremented. michael@0: The layout parameter is returned. michael@0: */ michael@0: Layout* setLayout(Layout*, bool invokeLayoutNow = true); michael@0: /** If a layout is attached to this view, call its layoutChildren() method michael@0: */ michael@0: void invokeLayout(); michael@0: michael@0: /** Call this to initialize this view based on the specified XML node michael@0: */ michael@0: void inflate(const SkDOM& dom, const SkDOM::Node* node); michael@0: /** After a view hierarchy is inflated, this may be called with a dictionary michael@0: containing pairs of , where the name string was the view's michael@0: "id" attribute when it was inflated. michael@0: michael@0: This will call the virtual onPostInflate for this view, and the recursively michael@0: call postInflate on all of the view's children. michael@0: */ michael@0: void postInflate(const SkTDict& ids); michael@0: michael@0: SkDEBUGCODE(void dump(bool recurse) const;) michael@0: michael@0: protected: michael@0: /** Override this to draw inside the view. Be sure to call the inherited version too */ michael@0: virtual void onDraw(SkCanvas*); michael@0: /** Override this to be notified when the view's size changes. Be sure to call the inherited version too */ michael@0: virtual void onSizeChange(); michael@0: /** Override this if you want to handle an inval request from this view or one of its children. michael@0: Tyically this is only overridden by the by the "window". If your subclass does handle the michael@0: request, return true so the request will not continue to propogate to the parent. michael@0: */ michael@0: virtual bool handleInval(const SkRect*); michael@0: //! called once before all of the children are drawn (or clipped/translated) michael@0: virtual SkCanvas* beforeChildren(SkCanvas* c) { return c; } michael@0: //! called once after all of the children are drawn (or clipped/translated) michael@0: virtual void afterChildren(SkCanvas* orig) {} michael@0: michael@0: //! called right before this child's onDraw is called michael@0: virtual void beforeChild(SkView* child, SkCanvas* canvas) {} michael@0: //! called right after this child's onDraw is called michael@0: virtual void afterChild(SkView* child, SkCanvas* canvas) {} michael@0: michael@0: /** Override this if you might handle the click michael@0: */ michael@0: virtual Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi); michael@0: /** Override this to decide if your children are targets for a click. michael@0: The default returns true, in which case your children views will be michael@0: candidates for onFindClickHandler. Returning false wil skip the children michael@0: and just call your onFindClickHandler. michael@0: */ michael@0: virtual bool onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi); michael@0: /** Override this to track clicks, returning true as long as you want to track michael@0: the pen/mouse. michael@0: */ michael@0: virtual bool onClick(Click*); michael@0: /** Override this to initialize your subclass from the XML node. Be sure to call the inherited version too */ michael@0: virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node); michael@0: /** Override this if you want to perform post initialization work based on the ID dictionary built michael@0: during XML parsing. Be sure to call the inherited version too. michael@0: */ michael@0: virtual void onPostInflate(const SkTDict&); michael@0: michael@0: public: michael@0: #ifdef SK_DEBUG michael@0: void validate() const; michael@0: #else michael@0: void validate() const {} michael@0: #endif michael@0: // default action is to inval the view michael@0: virtual void onFocusChange(bool gainFocusP); michael@0: michael@0: protected: michael@0: michael@0: // override these if you're acting as a layer/host michael@0: virtual bool onGetFocusView(SkView**) const { return false; } michael@0: virtual bool onSetFocusView(SkView*) { return false; } michael@0: michael@0: private: michael@0: SkScalar fWidth, fHeight; michael@0: SkMatrix fMatrix; michael@0: SkPoint fLoc; michael@0: SkView* fParent; michael@0: SkView* fFirstChild; michael@0: SkView* fNextSibling; michael@0: SkView* fPrevSibling; michael@0: uint8_t fFlags; michael@0: uint8_t fContainsFocus; michael@0: michael@0: friend class B2FIter; michael@0: friend class F2BIter; michael@0: michael@0: friend class SkLayerView; michael@0: michael@0: bool setFocusView(SkView* fvOrNull); michael@0: SkView* acceptFocus(FocusDirection); michael@0: void detachFromParent_NoLayout(); michael@0: /** Compute the matrix to transform view-local coordinates into global ones */ michael@0: void localToGlobal(SkMatrix* matrix) const; michael@0: }; michael@0: michael@0: #endif