Coverage for paintmaskanimator/main_window_ui_build.py: 97%

694 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-11-02 04:50 +0000

1"""Window construction for MainWindow: actions, menus, layout and signal wiring. 

2 

3Split out of ``main_window.py`` as a mixin. These methods build the UI itself -- 

4the ``QAction`` set and shortcut actions, the menu bar, the dock/canvas layout in 

5``build_ui``, the action panel, and the ``connect`` pass that wires every widget 

6signal to its handler. They run once during ``MainWindow.__init__`` (plus on 

7theme changes) against a live ``MainWindow`` instance, and hold no state of their 

8own -- everything is assigned onto ``self``. 

9""" 

10from typing import Any 

11from PySide6.QtCore import QSize, QTimer, Qt 

12from PySide6.QtGui import QAction, QGuiApplication, QKeySequence 

13from PySide6.QtWidgets import ( 

14 QFrame, 

15 QHBoxLayout, 

16 QLabel, 

17 QMessageBox, 

18 QPushButton, 

19 QScrollArea, 

20 QSlider, 

21 QSplitter, 

22 QVBoxLayout, 

23 QWidget, 

24) 

25from .constants import APP_DISPLAY_NAME, APP_NAME, GITHUB_REPO, HOLD_ZOOM_SHORTCUT 

26from ._main_window_members import MainWindowMembers 

27import PySide6QtAds as QtAds 

28from . import icons, theme, view_preview 

29from .i18n import tr 

30from .main_window_view_preview import channel_labels 

31from .preview_controls import ChannelPreviewButton, ExposureControl 

32from .theme import StatusBar 

33from .preferences_dialog import PreferencesDialog 

34from .tool_window import ToolWindow 

35from .toolpanel import ToolPanel, tool_label 

36from .errors import OPERATION_ERRORS 

37from .logging_setup import get_logger 

38 

39log = get_logger(__name__) 

40 

41_OPERATION_ERRORS = OPERATION_ERRORS 

42 

43 

44class UIBuildMixin(MainWindowMembers): 

45 def make_shortcut_action(self, name, callback, shortcut=""): 

46 action = QAction(name, self) 

47 if shortcut: 

48 action.setShortcut(shortcut) 

49 action.setShortcutContext(Qt.ShortcutContext.ApplicationShortcut) 

50 action.triggered.connect(callback) 

51 self.addAction(action) 

52 return action 

53 

54 def build_action_panel(self): 

55 # Built-in actions are now editable default scripts seeded into the 

56 # actions folder and registered via ActionPanel.reload_python_actions(). 

57 # See paintmaskanimator.actionpanel.BUILTIN_SCRIPTS. 

58 pass 

59 

60 def build_actions(self): 

61 self.a_new=QAction(tr("新規作成…"),self);self.a_new.setShortcut("Ctrl+N");self.a_new.triggered.connect(self.new_doc) 

62 self.a_resize=QAction(tr("キャンバスサイズの変更…"),self);self.a_resize.triggered.connect(self.resize_doc) 

63 self.a_undo=QAction(tr("元に戻す"),self);self.a_undo.setShortcut("Ctrl+Z");self.a_undo.triggered.connect(self.used_color.undo) 

64 self.a_redo=QAction(tr("やり直す"),self);self.a_redo.setShortcuts([QKeySequence("Ctrl+Y"),QKeySequence("Ctrl+Shift+Z")]);self.a_redo.triggered.connect(self.used_color.redo) 

65 self.a_copy=QAction(tr("コピー"),self);self.a_copy.setShortcut("Ctrl+C");self.a_copy.triggered.connect(self.canvas.copy_selection) 

66 self.a_cut=QAction(tr("切り取り"),self);self.a_cut.setShortcut("Ctrl+X");self.a_cut.triggered.connect(self.canvas.cut_selection) 

67 self.a_paste=QAction(tr("貼り付け"),self);self.a_paste.setShortcut("Ctrl+V");self.a_paste.triggered.connect(self.paste_from_clipboard) 

68 self.a_open_project=QAction(tr("プロジェクトを開く…"),self) 

69 self.a_open_project.setShortcut("Ctrl+O") 

70 self.a_open_project.triggered.connect(self.project.open_dialog) 

71 

72 self.a_import_images=QAction(tr("画像を読み込む…"),self) 

73 self.a_import_images.triggered.connect(self.import_images_dialog) 

74 self.a_import_folder=QAction(tr("画像フォルダーを読み込む…"),self) 

75 self.a_import_folder.triggered.connect(self.import_image_folder_dialog) 

76 self.a_import_images_raw=QAction(tr("変換せず読み込む(下書きレイヤー)…"),self) 

77 self.a_import_images_raw.triggered.connect(self.import_images_raw_dialog) 

78 self.a_import_psd=QAction(tr("PSDを読み込む…"),self) 

79 self.a_import_psd.triggered.connect(self.importer.psd_dialog) 

80 self.a_import_clip=QAction(tr("CLIP STUDIOアニメーションを読み込む…"),self) 

81 self.a_import_clip.triggered.connect(self.importer.clip_animation_dialog) 

82 self.a_open_cut_folder=QAction(tr("カットフォルダーを開く…"),self) 

83 self.a_open_cut_folder.triggered.connect(self.importer.cut_folder_dialog) 

84 

85 self.a_save_project=QAction(tr("上書き保存"),self) 

86 self.a_save_project.setShortcut("Ctrl+S") 

87 self.a_save_project.triggered.connect(self.project.save) 

88 

89 self.a_save_project_as=QAction(tr("名前を付けて保存…"),self) 

90 self.a_save_project_as.setShortcut("Ctrl+Shift+S") 

91 self.a_save_project_as.triggered.connect(self.project.save_as) 

92 

93 self.a_save=QAction(tr("現在のコマをPNG書き出し…"),self) 

94 self.a_save.triggered.connect(self.save_png) 

95 self.a_save_tga=QAction(tr("現在のコマをTGA書き出し…"),self) 

96 self.a_save_tga.triggered.connect(self.save_tga) 

97 self.a_export_png_seq=QAction(tr("連番PNG+CSV書き出し…"),self);self.a_export_png_seq.triggered.connect(lambda:self.export.key_sequence("PNG")) 

98 self.a_export_tga_seq=QAction(tr("連番TGA+CSV書き出し…"),self);self.a_export_tga_seq.triggered.connect(lambda:self.export.key_sequence("TGA")) 

99 self.a_export_cut_folder=QAction(tr("カットフォルダーへ書き出し…"),self) 

100 self.a_export_cut_folder.triggered.connect(self.export.cut_folder) 

101 self.a_export_shadow=QAction(tr("影素材を書き出し…"),self) 

102 self.a_export_shadow.triggered.connect(self.export.shadow_sequence) 

103 self.a_export_xdts=QAction(tr("XDTSタイムシートを書き出す…"),self) 

104 self.a_export_xdts.triggered.connect(self.export.xdts_dialog) 

105 self.a_export_psd=QAction(tr("PSDを書き出す…"),self) 

106 self.a_export_psd.triggered.connect(self.export.psd_dialog) 

107 self.a_prev=QAction(tr("前のフレーム"),self);self.a_prev.setShortcut("1");self.a_prev.triggered.connect(self.timeline_ops.previous_frame) 

108 self.a_next=QAction(tr("次のフレーム"),self);self.a_next.setShortcut("2");self.a_next.triggered.connect(self.timeline_ops.next_frame) 

109 self.a_pressure=QAction(tr("筆圧設定…"),self);self.a_pressure.triggered.connect(self.pressure) 

110 self.a_memo = self.make_shortcut_action( 

111 tr("メモを開く"), self.show_memo_window 

112 ) 

113 self.a_isolate_color=QAction(tr("選択色だけ表示"),self) 

114 self.a_isolate_color.triggered.connect(self.colors.isolate_selected_color) 

115 self.a_clear_color_filter=QAction(tr("特定色表示を解除"),self) 

116 self.a_clear_color_filter.triggered.connect(self.colors.clear_selected_color_filter) 

117 self.a_silhouette=QAction(tr("背景以外を黒シルエット表示"),self); self.a_silhouette.setCheckable(True); self.a_silhouette.setShortcut("Ctrl+B") 

118 self.a_silhouette.triggered.connect(self.line_ops.toggle_silhouette) 

119 self.a_preview_map=QAction(tr("隣接色分けで表示"),self); self.a_preview_map.setCheckable(True) 

120 self.a_preview_map.triggered.connect(self.view_preview.set_map_colors) 

121 self.a_exposure_toggle=QAction(tr("露光量の調整を切り替え"),self) 

122 self.a_exposure_toggle.triggered.connect(self.view_preview.toggle_exposure) 

123 self.a_channel_red=QAction(tr("赤チャンネルを表示"),self) 

124 self.a_channel_red.triggered.connect(lambda: self.view_preview.set_channel("red")) 

125 self.a_channel_green=QAction(tr("緑チャンネルを表示"),self) 

126 self.a_channel_green.triggered.connect(lambda: self.view_preview.set_channel("green")) 

127 self.a_channel_blue=QAction(tr("青チャンネルを表示"),self) 

128 self.a_channel_blue.triggered.connect(lambda: self.view_preview.set_channel("blue")) 

129 self.a_channel_alpha=QAction(tr("アルファチャンネルを表示"),self) 

130 self.a_channel_alpha.triggered.connect(lambda: self.view_preview.set_channel("alpha")) 

131 self.a_remove_dust=QAction(tr("ゴミ取り/塗り抜け…"),self) 

132 self.a_remove_dust.triggered.connect(self.line_ops.remove_dust_fill_surrounding) 

133 self.a_auto_paint=QAction(tr("自動で塗る…"),self) 

134 self.a_auto_paint.setStatusTip(tr( 

135 "黒と赤・緑・青などの色トレス線を境界にして、見本のセルから同じレイヤーのほかのセルを" 

136 "塗ります。" 

137 )) 

138 self.a_auto_paint.triggered.connect(self.auto_paint.open) 

139 self.a_keep_initial_state=QAction(tr("今の絵を初期状態として保持"),self) 

