Skip to content

Commit

Permalink
Merge pull request #49 from Amulet-Team/operation-rewrite
Browse files Browse the repository at this point in the history
Rewrite of operations and rewrite of UI to support that
  • Loading branch information
gentlegiantJGC authored Jun 9, 2020
2 parents a0b729f + 6b8e1a2 commit fd25e05
Show file tree
Hide file tree
Showing 93 changed files with 2,880 additions and 2,235 deletions.
88 changes: 58 additions & 30 deletions amulet_map_editor/amulet_ui.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import wx
import wx.lib.inspection
from wx.lib.agw import flatnotebook
import os
from typing import Dict
from typing import Dict, Union
import webbrowser

from amulet.api.errors import LoaderNoneMatched
from amulet_map_editor.amulet_wx.world_select import WorldSelectDialog
from amulet_map_editor.amulet_wx.ui.select_world import WorldSelectDialog
from amulet_map_editor import lang, version, log, IMG_DIR
from amulet_map_editor.programs import WorldManagerUI
from amulet_map_editor.amulet_wx import simple
from amulet_map_editor.programs import BaseWorldUI

NOTEBOOK_MENU_STYLE = flatnotebook.FNB_NO_X_BUTTON | flatnotebook.FNB_HIDE_ON_SINGLE_TAB | flatnotebook.FNB_NAV_BUTTONS_WHEN_NEEDED
NOTEBOOK_STYLE = NOTEBOOK_MENU_STYLE | flatnotebook.FNB_X_ON_TAB

CLOSEABLE_PAGE_TYPE = Union[WorldManagerUI]


class AmuletMainWindow(wx.Frame):
def __init__(self, parent):
Expand All @@ -35,12 +41,15 @@ def __init__(self, parent):
icon.CopyFromBitmap(wx.Bitmap(os.path.join(os.path.dirname(__file__), 'img', 'icon64.png'), wx.BITMAP_TYPE_ANY))
self.SetIcon(icon)

self._open_worlds: Dict[str, BaseWorldUI] = {}
self._open_worlds: Dict[str, CLOSEABLE_PAGE_TYPE] = {}

self.world_tab_holder = wx.Notebook(
self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0
self.world_tab_holder = flatnotebook.FlatNotebook(
self,
agwStyle=NOTEBOOK_MENU_STYLE
)

self.world_tab_holder.Bind(flatnotebook.EVT_FLATNOTEBOOK_PAGE_CLOSING, self._on_page_close)

self._main_menu = AmuletMainMenu(self.world_tab_holder, self._open_world)

self._last_page: BaseWorldUI = self._main_menu
Expand All @@ -50,7 +59,7 @@ def __init__(self, parent):
lang.get('main_menu')
)

self.Bind(wx.EVT_CLOSE, self._on_close)
self.Bind(wx.EVT_CLOSE, self._on_close_app)
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self._page_change)

self.Show()
Expand Down Expand Up @@ -104,28 +113,32 @@ def _disable_enable(self):
if self._last_page is not None:
self._last_page.disable()
self._last_page: BaseWorldUI = current
if self._last_page is self._main_menu:
self.world_tab_holder.SetAGWWindowStyleFlag(NOTEBOOK_MENU_STYLE)
else:
self.world_tab_holder.SetAGWWindowStyleFlag(NOTEBOOK_STYLE)
if self._last_page is not None:
self._last_page.enable()

def _add_world_tab(self, obj, obj_name):
# TODO: find a way for the tab to be optionally closeable
self.world_tab_holder.AddPage(obj, obj_name, True)
self._disable_enable()

def _show_open_world(self):
select_world = WorldSelectDialog(self, self._open_world)
select_world.ShowModal()
select_world.Destroy()

def _open_world(self, path: str):
"""Open a world panel add add it to the notebook"""
if path in self._open_worlds:
self.world_tab_holder.SetSelection(
self.world_tab_holder.FindPage(self._open_worlds[path])
self.world_tab_holder.GetPageIndex(self._open_worlds[path])
)
self._disable_enable()
else:
try:
world = WorldManagerUI(self.world_tab_holder, path)
world = WorldManagerUI(self.world_tab_holder, path, lambda: self.close_world(path))
except LoaderNoneMatched as e:
log.error(e)
wx.MessageBox(str(e))
Expand All @@ -137,22 +150,30 @@ def close_world(self, path: str):
"""Close a given world and remove it from the notebook"""
if path in self._open_worlds:
world = self._open_worlds[path]
world.disable()
world.close()
self.world_tab_holder.DeletePage(
self.world_tab_holder.FindPage(world)
self.world_tab_holder.GetPageIndex(world)
)
del self._open_worlds[path]
self._last_page: BaseWorldUI = self.world_tab_holder.GetCurrentPage()
if self._last_page is not None:
self._last_page.enable()

