Menu

Skin Part Types

SourceForge Editorial Staff

Skin Part Types

Problem Description

Currently all of our skin parts are typed to concrete classes. We try to type it to a generic model class where appropriate, but can't all the time. For the video player, we want the concept of optional behavior--a ScrubBar is a Range with extra buffering information. Currently we explicitly type it as a ScrubBar, but that's tied to a specific HSlider implementation. Do we have optional interfaces? What do we type the part as? How does Thermo know what to create for a part typed as a model class or an interface? Should everything be typed as an interface (IText, IValue, IRange, IDoubleRange, IClickable)?

Decision

Option #1

Decision Criteria

A good decision should:

  • Allow the component access to all the necessary parts of the contract (model properties as well as skin parts).
  • Should not tie skin parts to a specific implementation and allow for different part types in user skin files (for instance, change the volume bar from a horizontal one to a vertical one)
  • Should be easily understood and documented
  • Be easily toolable
  • Easy to implement at this late stage

Proposed Solution(s):

  1. Type the skin part as the framework implementation class: For the scrub bar case, this means typing the scrub bar part as a VideoPlayerScrubBar. If VideoScrubBar extends HSlider, then user's part type must also be HSlider (that means a VolumeBar is typed as a VSlider and would have to be hacked to be horizontal--or a new skin part would have to be created by the user).
    1. Pros: Easy for Catalyst to figure out what the type is; very straight-forward to customers what type is required; easy to implement
    2. Cons: Users cannot easily change the view-specific logic or customize the control fully, but they could subclass to add a new view-specific part if they want to change it (for instance horizontalVolumeBar)
  2. Type the class as a model; check for optional add-on interface: For the scrub bar case, this means typing the scrub bar part as a Range. The VideoPlayer would use the properties defined on the range and also check for an extra optional interface, IDoubleRange, to push the extra information into the scrub bar.
    1. Pros: Fits in well with out current part types; works for multiple optional pieces
    2. Cons: Requires extra metadata around "suggested part type" for Catalyst; hard for customers to understand the skin part type
  3. Type the skin part as a "model" class: For the scrub bar case, this means creating a new model class, DoubleRange, which defines the new properties needed. Then VideoScrubBar will extend DoubleRange and define the specific parts and the view-specific logic.
    1. Pros: Fits in well with our current part types; straight-forward for customers to figure out what type is required
    2. Cons: Requires extra metadata around "suggested part type" for Catalyst; lots of extra classes and code; the implementation details are really ugly (either duplicate the code or do it through composition, but composition requires a lot of proxying values back and forth); Doesn't scale very well
  4. Type the skin part as an interface: For the scrub bar case, this means typing the skin part as an IVideoScrubBar, which contains all of the model
    1. Pros: Straight-forward for customers to figure out what type is required; scales well as we need to make small tweaks with model classes
    2. Cons: Requires extra metadata around "suggested part type" for Catalyst; either we're inconsistent and have some parts typed concretely and some as interfaces or we take on lots of extra work for consistency (all parts should be interfaces); could be an issue when trying to add new dependencies on these skin parts later on; is a new approach for the team and one that has backwards-compatibility implications when trying to add new features/behavior later on (need to create IVideoScrubBar2); defining such a concrete and restrictive contract is limiting and hard to get right (and has big backwards-compatibility implications)

Option #1. This option is easy for our customers to understand and fits in with our current model.  All the solutions are compelling and all have their own cons, but we feel this is the best solution.  Though interfaces may be the right long-term solution, interfaces have a lot of implications and make backwards-compatibility much harder.  Before committing to such a large change, we'd like to look at what customers are doing with our skinnable components and what they're doing with their own.  Plus, we'd like to do such a change consistently across the framework. If we later decide to go with interfaces, we can do so with minimal backwards-compatibility impact since the parts will be typed concretely and automatically implement that interface.  Also, looking at how we use our skin parts today, sometimes there's no clear contract, and defining one with an interface may prove too restrictive. So option #1 seems like the best option. Ideally, if someone wants to create a horizontal volume bar, they could just re-skin it, but even with option #1, it's fairly easy to subclass VideoPlayer and add a new horizontalVolumeBar skin type to do this, though it does require a developer.

Notes:

In most cases the skin part type probably doesn't matter too much, but we do want to allow maximum flexibility. The 99% use case is just to skin without changing too much functionality.


Related

Wiki: Flex 4

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.