140 self.a_keep_initial_state.setStatusTip(tr( 

141 "全レイヤーの今の絵を、色塗り前の初期状態として保持します。自動塗りは初期状態の" 

142 "線で部分を分けるので、精度が上がります。" 

143 )) 

144 self.a_keep_initial_state.triggered.connect(lambda: self.initial_state.keep()) 

145 self.a_import_initial_state=QAction(tr("線画カットフォルダーを初期状態として読み込む…"),self) 

146 self.a_import_initial_state.setStatusTip(tr( 

147 "レイヤー名とセル番号が一致する線画を初期状態に設定します。今の絵とタイムラインは維持します。" 

148 )) 

149 self.a_import_initial_state.triggered.connect(self.initial_state.import_line_art_dialog) 

150 self.a_import_clip_initial_state=QAction(tr("CLIPの線画を初期状態として読み込む…"),self) 

151 self.a_import_clip_initial_state.setStatusTip(tr( 

152 "CLIPのフォルダー名とセル番号が一致する線画を初期状態に設定します。今の絵とタイムラインは維持します。" 

153 )) 

154 self.a_import_clip_initial_state.triggered.connect(self.initial_state.import_clip_line_art_dialog) 

155 self.a_clear_initial_state=QAction(tr("保持した初期状態を消す"),self) 

156 self.a_clear_initial_state.triggered.connect(self.initial_state.clear) 

157 self.a_reference_check=QAction(tr("見本との違いチェック…"),self) 

158 self.a_reference_check.triggered.connect(self.reference_check.run) 

159 self.a_shortcuts=QAction(tr("ショートカット設定…"),self);self.a_shortcuts.triggered.connect(self.shortcuts) 

160 # macOS ではアプリ名のメニューへ移る(⌘,)。 

161 self.a_preferences=QAction(tr("環境設定…"),self) 

162 self.a_preferences.setMenuRole(QAction.MenuRole.PreferencesRole) 

163 self.a_preferences.setShortcut("Ctrl+,") 

164 self.a_preferences.triggered.connect(lambda: self.show_preferences()) 

165 self.tool_actions={} 

166 defaults={"brush":"P","line":"U","shape":"O","bucket":"G","closed_fill":"K","lasso_fill":"F","lasso":"L","rect_select":"R","auto_select":"W","eyedropper":"I","dust":"D"} 

167 for tid,_source_label in ToolPanel.TOOLS: 

168 a=QAction(tr("ツール:{tool}").format(tool=tool_label(tid)),self);a.setShortcut(defaults.get(tid,""));a.setShortcutContext(Qt.ShortcutContext.ApplicationShortcut);a.triggered.connect(lambda _=False,t=tid,action=a:self.tool_hold.select(t,action));self.addAction(a);self.tool_actions[tid]=a 

169 self.general_actions=[(tr("新規作成"),self.a_new),(tr("プロジェクトを開く"),self.a_open_project),(tr("上書き保存"),self.a_save_project),(tr("元に戻す"),self.a_undo),(tr("やり直す"),self.a_redo),(tr("前のフレーム"),self.a_prev),(tr("次のフレーム"),self.a_next)] 

170 self.tool_action_list=[ 

171 (tr("ツール:{tool}").format(tool=tool_label(tid)), self.tool_actions[tid]) 

172 for tid, _source_label in ToolPanel.TOOLS 

173 ] 

174 

175 # 押している間だけ有効になるキャンバス操作。QActionは設定値の保持に使い、 

176 # 通常のアプリケーションショートカットとしては登録しない。 

177 self.a_hold_hand = QAction(tr("ハンド(押している間)"), self) 

178 self.a_hold_hand.setProperty("holdOperation", True) 

179 self.a_hold_hand.setProperty("holdShortcutText", "Space") 

180 self.a_hold_hand.setShortcut(QKeySequence("Space")) 

181 self.a_hold_zoom = QAction(tr("拡大縮小(押している間)"), self) 

182 self.a_hold_zoom.setProperty("holdOperation", True) 

183 self.a_hold_zoom.setProperty("holdShortcutText", HOLD_ZOOM_SHORTCUT) 

184 self.a_hold_zoom.setShortcut(QKeySequence(HOLD_ZOOM_SHORTCUT)) 

185 self.a_hold_rotate = QAction(tr("回転(押している間)"), self) 

186 self.a_hold_rotate.setProperty("holdOperation", True) 

187 self.a_hold_rotate.setProperty("holdShortcutText", "Shift+Space") 

188 self.a_hold_rotate.setShortcut(QKeySequence("Shift+Space")) 

189 self.a_hold_eyedropper = QAction(tr("スポイト(押している間)"), self) 

190 self.a_hold_eyedropper.setProperty("holdOperation", True) 

191 self.a_hold_eyedropper.setProperty("holdShortcutText", "Alt") 

192 self.a_hold_eyedropper.setShortcut(QKeySequence("Alt")) 

193 self.canvas_operation_actions = [ 

194 (tr("ハンド"), self.a_hold_hand), 

195 (tr("拡大縮小"), self.a_hold_zoom), 

196 (tr("回転"), self.a_hold_rotate), 

197 (tr("スポイト"), self.a_hold_eyedropper), 

198 ] 

199 

200 # File and edit actions not previously exposed in the shortcut dialog. 

201 for action in ( 

202 self.a_new, self.a_open_project, self.a_open_cut_folder, 

203 self.a_import_images, 

204 self.a_save_project, self.a_save_project_as, 

205 self.a_resize, self.a_undo, self.a_redo, 

206 self.a_cut, self.a_copy, self.a_paste, self.a_save, self.a_save_tga, 

207 self.a_export_png_seq, self.a_export_tga_seq, self.a_export_cut_folder, 

208 self.a_export_shadow, 

209 self.a_prev, self.a_next, 

210 self.a_pressure, self.a_isolate_color, self.a_clear_color_filter, 

211 self.a_silhouette, self.a_remove_dust, self.a_preview_map, 

212 self.a_exposure_toggle, self.a_channel_red, self.a_channel_green, 

213 self.a_channel_blue, self.a_channel_alpha, 

214 ): 

215 action.setShortcutContext(Qt.ShortcutContext.ApplicationShortcut) 

216 

217 self.a_export_mp4 = self.make_shortcut_action( 

218 tr("MP4書き出し"), self.export.mp4 

219 ) 

220 

221 # Tool-panel commands. 

222 self.a_select_main = self.make_shortcut_action( 

223 tr("描画色:メインを選択"), lambda: self.colors.set_color_mode("main") 

224 ) 

225 self.a_select_sub = self.make_shortcut_action( 

226 tr("描画色:サブを選択"), lambda: self.colors.set_color_mode("sub") 

227 ) 

228 self.a_select_transparent = self.make_shortcut_action( 

229 tr("描画色:背景色を選択"), self.colors.select_background_color, "E" 

230 ) 

231 self.a_toggle_draw_background = self.make_shortcut_action( 

232 tr("描画色と背景色を切り替え"), self.colors.toggle_draw_background_color, "C" 

233 ) 

234 self.a_swap_main_sub = self.make_shortcut_action( 

235 tr("メイン色とサブ色を切り替え"), self.line_ops.swap_main_sub, "X" 

236 ) 

237 self.a_choose_background = self.make_shortcut_action( 

238 tr("背景色の表示色を変更"), self.colors.choose_background_color 

239 ) 

240 self.a_mainline_repaint = self.make_shortcut_action( 

241 "MainLineRepaint", self.line_ops.main_line_repaint 

242 ) 

243 self.a_selection_transform = self.make_shortcut_action( 

244 tr("選択範囲:自由変形"), lambda: self.line_ops.start_wire_transform("free"), 

245 "Ctrl+T", 

246 ) 

247 self.a_selection_scale = self.make_shortcut_action( 

248 tr("選択範囲:拡大縮小"), lambda: self.line_ops.start_wire_transform("scale") 

249 ) 

250 self.a_selection_mesh = self.make_shortcut_action( 

251 tr("選択範囲:メッシュ変形"), lambda: self.line_ops.start_wire_transform("mesh") 

252 ) 

253 self.a_selection_clear = self.make_shortcut_action( 

254 tr("選択範囲を解除"), self.canvas.clear_selection, "Ctrl+D" 

255 ) 

256 # これまでの Ctrl+Shift+A でも解除できるよう、2つ目のキーとして残す。 

257 self.a_selection_clear.setShortcuts([ 

258 QKeySequence("Ctrl+D"), QKeySequence("Ctrl+Shift+A"), 

259 ]) 

260 self.a_selection_all = self.make_shortcut_action( 

261 tr("すべてを選択"), self.canvas.select_all, "Ctrl+A" 

262 ) 

263 self.a_selection_invert = self.make_shortcut_action( 

264 tr("選択範囲を反転"), self.canvas.invert_selection, "Ctrl+Shift+I" 

265 ) 

266 self.a_selection_delete = self.make_shortcut_action( 

267 tr("選択範囲の中を消去"), self.canvas.delete_selection_contents, "Delete" 

268 ) 

269 # Mac のキーボードの delete キーは Backspace として届く。 

270 self.a_selection_delete.setShortcuts([ 

271 QKeySequence("Delete"), QKeySequence("Backspace"), 

272 ]) 

273 self.a_view_zoom_in = self.make_shortcut_action( 

274 tr("表示:拡大"), lambda: self.step_canvas_zoom(1.25), "Ctrl+=" 

275 ) 

276 # 「Ctrl++」は配列によって Ctrl+= や Ctrl+Shift+= で届くので両方受ける。 

277 self.a_view_zoom_in.setShortcuts([ 

278 QKeySequence("Ctrl+="), QKeySequence("Ctrl++"), 

279 ]) 

280 self.a_view_zoom_out = self.make_shortcut_action( 

281 tr("表示:縮小"), lambda: self.step_canvas_zoom(1 / 1.25), "Ctrl+-" 

282 ) 

283 self.a_view_fit = self.make_shortcut_action( 

284 tr("表示:全体を表示"), self.fit_canvas, "Ctrl+0" 

285 ) 

