mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
继续为scene.py添加中文注释
This commit is contained in:
parent
a2fa6da6f7
commit
6aa3251e81
1 changed files with 148 additions and 146 deletions
294
beeref/scene.py
294
beeref/scene.py
|
|
@ -56,210 +56,212 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene): # 定义场景类,继承自
|
|||
self._clear_ongoing = False # 初始化清除操作标志为False
|
||||
|
||||
def clear(self):
|
||||
self._clear_ongoing = True
|
||||
super().clear()
|
||||
self.internal_clipboard = []
|
||||
self.rubberband_item = RubberbandItem()
|
||||
self.multi_select_item = MultiSelectItem()
|
||||
self._clear_ongoing = False
|
||||
self._clear_ongoing = True # 设置清理进行中标志,避免清理过程中触发其他依赖状态的逻辑
|
||||
super().clear() # 调用父类的清除方法,清除场景中的所有项目
|
||||
self.internal_clipboard = [] # 初始化内部剪贴板为空列表,用于存储复制到剪贴板的项目
|
||||
self.rubberband_item = RubberbandItem() # 重新创建橡皮筋选择框实例,重置选择框状态
|
||||
self.multi_select_item = MultiSelectItem() # 重新创建多选项实例,重置多选项状态
|
||||
self._clear_ongoing = False # 清除操作完成,重置清除进行中标志
|
||||
|
||||
def addItem(self, item):
|
||||
logger.debug(f'Adding item {item}')
|
||||
super().addItem(item)
|
||||
def addItem(self, item): # 添加项目到场景
|
||||
logger.debug(f'Adding item {item}') # 记录添加项目的调试日志
|
||||
super().addItem(item) # 调用父类的添加项目方法,将项目添加到场景中
|
||||
|
||||
def removeItem(self, item):
|
||||
logger.debug(f'Removing item {item}')
|
||||
super().removeItem(item)
|
||||
def removeItem(self, item): # 从场景中移除项目
|
||||
logger.debug(f'Removing item {item}') # 记录移除项目的调试日志
|
||||
super().removeItem(item) # 调用父类的移除项目方法,将项目从场景中移除
|
||||
|
||||
def cancel_active_modes(self):
|
||||
def cancel_active_modes(self): # 取消所有活动模式
|
||||
"""Cancels ongoing crop modes, rubberband modes etc, if there are
|
||||
any.
|
||||
"""
|
||||
self.cancel_crop_mode()
|
||||
self.end_rubberband_mode()
|
||||
self.cancel_crop_mode() # 取消当前的裁剪模式
|
||||
self.end_rubberband_mode() # 结束当前的橡皮筋选择模式
|
||||
|
||||
def end_rubberband_mode(self):
|
||||
if self.rubberband_item.scene():
|
||||
logger.debug('Ending rubberband selection')
|
||||
self.removeItem(self.rubberband_item)
|
||||
self.active_mode = None
|
||||
def end_rubberband_mode(self): # 结束橡皮筋选择模式
|
||||
if self.rubberband_item.scene(): # 如果橡皮筋选择框存在于场景中
|
||||
logger.debug('Ending rubberband selection') # 记录结束橡皮筋选择模式的调试日志
|
||||
self.removeItem(self.rubberband_item) # 从场景中移除橡皮筋选择框
|
||||
self.active_mode = None # 重置当前活动模式为None
|
||||
|
||||
def cancel_crop_mode(self):
|
||||
"""Cancels an ongoing crop mode, if there is any."""
|
||||
if self.crop_item:
|
||||
self.crop_item.exit_crop_mode(confirm=False)
|
||||
def cancel_crop_mode(self): # 取消当前的裁剪模式
|
||||
"""Cancels an ongoing crop mode, if there is any."""
|
||||
if self.crop_item: # 如果存在裁剪项目
|
||||
self.crop_item.exit_crop_mode(confirm=False) # 退出裁剪模式,不确认裁剪
|
||||
|
||||
def copy_selection_to_internal_clipboard(self):
|
||||
self.internal_clipboard = []
|
||||
for item in self.selectedItems(user_only=True):
|
||||
self.internal_clipboard.append(item)
|
||||
def copy_selection_to_internal_clipboard(self): # 复制当前选择的项目到内部剪贴板
|
||||
self.internal_clipboard = [] # 清空内部剪贴板
|
||||
for item in self.selectedItems(user_only=True): # 遍历当前用户选择的项目
|
||||
self.internal_clipboard.append(item) # 将项目添加到内部剪贴板
|
||||
|
||||
def paste_from_internal_clipboard(self, position):
|
||||
copies = []
|
||||
def paste_from_internal_clipboard(self, position): # 从内部剪贴板粘贴项目到指定位置
|
||||
copies = [] # 创建一个空列表,用于存储复制的项目
|
||||
for item in self.internal_clipboard:
|
||||
copy = item.create_copy()
|
||||
copies.append(copy)
|
||||
self.undo_stack.push(commands.InsertItems(self, copies, position))
|
||||
copy = item.create_copy() # 创建当前项目的副本
|
||||
copies.append(copy) # 将副本添加到复制列表中
|
||||
self.undo_stack.push(commands.InsertItems(self, copies, position)) # 将复制操作添加到撤销栈中
|
||||
|
||||
def raise_to_top(self):
|
||||
self.cancel_active_modes()
|
||||
items = self.selectedItems(user_only=True)
|
||||
z_values = map(lambda i: i.zValue(), items)
|
||||
delta = self.max_z + self.Z_STEP - min(z_values)
|
||||
logger.debug(f'Raise to top, delta: {delta}')
|
||||
for item in items:
|
||||
item.setZValue(item.zValue() + delta)
|
||||
def raise_to_top(self): # 将当前选择的项目提升到顶部
|
||||
self.cancel_active_modes() # 取消所有活动模式,确保没有正在进行的操作干扰
|
||||
items = self.selectedItems(user_only=True) # 获取当前用户选择的项目
|
||||
z_values = map(lambda i: i.zValue(), items) # 提取项目的Z轴值
|
||||
delta = self.max_z + self.Z_STEP - min(z_values) # 计算需要提升的Z轴值增量
|
||||
logger.debug(f'Raise to top, delta: {delta}') # 记录提升到顶部的调试日志
|
||||
for item in items: # 遍历选择的项目
|
||||
item.setZValue(item.zValue() + delta) # 提升项目的Z轴值,将其提升到顶部
|
||||
|
||||
def lower_to_bottom(self):
|
||||
self.cancel_active_modes()
|
||||
items = self.selectedItems(user_only=True)
|
||||
z_values = map(lambda i: i.zValue(), items)
|
||||
delta = self.min_z - self.Z_STEP - max(z_values)
|
||||
logger.debug(f'Lower to bottom, delta: {delta}')
|
||||
def lower_to_bottom(self): # 将当前选择的项目降低到底部
|
||||
self.cancel_active_modes() # 取消所有活动模式,确保没有正在进行的操作干扰
|
||||
items = self.selectedItems(user_only=True) # 获取当前用户选择的项目
|
||||
z_values = map(lambda i: i.zValue(), items) # 提取项目的Z轴值
|
||||
delta = self.min_z - self.Z_STEP - max(z_values) # 计算需要降低的Z轴值增量
|
||||
logger.debug(f'Lower to bottom, delta: {delta}') # 记录降低到底部的调试日志
|
||||
|
||||
for item in items:
|
||||
item.setZValue(item.zValue() + delta)
|
||||
for item in items: # 遍历选择的项目
|
||||
item.setZValue(item.zValue() + delta) # 降低项目的Z轴值,将其降低到底部
|
||||
|
||||
def normalize_width_or_height(self, mode):
|
||||
def normalize_width_or_height(self, mode): # 归一化选择项目的宽度或高度
|
||||
"""Scale the selected images to have the same width or height, as
|
||||
specified by ``mode``.
|
||||
|
||||
:param mode: "width" or "height".
|
||||
"""
|
||||
|
||||
self.cancel_active_modes()
|
||||
values = []
|
||||
items = self.selectedItems(user_only=True)
|
||||
for item in items:
|
||||
rect = self.itemsBoundingRect(items=[item])
|
||||
values.append(getattr(rect, mode)())
|
||||
if len(values) < 2:
|
||||
return
|
||||
avg = sum(values) / len(values)
|
||||
logger.debug(f'Calculated average {mode} {avg}')
|
||||
self.cancel_active_modes() # 取消所有活动模式,确保没有正在进行的操作干扰
|
||||
values = [] # 创建一个空列表,用于存储选择项目的宽度或高度值
|
||||
items = self.selectedItems(user_only=True) # 获取当前用户选择的项目
|
||||
for item in items: # 遍历选择的项目
|
||||
rect = self.itemsBoundingRect(items=[item]) # 获取项目的边界矩形
|
||||
values.append(getattr(rect, mode)()) # 提取矩形的宽度或高度值,并添加到列表中
|
||||
if len(values) < 2: # 如果选择的项目数量小于2
|
||||
return # 直接返回,无需归一化
|
||||
avg = sum(values) / len(values) # 计算宽度或高度的平均值
|
||||
logger.debug(f'Calculated average {mode} {avg}') # 记录归一化的平均值调试日志
|
||||
|
||||
scale_factors = []
|
||||
for item in items:
|
||||
rect = self.itemsBoundingRect(items=[item])
|
||||
scale_factors.append(avg / getattr(rect, mode)())
|
||||
scale_factors = [] # 创建一个空列表,用于存储每个项目的归一化缩放因子
|
||||
for item in items: # 遍历选择的项目
|
||||
rect = self.itemsBoundingRect(items=[item]) # 获取项目的边界矩形
|
||||
scale_factors.append(avg / getattr(rect, mode)()) # 计算项目的归一化缩放因子,并添加到列表中
|
||||
self.undo_stack.push(
|
||||
commands.NormalizeItems(items, scale_factors))
|
||||
commands.NormalizeItems(items, scale_factors)) # 将归一化操作添加到撤销栈中
|
||||
|
||||
def normalize_height(self):
|
||||
def normalize_height(self): # 归一化选择项目的高度
|
||||
"""Scale selected images to the same height."""
|
||||
return self.normalize_width_or_height('height')
|
||||
return self.normalize_width_or_height('height') # 归一化选择项目的高度
|
||||
|
||||
def normalize_width(self):
|
||||
def normalize_width(self): # 归一化选择项目的宽度
|
||||
"""Scale selected images to the same width."""
|
||||
return self.normalize_width_or_height('width')
|
||||
return self.normalize_width_or_height('width') # 归一化选择项目的宽度
|
||||
|
||||
def normalize_size(self):
|
||||
def normalize_size(self): # 归一化选择项目的大小
|
||||
"""Scale selected images to the same size.
|
||||
|
||||
Size meaning the area = widh * height.
|
||||
"""
|
||||
|
||||
self.cancel_active_modes()
|
||||
sizes = []
|
||||
items = self.selectedItems(user_only=True)
|
||||
for item in items:
|
||||
rect = self.itemsBoundingRect(items=[item])
|
||||
sizes.append(rect.width() * rect.height())
|
||||
self.cancel_active_modes() # 取消所有活动模式,确保没有正在进行的操作干扰
|
||||
sizes = [] # 创建一个空列表,用于存储选择项目的面积值
|
||||
items = self.selectedItems(user_only=True) # 获取当前用户选择的项目
|
||||
for item in items: # 遍历选择的项目
|
||||
rect = self.itemsBoundingRect(items=[item]) # 获取项目的边界矩形
|
||||
sizes.append(rect.width() * rect.height()) # 计算项目的面积值,并添加到列表中
|
||||
|
||||
if len(sizes) < 2:
|
||||
return
|
||||
if len(sizes) < 2: # 如果选择的项目数量小于2
|
||||
return # 直接返回,无需归一化
|
||||
|
||||
avg = sum(sizes) / len(sizes)
|
||||
logger.debug(f'Calculated average size {avg}')
|
||||
avg = sum(sizes) / len(sizes) # 计算选择项目的面积平均值
|
||||
logger.debug(f'Calculated average size {avg}') # 记录归一化的平均值调试日志
|
||||
|
||||
scale_factors = []
|
||||
for item in items:
|
||||
rect = self.itemsBoundingRect(items=[item])
|
||||
scale_factors.append(math.sqrt(avg / rect.width() / rect.height()))
|
||||
scale_factors = [] # 创建一个空列表,用于存储每个项目的归一化缩放因子
|
||||
for item in items: # 遍历选择的项目
|
||||
rect = self.itemsBoundingRect(items=[item]) # 获取项目的边界矩形
|
||||
scale_factors.append(math.sqrt(avg / rect.width() / rect.height())) # 计算项目的归一化缩放因子,并添加到列表中
|
||||
self.undo_stack.push(
|
||||
commands.NormalizeItems(items, scale_factors))
|
||||
commands.NormalizeItems(items, scale_factors)) # 将归一化操作添加到撤销栈中
|
||||
|
||||
def arrange_default(self):
|
||||
default = self.settings.valueOrDefault('Items/arrange_default')
|
||||
|
||||
|
||||
def arrange_default(self): # 按默认方式排列选择的项目
|
||||
default = self.settings.valueOrDefault('Items/arrange_default') # 获取默认的排列方式
|
||||
MAPPING = {
|
||||
'optimal': self.arrange_optimal,
|
||||
'horizontal': self.arrange,
|
||||
'vertical': partial(self.arrange, vertical=True),
|
||||
'square': self.arrange_square,
|
||||
'optimal': self.arrange_optimal, # 最优排列方式
|
||||
'horizontal': self.arrange, # 水平排列方式
|
||||
'vertical': partial(self.arrange, vertical=True), # 垂直排列方式
|
||||
'square': self.arrange_square, # 正方形排列方式
|
||||
}
|
||||
|
||||
MAPPING[default]()
|
||||
MAPPING[default]() # 调用默认的排列方式
|
||||
|
||||
def arrange(self, vertical=False):
|
||||
"""Arrange items in a line (horizontally or vertically)."""
|
||||
def arrange(self, vertical=False): # 按指定方式排列选择的项目
|
||||
"""Arrange items in a line (horizontally or vertically).""" # 按指定方式排列选择的项目
|
||||
|
||||
self.cancel_active_modes()
|
||||
self.cancel_active_modes() # 取消所有活动模式,确保没有正在进行的操作干扰
|
||||
|
||||
items = sort_by_filename(self.selectedItems(user_only=True))
|
||||
if len(items) < 2:
|
||||
return
|
||||
items = sort_by_filename(self.selectedItems(user_only=True)) # 获取当前用户选择的项目,并按文件名排序
|
||||
if len(items) < 2:# 如果选择的项目数量小于2
|
||||
return # 直接返回,无需排列
|
||||
|
||||
gap = self.settings.valueOrDefault('Items/arrange_gap')
|
||||
center = self.get_selection_center()
|
||||
positions = []
|
||||
rects = []
|
||||
for item in items:
|
||||
rects.append({
|
||||
'rect': self.itemsBoundingRect(items=[item]),
|
||||
'item': item})
|
||||
gap = self.settings.valueOrDefault('Items/arrange_gap') # 获取项目之间的间距
|
||||
center = self.get_selection_center() # 获取选择项目的中心位置
|
||||
positions = [] # 创建一个空列表,用于存储每个项目的新位置
|
||||
rects = [] # 创建一个空列表,用于存储每个项目的边界矩形和项目本身
|
||||
for item in items: # 遍历选择的项目
|
||||
rects.append({ # 为每个项目创建一个字典,包含项目的边界矩形和项目本身
|
||||
'rect': self.itemsBoundingRect(items=[item]), # 获取项目的边界矩形
|
||||
'item': item}) # 包含项目的边界矩形和项目本身
|
||||
|
||||
if vertical:
|
||||
rects.sort(key=lambda r: r['rect'].topLeft().y())
|
||||
sum_height = sum(map(lambda r: r['rect'].height(), rects))
|
||||
y = round(center.y() - sum_height/2)
|
||||
for rect in rects:
|
||||
positions.append(
|
||||
QtCore.QPointF(
|
||||
round(center.x() - rect['rect'].width()/2), y))
|
||||
y += rect['rect'].height() + gap
|
||||
if vertical: # 如果按垂直方向排列
|
||||
rects.sort(key=lambda r: r['rect'].topLeft().y()) # 按项目的顶部坐标排序
|
||||
sum_height = sum(map(lambda r: r['rect'].height(), rects)) # 计算所有项目的总高度
|
||||
y = round(center.y() - sum_height/2) # 计算垂直方向上的起始位置
|
||||
for rect in rects: # 遍历每个项目
|
||||
positions.append( # 为每个项目计算新的位置
|
||||
QtCore.QPointF( # 计算每个项目的新位置
|
||||
round(center.x() - rect['rect'].width()/2), y)) # 计算每个项目的新位置
|
||||
y += rect['rect'].height() + gap # 更新垂直方向上的位置,考虑项目高度和间距
|
||||
|
||||
else:
|
||||
rects.sort(key=lambda r: r['rect'].topLeft().x())
|
||||
sum_width = sum(map(lambda r: r['rect'].width(), rects))
|
||||
x = round(center.x() - sum_width/2)
|
||||
for rect in rects:
|
||||
positions.append(
|
||||
QtCore.QPointF(
|
||||
x, round(center.y() - rect['rect'].height()/2)))
|
||||
x += rect['rect'].width() + gap
|
||||
else: # 如果按水平方向排列
|
||||
rects.sort(key=lambda r: r['rect'].topLeft().x()) # 按项目的左侧坐标排序
|
||||
sum_width = sum(map(lambda r: r['rect'].width(), rects)) # 计算所有项目的总宽度
|
||||
x = round(center.x() - sum_width/2) # 计算水平方向上的起始位置
|
||||
for rect in rects: # 遍历每个项目
|
||||
positions.append( # 为每个项目计算新的位置
|
||||
QtCore.QPointF( # 计算每个项目的新位置
|
||||
x, round(center.y() - rect['rect'].height()/2))) # 计算每个项目的新位置
|
||||
x += rect['rect'].width() + gap # 更新水平方向上的位置,考虑项目宽度和间距
|
||||
|
||||
self.undo_stack.push(
|
||||
commands.ArrangeItems(self,
|
||||
[r['item'] for r in rects],
|
||||
positions))
|
||||
self.undo_stack.push( # 将排列操作添加到撤销栈中
|
||||
commands.ArrangeItems(self, # 创建一个排列项目的命令对象
|
||||
[r['item'] for r in rects], # 包含所有要排列的项目
|
||||
positions)) # 包含所有项目的新位置
|
||||
|
||||
def arrange_optimal(self):
|
||||
self.cancel_active_modes()
|
||||
def arrange_optimal(self): # 按最优方式排列选择的项目
|
||||
self.cancel_active_modes() # 取消所有活动模式,确保没有正在进行的操作干扰
|
||||
|
||||
items = self.selectedItems(user_only=True)
|
||||
if len(items) < 2:
|
||||
return
|
||||
items = self.selectedItems(user_only=True) # 获取当前用户选择的项目
|
||||
if len(items) < 2: # 如果选择的项目数量小于2
|
||||
return # 直接返回,无需排列
|
||||
|
||||
gap = self.settings.valueOrDefault('Items/arrange_gap')
|
||||
gap = self.settings.valueOrDefault('Items/arrange_gap') # 获取项目之间的间距
|
||||
|
||||
sizes = []
|
||||
for item in items:
|
||||
rect = self.itemsBoundingRect(items=[item])
|
||||
sizes.append((round(rect.width() + gap),
|
||||
round(rect.height() + gap)))
|
||||
sizes = [] # 创建一个空列表,用于存储每个项目的宽度和高度
|
||||
for item in items: # 遍历选择的项目
|
||||
rect = self.itemsBoundingRect(items=[item]) # 获取项目的边界矩形
|
||||
sizes.append((round(rect.width() + gap), # 包含每个项目的宽度和高度
|
||||
round(rect.height() + gap))) # 包含每个项目的宽度和高度
|
||||
|
||||
# The minimal area the items need if they could be packed optimally;
|
||||
# we use this as a starting shape for the packing algorithm
|
||||
min_area = sum(map(lambda s: s[0] * s[1], sizes))
|
||||
width = math.ceil(math.sqrt(min_area))
|
||||
min_area = sum(map(lambda s: s[0] * s[1], sizes)) # 计算所有项目的最小面积
|
||||
width = math.ceil(math.sqrt(min_area)) # 计算最小面积的平方根,向上取整作为初始宽度
|
||||
|
||||
positions = None
|
||||
while not positions:
|
||||
try:
|
||||
positions = rpack.pack(
|
||||
positions = None # 初始化位置列表为None
|
||||
while not positions: # 循环直到成功打包项目
|
||||
try: # 尝试使用当前宽度打包项目
|
||||
positions = rpack.pack(
|
||||
sizes, max_width=width, max_height=width)
|
||||
except rpack.PackingImpossibleError:
|
||||
width = math.ceil(width * 1.2)
|
||||
width = math.ceil(width * 1.2) # 如果打包失败,将宽度增加20%,并向上取整
|
||||
|
||||
# We want the items to center around the selection's center,
|
||||
# not (0, 0)
|
||||
|
|
|
|||
Loading…
Reference in a new issue