h-1.flet.3/components/pinch_handler.py
2026-02-20 23:24:01 +09:00

180 lines
6.1 KiB
Python

"""
ピンチ操作ハンドラー
アプリ全体でピンチイン・ズーム機能を提供する共通コンポーネント
"""
import flet as ft
from typing import Optional, Callable
class PinchHandler:
"""ピンチ操作ハンドラー"""
def __init__(self, page: ft.Page):
self.page = page
self.zoom_level = 1.0
self.min_zoom = 0.6
self.max_zoom = 2.0
self.zoom_step = 0.2
# コールバック関数
self.on_zoom_change: Optional[Callable[[float], None]] = None
self.on_tap: Optional[Callable] = None
self.on_double_tap: Optional[Callable] = None
self.on_long_press: Optional[Callable] = None
# 状態管理
self.last_distance = 0
self.is_zooming = False
def set_callbacks(self,
on_zoom_change: Optional[Callable[[float], None]] = None,
on_tap: Optional[Callable] = None,
on_double_tap: Optional[Callable] = None,
on_long_press: Optional[Callable] = None):
"""コールバック関数設定"""
self.on_zoom_change = on_zoom_change
self.on_tap = on_tap
self.on_double_tap = on_double_tap
self.on_long_press = on_long_press
def create_gesture_detector(self, content: ft.Control, on_click: Optional[Callable] = None) -> ft.GestureDetector:
"""ジェスチャー検出付きコンテナ作成"""
return ft.GestureDetector(
content=content,
on_tap=on_click
)
def _handle_tap(self, e):
"""タップ処理"""
if self.on_tap:
self.on_tap(e)
def _handle_double_tap(self, e):
"""ダブルタップ処理"""
self.zoom_in()
if self.on_double_tap:
self.on_double_tap(e)
def _handle_long_press(self, e):
"""長押し処理"""
if self.on_long_press:
self.on_long_press(e)
def _handle_tap_update(self, e):
"""タップ位置更新(ピンチ検出用)"""
# TODO: 実際のピンチ検出ロジック
# Fletの制限により、現在はボタンでのズームをメインに
pass
def zoom_in(self):
"""ズームイン"""
if self.zoom_level < self.max_zoom:
self.zoom_level += self.zoom_step
self._notify_zoom_change()
def zoom_out(self):
"""ズームアウト"""
if self.zoom_level > self.min_zoom:
self.zoom_level -= self.zoom_step
self._notify_zoom_change()
def set_zoom(self, level: float):
"""ズームレベル設定"""
self.zoom_level = max(self.min_zoom, min(self.max_zoom, level))
self._notify_zoom_change()
def reset_zoom(self):
"""ズームリセット"""
self.zoom_level = 1.0
self._notify_zoom_change()
def _notify_zoom_change(self):
"""ズーム変更通知"""
if self.on_zoom_change:
self.on_zoom_change(self.zoom_level)
def get_zoom_controls(self) -> ft.Row:
"""ズームコントロールUI作成"""
return ft.Row([
ft.IconButton(
ft.Icons.ZOOM_OUT,
icon_size=20,
tooltip="縮小",
on_click=lambda _: self.zoom_out()
),
ft.Text(f"{int(self.zoom_level * 100)}%", size=12),
ft.IconButton(
ft.Icons.ZOOM_IN,
icon_size=20,
tooltip="拡大",
on_click=lambda _: self.zoom_in()
),
ft.IconButton(
ft.Icons.REFRESH,
icon_size=20,
tooltip="リセット",
on_click=lambda _: self.reset_zoom()
)
], spacing=5)
def apply_zoom_to_size(self, base_size: float) -> float:
"""ズームをサイズに適用"""
return base_size * self.zoom_level
def apply_zoom_to_text_size(self, base_size: float) -> float:
"""ズームをテキストサイズに適用"""
return base_size * self.zoom_level
class ZoomableContainer:
"""ズーム対応コンテナ"""
def __init__(self, pinch_handler: PinchHandler):
self.pinch_handler = pinch_handler
self.base_width = 100
self.base_height = 100
self.base_text_size = 12
self.base_padding = 10
def create_zoomable_card(self,
icon: str,
title: str,
subtitle: str,
color: ft.Colors,
on_click: Optional[Callable] = None) -> ft.Container:
"""ズーム対応カード作成"""
# ズーム適用
width = self.pinch_handler.apply_zoom_to_size(self.base_width)
height = self.pinch_handler.apply_zoom_to_size(self.base_height)
text_size = self.pinch_handler.apply_zoom_to_text_size(self.base_text_size)
padding = self.pinch_handler.apply_zoom_to_size(self.base_padding)
card = ft.Container(
content=ft.Column([
ft.Container(
content=ft.Text(icon, size=text_size * 2),
width=width * 0.5,
height=height * 0.5,
bgcolor=color,
alignment=ft.alignment.Alignment(0, 0),
border_radius=padding
),
ft.Text(title, size=text_size, weight=ft.FontWeight.BOLD),
ft.Text(subtitle, size=text_size * 0.8, color=ft.Colors.GREY_600)
], spacing=5),
width=width,
height=height,
padding=padding,
bgcolor=ft.Colors.WHITE,
border_radius=padding,
shadow=ft.BoxShadow(
spread_radius=1,
blur_radius=5,
color=ft.Colors.with_opacity(0.2, ft.Colors.GREY),
offset=ft.Offset(0, 2)
),
on_click=on_click
)
return self.pinch_handler.create_gesture_detector(card)