286 self.a_brush_smaller = self.make_shortcut_action( 

287 tr("ブラシサイズを小さく"), lambda: self.tools.step_brush_size(-1), "[" 

288 ) 

289 self.a_brush_larger = self.make_shortcut_action( 

290 tr("ブラシサイズを大きく"), lambda: self.tools.step_brush_size(1), "]" 

291 ) 

292 self.a_transform_rotate_left = self.make_shortcut_action( 

293 tr("変形:左へ90°回転"), 

294 lambda: self.canvas.rotate_selection_transform(-90.0) 

295 ) 

296 self.a_transform_rotate_right = self.make_shortcut_action( 

297 tr("変形:右へ90°回転"), 

298 lambda: self.canvas.rotate_selection_transform(90.0) 

299 ) 

300 self.a_transform_mesh_grid = self.make_shortcut_action( 

301 tr("メッシュ変形:格子数を変更…"), 

302 self.line_ops.choose_transform_mesh_grid 

303 ) 

304 self.a_transform_commit = self.make_shortcut_action( 

305 tr("変形を確定"), self.tween.commit_transform_or_tween 

306 ) 

307 self.a_transform_commit.setShortcuts([ 

308 QKeySequence(Qt.Key.Key_Return), 

309 QKeySequence(Qt.Key.Key_Enter), 

310 ]) 

311 self.a_transform_cancel = self.make_shortcut_action( 

312 tr("変形をキャンセル"), self.tween.cancel_transform_or_tween 

313 ) 

314 self.a_focus_used_color = self.make_shortcut_action( 

315 tr("使用色:この色を選択範囲にする"), 

316 self.colors.focus_selected_used_color, 

317 ) 

318 self.a_bucket_include_sub = self.make_shortcut_action( 

319 tr("バケツ:含み塗り ON/OFF"), 

320 lambda: self.tools.bucket_include_sub.toggle() 

321 ) 

322 self.a_bucket_close_gap = self.make_shortcut_action( 

323 tr("バケツ:隙間閉じ ON/OFF"), 

324 lambda: self.tools.bucket_close_gap.toggle() 

325 ) 

326 self.a_bucket_all_frames = self.make_shortcut_action( 

327 tr("バケツ:串刺し塗り ON/OFF"), 

328 lambda: self.tools.bucket_all_frames.toggle() 

329 ) 

330 self.a_dust_all_frames = self.make_shortcut_action( 

331 tr("ゴミ取り:すべてのコマ ON/OFF"), 

332 lambda: self.tools.dust_all_frames.toggle() 

333 ) 

334 self.a_dust_apply = self.make_shortcut_action( 

335 tr("ゴミ取り/塗り抜けを適用"), self.line_ops.remove_dust_fill_surrounding 

336 ) 

337 self.a_selection_all_frames = self.make_shortcut_action( 

338 tr("選択変形:すべてのコマ ON/OFF"), 

339 self.tools.toggle_selection_all_frames 

340 ) 

341 

342 # Timeline commands. 

343 self.a_tl_add_exposure = self.make_shortcut_action( 

344 tr("タイムライン:コマ数を1つ増やす"), 

345 self.timeline._extend_current_exposure, 

346 ) 

347 self.a_tl_delete_frame = self.make_shortcut_action( 

348 tr("タイムライン:コマを削除"), 

349 self.timeline_ops.delete_frame, 

350 "Shift+E", 

351 ) 

352 self.a_tl_previous = self.make_shortcut_action( 

353 tr("タイムライン:前のフレーム"), 

354 self.timeline_ops.previous_frame, 

355 ) 

356 self.a_tl_next = self.make_shortcut_action( 

357 tr("タイムライン:次のフレーム"), 

358 self.timeline_ops.next_frame, 

359 ) 

360 self.a_tl_previous_key = self.make_shortcut_action( 

361 tr("タイムライン:前のコマ"), 

362 self.timeline_ops.previous_key, 

363 "A", 

364 ) 

365 self.a_tl_next_key = self.make_shortcut_action( 

366 tr("タイムライン:次のコマ"), 

367 self.timeline_ops.next_key, 

368 "S", 

369 ) 

370 self.a_tl_play = self.make_shortcut_action( 

371 tr("タイムライン:再生/停止"), 

372 lambda: self.timeline.play.toggle(), 

373 ) 

374 self.a_tl_paste_time_remap = self.make_shortcut_action( 

375 tr("タイムライン:タイムリマップを貼り付け"), 

376 self.time_remap.show_paste_dialog, 

377 ) 

378 self.a_tl_copy_time_remap = self.make_shortcut_action( 

379 tr("タイムライン:タイムリマップをコピー"), 

380 self.time_remap.copy_from_timeline, 

381 ) 

382 self.a_tl_onion = self.make_shortcut_action( 

383 tr("タイムライン:オニオンスキン設定"), 

384 lambda: self.timeline.onion.toggle(), 

385 ) 

386 self.a_tl_layer_add = self.make_shortcut_action( 

387 tr("タイムライン:レイヤー追加"), 

388 self.canvas.add_layer, 

389 "Ctrl+Shift+N", 

390 ) 

391 self.a_tl_layer_delete = self.make_shortcut_action( 

392 tr("タイムライン:レイヤー削除"), 

393 self.canvas.delete_layer, 

394 ) 

395 self.a_tl_layer_rename = self.make_shortcut_action( 

396 tr("タイムライン:レイヤー名変更"), 

397 self.timeline.rename_selected_layer, 

398 ) 

399 self.file_edit_actions = [ 

400 (tr("新規作成"), self.a_new), 

401 (tr("プロジェクトを開く"), self.a_open_project), 

402 (tr("カットフォルダーを開く"), self.a_open_cut_folder), 

403 (tr("画像を読み込む"), self.a_import_images), 

404 (tr("画像フォルダーを読み込む"), self.a_import_folder), 

405 (tr("上書き保存"), self.a_save_project), 

406 (tr("名前を付けて保存"), self.a_save_project_as), 

407 (tr("現在のコマをPNG書き出し"), self.a_save), 

408 (tr("現在のコマをTGA書き出し"), self.a_save_tga), 

409 (tr("連番PNG+CSV書き出し"), self.a_export_png_seq), 

410 (tr("連番TGA+CSV書き出し"), self.a_export_tga_seq), 

411 (tr("カットフォルダーへ書き出し"), self.a_export_cut_folder), 

412 (tr("影素材を書き出し"), self.a_export_shadow), 

413 (tr("MP4書き出し"), self.a_export_mp4), 

414 (tr("元に戻す"), self.a_undo), 

415 (tr("やり直す"), self.a_redo), 

416 (tr("切り取り"), self.a_cut), 

417 (tr("コピー"), self.a_copy), 

418 (tr("貼り付け"), self.a_paste), 

419 (tr("キャンバスサイズ変更"), self.a_resize), 

420 (tr("筆圧設定"), self.a_pressure), 

421 (tr("メモを開く"), self.a_memo), 

422 (tr("環境設定"), self.a_preferences), 

423 (tr("背景以外を黒シルエット表示"), self.a_silhouette), 

424 (tr("隣接色分けで表示"), self.a_preview_map), 

425 (tr("露光量の調整を切り替え"), self.a_exposure_toggle), 

426 (tr("赤チャンネルを表示"), self.a_channel_red), 

427 (tr("緑チャンネルを表示"), self.a_channel_green), 

428 (tr("青チャンネルを表示"), self.a_channel_blue), 

429 (tr("アルファチャンネルを表示"), self.a_channel_alpha), 

430 (tr("選択色だけ表示"), self.a_isolate_color), 

431 (tr("特定色表示を解除"), self.a_clear_color_filter), 

432 (tr("ゴミ取り"), self.a_remove_dust), 

433 (tr("自動で塗る"), self.a_auto_paint), 

434 (tr("今の絵を初期状態として保持"), self.a_keep_initial_state), 

435 (tr("線画カットフォルダーを初期状態として読み込む"), self.a_import_initial_state), 

436 (tr("CLIPの線画を初期状態として読み込む"), self.a_import_clip_initial_state), 

437 (tr("保持した初期状態を消す"), self.a_clear_initial_state), 

438 (tr("見本との違いチェック"), self.a_reference_check), 

439 ] 

440 self.tool_command_actions = [ 

441 (tr("描画色:メインを選択"), self.a_select_main), 

442 (tr("描画色:サブを選択"), self.a_select_sub), 

443 (tr("描画色:背景色を選択"), self.a_select_transparent), 

444 (tr("描画色と背景色を切り替え"), self.a_toggle_draw_background), 

445 (tr("メイン色とサブ色を切り替え"), self.a_swap_main_sub), 

446 (tr("背景色の表示色を変更"), self.a_choose_background), 

447 ("MainLineRepaint", self.a_mainline_repaint), 

448 (tr("選択範囲:自由変形"), self.a_selection_transform), 

449 (tr("選択範囲:拡大縮小"), self.a_selection_scale), 

450 (tr("選択範囲:メッシュ変形"), self.a_selection_mesh), 

451 (tr("すべてを選択"), self.a_selection_all), 

452 (tr("選択範囲を解除"), self.a_selection_clear), 

453 (tr("選択範囲を反転"), self.a_selection_invert), 

454 (tr("選択範囲の中を消去"), self.a_selection_delete), 

455 (tr("表示:拡大"), self.a_view_zoom_in), 

456 (tr("表示:縮小"), self.a_view_zoom_out), 

457 (tr("表示:全体を表示"), self.a_view_fit), 

458 (tr("ブラシサイズを小さく"), self.a_brush_smaller), 

459 (tr("ブラシサイズを大きく"), self.a_brush_larger), 

460 (tr("変形:左へ90°回転"), self.a_transform_rotate_left), 

461 (tr("変形:右へ90°回転"), self.a_transform_rotate_right), 

462 (tr("メッシュ変形:格子数を変更"), self.a_transform_mesh_grid), 

463 (tr("変形を確定"), self.a_transform_commit), 

464 (tr("変形をキャンセル"), self.a_transform_cancel), 

465 (tr("使用色:この色を選択範囲にする"), self.a_focus_used_color), 

466 (tr("バケツ:含み塗り ON/OFF"), self.a_bucket_include_sub), 

467 (tr("バケツ:隙間閉じ ON/OFF"), self.a_bucket_close_gap), 

468 (tr("バケツ:串刺し塗り ON/OFF"), self.a_bucket_all_frames), 

469 (tr("ゴミ取り:すべてのコマ ON/OFF"), self.a_dust_all_frames), 

470 (tr("ゴミ取り/塗り抜けを適用"), self.a_dust_apply), 

471 (tr("選択変形:すべてのコマ ON/OFF"), self.a_selection_all_frames), 

472 ] 

