Skip to content

Commit cbb434b

Browse files
authored
SelectionArea control (#2152)
* SelectionArea initial commit * removed commented code * content is required * returns ErrorControl when child is not visible * deleted commented code
1 parent 1a548bd commit cbb434b

File tree

5 files changed

+151
-39
lines changed

5 files changed

+151
-39
lines changed

package/lib/src/controls/create_control.dart

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'animated_switcher.dart';
1818
import 'bottom_app_bar.dart';
1919
import 'audio.dart';
2020
import 'badge.dart';
21+
import 'selection_area.dart';
2122
import 'banner.dart';
2223
import 'barchart.dart';
2324
import 'bottom_sheet.dart';
@@ -209,6 +210,14 @@ Widget createWidget(Key? key, ControlViewModel controlView, Control? parent,
209210
children: controlView.children,
210211
parentDisabled: parentDisabled,
211212
);
213+
case "selectionarea":
214+
return SelectionAreaControl(
215+
key: key,
216+
parent: parent,
217+
control: controlView.control,
218+
children: controlView.children,
219+
parentDisabled: parentDisabled,
220+
);
212221
case "clipboard":
213222
return ClipboardControl(
214223
parent: parent, control: controlView.control, nextChild: nextChild);
@@ -572,10 +581,10 @@ Widget createWidget(Key? key, ControlViewModel controlView, Control? parent,
572581
dispatch: controlView.dispatch);
573582
case "bottomappbar":
574583
return BottomAppBarControl(
575-
parent: parent,
576-
control: controlView.control,
577-
parentDisabled: parentDisabled,
578-
children: controlView.children,
584+
parent: parent,
585+
control: controlView.control,
586+
parentDisabled: parentDisabled,
587+
children: controlView.children,
579588
);
580589
case "windowdragarea":
581590
return WindowDragAreaControl(

package/lib/src/controls/dismissible.dart

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'package:collection/collection.dart';
21
import 'package:flet/src/utils/dismissible.dart';
32
import 'package:flutter/material.dart';
43

@@ -38,10 +37,6 @@ class DismissibleControl extends StatelessWidget {
3837
var secondaryBackgroundCtrls =
3938
children.where((c) => c.name == "secondaryBackground");
4039

41-
SnackBarBehavior? behavior = SnackBarBehavior.values.firstWhereOrNull((a) =>
42-
a.name.toLowerCase() ==
43-
control.attrString("behavior", "")!.toLowerCase());
44-
4540
var dismissThresholds =
4641
parseDismissThresholds(control, "dismissThresholds");
4742

@@ -54,35 +49,35 @@ class DismissibleControl extends StatelessWidget {
5449
return constrainedControl(
5550
context,
5651
Dismissible(
57-
key: ValueKey<String>(control.id),
58-
direction: direction,
59-
background: backgroundCtrls.isNotEmpty
60-
? createControl(control, backgroundCtrls.first.id, disabled)
61-
: Container(color: Colors.transparent),
62-
secondaryBackground: secondaryBackgroundCtrls.isNotEmpty
63-
? createControl(
64-
control, secondaryBackgroundCtrls.first.id, disabled)
65-
: Container(color: Colors.transparent),
66-
onDismissed: (DismissDirection d) {
67-
server.sendPageEvent(
68-
eventTarget: control.id, eventName: "dismiss", eventData: "");
69-
},
70-
onResize: () {
71-
server.sendPageEvent(
72-
eventTarget: control.id, eventName: "resize", eventData: "");
73-
},
74-
onUpdate: (DismissUpdateDetails d) {
75-
server.sendPageEvent(
76-
eventTarget: control.id, eventName: "update", eventData: "");
77-
},
78-
// confirmDismiss: // TODO: implement
79-
movementDuration:
80-
Duration(milliseconds: control.attrInt("duration", 200)!),
81-
resizeDuration:
82-
Duration(milliseconds: control.attrInt("resizeDuration", 300)!),
83-
crossAxisEndOffset: control.attrDouble("crossAxisEndOffset", 0.0)!,
84-
dismissThresholds: dismissThresholds ?? {},
85-
child: createControl(control, contentCtrls.first.id, disabled)),
52+
key: ValueKey<String>(control.id),
53+
direction: direction,
54+
background: backgroundCtrls.isNotEmpty
55+
? createControl(control, backgroundCtrls.first.id, disabled)
56+
: Container(color: Colors.transparent),
57+
secondaryBackground: secondaryBackgroundCtrls.isNotEmpty
58+
? createControl(
59+
control, secondaryBackgroundCtrls.first.id, disabled)
60+
: Container(color: Colors.transparent),
61+
onDismissed: (DismissDirection d) {
62+
server.sendPageEvent(
63+
eventTarget: control.id, eventName: "dismiss", eventData: "");
64+
},
65+
onResize: () {
66+
server.sendPageEvent(
67+
eventTarget: control.id, eventName: "resize", eventData: "");
68+
},
69+
onUpdate: (DismissUpdateDetails d) {
70+
server.sendPageEvent(
71+
eventTarget: control.id, eventName: "update", eventData: "");
72+
},
73+
// confirmDismiss: // TODO: implement
74+
movementDuration:
75+
Duration(milliseconds: control.attrInt("duration", 200)!),
76+
resizeDuration:
77+
Duration(milliseconds: control.attrInt("resizeDuration", 300)!),
78+
crossAxisEndOffset: control.attrDouble("crossAxisEndOffset", 0.0)!,
79+
dismissThresholds: dismissThresholds ?? {},
80+
child: createControl(control, contentCtrls.first.id, disabled)),
8681
parent,
8782
control);
8883
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import 'package:flutter/material.dart';
2+
import '../models/control.dart';
3+
import 'create_control.dart';
4+
import 'error.dart';
5+
6+
class SelectionAreaControl extends StatelessWidget {
7+
final Control? parent;
8+
final Control control;
9+
final List<Control> children;
10+
final bool parentDisabled;
11+
12+
const SelectionAreaControl(
13+
{Key? key,
14+
required this.parent,
15+
required this.control,
16+
required this.children,
17+
required this.parentDisabled})
18+
: super(key: key);
19+
20+
@override
21+
Widget build(BuildContext context) {
22+
debugPrint("SelectionArea build: ${control.id}");
23+
24+
var contentCtrls =
25+
children.where((c) => c.name == "content" && c.isVisible);
26+
if (contentCtrls.isEmpty) {
27+
return const ErrorControl(
28+
"Content control must be specified and be visible.");
29+
}
30+
bool disabled = control.isDisabled || parentDisabled;
31+
32+
Widget child = createControl(control, contentCtrls.first.id, disabled);
33+
34+
return baseControl(
35+
context,
36+
SelectionArea(
37+
child: child,
38+
),
39+
parent,
40+
control);
41+
}
42+
}

sdk/python/packages/flet-core/src/flet_core/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,10 @@
8686
from flet_core.filled_button import FilledButton
8787
from flet_core.filled_tonal_button import FilledTonalButton
8888
from flet_core.flet_app import FletApp
89-
from flet_core.floating_action_button import FloatingActionButton, FloatingActionButtonLocation
89+
from flet_core.floating_action_button import (
90+
FloatingActionButton,
91+
FloatingActionButtonLocation,
92+
)
9093
from flet_core.form_field_control import InputBorder
9194
from flet_core.gesture_detector import (
9295
DragEndEvent,
@@ -221,3 +224,4 @@
221224
from flet_core.range_slider import RangeSlider
222225
from flet_core.badge import Badge
223226
from flet_core.navigation_drawer import NavigationDrawer, NavigationDrawerDestination
227+
from flet_core.selection_area import SelectionArea
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from typing import Any, Optional
2+
3+
from flet_core.control import Control
4+
from flet_core.ref import Ref
5+
6+
7+
class SelectionArea(Control):
8+
"""
9+
Flet controls are not selectable by default. SelectionArea is used to enable selection for its child control.
10+
11+
Example:
12+
```
13+
import flet as ft
14+
15+
def main(page: ft.Page):
16+
page.add(
17+
ft.SelectionArea(
18+
content=ft.Column([ft.Text("Selectable text"), ft.Text("Also selectable")])
19+
)
20+
)
21+
page.add(ft.Text("Not selectable"))
22+
23+
ft.app(target=main)
24+
```
25+
26+
-----
27+
28+
Online docs: https://flet.dev/docs/controls/selectionarea
29+
"""
30+
31+
def __init__(
32+
self,
33+
content: Control,
34+
ref: Optional[Ref] = None,
35+
data: Any = None,
36+
):
37+
Control.__init__(
38+
self,
39+
ref=ref,
40+
data=data,
41+
)
42+
43+
self.content = content
44+
45+
def _get_control_name(self):
46+
return "selectionarea"
47+
48+
def _get_children(self):
49+
children = []
50+
if self.__content is not None:
51+
self.__content._set_attr_internal("n", "content")
52+
children.append(self.__content)
53+
return children
54+
55+
# content
56+
@property
57+
def content(self) -> Control:
58+
return self.__content
59+
60+
@content.setter
61+
def content(self, value: Control):
62+
self.__content = value

0 commit comments

Comments
 (0)