This tutorial explains how you can customize an existing handles provider to:

  • Change the default settings of a handles provider

  • Customize the handles used by a handles provider

  • Make sure that the customized handles provider is used during editing

Other customizations

You need to customize a handles provider for advanced use cases only. For other customization methods, see this article.

The code snippets in this tutorial are available in the editing sample.

See this article for more information about editing.

Configuring a handles provider

You can change the configuration of most handles provider implementations. For example, you can change the minimum and maximum point counts for the PolylineHandlesProvider and PolylineRingHandlesProvider, or you can change the handles they use.

The following sample code shows you how to create and customize a handles provider.

Program: Creating a handles provider
auto handlesProvider = std::make_shared<PolylineHandlesProvider>();
handlesProvider->setMaxPointCount(8);

After creating a handles provider, you must configure it so that it’s used during editing:

  1. Make sure that an IFeatureHandlesProvider uses the geometry handles provider.

    Program: Let the feature handles provider use the custom geometry handles provider
    // Register the custom handles provider in a default composite with a high priority, so that it is used before all other handles providers
    // Using a composite instead of directly using the custom PolylineHandlesProvider makes sure that other geometries remain supported.
    auto geometryHandlesProvider = CompositeGeometryHandlesProvider::createDefault();
    geometryHandlesProvider->add(handlesProvider, Priority::high());
    // Make sure the custom geometry handles provider is used to editing the features
    auto featureHandlesProvider = std::make_shared<FeatureHandlesProvider>();
    featureHandlesProvider->setGeometryHandlesProvider(geometryHandlesProvider);
  2. Configure that IFeatureHandlesProvider in an IFeatureEditConfiguration

    Program: Configure the feature handles provider in a feature edit configuration
    class CustomEditConfiguration final : public IFeatureEditConfiguration {
    public:
    void edit(const Feature& /*feature*/, LayerId /*layerId*/, const std::shared_ptr<Map>& /*map*/, FeatureEditConfigurationBuilder& builder) const override {
    // Use a custom handles provider for all features
    builder.handlesProvider(_featureHandlesProvider).submit();
    }
    private:
    std::shared_ptr<IFeatureHandlesProvider> _featureHandlesProvider;
    };
  3. Configure that IFeatureEditConfiguration on the FeatureLayer.

    Program: Configuring the feature edit configuration on the layer
    // Use a custom edit configuration that changes the editing behavior for this layer
    auto customEditConfiguration = std::make_shared<CustomEditConfiguration>();
    // Register the configuration. This makes the layer editable by default
    return FeatureLayer::newBuilder()
    .model(model) //
    .title("Tutorial 1")
    .editConfiguration(customEditConfiguration)
    .build();

Changing the handles of a handle provider

For more fine-grained control over the handles used by a handles provider, you can implement your own handle factory. For example, if you implement your own handle factory for polylines, you can decide which handles it creates and uses to:

  • Move points

  • Remove points

  • Insert points

  • Change the elevation of a point

You can customize the handle factories for other geometries in a similar way. The handle to translate a Feature is provided by an IFeatureHandlesProvider. You can use the handle factory for the default implementation, FeatureHandlesProvider to customize the translate handle.

The following sections show you how to implement and use a handle factory.

Using a handle factory wrapper

You can configure custom handle factory implementations, typically wrappers, on the corresponding handles provider.

Program: Configuring custom handle factory implementations
// A custom handle factory provides fine-grained control over the handles that are used by the handles provider
auto defaultHandleFactory = handlesProvider->getHandleFactory();
auto customHandleFactory = std::make_shared<CustomPolylineHandleFactory>(defaultHandleFactory);
handlesProvider->setHandleFactory(customHandleFactory);

Omitting a handle

To omit a type of handle, the corresponding factory method must return null.

Program: Omitting a handle type
std::shared_ptr<IEditHandle> CustomPolylineHandleFactory::createInsertPointHandle(const std::shared_ptr<Observable<std::shared_ptr<Polyline>>>& /*polyline*/,
size_t /*insertIndex*/,
const std::shared_ptr<IPointEditAction>& /*editAction*/,
const std::shared_ptr<FeatureEditContext>& /*context*/) {
// Make sure that PolylineHandlesProvider doesn't create insert handles anymore
// Note that it will still create append and prepend handles though.
return nullptr;
}

Replacing a handle

To replace a handle, you must re-implement the corresponding factory method. In the following example, we replace the handle to remove points from a polyline.

Program: Replacing a handle
std::shared_ptr<IEditHandle> CustomPolylineHandleFactory::createRemovePointHandle(const std::shared_ptr<Observable<std::shared_ptr<Polyline>>>& polyline,
size_t pointIndex,
const std::shared_ptr<IPointEditAction>& editAction,
const std::shared_ptr<FeatureEditContext>& /*context*/) {
// Derive an observable Point from the observable Polyline. This point will be updated whenever the polyline is changed
auto observableLocation = ObservablePolylineUtil::derivePointAtIndex(polyline, pointIndex);
// Create a handle that is initially positioned on this location
auto handle = std::make_shared<PointEditHandle>(observableLocation);
// The handle will call the edit action when clicking on it using the right mouse button
handle->addOnClickAction(editAction, 1).mouseButton(MouseButton::right()).cursor(MouseCursor::arrow());
// The handle will call the edit action when performing a touch long press action
handle->addOnTouchLongPressAction(editAction).cursor(MouseCursor::arrow());
// Use a small red icon
handle->setRegularIcon(std::make_shared<BasicIcon>(IconType::FilledRectangle, 6, Color(255, 0, 0, 64)));
handle->setHighlightedIcon(std::make_shared<BasicIcon>(IconType::FilledRectangle, 6, Color(255, 0, 0, 192)));
return handle;
}

Adding a handle

You can’t use the handle factories to add an extra handle. It requires a different approach. For a demonstration, see this tutorial.