473 self.timeline_actions = [ 

474 (tr("コマ数を1つ増やす"), self.a_tl_add_exposure), 

475 (tr("コマを削除"), self.a_tl_delete_frame), 

476 (tr("タイムリマップを貼り付け"), self.a_tl_paste_time_remap), 

477 (tr("タイムリマップをコピー"), self.a_tl_copy_time_remap), 

478 (tr("前のフレーム"), self.a_tl_previous), 

479 (tr("前のコマ"), self.a_tl_previous_key), 

480 (tr("再生/停止"), self.a_tl_play), 

481 (tr("次のコマ"), self.a_tl_next_key), 

482 (tr("次のフレーム"), self.a_tl_next), 

483 (tr("オニオンスキン設定"), self.a_tl_onion), 

484 (tr("レイヤー追加"), self.a_tl_layer_add), 

485 (tr("レイヤー削除"), self.a_tl_layer_delete), 

486 (tr("レイヤー名変更"), self.a_tl_layer_rename), 

487 ] 

488 def build_menu(self): 

489 f=self.menuBar().addMenu(tr("ファイル")) 

490 f.addAction(self.a_new) 

491 f.addAction(self.a_open_project) 

492 self.recent_menu = f.addMenu(tr("最近使用したファイル")) 

493 self.recent_menu.aboutToShow.connect( 

494 lambda: self.project.fill_recent_menu(self.recent_menu) 

495 ) 

496 f.addAction(self.a_open_cut_folder) 

497 f.addAction(self.a_import_images) 

498 f.addAction(self.a_import_folder) 

499 f.addAction(self.a_import_images_raw) 

500 f.addAction(self.a_import_psd) 

501 f.addAction(self.a_import_clip) 

502 f.addSeparator() 

503 f.addAction(self.a_save_project) 

504 f.addAction(self.a_save_project_as) 

505 f.addSeparator() 

506 f.addAction(self.a_save) 

507 f.addAction(self.a_save_tga) 

508 f.addAction(self.a_export_cut_folder) 

509 f.addAction(self.a_export_shadow) 

510 f.addAction(self.a_export_png_seq) 

511 f.addAction(self.a_export_tga_seq) 

512 f.addAction(self.a_export_xdts) 

513 f.addAction(self.a_export_psd) 

514 f.addAction(self.a_export_mp4) 

515 e=self.menuBar().addMenu(tr("編集"));e.addAction(self.a_undo);e.addAction(self.a_redo);e.addSeparator();e.addAction(self.a_cut);e.addAction(self.a_copy);e.addAction(self.a_paste);e.addSeparator();e.addAction(self.a_silhouette);e.addAction(self.a_preview_map);e.addAction(self.a_isolate_color);e.addAction(self.a_clear_color_filter);e.addAction(self.a_swap_main_sub);e.addAction(self.a_remove_dust);e.addSeparator();e.addAction(self.a_resize);e.addAction(self.a_pressure);e.addSeparator();e.addAction(self.a_memo) 

516 e.addSeparator() 

517 self.a_color_chart = QAction(tr("カラーチャート…"), self) 

518 self.a_color_chart.triggered.connect( 

519 lambda: self._set_color_chart_visible(True) 

520 ) 

521 e.addAction(self.a_color_chart) 

522 e.addSeparator() 

523 e.addAction(self.a_shortcuts) 

524 e.addAction(self.a_preferences) 

525 # 自動で塗る道具と、その仕上がりの確認。 

526 auto_menu=self.menuBar().addMenu(tr("自動塗り")) 

527 auto_menu.addAction(self.a_auto_paint) 

528 auto_menu.addSeparator() 

529 auto_menu.addAction(self.a_keep_initial_state) 

530 auto_menu.addAction(self.a_import_initial_state) 

531 auto_menu.addAction(self.a_import_clip_initial_state) 

532 auto_menu.addAction(self.a_clear_initial_state) 

533 auto_menu.addSeparator() 

534 auto_menu.addAction(self.a_reference_check) 

535 selection_menu=self.menuBar().addMenu(tr("選択範囲")) 

536 selection_menu.addAction(self.a_selection_all) 

537 selection_menu.addAction(self.a_selection_clear) 

538 selection_menu.addAction(self.a_selection_invert) 

539 selection_menu.addAction(self.a_selection_delete) 

540 selection_menu.addSeparator() 

541 selection_menu.addAction(self.a_selection_transform) 

542 selection_menu.addAction(self.a_selection_scale) 

543 selection_menu.addAction(self.a_selection_mesh) 

544 selection_menu.addSeparator() 

545 selection_menu.addAction(self.a_transform_rotate_left) 

546 selection_menu.addAction(self.a_transform_rotate_right) 

547 selection_menu.addAction(self.a_transform_mesh_grid) 

548 selection_menu.addSeparator() 

549 selection_menu.addAction(self.a_transform_commit) 

550 selection_menu.addAction(self.a_transform_cancel) 

551 a=self.menuBar().addMenu(tr("アニメーション")) 

552 a.addAction(self.a_prev) 

553 a.addAction(self.a_next) 

554 a.addSeparator() 

555 a.addAction(self.a_tl_previous_key) 

556 a.addAction(self.a_tl_next_key) 

557 a.addSeparator() 

558 a.addAction(self.a_tl_paste_time_remap) 

559 a.addAction(self.a_tl_copy_time_remap) 

560 # 「システムに合わせる」のときは、OSの外観の切り替えに追従する。 

561 QGuiApplication.styleHints().colorSchemeChanged.connect( 

562 self._on_system_color_scheme_changed 

563 ) 

564 

565 def _on_system_color_scheme_changed(self, *_args): 

566 if theme.current_theme() == theme.SYSTEM: 

567 self.set_theme(theme.SYSTEM) 

568 

569 def show_preferences(self, section=None): 

570 dialog = getattr(self, "preferences_dialog", None) 

571 if dialog is None: 

572 dialog = self.preferences_dialog = PreferencesDialog(self) 

573 if section: 

574 dialog.show_section(section) 

575 dialog.show_and_raise() 

576 

577 def _set_color_chart_visible(self, visible): 

578 window = getattr(self, "color_chart_window", None) 

579 if window is None: 579 ↛ 580line 579 didn't jump to line 580 because the condition on line 579 was never true

580 return 

581 if visible: 581 ↛ 584line 581 didn't jump to line 584 because the condition on line 581 was always true

582 window.show_and_raise() 

583 else: 

584 window.close() 

585 def _save_canvas_snapshot_clicked(self): 

586 """カメラボタン。Shiftを押していれば保存先を選び直してから保存する。""" 

587 shift = bool( 

588 QGuiApplication.keyboardModifiers() & Qt.KeyboardModifier.ShiftModifier 

589 ) 

590 return self.export.save_canvas_snapshot(choose_folder=shift) 

591 

592 def _apply_canvas_bar_icons(self): 

593 for button, name in getattr(self, "_canvas_bar_icons", {}).items(): 

594 button.setIcon(icons.icon(name)) 

595 def _refresh_theme_dependent_ui(self): 

596 """Re-apply palette-derived styles after a theme/accent change.""" 

597 bar: Any = self.statusBar() 

598 if hasattr(bar, "refresh_palette"): 598 ↛ 600line 598 didn't jump to line 600 because the condition on line 598 was always true

599 bar.refresh_palette() 

600 if hasattr(self.tools, "apply_theme"): 600 ↛ 602line 600 didn't jump to line 602 because the condition on line 600 was always true

601 self.tools.apply_theme() 

602 if hasattr(self.tool_selector, "apply_theme"): 602 ↛ 604line 602 didn't jump to line 604 because the condition on line 602 was always true

603 self.tool_selector.apply_theme() 

604 if hasattr(self.timeline, "apply_theme"): 604 ↛ 606line 604 didn't jump to line 606 because the condition on line 604 was always true

605 self.timeline.apply_theme() 

606 self._apply_canvas_bar_icons() 

607 if hasattr(self, "update_notice"): 607 ↛ 609line 607 didn't jump to line 609 because the condition on line 607 was always true

608 self.update_notice.refresh_style() 

609 if hasattr(self.palette, "apply_theme"): 609 ↛ 611line 609 didn't jump to line 611 because the condition on line 609 was always true

610 self.palette.apply_theme() 

611 if hasattr(self, "dock_manager"): 611 ↛ exitline 611 didn't return from function '_refresh_theme_dependent_ui' because the condition on line 611 was always true

612 self._customize_docking_hover() 

613 # スタイルシートの付け直しでタブの min/max-height が QSS の値に 

614 # 戻るため、固定の高さを付け直す。 

615 self._sync_all_area_hamburgers() 

616 def build_ui(self): 

617 QtAds.CDockManager.setConfigFlag( 

618 QtAds.CDockManager.eConfigFlag.AlwaysShowTabs, True 

619 ) 

620 QtAds.CDockManager.setConfigFlag( 

621 QtAds.CDockManager.eConfigFlag.DockAreaHasUndockButton, False 

622 ) 

623 QtAds.CDockManager.setConfigFlag( 

624 QtAds.CDockManager.eConfigFlag.DockAreaHasTabsMenuButton, False 

625 ) 

626 QtAds.CDockManager.setConfigFlag( 

627 QtAds.CDockManager.eConfigFlag.ActiveTabHasCloseButton, False 

628 ) 

