pro_image_editor icon indicating copy to clipboard operation
pro_image_editor copied to clipboard

[Feature request] Multiselect

Open hblab-dungnp opened this issue 9 months ago • 3 comments

Platforms

Android, iOS

Description

Hi @hm21,

First of all, thank you for this awesome package! I’m currently using pro_image_editor in my project and it’s been really helpful. 🙌

I’d love to see support for multi-selecting items (like shapes, texts, or stickers) in the editor. Right now, it seems like I can only select and move/edit one item at a time. For certain workflows, being able to select multiple elements together and move or scale them as a group would be incredibly useful.

Possible Use Case • Grouping elements together (e.g., multiple texts and shapes) • Aligning or repositioning multiple items simultaneously • Applying transformations (scale, rotate, delete) to all selected items at once

Suggested Behavior • Hold down a key (on desktop) or long-press + tap (on mobile) to multi-select • Visual indicators for selected items (like bounding boxes or highlights) • Actions like move/scale/rotate/delete to affect all selected items

Thanks again for your hard work on this package! Let me know if I can help test or provide more details.

Why

No response

hblab-dungnp avatar Apr 21 '25 07:04 hblab-dungnp

Thanks, I'm really glad to hear that you like my package! It means a lot to me.

I also agree that your feature request could be quite helpful. However, implementing it would require a few changes. Currently, the editor uses a simple String to represent the selectedLayerId, as you noted in your recent PR. To support the requested feature, we would likely need to change this to a List or Map in order to track multiple selected layers.

At the moment, I don't have enough time to work on this implementation, but I'll leave the request open, as I do think it could be a valuable addition.

hm21 avatar Apr 22 '25 17:04 hm21

Totally agree, I’ve had the same thought about how selectedLayerId limits flexibility. I’m currently working on a PR to refactor this to support multiple selections, probably switching to a List<String> or Set<String> to make it more robust and scalable. I’ll keep the changes as clean and minimal as possible to avoid breaking existing behavior.

Looking forward to your feedback once I have something up!

hblab-dungnp avatar Apr 23 '25 02:04 hblab-dungnp

I'm glad to hear you want to create a PR for that feature. I will make sure to review it as quickly as possible once it has been submitted.

FYI: The editor automatically generates the final output image in the background after each change a user makes. This process runs as an isolated task. Because of this, when a layer is selected and the user moves it, the editor typically deselects the active layer before recording what is displayed on the screen. This prevents the layer selection itself from being captured in the output.

Therefore, when multiple layers are selected, it is still necessary to deselect them to ensure that the selection widget around the layer is not recorded.

In the future, I plan to create a solution that would eliminate the need to deselect layers. Possibly, it could be achieved by using an overlay-based approach.

hm21 avatar Apr 23 '25 11:04 hm21

Hi @hm21,

Thanks again for the amazing pro_image_editor package — it’s been a crucial tool in my app development. 🙏

I saw the recent feature request for multi-selecting elements like texts, shapes, or stickers in the editor, and I wanted to express my full support for this feature. I’m also using this package in a chat app similar to WhatsApp, and I’ve integrated the predefined WhatsApp design. Being able to multi-select elements would significantly improve user experience when customizing media before sending.

Why I Need This Feature: • In media editing before sending a message, users often want to position multiple texts, stickers, or drawings simultaneously. • Currently, each item must be adjusted individually, which is time-consuming and less intuitive. • Multi-select would allow bulk editing, mirroring the flexible editing experience users are familiar with in modern apps.

My Use Case: • Users can add text, emojis, or shapes on images before sending. • They frequently want to reposition several items together (e.g., placing a caption with emojis and a background shape). • Without grouping, alignment and scaling are frustrating.

Strong Support for These Suggestions: • Long-press + tap for multi-select on mobile • Highlighting selected items with bounding boxes • Common operations like move, scale, rotate, delete should apply to the group

