#!/usr/bin/env python3
#
# __init__.py
"""
wxPython GUI for saving icons to files.
"""
#
# Copyright (c) 2019-2021 Dominic Davis-Foster <dominic@davis-foster.co.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
# generated by wxGlade 0.9.0 on Mon Feb 25 13:14:25 2019
#
__author__ = "Dominic Davis-Foster"
__copyright__ = "2019-2020 Dominic Davis-Foster"
__license__ = "GNU General Public License v3 or later (GPLv3+)"
__version__ = "0.1.7"
__email__ = "dominic@davis-foster.co.uk"
# stdlib
import enum
import os
# 3rd party
import wx # type: ignore
__all__ = ["BUILTIN_ICONS", "ART_PROVIDERS", "FileTypesEnum", "BitmapSaverFrame"]
# begin wxGlade: dependencies
# end wxGlade
# begin wxGlade: extracode
# end wxGlade
#: A list of wxPython's builtin icons.
BUILTIN_ICONS = [
"ART_ADD_BOOKMARK",
"ART_CDROM",
"ART_CLOSE",
"ART_COPY",
"ART_CROSS_MARK",
"ART_CUT",
"ART_DELETE",
"ART_DEL_BOOKMARK",
"ART_ERROR",
"ART_EXECUTABLE_FILE",
"ART_FILE_OPEN",
"ART_FILE_SAVE",
"ART_FILE_SAVE_AS",
"ART_FIND",
"ART_FIND_AND_REPLACE",
"ART_FLOPPY",
"ART_FOLDER",
"ART_FOLDER_OPEN",
"ART_GOTO_FIRST",
"ART_GOTO_LAST",
"ART_GO_BACK",
"ART_GO_DIR_UP",
"ART_GO_DOWN",
"ART_GO_FORWARD",
"ART_GO_HOME",
"ART_GO_TO_PARENT",
"ART_GO_UP",
"ART_HARDDISK",
"ART_HELP",
"ART_HELP_BOOK",
"ART_HELP_FOLDER",
"ART_HELP_PAGE",
"ART_HELP_SETTINGS",
"ART_HELP_SIDE_PANEL",
"ART_INFORMATION",
"ART_LIST_VIEW",
"ART_MINUS",
"ART_MISSING_IMAGE",
"ART_NEW",
"ART_NEW_DIR",
"ART_NORMAL_FILE",
"ART_PASTE",
"ART_PLUS",
"ART_PRINT",
"ART_QUESTION",
"ART_QUIT",
"ART_REDO",
"ART_REPORT_VIEW",
"ART_TICK_MARK",
"ART_TIP",
"ART_UNDO",
"ART_WARNING",
]
#: A list of wxPython's art providers.
ART_PROVIDERS = [
"ART_TOOLBAR",
"ART_MENU",
"ART_BUTTON",
"ART_FRAME_ICON",
"ART_CMN_DIALOG",
"ART_HELP_BROWSER",
"ART_MESSAGE_BOX",
"ART_OTHER",
]
[docs]class FileTypesEnum(enum.Enum):
"""
An enumeration for supported filetypes.
"""
# TODO: use autonumber enum for indices
wildcard: str
extension: str
filetype_string: str
ftype: int
value: int
BITMAP_TYPE_BMP = 1, 0, ".bmp", "BMP"
BITMAP_TYPE_ICO = 3, 1, ".ico", "ICO"
BITMAP_TYPE_CUR = 5, 2, ".cur", "CUR"
BITMAP_TYPE_XBM = 7, 3, ".xbm", "XBM"
BITMAP_TYPE_XBM_DATA = 8, 4, ".bmp", "XBM DATA"
BITMAP_TYPE_XPM = 9, 5, ".xpm", "XBM"
BITMAP_TYPE_XPM_DATA = 10, 6, ".xpm", "XPM DATA"
BITMAP_TYPE_TIFF = 11, 7, ".tiff", "TIFF"
BITMAP_TYPE_TIF = 11, 8, ".tiff", "TIFF"
BITMAP_TYPE_GIF = 13, 9, ".gif", "GIF"
BITMAP_TYPE_PNG = 15, 10, ".png", "PNG"
BITMAP_TYPE_JPEG = 17, 11, ".jpg", "JPEG"
BITMAP_TYPE_PNM = 19, 12, ".pnm", "PNM"
BITMAP_TYPE_PCX = 21, 13, ".pcx", "PCX"
BITMAP_TYPE_PICT = 23, 14, ".pict", "PICT"
BITMAP_TYPE_ICON = 25, 15, ".ico", "ICON"
BITMAP_TYPE_ANI = 27, 16, ".ani", "ANI"
BITMAP_TYPE_IFF = 28, 17, ".iff", "IFF"
BITMAP_TYPE_TGA = 29, 18, ".tga", "TGA"
BITMAP_TYPE_MACCURSOR = 30, 19, ".*", "Mac Cursor"
def __init__(self, *vals):
pass
def __new__(cls, ftype, index, extension, filetype_string): # noqa: D102
obj = object.__new__(cls)
# index is canonical value
obj._value_ = index
obj.ftype = ftype
obj.wildcard = f"{filetype_string} files (*{extension})|*{extension}"
obj.extension = extension
obj.filetype_string = filetype_string
return obj
def __int__(self):
return self.ftype
def __repr__(self):
return f'<{self.__class__.__qualname__}.{self._name_}: {f"{self.value}, {self.wildcard}, ftype={self.ftype}"}>'
[docs]class BitmapSaverFrame(wx.Frame):
"""
Frame for configuring the bitmap icon to be saved.
:param parent: The parent window. This may be, and often is, :py:obj:`None`.
If it is not :py:obj:`None`, the frame will be minimized when its parent is minimized and restored
when it is restored (although it will still be possible to minimize and restore just this frame itself).
:param id: The window identifier.
:param title: The caption to be displayed on the frame's title bar.
:param pos: The window position. The value :py:obj:`wx.DefaultPosition` indicates a default position,
chosen by either the windowing system or wxWidgets, depending on the platform.
:param size: The window size. The value :py:obj:`wx.DefaultSize` indicates a default size,
chosen by either the windowing system or wxWidgets, depending on the platform.
:param style: The `window style <https://docs.wxpython.org/wx.Frame.html#styles-window-styles>`_.
:param name: The name of the frame. This parameter is used to associate a name with the frame.
"""
def __init__(
self,
parent: wx.Window,
id: int = wx.ID_ANY, # noqa: A002 # pylint: disable=redefined-builtin
title: str = '',
pos: wx.Point = wx.DefaultPosition,
size: wx.Size = wx.DefaultSize,
style: str = wx.DEFAULT_FRAME_STYLE,
name: str = wx.FrameNameStr,
):
args = (parent, id)
kwds = dict(
title=title,
pos=pos,
size=size,
style=style,
name=name,
)
# begin wxGlade: BitmapSaverFrame.__init__
kwds["style"] = kwds.get(
"style", 0
) | wx.CAPTION | wx.CLIP_CHILDREN | wx.CLOSE_BOX | wx.MINIMIZE_BOX | wx.SYSTEM_MENU
wx.Frame.__init__(self, *args, **kwds)
self.SetSize((467, 577))
self.SetMinSize((467, 577))
self.SetMaxSize((467, 577))
self.SetSize((467, 577))
self.size_spin_ctrl = wx.SpinCtrl(self, wx.ID_ANY, "16", min=1, max=512)
self.icon_list_box = wx.ListBox(self, wx.ID_ANY, choices=[''])
self.provider_list_box = wx.ListBox(self, wx.ID_ANY, choices=[''])
self.filetype_list_box = wx.ListBox(self, wx.ID_ANY, choices=[''])
self.close_button = wx.Button(self, wx.ID_ANY, "Close")
self.save_button = wx.Button(self, wx.ID_ANY, "Save")
self.__set_properties()
self.__do_layout()
self.Bind(wx.EVT_LISTBOX, self.update_preview, self.icon_list_box)
self.Bind(wx.EVT_LISTBOX, self.update_preview, self.provider_list_box)
self.Bind(wx.EVT_LISTBOX, self.update_preview, self.filetype_list_box)
self.Bind(wx.EVT_BUTTON, self.on_close, self.close_button)
self.Bind(wx.EVT_BUTTON, self.on_save, self.save_button)
# end wxGlade
self.Bind(wx.EVT_SPINCTRL, self.update_preview, self.size_spin_ctrl)
self.size_spin_ctrl.SetValue("16")
self.size_spin_ctrl.SetMin(1)
self.size_spin_ctrl.SetMax(512)
# style=wx.TE_NO_VSCROLL | wx.TE_PROCESS_ENTER)
self.size: int = 16
self.icon: bytes = b''
self.provider: bytes = b''
self.filetype: FileTypesEnum = FileTypesEnum(0)
self.filename: str = ''
self.icon_list_box.Clear()
self.icon_list_box.AppendItems(BUILTIN_ICONS)
self.icon_list_box.SetSelection(0)
self.provider_list_box.Clear()
self.provider_list_box.AppendItems(ART_PROVIDERS)
self.provider_list_box.SetSelection(0)
self.filetype_list_box.Clear()
self.filetype_list_box.AppendItems([member.name for member in FileTypesEnum])
self.filetype_list_box.SetSelection(0)
self.update_preview()
def __set_properties(self) -> None:
# begin wxGlade: BitmapSaverFrame.__set_properties
self.SetTitle("wxIconSaver")
# end wxGlade
_icon = wx.NullIcon
_icon.CopyFromBitmap(wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_BUTTON, wx.Size(64, 64)))
self.SetIcon(_icon)
def __do_layout(self) -> None:
# begin wxGlade: BitmapSaverFrame.__do_layout
sizer_1 = wx.BoxSizer(wx.VERTICAL)
sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
sizer_4 = wx.BoxSizer(wx.VERTICAL)
sizer_3 = wx.BoxSizer(wx.VERTICAL)
size_sizer = wx.BoxSizer(wx.HORIZONTAL)
size_label = wx.StaticText(self, wx.ID_ANY, "Size")
size_sizer.Add(size_label, 0, wx.ALIGN_CENTER | wx.ALL, 10)
size_sizer.Add(self.size_spin_ctrl, 0, wx.ALIGN_CENTER, 0)
sizer_1.Add(size_sizer, 1, wx.EXPAND, 0)
icon_label = wx.StaticText(self, wx.ID_ANY, "Icon")
sizer_3.Add(icon_label, 0, wx.LEFT | wx.RIGHT | wx.TOP, 10)
sizer_3.Add(self.icon_list_box, 0, wx.BOTTOM | wx.LEFT | wx.RIGHT, 10)
provider_label = wx.StaticText(self, wx.ID_ANY, "Provider")
sizer_3.Add(provider_label, 0, wx.LEFT | wx.RIGHT | wx.TOP, 10)
sizer_3.Add(self.provider_list_box, 0, wx.BOTTOM | wx.LEFT | wx.RIGHT, 10)
sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
filetype_label = wx.StaticText(self, wx.ID_ANY, "Filetype")
sizer_4.Add(filetype_label, 0, wx.LEFT | wx.RIGHT | wx.TOP, 10)
sizer_4.Add(self.filetype_list_box, 0, wx.BOTTOM | wx.LEFT | wx.RIGHT, 10)
preview_label = wx.StaticText(self, wx.ID_ANY, "Preview")
sizer_4.Add(preview_label, 0, wx.LEFT | wx.RIGHT | wx.TOP, 10)
preview_bitmap = wx.StaticBitmap(self, wx.ID_ANY, wx.NullBitmap)
sizer_4.Add(preview_bitmap, 0, 0, 0)
sizer_2.Add(sizer_4, 1, wx.EXPAND, 0)
sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
sizer_5.AddStretchSpacer()
sizer_5.Add(self.close_button, 0, wx.ALIGN_CENTER | wx.LEFT, 100)
sizer_5.Add(self.save_button, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, 5)
sizer_5.AddStretchSpacer()
sizer_1.Add(sizer_5, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
self.Layout()
# end wxGlade
# sizer_5.AddStretchSpacer()
self.preview_bitmap = preview_bitmap
[docs] def on_close(self, *events) -> None: # wxGlade: BitmapSaverFrame.<event_handler>
"""
Close the window.
"""
self.Close()
[docs] def on_save(self, event: wx.Event) -> None: # wxGlade: BitmapSaverFrame.<event_handler>
"""
Save the icon with the current settings.
:param event:
"""
self.update_preview(self, event)
# from https://wxpython.org/Phoenix/docs/html/wx.FileDialog.html
filedlg = wx.FileDialog(
self,
f"Save {self.filetype.filetype_string} file",
wildcard=self.filetype.wildcard,
style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
)
if filedlg.ShowModal() == wx.ID_CANCEL:
return # the user changed their mind
# save the current contents in the file
self.filename = filedlg.GetPath()
if os.path.splitext(self.filename)[-1] != self.filetype.extension:
self.filename = self.filename + self.filetype.extension
wx.ArtProvider.GetBitmap(
self.icon,
self.provider,
wx.Size(self.size, self.size),
).SaveFile(self.filename, self.filetype.ftype)
filedlg.Destroy()
event.Skip()
[docs] def update_preview(self, *events) -> None: # wxGlade: BitmapSaverFrame.<event_handler>
"""
Update the preview image.
"""
self.size = int(self.size_spin_ctrl.GetValue())
self.icon = bytes(f"wx{self.icon_list_box.GetString(self.icon_list_box.GetSelection())}", "utf-8")
self.provider = bytes(
f"wx{self.provider_list_box.GetString(self.provider_list_box.GetSelection())}_C",
"utf-8",
)
filetype_raw_index = self.filetype_list_box.GetSelection()
self.filetype = FileTypesEnum(filetype_raw_index)
self.preview_bitmap.SetBitmap(
wx.ArtProvider.GetBitmap(self.icon, self.provider, wx.Size(self.size, self.size))
)
# end of class BitmapSaverFrame