629 QtAds.CDockManager.setConfigFlag( 

630 QtAds.CDockManager.eConfigFlag.DockAreaHasCloseButton, False 

631 ) 

632 QtAds.CDockManager.setConfigFlag( 

633 QtAds.CDockManager.eConfigFlag.OpaqueSplitterResize, True 

634 ) 

635 QtAds.CDockManager.setConfigFlag( 

636 QtAds.CDockManager.eConfigFlag.FloatingContainerForceQWidgetTitleBar, 

637 True, 

638 ) 

639 QtAds.CDockManager.setConfigFlag( 

640 QtAds.CDockManager.eConfigFlag.FloatingContainerForceNativeTitleBar, 

641 False, 

642 ) 

643 QtAds.CDockManager.setConfigFlag( 

644 QtAds.CDockManager.eConfigFlag.DoubleClickUndocksWidget, True 

645 ) 

646 self.setDockNestingEnabled(True) 

647 self.status_bar = StatusBar(self) 

648 self.setStatusBar(self.status_bar) 

649 center=QWidget() 

650 cv=QVBoxLayout(center) 

651 cv.setContentsMargins(0,0,0,0) 

652 self.canvas.setMinimumSize(160, 40) 

653 cv.addWidget(self.canvas,1) 

654 bar=QHBoxLayout() 

655 self.zoom=QSlider(Qt.Orientation.Horizontal) 

656 self.zoom.setRange(5,1600) 

657 self.zoom.setValue(100) 

658 self.zoom.setFixedWidth(72) 

659 self.zoom_label=QLabel("100%") 

660 self.rot=QSlider(Qt.Orientation.Horizontal) 

661 self.rot.setRange(-180,180) 

662 self.rot.setFixedWidth(72) 

663 self.rot_label=QLabel("0°") 

664 b100=QPushButton() 

665 b100.setToolTip(tr("100%表示")) 

666 bfit=QPushButton() 

667 bfit.setToolTip(tr("全体を表示")) 

668 b0=QPushButton() 

669 b0.setToolTip(tr("回転を0°に戻す")) 

670 self.flip_horizontal_button=QPushButton() 

671 self.flip_horizontal_button.setCheckable(True) 

672 self.flip_horizontal_button.setToolTip(tr("左右反転プレビュー")) 

673 self.flip_horizontal_button.toggled.connect(self.view_preview.set_flip_horizontal) 

674 self.flip_vertical_button=QPushButton() 

675 self.flip_vertical_button.setCheckable(True) 

676 self.flip_vertical_button.setToolTip(tr("上下反転プレビュー")) 

677 self.flip_vertical_button.toggled.connect(self.view_preview.set_flip_vertical) 

678 # 今の絵の書き出し(クリップボード/フォルダー)。見え方のチェックとは 

679 # 役割が違うので、区切りを挟んで比較ボタンの左へ置く。 

680 self.copy_canvas_button=QPushButton() 

681 self.copy_canvas_button.setToolTip(tr( 

682 "今の絵をクリップボードへ書き出す" 

683 )) 

684 self.copy_canvas_button.clicked.connect(self.export.copy_canvas_to_clipboard) 

685 self.save_canvas_button=QPushButton() 

686 self.save_canvas_button.setToolTip(tr( 

687 "今の絵をフォルダーへ書き出す(年月日時分秒のファイル名)。" 

688 "Shift+クリックで保存先を選び直す" 

689 )) 

690 self.save_canvas_button.clicked.connect(self._save_canvas_snapshot_clicked) 

691 self.canvas_export_separator=QFrame() 

692 self.canvas_export_separator.setFrameShape(QFrame.Shape.VLine) 

693 self.canvas_export_separator.setFrameShadow(QFrame.Shadow.Plain) 

694 self.canvas_export_separator.setFixedHeight(16) 

695 self.compare_initial_button=QPushButton() 

696 self.compare_initial_button.setCheckable(True) 

697 self.compare_initial_button.setToolTip(tr( 

698 "色塗り前の初期状態と比べる(押すと初期状態を表示、もう一度押すと今の絵に戻る)" 

699 )) 

700 self.compare_initial_button.toggled.connect(self.initial_state.set_compare) 

701 # 見え方のチェック(画面だけを変え、書き出しには影響しない)。 

702 self.black_check_button=QPushButton() 

703 self.black_check_button.setCheckable(True) 

704 self.black_check_button.setToolTip(tr("ブラックチェック(背景以外を黒シルエット表示)")) 

705 self.black_check_button.toggled.connect(self.line_ops.toggle_silhouette) 

706 self.map_colors_button=QPushButton() 

707 self.map_colors_button.setCheckable(True) 

708 self.map_colors_button.setToolTip(tr( 

709 "隣接色分け:隣り合う部分を見分けやすい仮の色で塗り分けて表示する" 

710 "(近い色の塗り漏れが見つかる。元の色が同じ部分は同じ色)。" 

711 "アクティブレイヤーだけに掛かる" 

712 )) 

713 self.map_colors_button.toggled.connect(self.view_preview.set_map_colors) 

714 self.channel_combo=ChannelPreviewButton(channel_labels()) 

715 self.channel_combo.channelChanged.connect(self.view_preview.set_channel) 

716 self.exposure_button=QPushButton() 

717 self.exposure_button.setCheckable(True) 

718 self.exposure_button.setToolTip(tr( 

719 "露光量の調整:押すと 0 に戻す。もう一度押すと直前の値に戻す" 

720 )) 

721 self.exposure_button.clicked.connect(self.view_preview.toggle_exposure) 

722 self.exposure_control=ExposureControl( 

723 view_preview.EXPOSURE_MIN, view_preview.EXPOSURE_MAX 

724 ) 

725 self.exposure_control.setToolTip(tr("露光量(段)。左右ドラッグ、またはクリックして入力")) 

726 self.exposure_spin=self.exposure_control.spin 

727 self.exposure_control.valueChanged.connect(self.view_preview.set_exposure) 

728 # 表示操作はアイコンボタンにして、キャンバスの下を細い1本のバーにする。 

729 self._canvas_bar_icons = { 

730 b100: "zoom_actual", bfit: "fit", self.compare_initial_button: "compare", 

731 b0: "rotate_reset", self.black_check_button: "black_check", 

732 self.flip_horizontal_button: "flip_horizontal", 

733 self.flip_vertical_button: "flip_vertical", 

734 self.map_colors_button: "map_colors", self.exposure_button: "exposure", 

735 self.copy_canvas_button: "clipboard", self.save_canvas_button: "camera", 

736 } 

737 for button in self._canvas_bar_icons: 

738 button.setProperty("iconButton", True) 

739 button.setFixedSize(26, 24) 

740 button.setIconSize(QSize(16, 16)) 

741 button.setFocusPolicy(Qt.FocusPolicy.NoFocus) 

742 self._apply_canvas_bar_icons() 

743 for label in (self.zoom_label, self.rot_label): 

744 label.setMinimumWidth(38) 

745 bar.setContentsMargins(8, 2, 8, 2) 

746 bar.setSpacing(4) 

747 zoom_title=QLabel(tr("拡大")) 

748 rot_title=QLabel(tr("回転")) 

749 for w in (zoom_title,self.zoom,self.zoom_label,b100,bfit): 

750 bar.addWidget(w) 

751 bar.addSpacing(16) 

752 for w in (rot_title,self.rot,self.rot_label,b0, 

753 self.flip_horizontal_button,self.flip_vertical_button): 

754 bar.addWidget(w) 

755 bar.addSpacing(16) 

756 bar.addStretch(1) 

757 for w in ( 

758 self.copy_canvas_button, self.save_canvas_button, 

759 self.canvas_export_separator, 

760 self.compare_initial_button, self.black_check_button, 

761 self.map_colors_button, self.channel_combo, 

762 self.exposure_button, self.exposure_control, 

763 ): 

764 bar.addWidget(w) 

765 cv.addLayout(bar) 

766 self.dock_manager = QtAds.CDockManager(self) 

767 # ADS の既定(FollowPalette)はパレットが変わるたびに組み込みの 

768 # スタイルシートを読み込み直し、テーマ切り替えの後に 

769 # _customize_docking_hover() のスタイルを上書きしてしまう。 

770 # 配色はこちらで付けるので、自動の読み込み直しを止める。 

771 self.dock_manager.setColorSchemeMode( 

772 QtAds.CDockManager.ColorSchemeMode.Light 

773 ) 

774 self._customize_docking_hover() 

775 self._setup_split_drop_overlay() 

776 self.dock_manager.floatingWidgetCreated.connect( 

777 self._configure_floating_window 

778 ) 

779 self.central_dock = QtAds.CDockWidget(self.dock_manager, tr("キャンバス")) 

780 self.central_dock.setObjectName("canvasDock") 

781 self.central_dock.setWidget( 

782 center, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

783 ) 

784 self.dock_manager.setCentralWidget(self.central_dock) 

785 # setCentralWidget() intentionally strips movable/floatable in ADS; 

786 # restore them afterwards because the canvas is detachable here. 

787 self.central_dock.setFeatures( 

788 QtAds.CDockWidget.DockWidgetFeature.DockWidgetFocusable 

789 | QtAds.CDockWidget.DockWidgetFeature.DockWidgetMovable 

790 | QtAds.CDockWidget.DockWidgetFeature.DockWidgetFloatable 

791 ) 

792 self.central_dock.topLevelChanged.connect( 

793 lambda floating: self._sync_floating_title( 

794 self.central_dock, floating 

795 ) 

796 ) 

797 

798 self.tools.setMinimumWidth(180) 

799 self.tools.setMaximumWidth(16777215) 

800 self.tools.setMinimumHeight(0) 

801 self.palette.setMinimumWidth(220) 

802 self.palette.setMaximumWidth(16777215) 

803 self.palette.setMinimumHeight(0) 

804 

805 self.tools_scroll = QScrollArea() 

806 self.tools_scroll.setWidgetResizable(True) 

807 self.tools_scroll.setMinimumSize(0, 0) 

808 self.tools_scroll.setWidget(self.tools) 

809 

810 self.palette_scroll = QScrollArea() 