I’d be happy to help test this feature when available or provide feedback on its behavior. This would be a game-changer for my app and many others using your package.

Thanks again for your continued support and awesome work! 💪

AnkitFlutterDev avatar May 27 '25 10:05 AnkitFlutterDev

Hi @AnkitFlutterDev

Glad to hear you like my package. As I mentioned above, I currently don't have the time to implement that feature. I'm not sure if @hblab-dungnp is still working on a solution, but if not, I recommend forking the repo and creating a PR if you need the feature quickly.

hm21 avatar May 27 '25 18:05 hm21

Hi @hm21 and @AnkitFlutterDev ,

Sorry for the late reply — I’ve been caught up with various small tasks. I did try working on the multiselect functionality, but there are a couple of reasons why I haven’t created a PR yet.

First, if the goal is only to allow multiple items to be selected at once for display purposes, it’s quite simple — we could just follow the approach we discussed earlier. However, that wouldn’t add much value, since users would still need to edit items one by one.

Second, if we want to support editing multiple items at once after selecting them, then I’d need to make quite a few changes in the source code. This would also mean disabling interactions with items until they’re selected. I haven’t had enough time to implement all of that properly, so I had to pause the work in order to focus on the main project.

Nonetheless, I am happy to submit a partial PR with the current progress, should anyone be available to continue the work. Let me know your thoughts. Thanks

hblab-dungnp avatar May 28 '25 02:05 hblab-dungnp

@hblab-dungnp Thanks for the update and your progress. I agree, it’s a great idea to create a partial PR marked as a draft so others who need that feature can also contribute🙂

hm21 avatar May 28 '25 06:05 hm21

It would be fantastic to have this feature, to move things together in groups, or even add an Interaction button to link them so they get constantly moved together! Looking forward to it!

saif-ellafi avatar Jun 04 '25 09:06 saif-ellafi

@saif-ellafi
The part about the "interaction button to link" sounds interesting and technically, it's pretty easy to handle externally. Since you can already add custom interaction buttons to the layer the only thing you’d need to do is manage the events from the outside.

Here’s a simple example that moves all layers at once, as long as no individual layer is selected. You could extend this with your own logic to only move the connected layers instead.

return ProImageEditor.asset(
  kImageEditorExampleAssetPath,
  key: editorKey,
  callbacks: ProImageEditorCallbacks(
    mainEditorCallbacks: MainEditorCallbacks(
      onScaleUpdate: (value) {
        var editor = editorKey.currentState!;

        /// Return if a layer is selected.
        if (editor.selectedLayerIndex >= 0) return;

        var offset = value.focalPointDelta;
        var layers = editor.activeLayers;

        for (var layer in layers) {
          layer.offset += offset;
        }

        editor.setState(() {});
      },
    ),
  ),
  configs: ProImageEditorConfigs(),
)

hm21 avatar Jun 05 '25 12:06 hm21

@hm21 with some modifications to your code I could get multiple layers to move together, but resizing does not work, because a bit surprisingly onScaleUpdate does not provide the actual scale (value.scale is always 1.0).

It was worth a try the experiment though, other odd situation is that it is not possible to easily show which layers are selected, as the library seems to allow only one at a time, but by storing their IDs at least I could move them together.

Probably this might be better eventually properly supported when possible.

saif-ellafi avatar Jun 07 '25 17:06 saif-ellafi

Tried a few more things, and I think indeed, the best approach would be to refactor the library so activeLayerIndex and selectedLayerId become a List, and then make the transform operations to operate from their own offset centers, so the move transform does not place them all in the same spot. Probably there's a bit more to it, but perhaps not impossible. Then to always select exactly one layer by default, unless the user is pressing CTRL (or a toggle function that enables multi-select), otherwise at that point it should behave like it always does.

saif-ellafi avatar Jun 07 '25 18:06 saif-ellafi

