Source code for wolfhece.PyPalette._gui

"""
Author: HECE - University of Liege, Pierre Archambeau
Date: 2024

Copyright (c) 2024 University of Liege. All rights reserved.

This script and its content are protected by copyright law. Unauthorized
copying or distribution of this file, via any medium, is strictly prohibited.
"""

import wx
import logging

from ..PyTranslate import _
from ..CpGrid import CpGrid
from ._model import wolfpaletteModel

import numpy as np


[docs] class wolfpalette(wolfpaletteModel, wx.Frame): """ Color palette with wxPython GUI support. Inherits all data/computation logic from :class:`wolfpaletteModel` and adds wx.Frame initialization, dialog-based file I/O, and CpGrid integration. """ def __init__(self, parent=None, title=_('Colormap'), w=100, h=500, nseg=1024): wolfpaletteModel.__init__(self, nseg=nseg)
[docs] self.wx_exists = wx.App.Get() is not None
# Call to initialize a general frame if (self.wx_exists): wx.Frame.__init__(self, parent, title=title, size=(w, h), style=wx.DEFAULT_FRAME_STYLE) # --------------------------------------------------------------- # Overrides with wx dialog support # ---------------------------------------------------------------
[docs] def distribute_values(self, minval: float = -99999, maxval: float = -99999, step=0, wx_permitted=True): """ Distribution of the palette values :param minval: minimum value :param maxval: maximum value :param step: distribution step :param wx_permitted: if True and wx app exists, show dialogs for missing values If the step is provided, it takes precedence over the maximum value. """ if self.wx_exists and wx_permitted: if minval == -99999: dlg = wx.TextEntryDialog(None, _('Minimum value'), value=str(self.values[0])) ret = dlg.ShowModal() try: self.values[0] = float(dlg.GetValue()) except: logging.warning('Bad value for minimum - No change') dlg.Destroy() else: self.values[0] = minval if maxval == -99999 and step == 0: dlg = wx.MessageDialog(None, _('Would you like to set the incremental step value ?'), style=wx.YES_NO | wx.YES_DEFAULT) ret = dlg.ShowModal() dlg.Destroy if ret == wx.ID_YES: dlg = wx.TextEntryDialog(None, _('Step value'), value='1') ret = dlg.ShowModal() try: step = float(dlg.GetValue()) except: logging.warning('Bad value for step - using default value 0.1 m') step = 0.1 dlg.Destroy() else: dlg = wx.TextEntryDialog(None, _('Maximum value'), value=str(self.values[-1])) ret = dlg.ShowModal() try: self.values[-1] = float(dlg.GetValue()) except: logging.warning('Bad value for maximum - using min value + 1 m') self.values[-1] = self.values[0] + 1. dlg.Destroy() elif maxval != -99999: self.values[-1] = maxval # Perform the computation (same as model) if step == 0: self.values = np.linspace(self.values[0], self.values[-1], num=self.nb, endpoint=True, dtype=np.float64)[0:self.nb] else: self.values = np.arange(self.values[0], self.values[0]+(self.nb)*step, step, dtype=np.float64)[0:self.nb] self.fill_segmentdata() else: super().distribute_values(minval=minval, maxval=maxval, step=step)
[docs] def export_image(self, fn='', h_or_v=None, figax=None): """ Export image from colormap — with wx.FileDialog fallback when fn is empty. """ if fn == '' and self.wx_exists: file = wx.FileDialog(None, "Choose .pal file", wildcard="png (*.png)|*.png|all (*.*)|*.*", style=wx.FD_SAVE) if file.ShowModal() == wx.ID_CANCEL: return else: # Retrieve the filename with path fn = file.GetPath() if h_or_v is None: h_or_v = '' return super().export_image(fn=fn, h_or_v=h_or_v, figax=figax)
[docs] def readfile(self, *args): """ Read the palette from a WOLF .pal file — with wx.FileDialog when no path given. """ if len(args) == 0: if self.wx_exists: # open a dialog box file = wx.FileDialog(None, "Choose .pal file", wildcard="pal (*.pal)|*.pal|all (*.*)|*.*") if file.ShowModal() == wx.ID_CANCEL: file.Destroy() return else: # retrieve the filename with path args = (file.GetPath(),) file.Destroy() else: return super().readfile(*args)
[docs] def savefile(self, *args): """Save the palette to a WOLF .pal file — with wx.FileDialog when no path given.""" if len(args) == 0: if self.wx_exists: # ouverture d'une boîte de dialogue file = wx.FileDialog(None, "Choose .pal file", wildcard="pal (*.pal)|*.pal|all (*.*)|*.*", style=wx.FD_SAVE) if file.ShowModal() == wx.ID_CANCEL: return else: # récupération du nom de fichier avec chemin d'accès args = (file.GetPath(),) else: return super().savefile(*args)
# --------------------------------------------------------------- # wx-specific lookup methods (return wx.Colour) # ---------------------------------------------------------------
[docs] def lookupcolor(self, x): if x < self.values[0]: return wx.Colour(self.colormin) if x > self.values[-1]: return wx.Colour(self.colormax) rgba = self.lookupcolor_rgba(x) return wx.Colour(*rgba)
[docs] def lookupcolorflt(self, x): if x < self.values[0]: return wx.Colour(self.colormin) if x > self.values[-1]: return wx.Colour(self.colormax) # Delegate to model for interpolation (returns list) return super().lookupcolorflt(x)
[docs] def lookupcolorrgb(self, x): if x < self.values[0]: return wx.Colour(self.colormin) if x > self.values[-1]: return wx.Colour(self.colormax) # Delegate to model for interpolation (returns tuple) return super().lookupcolorrgb(x)
# --------------------------------------------------------------- # CpGrid integration (wx-only) # ---------------------------------------------------------------
[docs] def fillgrid(self, gridto: CpGrid): """ Fill a grid with the palette values """ gridto.SetColLabelValue(0, 'Value') gridto.SetColLabelValue(1, 'R') gridto.SetColLabelValue(2, 'G') gridto.SetColLabelValue(3, 'B') nb = gridto.GetNumberRows() if len(self.values)-nb > 0: gridto.AppendRows(len(self.values)-nb) k = 0 for curv, rgba in zip(self.values, self.colors): gridto.SetCellValue(k, 0, str(curv)) gridto.SetCellValue(k, 1, str(rgba[0])) gridto.SetCellValue(k, 2, str(rgba[1])) gridto.SetCellValue(k, 3, str(rgba[2])) k += 1 nb = gridto.GetNumberRows() while k < nb: gridto.SetCellValue(k, 0, '') gridto.SetCellValue(k, 1, '') gridto.SetCellValue(k, 2, '') gridto.SetCellValue(k, 3, '') k += 1
[docs] def updatefromgrid(self, gridfrom: CpGrid): """ Update the palette based on a grid """ nbl = gridfrom.GetNumberRows() notnull = 0 for i in range(nbl): if gridfrom.GetCellValue(i, 0) != '': notnull += 1 else: break if notnull < self.nb: self.nb = notnull self.values = self.values[0:notnull] self.colors = self.colors[0:notnull, :] else: self.nb = notnull oldvalues = self.values oldcolors = self.colors self.values = np.zeros(self.nb, dtype=np.float64) self.colors = np.zeros((self.nb, 4), dtype=int) self.values[0:len(oldvalues)] = oldvalues self.colors[0:len(oldcolors), :] = oldcolors update = False for k in range(self.nb): update = update or self.values[k] != float(gridfrom.GetCellValue(k, 0)) update = update or self.colors[k, 0] != float(gridfrom.GetCellValue(k, 1)) update = update or self.colors[k, 1] != float(gridfrom.GetCellValue(k, 2)) update = update or self.colors[k, 2] != float(gridfrom.GetCellValue(k, 3)) self.values[k] = float(gridfrom.GetCellValue(k, 0)) self.colors[k, 0] = int(gridfrom.GetCellValue(k, 1)) self.colors[k, 1] = int(gridfrom.GetCellValue(k, 2)) self.colors[k, 2] = int(gridfrom.GetCellValue(k, 3)) self.fill_segmentdata() return update