811 self.palette_scroll.setWidgetResizable(True) 

812 self.palette_scroll.setMinimumSize(0, 0) 

813 self.palette_scroll.setWidget(self.palette) 

814 

815 self.history_scroll = QScrollArea() 

816 self.history_scroll.setWidgetResizable(True) 

817 self.history_scroll.setMinimumSize(0, 0) 

818 self.history_scroll.setWidget(self.history_panel) 

819 

820 # 描画色(メイン/サブ/背景)はツールバー最下部のスウォッチに加え、 

821 # カラーサークルのドック上部(tools.drawing_color_box)にも大きく表示する。 

822 self.color_wheel_scroll = QScrollArea() 

823 self.color_wheel_scroll.setWidgetResizable(True) 

824 self.color_wheel_scroll.setMinimumSize(0, 0) 

825 self.color_wheel_scroll.setFrameShape(QScrollArea.Shape.NoFrame) 

826 self.color_wheel_scroll.setWidget(self.tools.color_wheel_box) 

827 

828 self.color_slider_scroll = QScrollArea() 

829 self.color_slider_scroll.setWidgetResizable(True) 

830 self.color_slider_scroll.setMinimumSize(0, 0) 

831 self.color_slider_scroll.setFrameShape(QScrollArea.Shape.NoFrame) 

832 self.color_slider_scroll.setWidget(self.tools.color_slider_box) 

833 

834 self.tool_selector_dock=QtAds.CDockWidget(self.dock_manager, tr("ツール")) 

835 self.tool_selector_dock.setObjectName("toolSelectorDock") 

836 self.tool_selector_dock.setFeatures( 

837 QtAds.CDockWidget.DockWidgetFeature.DockWidgetMovable 

838 | QtAds.CDockWidget.DockWidgetFeature.DockWidgetFocusable 

839 | QtAds.CDockWidget.DockWidgetFeature.DockWidgetFloatable 

840 ) 

841 self.tool_selector_dock.setMinimumSizeHintMode( 

842 QtAds.CDockWidget.eMinimumSizeHintMode.MinimumSizeHintFromContentMinimumSize 

843 ) 

844 self.tool_selector_dock.setWidget( 

845 self.tool_selector, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

846 ) 

847 tool_area = self.dock_manager.addDockWidget( 

848 QtAds.LeftDockWidgetArea, self.tool_selector_dock 

849 ) 

850 

851 self.tools_dock=QtAds.CDockWidget(self.dock_manager, tr("ツールプロパティ")) 

852 self.tools_dock.setObjectName("toolsDock") 

853 self.tools_dock.setWidget( 

854 self.tools_scroll, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

855 ) 

856 tools_area = self.dock_manager.addDockWidget( 

857 QtAds.RightDockWidgetArea, self.tools_dock, tool_area 

858 ) 

859 

860 self.action_panel_scroll = QScrollArea() 

861 self.action_panel_scroll.setWidgetResizable(True) 

862 self.action_panel_scroll.setMinimumSize(0, 0) 

863 self.action_panel_scroll.setWidget(self.action_panel) 

864 self.action_panel_dock=QtAds.CDockWidget(self.dock_manager, tr("アクション")) 

865 self.action_panel_dock.setObjectName("actionPanelDock") 

866 self.action_panel_dock.setWidget( 

867 self.action_panel_scroll, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

868 ) 

869 self.dock_manager.addDockWidget( 

870 QtAds.BottomDockWidgetArea, self.action_panel_dock, tools_area 

871 ) 

872 

873 self.color_wheel_dock=QtAds.CDockWidget(self.dock_manager, tr("カラーサークル")) 

874 self.color_wheel_dock.setObjectName("colorWheelDock") 

875 self.color_wheel_dock.setWidget( 

876 self.color_wheel_scroll, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

877 ) 

878 # カラーサークルを右エリアのアンカーにする(旧・描画色ドックの位置)。 

879 drawing_area = self.dock_manager.addDockWidget( 

880 QtAds.RightDockWidgetArea, self.color_wheel_dock 

881 ) 

882 wheel_area = drawing_area 

883 

884 self.color_slider_dock=QtAds.CDockWidget(self.dock_manager, tr("カラースライダー")) 

885 self.color_slider_dock.setObjectName("colorSliderDock") 

886 self.color_slider_dock.setWidget( 

887 self.color_slider_scroll, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

888 ) 

889 self.dock_manager.addDockWidget( 

890 QtAds.BottomDockWidgetArea, self.color_slider_dock, wheel_area 

891 ) 

892 

893 self.palette_dock=QtAds.CDockWidget(self.dock_manager, tr("使用色")) 

894 self.palette_dock.setObjectName("paletteDock") 

895 self.palette_dock.setWidget( 

896 self.palette_scroll, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

897 ) 

898 palette_area = self.dock_manager.addDockWidget( 

899 QtAds.BottomDockWidgetArea, self.palette_dock, drawing_area 

900 ) 

901 # タイトルバーの×の左側に「?」ヘルプボタンを置き、 

902 # 常時表示していた使い方の説明をそこへ収める。 

903 self.palette_help_action = QAction("?", self) 

904 self.palette_help_action.setToolTip(tr("使用色パネルの使い方を表示します。")) 

905 self.palette_help_action.triggered.connect(self.palette.show_help) 

906 self.palette_dock.setTitleBarActions([self.palette_help_action]) 

907 

908 self.history_dock=QtAds.CDockWidget(self.dock_manager, tr("ヒストリー")) 

909 self.history_dock.setObjectName("historyDock") 

910 self.history_dock.setWidget( 

911 self.history_scroll, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

912 ) 

913 # 使用色パネルと同じ場所にタブとして重ねる。 

914 self.dock_manager.addDockWidget( 

915 QtAds.CenterDockWidgetArea, self.history_dock, palette_area 

916 ) 

917 self.history_help_action = QAction("?", self) 

918 self.history_help_action.setToolTip(tr("ヒストリーパネルの使い方を表示します。")) 

919 self.history_help_action.triggered.connect(self.history_panel.show_help) 

920 self.history_dock.setTitleBarActions([self.history_help_action]) 

921 # 使用色をヒストリーより前のタブとして、起動時の前面にする。 

922 palette_area.setCurrentDockWidget(self.palette_dock) 

923 

924 # カラーチャートはたまに使う道具なので、パネルではなく「編集」メニュー 

925 # から開く別ウィンドウにする(パネルの列には幅が足りず中身が切れていた)。 

926 self.color_chart_window = ToolWindow( 

927 self, tr("カラーチャート"), "color_chart", self.color_chart, 

928 default_size=(520, 460), 

929 ) 

930 

931 self.subview_dock=QtAds.CDockWidget(self.dock_manager, tr("サブビュー")) 

932 self.subview_dock.setObjectName("subviewDock") 

933 self.subview_dock.setWidget( 

934 self.subview, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

935 ) 

936 self.dock_manager.addDockWidget( 

937 QtAds.RightDockWidgetArea, self.subview_dock 

938 ) 

939 

940 self.timeline_dock=QtAds.CDockWidget(self.dock_manager, tr("タイムライン")) 

941 self.timeline_dock.setObjectName("timelineDock") 

942 self.timeline.setMaximumHeight(16777215) 

943 self.timeline_dock.setWidget( 

944 self.timeline, QtAds.CDockWidget.eInsertMode.ForceNoScrollArea 

945 ) 

946 self.timeline_dock.setMinimumHeight(70) 

947 self.timeline_dock.setMaximumHeight(16777215) 

948 self.dock_manager.addDockWidget( 

949 QtAds.BottomDockWidgetArea, self.timeline_dock 

950 ) 

951 # 各パネルのタブ左端に付けるハンバーガーメニューの内容。 

952 # 未登録のパネルは閉じる/フロートの共通項目だけになる。 

953 dock_menu_builders = { 

954 self.action_panel_dock: self._build_action_panel_menu, 

955 self.color_wheel_dock: self._build_color_wheel_menu, 

956 self.color_slider_dock: self._build_color_slider_menu, 

957 } 

958 for dock in ( 

959 self.tool_selector_dock, 

960 self.tools_dock, 

961 self.action_panel_dock, 

962 self.color_wheel_dock, 

963 self.color_slider_dock, 

964 self.palette_dock, 

965 self.history_dock, 

966 self.subview_dock, 

967 self.timeline_dock, 

968 ): 

969 dock.topLevelChanged.connect( 

970 lambda floating, current=dock: 

971 self._sync_floating_title(current, floating) 

972 ) 

973 self._add_dock_hamburger(dock, dock_menu_builders.get(dock)) 

974 self._sync_floating_title(dock, False) 

975 self.dock_manager.dockAreasAdded.connect( 

976 lambda *_args: QTimer.singleShot( 

977 0, self._sync_all_area_hamburgers 

978 ) 

979 ) 

980 self.dock_manager.dockWidgetAdded.connect( 

981 lambda *_args: QTimer.singleShot( 

982 0, self._sync_all_area_hamburgers 

983 ) 

984 ) 

985 self.workspace.build_menu() 

986 self._finalize_startup_dock_ui() 

987 for dock in ( 

988 self.tool_selector_dock, 

989 self.tools_dock, 

990 self.action_panel_dock, 

991 self.color_wheel_dock, 

992 self.color_slider_dock, 

993 self.palette_dock, 

994 self.history_dock, 

995 self.subview_dock, 

996 self.timeline_dock, 

997 ): 

998 self._sync_floating_title(dock, dock.isFloating()) 

999 QTimer.singleShot( 

1000 0, 

1001 lambda: self._resize_tool_selector_area( 

1002 self.tool_selector.width_for_columns(1) 

1003 ), 

1004 ) 

1005 

1006 panel_menu=self.menuBar().addMenu(tr("パネル")) 

1007 view_menu=panel_menu 

1008 view_menu.addAction(self.tool_selector_dock.toggleViewAction()) 

1009 view_menu.addAction(self.tools_dock.toggleViewAction()) 

1010 view_menu.addAction(self.action_panel_dock.toggleViewAction()) 

1011 view_menu.addAction(self.color_wheel_dock.toggleViewAction()) 