@saif-ellafi It's normal for onScaleUpdate to return 1 unless you're using a mobile device to zoom. In that case, it will return a different value. The onScaleUpdate callback comes directly from a GestureDetector that overlays the entire content, so it gives you those base values. If you want to track zoom transformations, you can use the onEditorZoomScaleUpdate callback, which provides the values from the InteractiveViewer. Alternatively, you can access editorKey.currentState.editorScaleFactor, which also gives you the current zoom factor.

I also agree that multiselect could be useful in some cases, but I think it's a rarely used feature, so it's not very high on my priority list right now. The editor is primarily built for image editing, similar to popular apps like WhatsApp, Line, Telegram, Messenger, and others. Even commercial mobile image editors like the one from img.ly don’t support multiselect.

Challenges

There's a big challenge with implementing multiselect. By default, the image editor starts generating the output image immediately after each change. This significantly reduces the wait time when the user taps the "Done" button, since the image is already being processed or even finished. FYI Dart is quite slow for operations like that. It would be much faster in C++, Swift, or Kotlin. However by avoiding native code, the package stays more flexible and easier to maintain so that's the trade-off we have to accept.

Anyway, the tricky part now is that when a user moves a layer, we automatically deselect it afterward so the selection border isn't included in the generated image. With multiselect, this would likely be very frustrating, if a user selects multiple layers and then just moves them slightly, they’d all get deselected right after. To fix that, we'll first need to rewrite the selection logic so that it uses Overlays instead of placing a widget directly above the layer widget.

I also think this feature would be most useful on desktop (and maybe tablets), but on mobile devices we’d have to rely on gestures like LongPress or possibly DoubleTap. Both could cause issues with existing gesture handling. For example, DoubleTap is already used by the GestureDetector for zooming, so that would conflict. On the other hand, LongPress might interfere with onScaleUpdate, which starts as soon as the user touches the screen unless the finger stays perfectly still, it would trigger layer moving. On desktop, implementing this would be much easier since we could use a key combination like CTRL + mouse click for multiselect like you mention before. There also some stuff to improve then cuz normaly i guess a user expect when multiple layers are selected it should just show one selection border around all layers with the interaction buttons like it do in Figma. And rotation will also work then different from the center point from all selected layers instant from the center from every selected layers.

Conclusion

I also think this could be a great improvement, especially for desktop users, but it will require more rewriting than it might seem at first glance. That said, this feature isn’t a priority for me right now. My main focus is on the other package, pro_video_editor, which extend that package with video editing.

However, for my use cases, improving layer selection is important because the current approach isn’t really professional. What I definitely plan to implement is using overlays, so it won't be necessary to unselect a layer after every change. This will also enable a dynamic interaction bar. I really like how layer selection works in img.ly, like below.

hm21 avatar Jun 10 '25 07:06 hm21

@hblab-dungnp @AnkitFlutterDev

Good news @saif-ellafi has started working on that feature in PR #581. It’s still in development, but he’s already made solid progress. I’ll be supporting him as well now, so I’m confident we can fully implement the feature in the coming days or weeks.

hm21 avatar Jul 25 '25 06:07 hm21

The feature has been implemented and just needs to be tested. Anyone who wants to test it can use the prerelease pro_image_editor: 11.0.0-dev.1.

hm21 avatar Jul 25 '25 16:07 hm21

I’ll go ahead and close that PR now, as it’s already included in the prerelease 11.0.0-dev.5 and will soon be released as the full version 11.0.0. If you guys test it and come across any issues, feel free to open a new issue.

hm21 avatar Jul 28 '25 12:07 hm21

@hm21 Plenty of food for thought for the future :) I already wonder what if multi-selection could become a single rectangle, or if the delete action should delete all selected layers, and what about the general layer interaction buttons by default. In the app using PIE I already have buttons to group, the bring to top/send to back, and to copy, which I find fantastic!

Thanks for all the amazing improvements, will battle test this release and share with some of my beta players too!

saif-ellafi avatar Jul 28 '25 12:07 saif-ellafi