Gallery
Sept 29, 2020 7:25:13 GMT -8
Post by Uncle Buddy on Sept 29, 2020 7:25:13 GMT -8
# gallery.py (import as gl)
import os
import files
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
import sqlite3
import styles as st
import widgets as wdg
import utes
from names import get_current_person
formats = st.make_formats_dict()
class Gallery(wdg.Frame):
def __init__(
self, master, notebook, graphics_tab, root,
canvas,
**options):
wdg.Frame.__init__(self, master, **options)
self.parent = master
self.nbook = notebook
self.t7 = graphics_tab
self.root = root
self.canvas = canvas
self.counter = 0
self.thumb_labels = []
self.width_strings = []
self.height_strings = []
formats = st.make_formats_dict()
self.current_person = get_current_person()[0]
themestyles = st.ThemeStyles(app=self.root)
themestyles.set_window_max_size(self.parent)
self.filter_pix_data()
self.make_widgets()
def make_widgets(self):
if self.parent.winfo_class() == 'Toplevel':
gallery_canvas = wdg.Canvas(
self.parent,
bd=0,
highlightthickness=0)
self.gallery_content = wdg.Frame(gallery_canvas)
gallery_canvas.grid(row=0, column=0, sticky='nsew')
self.parent.grid_columnconfigure(0, weight=1)
self.parent.grid_rowconfigure(0, weight=1)
else:
self.gallery_content = wdg.Frame(self.parent)
self.gallery_content.grid(column=0, row=0)
self.thumb_canvas = wdg.Canvas(
self.gallery_content,
bd=0,
highlightthickness=0,
bg=formats['bg'])
self.thumb_canvas.pack(padx=12, pady=12)
self.thumbstrip = wdg.Frame(self.thumb_canvas)
self.thumbstrip.pack(side='top')
self.previous_img = wdg.Button(self.gallery_content, text='<<', width=6)
self.pic_canvas = wdg.Canvas(
self.gallery_content,
highlightbackground=formats['bg'])
self.pic_canvas.bind('<Button-1>', self.focus_clicked)
self.pic_canvas.bind('<Button-1>', self.scroll_start, add='+')
self.pic_canvas.bind('<B1-Motion>', self.scroll_move)
self.img_path = '{}treebard_gps\data\{}\images\{}'.format(
st.root_drive, self.image_dir, self.main_pic)
img_big = Image.open(self.img_path)
self.tk_img = ImageTk.PhotoImage(img_big)
self.pic_canvas.image = self.tk_img
z = 0
self.current_pictures = sorted(self.current_pictures)
for img in self.current_pictures:
pic_col = wdg.Frame(self.thumbstrip)
pic_col.pack(side='left', expand=1, fill='y')
pic_file = img
self.img_path = '{}treebard_gps\data\{}\images\{}'.format(st.root_drive, self.image_dir, pic_file)
idx = len(pic_file)
bare = pic_file[0:idx-4]
thumbsy = Image.open(self.img_path)
self.width_strings.append(thumbsy.width)
self.height_strings.append(thumbsy.height)
thumbsy.thumbnail((185,85))
thumb_path = 'images/{}_tmb.png'.format(bare)
# overwrites file by same name if it exists
thumbsy.save(thumb_path)
small = ImageTk.PhotoImage(file=thumb_path, master=self.thumbstrip)
thumb = wdg.Label(
pic_col,
image=small)
thumb.pack(expand=1, fill='y')
thumb.image = small
self.thumb_labels.append(thumb)
# lambda used to save value in loop
if self.parent.winfo_class() == 'Toplevel':
rad = wdg.Radiobutton(
pic_col,
takefocus=0,
value=pic_file,
command=lambda pic_file=pic_file: self.set_main_pic(
pic_file))
rad.pack()
if rad['value'] == self.main_pic:
rad.select()
else:
rad = wdg.Frame(
pic_col,
height=24,
width=24)
rad.pack(expand=1, fill='both')
if self.parent.winfo_name() == 'source_tab':
pic_file = '{}, {}'.format(self.source, pic_file)
utes.create_tooltip(rad, pic_file)
z += 1
self.pil_img = img_big
self.fit_canvas_to_pic()
self.thumb_dict = dict(zip(self.thumb_labels, self.current_pictures))
self.next_img = wdg.Button(self.gallery_content, text='>>', width=6)
panel = wdg.Frame(self.gallery_content)
subject = wdg.LabelH3(panel, text=self.curr_entity)
subject.grid(column=0, row=0, sticky='ew')
# labels with selectable multiline text
self.caption_lab = wdg.MessageCopiable(panel, width=36)
self.picfile_lab = wdg.MessageCopiable(panel, width=36)
self.picsize_lab = wdg.MessageCopiable(panel, width=36)
edit = wdg.Button(
panel,
text='EDIT',
width=8,
command=lambda graphics=self.t7: self.go_to_graphics(graphics))
self.previous_img.config(command=self.back)
self.next_img.config(command=self.forward)
panel.grid_rowconfigure(0, weight=2)
panel.grid_rowconfigure(1, weight=1)
panel.grid_rowconfigure(4, weight=2)
self.caption_lab.grid(column=0, row=1, pady=(12,12), sticky='ew')
self.caption_lab.insert(1.0, self.caption_text)
self.picfile_lab.grid(column=0, row=2, pady=(12,0), sticky='ew')
self.picfile_lab.insert(1.0, self.img_path)
self.picsize_lab.grid(column=0, row=3, pady=(0,24), sticky='ew')
self.picsize_lab.insert(
1.0,
'width: {}, height: {}'.format(
self.pil_img.width, self.pil_img.height))
edit.grid(column=0, row=4)
self.caption_lab.set_height()
self.picfile_lab.set_height()
self.picsize_lab.set_height()
self.previous_img.pack(side='left', padx=12)
self.pic_canvas.pack(side='left', expand=1, fill='y')
self.next_img.pack(side='left', padx=12)
panel.pack(side='left', expand=1, fill='y')
for thumb in self.thumb_labels:
thumb.bind('<Button-1>', self.show_clicked)
self.pic_canvas.bind('<Key-Left>', lambda evt: self.back())
self.pic_canvas.bind('<Key-Right>', lambda evt: self.forward())
# add statusbar-tooltips
self.visited = (
(self.thumbstrip,
"Thumbnail Views",
"Click thumbnail to display. Hover below to see "
"file name. If radio, click to make main image."),
(self.pic_canvas,
"Image",
"Arrow keys change image when it's in focus."),
(self.previous_img,
"Left Button",
"Click with mouse or when highlighted click with spacebar."),
(self.next_img,
"Right Button",
"Click with mouse or when highlighted click with spacebar."))
if self.parent.winfo_class() == 'Toplevel':
box = wdg.Frame(self.parent)
box.grid(column=0, row=1, pady=12)
close = wdg.Button(
box,
text='CLOSE',
width=8,
command=self.cancel_gallery)
close.grid()
self.parent.protocol('WM_DELETE_WINDOW', self.cancel_gallery)
self.thumb_canvas.create_window(0, 0, anchor='nw', window=self.thumbstrip)
self.thumb_canvas.config(
scrollregion=(
0, 0,
self.thumbstrip.winfo_reqwidth(),
self.thumbstrip.winfo_reqheight()))
self.thumb_canvas.config(
width=self.root.maxsize()[0],
height=self.thumbstrip.winfo_reqheight())
scroll_width = int(self.thumb_canvas['scrollregion'].split(' ')[2])
if scroll_width >= int(self.thumb_canvas['width']):
for child in self.thumbstrip.winfo_children():
for gchild in child.winfo_children():
gchild.bind("<Enter>", self.thumb_start)
gchild.bind("<Motion>", self.thumb_move)
if self.parent.winfo_class() == 'Toplevel':
gallery_canvas.create_window(
0, 0, anchor=tk.NW, window=self.gallery_content)
self.resize_scrollbar()
self.resize_window()
self.config_labels()
def resize_scrollbar(self):
self.parent.update_idletasks()
self.pic_canvas.config(scrollregion=self.pic_canvas.bbox("all"))
def resize_window(self):
self.parent.update_idletasks()
page_x = self.gallery_content.winfo_reqwidth()
page_y = self.gallery_content.winfo_reqheight()+48
self.parent.geometry('{}x{}'.format(page_x, page_y))
def cancel_gallery(self, event=None):
self.root.focus_set()
self.parent.destroy()
def focus_clicked(self, evt):
evt.widget.focus_set()
def hilite(evt):
evt.widget.config(bg=formats['highlight_bg'])
def unhilite(evt):
evt.widget.config(bg=formats['bg'])
def show_clicked(self, evt):
select_pic = self.current_pictures.index(self.thumb_dict[evt.widget])
self.chosen_picfile = self.current_pictures[select_pic]
current_dir = files.get_current_file()[1]
self.img_path = '{}treebard_gps\data\{}\images\{}'.format(st.root_drive, current_dir, self.chosen_picfile)
pix_data = self.get_current_pix_data()
for tup in pix_data:
if tup[1] == self.chosen_picfile:
self.caption_text = tup[2]
new = Image.open(self.img_path)
self.tk_img = ImageTk.PhotoImage(new)
self.pil_img = new
self.fit_canvas_to_pic()
self.pic_canvas.image = self.tk_img
self.pic_canvas.config(
scrollregion=(0, 0, self.pil_img.width, self.pil_img.height))
self.config_labels()
self.counter = select_pic
def scroll_start(self, event):
self.pic_canvas.scan_mark(event.x, event.y)
def scroll_move(self, event):
self.pic_canvas.scan_dragto(event.x, event.y, gain=5)
def thumb_start(self, event):
self.thumb_canvas.scan_mark(event.x, event.y)
def thumb_move(self, event):
self.thumb_canvas.scan_dragto(event.x, event.y, gain=1)
def go_to_graphics(self, graphics):
# if frame with this name already exists it's replaced
# https://stackoverflow.com/questions/59518905/naming-a-widget-to-auto-destroy-replace-it
picwin = wdg.Frame(graphics, name='exists')
picwin.pack()
curr_pic = self.picfile_lab.get(1.0, 'end')
curr_pic = curr_pic.strip('\n')
img_path = curr_pic
edit_pic = Image.open(img_path)
edit_img = ImageTk.PhotoImage(edit_pic)
editlab = wdg.LabelStay(
picwin,
image=edit_img)
editlab.image = edit_img
self.nbook.select(graphics)
# scroll to top so controls are seen when tab opens
self.canvas.yview_moveto(0.0)
if self.parent.winfo_class() == 'Toplevel':
self.parent.lower(belowThis=self.nbook)
editlab.pack() # When this grids a big pic, the whole notebook gets big
# prevent large pics from blowing up size of the whole notebook
# when placed here by edit button on a gallery
# Will need more attention when ready to make the graphics tab.
editlab.config(width=700, height=700)
def filter_pix_data(self):
def second_item(s):
return s[1]
pix_data = self.get_current_pix_data()
pix_data = sorted(pix_data, key=second_item)
for tup in pix_data:
if tup[3] == 1:
self.main_pic = tup[1]
self.caption_text = tup[2]
if self.parent.winfo_name() == 'source_tab':
self.source = tup[4]
self.current_pictures = []
for tup in pix_data:
self.current_pictures.append(tup[1])
curr_entity = tup[0]
self.curr_entity = curr_entity
self.caption_path = []
for tup in pix_data:
self.caption_path.append((tup[1], tup[2]))
def back(self, evt=None):
if self.counter == 0:
self.counter = len(self.caption_path)
self.counter -= 1
current_dir = files.get_current_file()[1]
self.img_path = '{}treebard_gps\data\{}\images\{}'.format(
st.root_drive, current_dir, self.caption_path[self.counter][0])
self.caption_text = self.caption_path[self.counter][1]
new = Image.open(self.img_path)
self.tk_img = ImageTk.PhotoImage(new)
self.pil_img = new
self.fit_canvas_to_pic()
self.pic_canvas.image = self.tk_img
self.pic_canvas.config(
scrollregion=(0, 0, self.pil_img.width, self.pil_img.height))
self.config_labels()
def forward(self, evt=None):
self.counter += 1
if self.counter == len(self.caption_path):
self.counter = 0
current_dir = files.get_current_file()[1]
self.img_path = '{}treebard_gps\\data\\{}\\images\\{}'.format(
st.root_drive, current_dir, self.caption_path[self.counter][0])
self.caption_text = self.caption_path[self.counter][1]
new = Image.open(self.img_path)
self.tk_img = ImageTk.PhotoImage(new)
self.pil_img = new
self.fit_canvas_to_pic()
self.pic_canvas.image = self.tk_img
self.pic_canvas.config(
scrollregion=(0, 0, self.pil_img.width, self.pil_img.height))
self.config_labels()
def get_current_pix_data(self):
current_file_tup = files.get_current_file()
current_file = current_file_tup[0]
self.image_dir = current_file_tup[1]
conn = sqlite3.connect(current_file)
cur = conn.cursor()
if self.parent.winfo_name() == 'place_tab':
cur.execute('''
SELECT places, images, caption, main_image
FROM images_entities
JOIN place
ON images_entities.place_id = place.place_id
JOIN current
ON current.place_id = place.place_id
JOIN image
ON image.image_id = images_entities.image_id
''')
elif self.parent.winfo_name() == 'source_tab':
cur.execute('''
SELECT citations, images, caption, main_image, sources
FROM images_entities
JOIN source
ON citation.source_id = source.source_id
JOIN citation
ON images_entities.citation_id = citation.citation_id
JOIN current
ON current.citation_id = citation.citation_id
JOIN image
ON image.image_id = images_entities.image_id
''')
elif self.parent.winfo_class() == 'Toplevel': # person images
cur.execute(
'''
SELECT names, images, caption, main_image
FROM images_entities
JOIN person
ON images_entities.person_id = person.person_id
JOIN image
ON image.image_id = images_entities.image_id
JOIN name
ON person.person_id = name.person_id
WHERE images_entities.person_id = ?
AND name_type_id = 1
''',
(self.current_person,))
if self.parent.winfo_class() != 'Toplevel':
pix_data = cur.fetchall()
else:
pix_data = cur.fetchall()
pix_data = [list(i) for i in pix_data]
cur.close()
conn.close()
return pix_data
def fit_canvas_to_pic(self):
# make the buttons stay in one place as pics change
max_wd = max(self.width_strings)
max_ht = max(self.height_strings)
scr_wd = self.root.winfo_screenwidth()
scr_ht = self.root.winfo_screenheight()
FULL = 0.55
if max_wd <= scr_wd * FULL:
gallery_wd = max_wd
else:
gallery_wd = scr_wd * FULL
if max_ht <= scr_ht * FULL:
gallery_ht = max_ht
else:
gallery_ht = scr_ht * FULL
self.pic_canvas.config(
scrollregion=(0, 0, self.pil_img.width, self.pil_img.height),
width=gallery_wd,
height=gallery_ht)
if (self.pil_img.width >= gallery_wd and
self.pil_img.height >= gallery_ht):
image = self.pic_canvas.create_image(
0, 0, anchor='nw', image=self.tk_img)
elif (self.pil_img.width <= gallery_wd and
self.pil_img.height >= gallery_ht):
image = self.pic_canvas.create_image(
self.pic_canvas.winfo_reqwidth()/2, 0,
anchor='n', image=self.tk_img)
elif (self.pil_img.width >= gallery_wd and
self.pil_img.height <= gallery_ht):
image = self.pic_canvas.create_image(
0, self.pic_canvas.winfo_reqheight()/2,
anchor='w', image=self.tk_img)
elif (self.pil_img.width <= gallery_wd and
self.pil_img.height <= gallery_ht):
image = self.pic_canvas.create_image(
self.pic_canvas.winfo_reqwidth()/2,
self.pic_canvas.winfo_reqheight()/2,
anchor='center',
image=self.tk_img)
def config_labels(self):
for widg in (self.caption_lab, self.picfile_lab, self.picsize_lab):
widg.config(state='normal')
widg.delete(1.0, 'end')
self.caption_lab.insert(1.0, self.caption_text)
self.picfile_lab.insert(1.0, self.img_path)
self.picsize_lab.insert(
1.0, 'width: {}, height: {}'.format(
self.pil_img.width, self.pil_img.height))
for widg in (self.caption_lab, self.picfile_lab, self.picsize_lab):
widg.set_height()
def set_main_pic(self, val):
radio_value = (val,)
current_file = files.get_current_file()[0]
conn = sqlite3.connect(current_file)
conn.execute("PRAGMA foreign_keys = 1")
cur = conn.cursor()
cur.execute('''
SELECT person_id
FROM current WHERE current_id = 1''')
curr_per = cur.fetchone()
curr_per = curr_per
cur.execute('''
SELECT images
FROM image
JOIN images_entities
ON image.image_id = images_entities.image_id
WHERE main_image = 1
AND images_entities.person_id = ?''', curr_per)
old_top_pic = cur.fetchone()
cur.execute('''
UPDATE images_entities
SET main_image = 0
WHERE main_image = 1
AND images_entities.person_id = ?''', curr_per)
conn.commit()
cur.execute('''
UPDATE images_entities SET main_image = 1
WHERE image_id = (
SELECT image_id
FROM image WHERE images = ?)
AND person_id =
(SELECT current.person_id
FROM current WHERE current_id = 1)''', radio_value)
conn.commit()
cur.close()
conn.close()