1012 view_menu.addAction(self.color_slider_dock.toggleViewAction()) 

1013 view_menu.addAction(self.palette_dock.toggleViewAction()) 

1014 view_menu.addAction(self.history_dock.toggleViewAction()) 

1015 view_menu.addAction(self.subview_dock.toggleViewAction()) 

1016 view_menu.addAction(self.timeline_dock.toggleViewAction()) 

1017 

1018 help_menu=self.menuBar().addMenu(tr("ヘルプ")) 

1019 a_check_update=QAction(tr("更新を確認…"), self) 

1020 a_check_update.triggered.connect(self.check_for_updates_interactive) 

1021 help_menu.addAction(a_check_update) 

1022 help_menu.addSeparator() 

1023 a_about=QAction(tr("バージョン情報…"), self) 

1024 a_about.triggered.connect(self.show_about_dialog) 

1025 help_menu.addAction(a_about) 

1026 

1027 self.zoom.valueChanged.connect(self.set_zoom) 

1028 b100.clicked.connect(self.show_canvas_at_100_percent) 

1029 bfit.clicked.connect(self.fit_canvas) 

1030 self.rot.valueChanged.connect(self.set_rot) 

1031 b0.clicked.connect(lambda:self.rot.setValue(0)) 

1032 

1033 

1034 def _resize_tool_selector_area(self, content_width): 

1035 dock = self.tool_selector_dock 

1036 frame_width = max(0, dock.width() - self.tool_selector.width()) 

1037 target_width = int(content_width) + frame_width 

1038 child = dock 

1039 parent = dock.parentWidget() 

1040 while parent is not None: 1040 ↛ exitline 1040 didn't return from function '_resize_tool_selector_area' because the condition on line 1040 was always true

1041 if isinstance(parent, QSplitter) and parent.orientation() == Qt.Orientation.Horizontal: 

1042 index = parent.indexOf(child) 

1043 sizes = parent.sizes() 

1044 if 0 <= index < len(sizes): 1044 ↛ 1052line 1044 didn't jump to line 1052 because the condition on line 1044 was always true

1045 delta = sizes[index] - target_width 

1046 sizes[index] = target_width 

1047 recipients = [i for i in range(len(sizes)) if i != index] 

1048 if recipients: 1048 ↛ 1051line 1048 didn't jump to line 1051 because the condition on line 1048 was always true

1049 recipient = max(recipients, key=lambda i: sizes[i]) 

1050 sizes[recipient] = max(1, sizes[recipient] + delta) 

1051 parent.setSizes(sizes) 

1052 return 

1053 child = parent 

1054 parent = parent.parentWidget() 

1055 

1056 def connect_signals(self): 

1057 """Wire every widget signal to its handler. 

1058 

1059 Named ``connect_signals`` rather than ``connect``: on a PySide6 object, 

1060 an override living on a non-``QObject`` base is shadowed by the built-in 

1061 ``QObject.connect`` at attribute-lookup time, so the plain name would 

1062 silently resolve to Qt's method. 

1063 """ 

1064 self.tool_selector.toolChanged.connect(self.tools.select_tool) 

1065 self.tool_selector.snapWidthRequested.connect( 

1066 self._snap_tool_selector_width 

1067 ) 

1068 self.tools.toolChanged.connect(self.tool_selector.set_active_tool) 

1069 self.tools.toolChanged.connect(self.canvas.set_tool) 

1070 self.tools.brush_size_spinbox.valueChanged.connect(self.canvas.set_pen_size) 

1071 self.tools.brush_stabilizer.valueChanged.connect( 

1072 self.canvas.set_brush_stabilizer 

1073 ) 

1074 self.tools.brush_size_spinbox.pressureRequested.connect(self.pressure) 

1075 self.tools.fill_opacity.valueChanged.connect( 

1076 lambda value: setattr(self.canvas, "fill_opacity", value / 100) 

1077 ) 

1078 self.tools.colorModeChanged.connect(self.colors.set_color_mode) 

1079 self.tools.colorChanged.connect(self.colors.set_color_value) 

1080 self.subview.colorPicked.connect(self.colors.apply_sampled_color) 

1081 self.color_chart.colorPicked.connect(self.colors.apply_sampled_color) 

1082 self.color_chart.chartChanged.connect(self.color_chart_ops.on_edited) 

1083 self.color_chart.captureRequested.connect(self.color_chart_ops.capture) 

1084 self.color_chart.applyRequested.connect(self.color_chart_ops.apply) 

1085 self.color_chart.saveRequested.connect(self.color_chart_ops.save_pmag) 

1086 self.color_chart.loadRequested.connect(self.color_chart_ops.load_pmag) 

1087 self.subview.set_color_provider( 

1088 lambda: ( 

1089 self.canvas.sub_color 

1090 if self.canvas.color_mode == "sub" 

1091 else self.canvas.main_color 

1092 ) 

1093 ) 

1094 self.subview.colorPicked.connect( 

1095 lambda color: self.status( 

1096 tr("サブビューから {color} を取得しました").format( 

1097 color=color.name().upper() 

1098 ), 

1099 "success", 

1100 2500, 

1101 ) 

1102 ) 

1103 # Keep the tool-bar drawing-colour swatch in sync with the panel. 

1104 self.tool_selector.colorModeRequested.connect(self.colors.set_color_mode) 

1105 self.tool_selector.backgroundColorRequested.connect( 

1106 self.colors.choose_background_color 

1107 ) 

1108 self.tool_selector.colorEditRequested.connect(self.colors.choose_color) 

1109 self.tools.colorModeChanged.connect( 

1110 lambda _m=None: self.colors._sync_tool_selector_swatch() 

1111 ) 

1112 self.tools.colorChanged.connect( 

1113 lambda *_a: self.colors._sync_tool_selector_swatch() 

1114 ) 

1115 self.tools.main_btn.colorPicked.connect( 

1116 lambda color: self.colors.apply_sampled_color_to_mode("main", color) 

1117 ) 

1118 self.tools.sub_btn.colorPicked.connect( 

1119 lambda color: self.colors.apply_sampled_color_to_mode("sub", color) 

1120 ) 

1121 self.tools.meshCommitRequested.connect(self.canvas.commit_mesh) 

1122 self.tools.meshCancelRequested.connect(self.canvas.cancel_mesh) 

1123 self.tools.selectionTransformRequested.connect( 

1124 lambda: self.line_ops.start_wire_transform("free") 

1125 ) 

1126 self.tools.selectionScaleRequested.connect( 

1127 lambda: self.line_ops.start_wire_transform("scale") 

1128 ) 

1129 self.tools.selectionMeshRequested.connect( 

1130 lambda: self.line_ops.start_wire_transform("mesh") 

1131 ) 

1132 self.tools.selectionClearRequested.connect(self.canvas.clear_selection) 

1133 self.tools.selectionRotateRequested.connect( 

1134 self.canvas.rotate_selection_transform 

1135 ) 

1136 self.tools.transformMeshGridChanged.connect( 

1137 self.canvas.set_transform_mesh_grid 

1138 ) 

1139 self.tools.transform_quality.toggled.connect( 

1140 self.canvas.set_transform_quality 

1141 ) 

1142 self.tools.transform_line_width.valueChanged.connect( 

1143 self.canvas.set_transform_line_threshold 

1144 ) 

1145 self.tools.transform_line_width.sliderPressed.connect( 

1146 self.canvas.begin_transform_line_adjustment 

1147 ) 

1148 self.tools.transform_line_width.sliderReleased.connect( 

1149 self.canvas.finish_transform_line_adjustment 

1150 ) 

1151 self.canvas.set_transform_quality( 

1152 self.tools.transform_quality.isChecked() 

1153 ) 

1154 self.canvas.set_transform_line_threshold( 

1155 self.tools.transform_line_width.value() 

1156 ) 

1157 self.tools.selectionCommitRequested.connect( 

1158 self.tween.commit_transform_or_tween 

1159 ) 

1160 self.tools.selectionCancelRequested.connect( 

1161 self.tween.cancel_transform_or_tween 

1162 ) 

1163 self.tools.flipLayerRequested.connect(self.canvas.flip_active_layer) 

1164 self.tools.swapMainSubRequested.connect(self.line_ops.swap_main_sub) 

1165 self.tools.resetMainSubRequested.connect(self.line_ops.reset_main_sub) 

1166 self.tools.removeDustRequested.connect(self.line_ops.remove_dust_fill_surrounding) 

1167 self.tools.backgroundColorRequested.connect(self.colors.choose_background_color) 

1168 self.tools.colorEditRequested.connect(self.colors.choose_color) 

1169 

1170 self.timeline.frameSelected.connect(self.timeline_ops.select_exposure) 

1171 self.timeline.addFrameRequested.connect( 

1172 self.canvas.add_frame 

1173 ) 

1174 self.timeline.extendExposureRequested.connect( 

1175 lambda row, key, exposure: 

1176 self.timeline_ops.resize_exposure( 

1177 row, 

1178 key, 

1179 key + max(1, exposure), 

1180 "right", 

1181 ) 

1182 ) 

1183 self.timeline.deleteFrameRequested.connect( 

1184 self.timeline_ops.delete_frame 

1185 ) 

1186 self.timeline.first.clicked.connect(lambda: self.timeline_ops.jump_boundary(False)) 

1187 self.timeline.last.clicked.connect(lambda: self.timeline_ops.jump_boundary(True)) 

1188 self.timeline.table.ruler.rangeResized.connect(self.timeline_ops.resize_range) 

1189 self.timeline.previousRequested.connect(self.timeline_ops.previous_frame) 

1190 self.timeline.nextRequested.connect(self.timeline_ops.next_frame) 

1191 self.timeline.previousKeyRequested.connect(self.timeline_ops.previous_key) 

1192 self.timeline.nextKeyRequested.connect(self.timeline_ops.next_key) 

1193 self.timeline.durationChanged.connect(self.canvas.set_duration) 

1194 self.timeline.cellMoveRequested.connect(self.timeline_ops.move_cell) 