def _on_close(self, evt):
def _on_page_close(self, evt: flatnotebook.EVT_FLATNOTEBOOK_PAGE_CLOSING):
page: CLOSEABLE_PAGE_TYPE = self.world_tab_holder.GetCurrentPage()
if page is not self._main_menu:
if page.is_closeable():
path = page.path
page.disable()
page.close()
self._last_page = None
del self._open_worlds[path]
else:
evt.Veto()

def _on_close_app(self, evt):
close = True
for path, world in list(self._open_worlds.items()):
if world.is_closeable():
for path, page in list(self._open_worlds.items()):
page: CLOSEABLE_PAGE_TYPE
if page.is_closeable():
self.close_world(path)
else:
log.info(f"{page.world_name} cannot be closed.")
close = False
if close:
evt.Skip()
Expand All @@ -162,14 +183,17 @@ def _on_close(self, evt):
)


class AmuletMainMenu(simple.SimplePanel, BaseWorldUI):
def __init__(self, parent, open_world):
class AmuletMainMenu(wx.Panel, BaseWorldUI):
def __init__(self, parent: wx.Window, open_world):
super(AmuletMainMenu, self).__init__(
parent
)
sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(sizer)
sizer.AddStretchSpacer(1)
self._open_world_callback = open_world
sizer = wx.BoxSizer()
self.add_object(sizer, 0, wx.ALL | wx.CENTER)
name_sizer = wx.BoxSizer()
sizer.Add(name_sizer, 0, wx.CENTER)
img = wx.Image(
os.path.join(IMG_DIR, 'icon128.png'),
wx.BITMAP_TYPE_ANY
Expand All @@ -189,33 +213,37 @@ def __init__(self, parent, open_world):
(0, 0),
(64, 64)
)
sizer.Add(icon, flag=wx.CENTER)
icon2.Bind(wx.EVT_LEFT_DOWN, lambda evt: wx.lib.inspection.InspectionTool().Show())
name_sizer.Add(icon, flag=wx.CENTER)

amulet_converter = wx.StaticText(self, label='Amulet')
amulet_converter.SetFont(wx.Font(40, wx.DECORATIVE, wx.NORMAL, wx.NORMAL))
sizer.Add(
name_sizer.Add(
amulet_converter, flag=wx.CENTER
)
sizer.Add(icon2, flag=wx.CENTER)
name_sizer.Add(icon2, flag=wx.CENTER)
button_font = wx.Font(20, wx.DECORATIVE, wx.NORMAL, wx.NORMAL)
self._open_world_button = wx.Button(self, label='Open World', size=(400, 70))
self._open_world_button.SetFont(button_font)
self._open_world_button.Bind(wx.EVT_BUTTON, self._show_world_select)
self.add_object(self._open_world_button, 0, wx.ALL|wx.CENTER)
sizer.Add(self._open_world_button, 0, wx.ALL | wx.CENTER, 5)

self._help_button = wx.Button(self, label='Help', size=(400, 70))
self._help_button.SetFont(button_font)
self._help_button.Bind(wx.EVT_BUTTON, self._documentation)
self.add_object(self._help_button, 0, wx.ALL | wx.CENTER)
sizer.Add(self._help_button, 0, wx.ALL | wx.CENTER, 5)

self._help_button = wx.Button(self, label='Amulet Discord', size=(400, 70))
self._help_button.SetFont(button_font)
self._help_button.Bind(wx.EVT_BUTTON, self._discord)
self.add_object(self._help_button, 0, wx.ALL | wx.CENTER)
sizer.Add(self._help_button, 0, wx.ALL | wx.CENTER, 5)

sizer.AddStretchSpacer(2)

def _show_world_select(self, evt):
select_world = WorldSelectDialog(self, self._open_world_callback)
select_world.ShowModal()
select_world.Destroy()

def _documentation(self, evt):
webbrowser.open('https://github.com/Amulet-Team/Amulet-Map-Editor/blob/master/amulet_map_editor/readme.md')
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
from amulet_map_editor.amulet_wx.simple import SimplePanel, SimpleText, SimpleChoice, SimpleChoiceAny
from amulet_map_editor.amulet_wx.ui.simple import SimpleChoice, SimpleChoiceAny
import wx
import PyMCTranslate
import amulet_nbt
from typing import Tuple, List, Optional, Type, Dict, Any
from amulet.api.block import Block


class BaseSelect(SimplePanel):
def __init__(self, parent):
super().__init__(parent)
class BaseSelect(wx.Panel):
def __init__(self, parent, **kwargs):
super().__init__(parent, **kwargs)
self._sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self._sizer)

