Tools to view, edit and create 7dtd world-maps https://chrani.net/map-tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
7.0 KiB

import math
import pathlib
from typing import TYPE_CHECKING
import numpy as np
from PyQt5.QtCore import (
Qt, QSize
)
from PyQt5.QtGui import (
QPixmap, QColor, QImage, QPainter
)
from PyQt5.QtWidgets import (
QLabel, QGraphicsColorizeEffect, QApplication, QMenu, QAction, QWidgetAction, QFileDialog
)
if TYPE_CHECKING:
from world_regions_widget import RegionLabelCollection
class RegionLabel(QLabel):
dimensions = QSize
raw_data_array = np.array
parent_collection = 'RegionLabelCollection'
region_string = str
is_marked = bool
is_region = bool
is_selected = bool
context_menu = QMenu
context_menu_is_shown = bool
adjacent_marked_region_labels = dict
def __init__(self, collection: 'RegionLabelCollection', x=None, y=None, dimensions=QSize(512, 512)):
super(RegionLabel, self).__init__()
self.dimensions = dimensions
pixmap = QPixmap(dimensions)
self.is_marked = False
self.is_region = False
self.context_menu_is_shown = False
self.is_selected = False
self.parent_collection = collection
self.region_string = self.parent_collection.create_region_string_from_grid_index(x=x, y=y)
self.setStatusTip(self.region_string)
pixmap.fill(self.get_color_by_coordinates(x, y))
self.setPixmap(pixmap)
self.setScaledContents(True)
self.init_context_menu()
def set_label_pixmap(self, chunk):
size = (512, 512)
pixmap = QPixmap(*size)
pixmap.fill(QColor("transparent"))
painter = QPainter(pixmap)
painter.drawPixmap(0, 0, *size, QPixmap.fromImage(chunk))
painter.end()
self.setPixmap(pixmap)
""" getter + setter"""
def set_raw_data_array(self, raw_data_array: np.array = None) -> None:
self.raw_data_array = raw_data_array
def mark_as_region(self) -> None:
self.is_region = True
def set_adjacent_marked_region_labels(self, adjacent_marked_region_labels) -> None:
self.adjacent_marked_region_labels = adjacent_marked_region_labels
""" context menu """
def init_context_menu(self):
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.on_context_menu)
menu = QMenu(self)
label = QLabel(self.region_string)
label.setContentsMargins(0, 0, 0, 0)
widget_action = QWidgetAction(self)
widget_action.setDefaultWidget(label)
menu.addAction(widget_action)
menu.addSeparator()
action_save_region = QAction("save region as...", self)
action_save_region.triggered.connect(self.save_region_as)
menu.addAction(action_save_region)
action_replace_region = QAction("replace region with file...", self)
action_replace_region.triggered.connect(self.load_region_from_file)
menu.addAction(action_replace_region)
menu.closeEvent = self.on_context_menu_close
self.context_menu = menu
def on_context_menu(self, point):
modifiers = QApplication.keyboardModifiers()
if modifiers == Qt.ShiftModifier and self.is_region:
self.parent_collection.toggle_open_in_context_menu(self)
self.context_menu.exec_(self.mapToGlobal(point))
def on_context_menu_close(self, point):
self.parent_collection.toggle_open_in_context_menu(self)
""" visual stuff"""
@staticmethod
def get_color_by_coordinates(x=0, y=0) -> QColor:
# if used in a grid, this is basically creating a gradient
return QColor(
int((((x + 1) * 4) + ((y + 1) * 4)) / 2 - 1),
int((((x + 1) * 4) + ((y + 1) * 4)) / 2 - 1),
int((((x + 1) * 4) + ((y + 1) * 4)) / 2 - 1)
)
def update_style_effects(self):
style = ""
if self.is_marked:
for direction in ["top", "right", "bottom", "left"]:
if direction not in self.adjacent_marked_region_labels.keys():
style += "border-{}: 1px solid #aaaaaa; ".format(direction)
else:
style += "border-{}: 0; ".format(direction)
self.setStyleSheet(style)
def update_graphics_effect(self):
effect = QGraphicsColorizeEffect()
if self.context_menu_is_shown:
effect.setColor(QColor(255, 63, 63, 32))
else:
effect.setColor(QColor(255, 255, 255, 16))
self.setGraphicsEffect(effect)
def remove_graphics_effects(self):
self.setGraphicsEffect(None)
""" file operations"""
def save_region_as(self):
options = QFileDialog.Options()
file_name, _ = QFileDialog.getSaveFileName(
self, caption='save region file', filter='RAW files (*.raw)', options=options, directory=self.region_string
)
if file_name:
with open(file_name, 'w+b') as raw_file:
raw_file.write(
bytearray(np.flipud(self.raw_data_array))
)
def load_region_from_file(self):
dialog = QFileDialog()
file_name = QFileDialog.getOpenFileName(
caption='load a raw region', options=dialog.options(), filter="RAW files (*.raw)"
)[0]
if file_name:
length = int(math.sqrt(pathlib.Path(file_name).stat().st_size / 2))
if int(length / 512) > 1:
return False
with open(file_name, 'r') as raw_file:
raw_data_array = np.fromfile(raw_file, dtype=np.uint16)
self.set_raw_data_array(np.flipud(np.reshape(raw_data_array, (length, length))))
index_x, index_y = self.parent_collection.create_grid_index_from_region_string(self.region_string)
offset = int(32 / 2) - int(self.parent_collection.world_regions.regions_per_row / 2)
self.parent_collection.blockshaped_map_data[index_y - offset][index_x - offset] = self.raw_data_array
chunk = QImage(self.raw_data_array.copy(), 512, 512, QImage.Format_Grayscale16)
self.set_label_pixmap(chunk)
""" altering class functions """
def mouse_any_click_event(self, event):
modifiers = QApplication.keyboardModifiers()
if modifiers == Qt.ControlModifier and self.is_region:
if event.buttons() == Qt.LeftButton:
self.parent_collection.toggle_marked(self)
def mousePressEvent(self, event):
self.mouse_any_click_event(event)
super().mousePressEvent(event)
def mouseDoubleClickEvent(self, event):
self.mouse_any_click_event(event)
super().mouseDoubleClickEvent(event)
def enterEvent(self, event) -> None:
self.is_selected = True
self.parent_collection.set_currently_hovered_label(self)
self.parent_collection.trigger_cursor_change(self)
super().enterEvent(event)
def leaveEvent(self, event) -> None:
self.is_selected = False
self.parent_collection.trigger_cursor_change(self)
super().leaveEvent(event)
def wheelEvent(self, event):
self.parent_collection.set_currently_hovered_label(self)