"""Редактор заметок""" import tkinter as tk from tkinter import ttk, messagebox from datetime import datetime from app.config import Config from app.ui.dialogs import ConfirmDialog class NoteEditor(tk.Frame): """Правая панель с редактором заметок""" def __init__(self, parent, db, on_note_saved=None, on_note_deleted=None, on_new_note=None): super().__init__(parent, bg=Config.COLORS['editor_bg']) self.db = db self.on_note_saved = on_note_saved self.on_note_deleted = on_note_deleted self.on_new_note = on_new_note self.current_note = None self.is_new_note = False self.is_editing = False self.create_widgets() self.show_empty_state() def create_widgets(self): # Панель инструментов self.toolbar = tk.Frame(self, bg=Config.COLORS['sidebar_bg'], height=40) self.toolbar.pack(fill='x') self.toolbar.pack_propagate(False) # Дата и время (левый край) self.date_label = tk.Label( self.toolbar, text="", bg=Config.COLORS['sidebar_bg'], fg=Config.COLORS['fg'], font=('Arial', 11) ) self.date_label.pack(side='left', padx=10) # Кнопки (правый край) buttons_frame = tk.Frame(self.toolbar, bg=Config.COLORS['sidebar_bg']) buttons_frame.pack(side='right', padx=5) # Кнопка сохранения self.save_btn = tk.Button( buttons_frame, text="💾", command=self.save_note, bg=Config.COLORS['button_bg'], fg=Config.COLORS['fg'], relief='flat', font=('Arial', 14), cursor='hand2', width=2 ) self.save_btn.pack(side='left', padx=2) # Кнопка удаления self.delete_btn = tk.Button( buttons_frame, text="🗑", command=self.delete_current_note, bg=Config.COLORS['button_bg'], fg=Config.COLORS['fg'], relief='flat', font=('Arial', 14), cursor='hand2', width=2 ) self.delete_btn.pack(side='left', padx=2) # Кнопка создания новой заметки self.new_btn = tk.Button( buttons_frame, text="+", command=self.create_new_note, bg=Config.COLORS['accent'], fg=Config.COLORS['fg'], relief='flat', font=('Arial', 14, 'bold'), cursor='hand2', width=2 ) self.new_btn.pack(side='left', padx=2) # Скрываем кнопки сохранения и удаления по умолчанию self.hide_editor_buttons() # Область контента self.content_frame = tk.Frame(self, bg=Config.COLORS['editor_bg']) self.content_frame.pack(fill='both', expand=True, padx=10, pady=10) # Текстовое поле для редактирования self.text_widget = tk.Text( self.content_frame, bg=Config.COLORS['text_bg'], fg=Config.COLORS['text_fg'], font=('Arial', 12), wrap='word', relief='flat', padx=10, pady=10, insertbackground=Config.COLORS['fg'] ) # Scrollbar для текстового поля self.text_scrollbar = ttk.Scrollbar( self.content_frame, orient='vertical', command=self.text_widget.yview ) self.text_widget.configure(yscrollcommand=self.text_scrollbar.set) # Метка для пустого состояния self.empty_label = tk.Label( self.content_frame, text="Выберите заметку из списка\nили создайте новую", bg=Config.COLORS['editor_bg'], fg=Config.COLORS['fg'], font=('Arial', 14), justify='center' ) self.empty_label.pack(expand=True) # Привязываем события изменения текста self.text_widget.bind('<>', self.on_text_modified) def show_editor_buttons(self): """Показать кнопки редактора""" self.save_btn.pack(side='left', padx=2) self.delete_btn.pack(side='left', padx=2) def hide_editor_buttons(self): """Скрыть кнопки редактора""" self.save_btn.pack_forget() self.delete_btn.pack_forget() def show_empty_state(self): """Показать пустое состояние""" self.text_widget.pack_forget() self.text_scrollbar.pack_forget() self.empty_label.pack(expand=True) self.date_label.config(text="") self.hide_editor_buttons() self.current_note = None self.is_new_note = False self.is_editing = False def show_note(self, note): """Показать существующую заметку""" self.current_note = note self.is_new_note = False self.is_editing = False # Скрываем пустую метку self.empty_label.pack_forget() # Показываем текстовое поле self.text_widget.pack(side='left', fill='both', expand=True) self.text_scrollbar.pack(side='right', fill='y') # Устанавливаем дату created_at = datetime.strptime( note['created_at'], '%Y-%m-%d %H:%M:%S' ) self.date_label.config( text=created_at.strftime('%d.%m.%Y %H:%M') ) # Очищаем и вставляем текст self.text_widget.delete('1.0', 'end') self.text_widget.insert('1.0', note.get('content', '')) self.text_widget.edit_modified(False) # Показываем кнопки self.show_editor_buttons() # Делаем поле только для чтения self.text_widget.configure(state='disabled') # Привязываем клик для редактирования self.text_widget.bind('', self.enable_editing) def enable_editing(self, event=None): """Включить режим редактирования""" if not self.is_editing and self.current_note: self.is_editing = True self.text_widget.configure(state='normal') self.text_widget.unbind('') def create_new_note(self): """Создать новую заметку""" self.current_note = None self.is_new_note = True self.is_editing = True # Скрываем пустую метку self.empty_label.pack_forget() # Показываем текстовое поле self.text_widget.pack(side='left', fill='both', expand=True) self.text_scrollbar.pack(side='right', fill='y') # Устанавливаем текущую дату now = datetime.now() self.date_label.config(text=now.strftime('%d.%m.%Y %H:%M')) # Очищаем текстовое поле self.text_widget.delete('1.0', 'end') self.text_widget.configure(state='normal') self.text_widget.edit_modified(False) # Показываем кнопки self.show_editor_buttons() # Убираем привязку клика self.text_widget.unbind('') # Ставим фокус self.text_widget.focus_set() if self.on_new_note: self.on_new_note() def save_note(self): """Сохранить заметку""" content = self.text_widget.get('1.0', 'end-1c') if not content.strip() and self.is_new_note: messagebox.showwarning( "Предупреждение", "Нельзя сохранить пустую заметку" ) return if self.is_new_note: # Создаем новую заметку now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') note_id = self.db.create_note( title=None, content=content, created_at=now ) self.current_note = self.db.get_note_by_id(note_id) self.is_new_note = False self.is_editing = False # Делаем поле только для чтения self.text_widget.configure(state='disabled') self.text_widget.bind('', self.enable_editing) messagebox.showinfo("Успех", "Заметка сохранена") else: # Обновляем существующую заметку self.db.update_note( self.current_note['id'], content=content ) self.current_note = self.db.get_note_by_id(self.current_note['id']) self.is_editing = False # Делаем поле только для чтения self.text_widget.configure(state='disabled') self.text_widget.bind('', self.enable_editing) messagebox.showinfo("Успех", "Заметка обновлена") self.text_widget.edit_modified(False) if self.on_note_saved: self.on_note_saved(self.current_note) def delete_current_note(self): """Удалить текущую заметку""" if not self.current_note: return dialog = ConfirmDialog( self.winfo_toplevel(), "Удаление заметки", "Вы уверены, что хотите удалить эту заметку?" ) self.wait_window(dialog) if dialog.result: self.db.delete_note(self.current_note['id']) self.show_empty_state() if self.on_note_deleted: self.on_note_deleted() def on_text_modified(self, event=None): """Обработчик изменения текста""" if self.text_widget.edit_modified() and self.current_note and not self.is_editing: # Текст был изменен программно, игнорируем self.text_widget.edit_modified(False)