def _add_ui_element(self, label: str, obj: Type[wx.Control], **kwargs) -> Any:
panel = SimplePanel(self, wx.HORIZONTAL)
self.add_object(panel, 0)
text = SimpleText(panel, label)
panel.add_object(text, 0, wx.CENTER | wx.ALL)
wx_obj = obj(panel, **kwargs)
panel.add_object(wx_obj, 0, wx.CENTER | wx.ALL)
sizer = wx.BoxSizer(wx.HORIZONTAL)
self._sizer.Add(sizer, 0, wx.ALIGN_CENTER_HORIZONTAL)
text = wx.StaticText(self, label=label)
sizer.Add(text, 0, wx.CENTER | wx.LEFT | wx.RIGHT, 5)
wx_obj = obj(self, **kwargs)
sizer.Add(wx_obj, 0, wx.CENTER | wx.BOTTOM | wx.TOP | wx.RIGHT, 5)
return wx_obj


Expand All @@ -31,7 +33,7 @@ def __init__(
allowed_platforms: Tuple[str, ...] = None,
**kwargs
):
super().__init__(parent)
super().__init__(parent, **kwargs)
self._translation_manager = translation_manager
self._allow_universal = allow_universal
self._allow_vanilla = allow_vanilla
Expand Down Expand Up @@ -269,6 +271,7 @@ def __init__(
base_name: str = None,
properties: Dict[str, str] = None,
wildcard: bool = False,
properties_style=0,
**kwargs
):
super().__init__(
Expand All @@ -281,11 +284,13 @@ def __init__(
base_name,
**kwargs
)
self._properties: List[SimplePanel] = []
self._properties: Dict[str, SimpleChoice] = {}
self._wildcard = wildcard
self._base_name_list.Bind(wx.EVT_CHOICE, self._on_base_name_change)
self._properties_panel: Optional[SimplePanel] = SimplePanel(self, wx.VERTICAL)
self.add_object(self._properties_panel, 0)
self._properties_panel: wx.Panel = wx.Panel(self, wx.VERTICAL, style=properties_style)
properties_sizer = wx.BoxSizer(wx.VERTICAL)
self._properties_panel.SetSizer(properties_sizer)
self._sizer.Add(self._properties_panel, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM, 5)
self._set_properties(properties)

@property
Expand All @@ -295,8 +300,8 @@ def options(self) -> Tuple[str, Tuple[int, int, int], bool, str, str, Dict[str,
@property
def properties(self) -> Dict[str, str]:
return {
prop.GetChildren()[0].GetLabel(): prop.GetChildren()[1].GetString(prop.GetChildren()[1].GetSelection())
for prop in self._properties
property_name: ui.GetString(ui.GetSelection())
for property_name, ui in self._properties.items()
}

@property
Expand All @@ -311,19 +316,20 @@ def block(self) -> Block:
)

def _clear_properties(self):
for prop in self._properties:
prop.Destroy()
for child in self._properties_panel.GetChildren():
child.Destroy()
self._properties.clear()
self._properties_panel.Layout()

def _add_property(self, property_name: str, property_values: List[str], default: str = None):
prop_panel = SimplePanel(self._properties_panel, wx.HORIZONTAL)
self._properties.append(prop_panel)
self._properties_panel.add_object(prop_panel, 0)
name_text = SimpleText(prop_panel, property_name)
prop_panel.add_object(name_text, 0, wx.CENTER | wx.ALL)
name_list = SimpleChoice(prop_panel)
prop_panel.add_object(name_list, 0, wx.CENTER | wx.ALL)
sizer = wx.BoxSizer(wx.HORIZONTAL)
self._properties_panel.GetSizer().Add(sizer, 0, wx.ALL, 5)
name_text = wx.StaticText(self._properties_panel, label=property_name)
sizer.Add(name_text, 0, wx.CENTER | wx.RIGHT, 5)
name_list = SimpleChoice(self._properties_panel)
sizer.Add(name_list, 0, wx.CENTER, 5)

self._properties[property_name] = name_list

if self._wildcard:
property_values.insert(0, "*")
Expand All @@ -349,6 +355,8 @@ def _set_properties(self, properties: Dict[str, str] = None):
if 'properties' in specification:
for prop, options in specification['properties'].items():
self._add_property(prop, options, properties.get(prop, None))
self.Fit()
self.Layout()
self.GetTopLevelParent().Fit()
self.SetMinSize(self.GetSizer().CalcMin())
parent = self.GetParent() # there may be a better way to do this
while parent is not None:
parent.Layout()
parent = parent.GetParent()
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import List, Dict, Tuple, Callable, TYPE_CHECKING
from amulet_map_editor import lang, CONFIG
from amulet import world_interface
from amulet_map_editor.amulet_wx import simple
from amulet_map_editor.amulet_wx.ui import simple
from amulet_map_editor import log

if TYPE_CHECKING:
Expand Down Expand Up @@ -281,7 +281,7 @@ def __init__(self, parent, open_world_callback):
wx.HORIZONTAL
)
self._open_world_callback = open_world_callback
self.add_object(WorldSelectUI(self, self._update_recent), 2, wx.ALL | wx.EXPAND)
self.add_object(WorldSelectUI(self, self._update_recent), 1, wx.ALL | wx.EXPAND)
self._recent_worlds = RecentWorldUI(self, self._update_recent)
self.add_object(self._recent_worlds, 1, wx.EXPAND)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
"""A collection of classes for wx objects to abstract away
the repeated code and make working with wx a bit more simple."""

import wx
from wx.lib.scrolledpanel import ScrolledPanel
from typing import Iterable, Union, Any, List, Optional, Sequence, Dict


class SimpleSizer:
def __init__(self, sizer_dir=wx.VERTICAL):
self.sizer = wx.BoxSizer(sizer_dir)
self._sizer = self.sizer = wx.BoxSizer(sizer_dir)

def add_object(self, obj, space=1, options=wx.ALL):
self.sizer.Add(
Expand All @@ -31,6 +34,7 @@ def __init__(self, parent: wx.Window, sizer_dir=wx.VERTICAL):


class SimpleScrollablePanel(ScrolledPanel, SimpleSizer):
"""A scrolled panel that automatically sets itself up."""
def __init__(self, parent: wx.Window, sizer_dir=wx.VERTICAL, **kwargs):
ScrolledPanel.__init__(
self,
Expand All @@ -43,19 +47,8 @@ def __init__(self, parent: wx.Window, sizer_dir=wx.VERTICAL, **kwargs):
self.SetAutoLayout(1)


class SimpleText(wx.StaticText):
def __init__(self, parent: wx.Window, text):
super().__init__(
parent,
wx.ID_ANY,
text,
wx.DefaultPosition,
wx.DefaultSize,
0
)


class SimpleChoice(wx.Choice):
"""A wrapper for wx.Choice that sets up the UI for you."""
def __init__(self, parent: wx.Window, choices: Sequence[str] = (), default: Optional[str] = None):
super().__init__(
parent,
Expand All @@ -75,6 +68,7 @@ def GetCurrentString(self) -> str:


class SimpleChoiceAny(wx.Choice):
"""An extension for wx.Choice that enables showing and returning objects that are not strings."""
def __init__(self, parent: wx.Window, sort=True, reverse=False):
super().__init__(
parent
Expand Down Expand Up @@ -127,6 +121,7 @@ def GetAny(self) -> Optional[Any]:


class SimpleDialog(wx.Dialog):
"""A dialog with ok and cancel buttons set up."""
def __init__(self, parent: wx.Window, title, sizer_dir=wx.VERTICAL):
wx.Dialog.__init__(
self,
Expand Down
File renamed without changes.
Loading

0 comments on commit fd25e05

Please sign in to comment.