Skip to content

Commit 84decfe

Browse files
committed
Add DragToMoveArea and DragToResizeArea with an example
DragToMoveArea is a custom title-bar region: a drag moves the window, a double tap toggles maximization. DragToResizeArea lays eight native resize handles over its child, with configurable thickness, inset, colour and enabled edges; the middle lets the pointer through. window_drag_areas_example shows both as custom chrome on a window without a native title bar, and is what the workspace's real-desktop test (tools/gui/flutter_window_drag_areas_test) drives. Sync with core dd522c1: Window.startDragging now moves the window on Windows, and on macOS the gesture after a native drag or resize is no longer lost.
1 parent 9b4c7f9 commit 84decfe

69 files changed

Lines changed: 3559 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.build/
9+
.buildlog/
10+
.history
11+
.svn/
12+
.swiftpm/
13+
migrate_working_dir/
14+
15+
# IntelliJ related
16+
*.iml
17+
*.ipr
18+
*.iws
19+
.idea/
20+
21+
# The .vscode folder contains launch configuration and tasks you configure in
22+
# VS Code which you may wish to be included in version control, so this line
23+
# is commented out by default.
24+
#.vscode/
25+
26+
# Flutter/Dart/Pub related
27+
**/doc/api/
28+
**/ios/Flutter/.last_build_id
29+
.dart_tool/
30+
.flutter-plugins-dependencies
31+
.pub-cache/
32+
.pub/
33+
/build/
34+
/coverage/
35+
36+
# Symbolication related
37+
app.*.symbols
38+
39+
# Obfuscation related
40+
app.*.map.json
41+
42+
# Android Studio will place build artifacts here
43+
/android/app/debug
44+
/android/app/profile
45+
/android/app/release
46+
47+
# Widget Preview related
48+
.widget_preview/
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# This file tracks properties of this Flutter project.
2+
# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+
#
4+
# This file should be version controlled and should not be manually edited.
5+
6+
version:
7+
revision: "c8c5e3bd7542962ee8b09a12ac469d7d1ff823e0"
8+
channel: "main"
9+
10+
project_type: app
11+
12+
# Tracks metadata for the flutter migrate command
13+
migration:
14+
platforms:
15+
- platform: root
16+
create_revision: c8c5e3bd7542962ee8b09a12ac469d7d1ff823e0
17+
base_revision: c8c5e3bd7542962ee8b09a12ac469d7d1ff823e0
18+
- platform: linux
19+
create_revision: c8c5e3bd7542962ee8b09a12ac469d7d1ff823e0
20+
base_revision: c8c5e3bd7542962ee8b09a12ac469d7d1ff823e0
21+
- platform: macos
22+
create_revision: c8c5e3bd7542962ee8b09a12ac469d7d1ff823e0
23+
base_revision: c8c5e3bd7542962ee8b09a12ac469d7d1ff823e0
24+
- platform: windows
25+
create_revision: c8c5e3bd7542962ee8b09a12ac469d7d1ff823e0
26+
base_revision: c8c5e3bd7542962ee8b09a12ac469d7d1ff823e0
27+
28+
# User provided section
29+
30+
# List of Local paths (relative to this file) that should be
31+
# ignored by the migrate tool.
32+
#
33+
# Files that are not part of the templates will be ignored by default.
34+
unmanaged_files:
35+
- 'lib/main.dart'
36+
- 'ios/Runner.xcodeproj/project.pbxproj'
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# window_drag_areas_example
2+
3+
Custom window chrome with the two drag widgets of `nativeapi`:
4+
5+
- `DragToMoveArea` — the coloured bar moves the window; a double click maximizes
6+
and restores it.
7+
- `DragToResizeArea` — the tinted frame is eight native resize handles (four
8+
edges, four corners). They are inset from the window edge on purpose, so it is
9+
clear the widget does the resizing, not the native frame. The button switches
10+
`enableResizeEdges` between all handles and right/bottom only.
11+
12+
The native title bar and window buttons are hidden, the minimum size is
13+
480 × 320.
14+
15+
```bash
16+
flutter run -d macos # or windows, linux
17+
```
18+
19+
The real-desktop test of this example lives in the workspace repository:
20+
`tools/gui/flutter_window_drag_areas_test.py` (macOS) and `.ps1` (Windows). It
21+
presses in the middle of the handle bands, so keep `kResizeEdgeSize` and
22+
`kResizeEdgeInset` in `lib/main.dart` in sync with it.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# This file configures the analyzer, which statically analyzes Dart code to
2+
# check for errors, warnings, and lints.
3+
#
4+
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5+
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6+
# invoked from the command line by running `flutter analyze`.
7+
8+
# The following line activates a set of recommended lints for Flutter apps,
9+
# packages, and plugins designed to encourage good coding practices.
10+
analyzer:
11+
exclude:
12+
- build/**
13+
- windows/**
14+
- macos/**
15+
- linux/**
16+
include: package:flutter_lints/flutter.yaml
17+
18+
linter:
19+
# The lint rules applied to this project can be customized in the
20+
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
21+
# included above or to enable additional rules. A list of all available lints
22+
# and their documentation is published at https://dart.dev/lints.
23+
#
24+
# Instead of disabling a lint rule for the entire project in the
25+
# section below, it can also be suppressed for a single line of code
26+
# or a specific dart file by using the `// ignore: name_of_lint` and
27+
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
28+
# producing the lint.
29+
rules:
30+
# avoid_print: false # Uncomment to disable the `avoid_print` rule
31+
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
32+
33+
# Additional information about this file can be found at
34+
# https://dart.dev/guides/language/analysis-options
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:nativeapi/nativeapi.dart';
3+
4+
/// Thickness of the resize handles and their distance from the window edge.
5+
///
6+
/// The handles are inset so that they are clearly the widget's, not the native
7+
/// window frame's. tools/gui/flutter_window_drag_areas_test.* in the workspace
8+
/// repository presses in the middle of these bands; keep the numbers in sync.
9+
const double kResizeEdgeSize = 12;
10+
const double kResizeEdgeInset = 16;
11+
12+
void main() {
13+
runApp(const DragAreasApp());
14+
}
15+
16+
class DragAreasApp extends StatelessWidget {
17+
const DragAreasApp({super.key});
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
return MaterialApp(
22+
debugShowCheckedModeBanner: false,
23+
theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),
24+
home: const DragAreasPage(),
25+
);
26+
}
27+
}
28+
29+
class DragAreasPage extends StatefulWidget {
30+
const DragAreasPage({super.key});
31+
32+
@override
33+
State<DragAreasPage> createState() => _DragAreasPageState();
34+
}
35+
36+
class _DragAreasPageState extends State<DragAreasPage> {
37+
static const _limitedEdges = [
38+
ResizeEdge.right,
39+
ResizeEdge.bottom,
40+
ResizeEdge.bottomRight,
41+
];
42+
43+
int _clicks = 0;
44+
bool _limited = false;
45+
46+
@override
47+
void initState() {
48+
super.initState();
49+
// Custom chrome: no native title bar or buttons, so moving and resizing
50+
// is left to the two drag areas.
51+
final window = WindowManager.instance.getCurrent();
52+
if (window == null) return;
53+
window.title = 'nativeapi · Drag areas';
54+
window.titleBarStyle = TitleBarStyle.hidden;
55+
window.isWindowControlButtonsVisible = false;
56+
window.minimumSize = const Size(480, 320);
57+
window.contentSize = const Size(720, 480);
58+
window.center();
59+
}
60+
61+
@override
62+
Widget build(BuildContext context) {
63+
final theme = Theme.of(context);
64+
final size = MediaQuery.sizeOf(context);
65+
return Scaffold(
66+
backgroundColor: theme.colorScheme.surfaceContainerHighest,
67+
body: DragToResizeArea(
68+
resizeEdgeSize: kResizeEdgeSize,
69+
resizeEdgeMargin: const EdgeInsets.all(kResizeEdgeInset),
70+
resizeEdgeColor: theme.colorScheme.primary.withValues(alpha: 0.25),
71+
enableResizeEdges: _limited ? _limitedEdges : null,
72+
child: Padding(
73+
padding: const EdgeInsets.all(kResizeEdgeInset + kResizeEdgeSize),
74+
child: Material(
75+
color: theme.colorScheme.surface,
76+
child: Column(
77+
crossAxisAlignment: CrossAxisAlignment.stretch,
78+
children: [
79+
DragToMoveArea(
80+
child: Container(
81+
height: 44,
82+
color: theme.colorScheme.primaryContainer,
83+
alignment: Alignment.center,
84+
child: const Text('Drag here to move'),
85+
),
86+
),
87+
Expanded(
88+
child: Center(
89+
child: Column(
90+
mainAxisSize: MainAxisSize.min,
91+
spacing: 12,
92+
children: [
93+
Text(
94+
'Size: ${size.width.round()} x ${size.height.round()}',
95+
style: theme.textTheme.titleMedium,
96+
),
97+
const Text(
98+
'Double-click the bar to maximize, drag the tinted '
99+
'frame to resize.',
100+
),
101+
// The middle of the resize area lets the pointer through.
102+
Text('Clicks: $_clicks'),
103+
FilledButton(
104+
onPressed: () => setState(() => _clicks++),
105+
child: const Text('+1'),
106+
),
107+
OutlinedButton(
108+
onPressed: () => setState(() => _limited = !_limited),
109+
child: Text(
110+
_limited ? 'Edges: right and bottom' : 'Edges: all',
111+
),
112+
),
113+
],
114+
),
115+
),
116+
),
117+
],
118+
),
119+
),
120+
),
121+
),
122+
);
123+
}
124+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
flutter/ephemeral
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Project-level configuration.
2+
cmake_minimum_required(VERSION 3.13)
3+
project(runner LANGUAGES CXX)
4+
5+
# The name of the executable created for the application. Change this to change
6+
# the on-disk name of your application.
7+
set(BINARY_NAME "window_drag_areas_example")
8+
# The unique GTK application identifier for this application. See:
9+
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
10+
set(APPLICATION_ID "com.example.window_drag_areas_example")
11+
12+
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
13+
# versions of CMake.
14+
cmake_policy(SET CMP0063 NEW)
15+
16+
# Load bundled libraries from the lib/ directory relative to the binary.
17+
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
18+
19+
# Root filesystem for cross-building.
20+
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
21+
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
22+
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
23+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
24+
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
25+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
26+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
27+
endif()
28+
29+
# Define build configuration options.
30+
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
31+
set(CMAKE_BUILD_TYPE "Debug" CACHE
32+
STRING "Flutter build mode" FORCE)
33+
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
34+
"Debug" "Profile" "Release")
35+
endif()
36+
37+
# Compilation settings that should be applied to most targets.
38+
#
39+
# Be cautious about adding new options here, as plugins use this function by
40+
# default. In most cases, you should add new options to specific targets instead
41+
# of modifying this function.
42+
function(APPLY_STANDARD_SETTINGS TARGET)
43+
target_compile_features(${TARGET} PUBLIC cxx_std_14)
44+
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
45+
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
46+
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
47+
endfunction()
48+
49+
# Flutter library and tool build rules.
50+
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
51+
add_subdirectory(${FLUTTER_MANAGED_DIR})
52+
53+
# System-level dependencies.
54+
find_package(PkgConfig REQUIRED)
55+
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
56+
57+
# Application build; see runner/CMakeLists.txt.
58+
add_subdirectory("runner")
59+
60+
# Run the Flutter tool portions of the build. This must not be removed.
61+
add_dependencies(${BINARY_NAME} flutter_assemble)
62+
63+
# Only the install-generated bundle's copy of the executable will launch
64+
# correctly, since the resources must in the right relative locations. To avoid
65+
# people trying to run the unbundled copy, put it in a subdirectory instead of
66+
# the default top-level location.
67+
set_target_properties(${BINARY_NAME}
68+
PROPERTIES
69+
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
70+
)
71+
72+
73+
# Generated plugin build rules, which manage building the plugins and adding
74+
# them to the application.
75+
include(flutter/generated_plugins.cmake)
76+
77+
78+
# === Installation ===
79+
# By default, "installing" just makes a relocatable bundle in the build
80+
# directory.
81+
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
82+
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
83+
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
84+
endif()
85+
86+
# Start with a clean build bundle directory every time.
87+
install(CODE "
88+
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
89+
" COMPONENT Runtime)
90+
91+
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
92+
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
93+
94+
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
95+
COMPONENT Runtime)
96+
97+
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
98+
COMPONENT Runtime)
99+
100+
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
101+
COMPONENT Runtime)
102+
103+
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
104+
install(FILES "${bundled_library}"
105+
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
106+
COMPONENT Runtime)
107+
endforeach(bundled_library)
108+
109+
# Copy the native assets provided by the build.dart from all packages.
110+
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
111+
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
112+
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
113+
COMPONENT Runtime)
114+
115+
# Fully re-copy the assets directory on each build to avoid having stale files
116+
# from a previous install.
117+
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
118+
install(CODE "
119+
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
120+
" COMPONENT Runtime)
121+
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
122+
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
123+
124+
# Install the AOT library on non-Debug builds only.
125+
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
126+
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
127+
COMPONENT Runtime)
128+
endif()

0 commit comments

Comments
 (0)