1195 self.timeline.cellCopyRequested.connect(self.timeline_ops.copy_cell) 

1196 self.timeline.sequenceRecallRequested.connect(self.timeline_ops.recall_sequence_number) 

1197 self.timeline.multiCellMoveRequested.connect( 

1198 self.timeline_ops.move_selection 

1199 ) 

1200 self.timeline.timelineModeChanged.connect( 

1201 self.timeline_ops.set_mode 

1202 ) 

1203 self.timeline.normalizeNumbersRequested.connect( 

1204 self.timeline_ops.normalize_numbers 

1205 ) 

1206 self.timeline.blankFrameRequested.connect( 

1207 self.timeline_ops.create_blank_key 

1208 ) 

1209 # セルの右クリックメニュー(Issue #48)。 

1210 self.timeline.newAnimationCellRequested.connect( 

1211 self.timeline_ops.new_animation_cell 

1212 ) 

1213 self.timeline.clearCellRequested.connect(self.timeline_ops.clear_cell) 

1214 self.timeline.cutCellRequested.connect( 

1215 self.timeline_ops.cut_cell_to_clipboard 

1216 ) 

1217 self.timeline.copyCellToClipboardRequested.connect( 

1218 self.timeline_ops.copy_cell_to_clipboard 

1219 ) 

1220 self.timeline.pasteCellRequested.connect( 

1221 self.timeline_ops.paste_cell_from_clipboard 

1222 ) 

1223 self.timeline.mergeClipRequested.connect(self.timeline_ops.merge_clip) 

1224 self.timeline.splitClipRequested.connect(self.timeline_ops.split_clip) 

1225 self.timeline.insertFrameAtRequested.connect( 

1226 self.timeline_ops.insert_frame_at 

1227 ) 

1228 self.timeline.deleteFrameAtRequested.connect( 

1229 self.timeline_ops.delete_frame_at 

1230 ) 

1231 self.timeline.playbackRangeEdgeRequested.connect( 

1232 self.timeline_ops.resize_range 

1233 ) 

1234 self.timeline.timeRemapCopyRequested.connect( 

1235 self.time_remap.copy_from_timeline 

1236 ) 

1237 self.timeline.exposureResizeRequested.connect(self.timeline_ops.resize_exposure) 

1238 self.timeline.tweenRequested.connect( 

1239 lambda row, column: self.tween.enable(row, column, "free") 

1240 ) 

1241 self.timeline.tweenMeshRequested.connect( 

1242 lambda row, column: self.tween.enable(row, column, "mesh") 

1243 ) 

1244 self.timeline.tweenCancelRequested.connect( 

1245 self.tween.cancel_transform_or_tween 

1246 ) 

1247 self.timeline.tweenEditRequested.connect(self.tween.edit) 

1248 self.timeline.tweenReleaseRequested.connect(self.tween.release) 

1249 self.timeline.onionPopupToggled.connect( 

1250 self.onion.toggle_settings_popup 

1251 ) 

1252 self.timeline.onionChanged.connect(self.onion.set_enabled) 

1253 self.timeline.timeRemapPasteRequested.connect( 

1254 self.time_remap.show_paste_dialog 

1255 ) 

1256 self.timeline.timeRemapFileDropped.connect( 

1257 self.time_remap.open_dropped 

1258 ) 

1259 self.timeline.playRequested.connect(self.play) 

1260 

1261 self.canvas.changed.connect(self.refresh_ui) 

1262 self.canvas.selectionChanged.connect(self.refresh_selection) 

1263 self.canvas.selectionCleared.connect( 

1264 self.palette._clear_used_color_selection 

1265 ) 

1266 self.canvas.cellChanged.connect(self._on_canvas_cell_changed) 

1267 self.canvas.colorUsed.connect(self.palette.add_color) 

1268 

1269 self.timeline.layerSelected.connect(self.layers.on_selected) 

1270 self.timeline.layerVisibilityChanged.connect(self.layers.set_visibility_row) 

1271 self.timeline.layerOpacityChanged.connect(self.layers.set_opacity_row) 

1272 self.timeline.layer_opacity_slider.sliderPressed.connect( 

1273 self.canvas.push_doc_undo 

1274 ) 

1275 self.timeline.layerNameChanged.connect(self.layers.rename_row) 

1276 self.timeline.layerMoveRequested.connect(self.layers.move_row) 

1277 self.timeline.addLayerRequested.connect(self.layers.add_fast) 

1278 self.timeline.deleteLayerRequested.connect(self.canvas.delete_layer) 

1279 self.timeline.duplicateLayersRequested.connect(self.layers.duplicate_rows) 

1280 self.timeline.mergeLayersRequested.connect(self.layers.merge_rows) 

1281 self.timeline.deleteLayersRequested.connect(self.layers.delete_rows) 

1282 self.timeline.toggleDraftLayersRequested.connect( 

1283 self.layers.set_draft_rows 

1284 ) 

1285 

1286 self.canvas.imagesDropped.connect(self.import_dropped_images) 

1287 self.canvas.projectDropped.connect(self.project.open_dropped) 

1288 self.canvas.timeRemapDropped.connect(self.time_remap.open_dropped) 

1289 self.canvas.clipAnimationDropped.connect(self.importer.clip_animation) 

1290 self.canvas.colorSampled.connect(self.colors.apply_sampled_color) 

1291 self.canvas.status_message.connect( 

1292 lambda message: self.statusBar().showMessage(message, 2500) 

1293 ) 

1294 self.canvas.viewChanged.connect(self.sync_canvas_view_controls) 

1295 self.canvas.onionInteractionChanged.connect( 

1296 self.onion.sync_browser_from_canvas 

1297 ) 

1298 self.canvas.onionInteractionFinished.connect( 

1299 self.onion.finish_browser_interaction 

1300 ) 

1301 

1302 self.palette.isolateColorClicked.connect(self.used_color.apply_palette_isolate_color) 

1303 self.palette.mainColorRequested.connect( 

1304 lambda color: self.colors.apply_sampled_color_to_mode("main", color) 

1305 ) 

1306 self.palette.sourceScreenColorPicked.connect(self.colors.apply_sampled_color) 

1307 self.palette.applyReplacementRequested.connect( 

1308 self.used_color.apply_palette_replacements 

1309 ) 

1310 self.palette.saveReplacementSetRequested.connect( 

1311 self.used_color.save_replacement_set 

1312 ) 

1313 self.palette.loadReplacementSetRequested.connect( 

1314 self.used_color.load_replacement_set 

1315 ) 

1316 self.palette.previewGroupsChanged.connect(self.colors.set_preview_color_groups) 

1317 self.palette.mergeColorsRequested.connect(self.used_color.apply_palette_merge) 

1318 self.palette.deleteColorsRequested.connect( 

1319 self.used_color.apply_palette_delete 

1320 ) 

1321 self.palette.adjustLineThicknessRequested.connect( 

1322 self.colors.adjust_parent_line_thickness 

1323 ) 

1324 self.palette.adjustHsvRequested.connect( 

1325 self.used_color.adjust_used_color_hsv 

1326 ) 

1327 self.palette.focusColorRequested.connect(self.colors.focus_used_color) 

1328 self.palette.clearIsolateRequested.connect( 

1329 self.colors.clear_selected_color_filter 

1330 ) 

1331 self.palette.maskColorsChanged.connect(self.colors.set_mask_colors) 

1332 self.palette.selectedColorsChanged.connect(self.colors.set_selected_used_colors) 

1333 self.palette.visibleColorsChanged.connect(self.colors.set_visible_colors) 

1334 self.palette.historyStatePush.connect(self.used_color.push_palette_history) 

1335 self.history_panel.jumpRequested.connect(self.used_color.jump_history) 

1336 self.history_panel.branchSwitchRequested.connect( 

1337 self.used_color.switch_history_branch 

1338 ) 

1339 # 編集のたびにヒストリー一覧を更新する。 

1340 self.canvas.selectionChanged.connect(self.used_color.refresh_history_panel) 

1341 self.canvas.changed.connect(self.used_color.refresh_history_panel) 

1342 self.canvas.cellChanged.connect( 

1343 lambda *_args: self.used_color.refresh_history_panel() 

1344 ) 

1345 

1346 

1347 def show_about_dialog(self): 

1348 """Show version, copyright and the license notices. 

1349 

1350 Crediting the LGPL-licensed Qt/PySide6 and Qt-Advanced-Docking-System 

1351 components is a distribution requirement (LGPLv3 4a/4c), not 

1352 decoration -- keep this reachable from the menu. See 

1353 THIRD_PARTY_LICENSES.md for the full compliance notes. 

1354 """ 

1355 repo_url = f"https://github.com/{GITHUB_REPO}" 

1356 QMessageBox.about( 

1357 self, 

1358 tr("{app} について").format(app=APP_NAME), 

1359 tr("""<h3>{app}</h3> 

1360<p>Copyright &copy; 2026 PaintMaskAnimator contributors</p> 

1361<p>本ソフトウェアは <b>Apache License 2.0</b> のもとで配布されています。 

1362商用・非商用を問わず、自由に利用・改変・再配布できます。</p> 

1363<p>本ソフトウェアは「現状有姿」で提供され、明示黙示を問わず<b>いかなる保証もありません</b>。 

1364詳細はライセンス全文を参照してください。</p> 

1365<p>ライセンス全文: <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a><br> 

1366ソースコード: <a href="{repo}">{repo}</a></p> 

1367<p><b>サードパーティコンポーネント</b><br> 

1368Qt for Python (PySide6) &mdash; LGPLv3<br> 

1369Qt Advanced Docking System &mdash; LGPL-2.1<br> 

1370NumPy &mdash; BSD-3-Clause / Pillow &mdash; MIT-CMU / psd-tools &mdash; MIT</p> 

1371<p>これらの LGPL ライブラリは差し替え可能な形で同梱されています。ライセンス全文と 

1372対応ソースの入手先は、配布物内の <tt>THIRD_PARTY_LICENSES.md</tt> を参照してください。</p>""").format( 

1373 app=APP_DISPLAY_NAME, repo=repo_url 

1374 ), 

1375 )