Various bugfixes & usability improvements.

1)  Assets window: adds clear list context menu item.
2)  Assets window: allow deleting multiple selected items.
3)  Assets window: fix list view cursor key navigation.
4)  Backend: correctly blend transparent background cursor cells with canvas character cells.
5)  Backend: correctly determine cell size & set font size.
6)  Backend: correctly unmask cursor.
7)  Backend: disable font anti-aliasing on Windows.
8)  Backend: render transparent background cells as RGBA #303030FF.
9)  Canvas window: adds <F1> accelerator for `View melp?' menu item.
10) Canvas window: implement {dockable,floating} toolbars w/ wx' AUI framework.
11) Canvas window: separate tools toolbar from edit commands toolbar & dock both on right-hand side alongside each other.
12) Flip horizontally tool: flip characters, including some Unicode symbols.
13) Flip vertically tool: flip additional Unicode symbols.
14) Text tool: don't process keyboard events w/ either of <{Alt,AltGr,Ctrl}> modifiers.

assets/images/roar.png: updated.
This commit is contained in:
Lucio Andrés Illanes Albornoz 2019-09-27 20:17:39 +02:00
parent c279086c57
commit d5935dfbba
14 changed files with 152 additions and 99 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -19,10 +19,10 @@
Release roadmap: Release roadmap:
1) {copy,cut,delete,insert from,paste}, edit asset in new canvas, import from {canvas,object} 1) {copy,cut,delete,insert from,paste}, edit asset in new canvas, import from {canvas,object}
2) operators: crop, scale, shift, slice 2) reimplement cursor unmasking w/ simple list of points
3) tools: unicode block elements 3) operators: crop, scale, shift, slice
4) floating/dockable toolbar https://wxpython.org/Phoenix/docs/html/wx.aui.AuiManager.html 4) auto{load,save} & {backup,restore}
5) reimplement cursor unmasking w/ simple list of points 5) tools: unicode block elements
6) auto{load,save} & {backup,restore} 6) bugs: a) undock all toolbars & resize window b) increase cell size, scroll down
vim:ff=dos tw=0 vim:ff=dos tw=0

View File

@ -12,6 +12,7 @@ Global hotkeys:
<Ctrl> S Save canvas as mIRC art file <Ctrl> S Save canvas as mIRC art file
<Ctrl> X Exit <Ctrl> X Exit
<Ctrl> Y, Z Redo, undo last action <Ctrl> Y, Z Redo, undo last action
<F1> View melp?
<Shift> <Pause> Break into Python debugger <Shift> <Pause> Break into Python debugger
Canvas hotkeys: Canvas hotkeys:

View File

@ -83,7 +83,7 @@ class GuiCanvasWxBackend():
def _initBrushesAndPens(self): def _initBrushesAndPens(self):
self._brushes, self._brushesBlend, self._lastBrush, self._lastPen, self._pens, self._pensBlend = [], {}, None, None, [], {} self._brushes, self._brushesBlend, self._lastBrush, self._lastPen, self._pens, self._pensBlend = [], {}, None, None, [], {}
self._brushAlpha, self._penAlpha = wx.Brush(wx.Colour(Colours[14][:4]), wx.BRUSHSTYLE_SOLID), wx.Pen(wx.Colour(Colours[14][:4]), 1) self._brushAlpha, self._penAlpha = wx.Brush(wx.Colour(48, 48, 48, 255), wx.BRUSHSTYLE_SOLID), wx.Pen(wx.Colour(48, 48, 48, 255), 1)
for mircColour in range(len(Colours)): for mircColour in range(len(Colours)):
self._brushes += [wx.Brush(wx.Colour(Colours[mircColour][:4]), wx.BRUSHSTYLE_SOLID)]; self._brushesBlend[mircColour] = {}; self._brushes += [wx.Brush(wx.Colour(Colours[mircColour][:4]), wx.BRUSHSTYLE_SOLID)]; self._brushesBlend[mircColour] = {};
self._pens += [wx.Pen(wx.Colour(Colours[mircColour][:4]), 1)]; self._pensBlend[mircColour] = {}; self._pens += [wx.Pen(wx.Colour(Colours[mircColour][:4]), 1)]; self._pensBlend[mircColour] = {};
@ -148,7 +148,7 @@ class GuiCanvasWxBackend():
def drawCursorMaskWithJournal(self, canvas, canvasJournal, eventDc): def drawCursorMaskWithJournal(self, canvas, canvasJournal, eventDc):
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0); eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
self.drawPatches(canvas, eventDc, canvasJournal.popCursor(), True) self.drawPatches(canvas, eventDc, canvasJournal.popCursor(), False)
eventDc.SetDeviceOrigin(*eventDcOrigin) eventDc.SetDeviceOrigin(*eventDcOrigin)
def drawPatches(self, canvas, eventDc, patches, isCursor=False): def drawPatches(self, canvas, eventDc, patches, isCursor=False):
@ -164,14 +164,12 @@ class GuiCanvasWxBackend():
for patchRender in patchesRender: for patchRender in patchesRender:
absPoint, charFlag = [a * b for a, b in zip(self.cellSize, patchRender[:2])], False absPoint, charFlag = [a * b for a, b in zip(self.cellSize, patchRender[:2])], False
if (patchRender[5] == " ") and (patchRender[3] == -1): if (patchRender[5] == " ") and (patchRender[3] == -1):
charFlag, patchRender = True, [*patchRender[:-1], ""] charFlag, patchRender, textFg = True, [*patchRender[:-1], ""], wx.Colour(0, 0, 0, 255)
textBg, textFg = wx.Colour(Colours[patchRender[3]][:4]), wx.Colour(Colours[patchRender[2]][:4]) elif isCursor and (patchRender[5] == " ") and ((canvas.map[patchRender[1]][patchRender[0]][3] != " ") or (canvas.map[patchRender[1]][patchRender[0]][2] & self._CellState.CS_UNDERLINE)):
if isCursor and (patchRender[5] == " ") and ((canvas.map[patchRender[1]][patchRender[0]][3] != " ") or (canvas.map[patchRender[1]][patchRender[0]][2] & self._CellState.CS_UNDERLINE)):
charFlag, patchRender = True, [*patchRender[:-2], *canvas.map[patchRender[1]][patchRender[0]][2:]] charFlag, patchRender = True, [*patchRender[:-2], *canvas.map[patchRender[1]][patchRender[0]][2:]]
textFg = wx.Colour(self._blendColours(canvas.map[patchRender[1]][patchRender[0]][0], patchRender[2])) textFg = wx.Colour(self._blendColours(canvas.map[patchRender[1]][patchRender[0]][0], patchRender[3]))
elif (patchRender[5] != " ") or (patchRender[4] & self._CellState.CS_UNDERLINE): elif (patchRender[5] != " ") or (patchRender[4] & self._CellState.CS_UNDERLINE):
charFlag = True charFlag, textFg = True, wx.Colour(Colours[patchRender[2]][:4])
textBg, textFg = wx.Colour(Colours[patchRender[3]][:4]), wx.Colour(Colours[patchRender[2]][:4])
brush, pen = self._setBrushColours(eventDc, isCursor, patchRender[2:], canvas.map[patchRender[1]][patchRender[0]]) brush, pen = self._setBrushColours(eventDc, isCursor, patchRender[2:], canvas.map[patchRender[1]][patchRender[0]])
eventDc.DrawRectangle(*absPoint, *self.cellSize) eventDc.DrawRectangle(*absPoint, *self.cellSize)
if charFlag: if charFlag:
@ -208,8 +206,17 @@ class GuiCanvasWxBackend():
else: else:
eventDc = GuiBufferedDC(self, self.canvasBitmap, clientSize, wx.PaintDC(panelWindow), viewRect) eventDc = GuiBufferedDC(self, self.canvasBitmap, clientSize, wx.PaintDC(panelWindow), viewRect)
def resize(self, canvasSize, cellSize): def resize(self, canvasSize):
winSize = [a * b for a, b in zip(canvasSize, cellSize)] if platform.system() == "Windows":
self._font = wx.TheFontList.FindOrCreateFont(self.fontSize, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, self.fontName)
fontInfoDesc = self._font.GetNativeFontInfoDesc().split(";"); fontInfoDesc[12] = "3";
self._font.SetNativeFontInfo(";".join(fontInfoDesc))
dc = wx.MemoryDC()
dc.SetFont(self._font); self.cellSize = dc.GetTextExtent("_");
dc.Destroy()
else:
self._font = wx.Font(self.cellSize[0] + 1, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
winSize = [a * b for a, b in zip(canvasSize, self.cellSize)]
if self.canvasBitmap == None: if self.canvasBitmap == None:
self.canvasBitmap = wx.Bitmap(winSize) self.canvasBitmap = wx.Bitmap(winSize)
else: else:
@ -218,11 +225,7 @@ class GuiCanvasWxBackend():
newDc.Blit(0, 0, *self.canvasBitmap.GetSize(), oldDc, 0, 0) newDc.Blit(0, 0, *self.canvasBitmap.GetSize(), oldDc, 0, 0)
oldDc.SelectObject(wx.NullBitmap) oldDc.SelectObject(wx.NullBitmap)
self.canvasBitmap.Destroy(); self.canvasBitmap = newBitmap; self.canvasBitmap.Destroy(); self.canvasBitmap = newBitmap;
self.canvasSize, self.cellSize = canvasSize, cellSize self.canvasSize = canvasSize
if platform.system() == "Windows":
self._font = wx.TheFontList.FindOrCreateFont(cellSize[0] + 1, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, self.fontName)
else:
self._font = wx.Font(cellSize[0] + 1, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
def xlateEventPoint(self, event, eventDc, viewRect): def xlateEventPoint(self, event, eventDc, viewRect):
eventPoint = event.GetLogicalPosition(eventDc) eventPoint = event.GetLogicalPosition(eventDc)
@ -235,11 +238,11 @@ class GuiCanvasWxBackend():
self.canvasBitmap.Destroy(); self.canvasBitmap = None; self.canvasBitmap.Destroy(); self.canvasBitmap = None;
self._finiBrushesAndPens() self._finiBrushesAndPens()
def __init__(self, canvasSize, cellSize, fontName="Dejavu Sans Mono", fontPathName=os.path.join("assets", "fonts", "DejaVuSansMono.ttf")): def __init__(self, canvasSize, fontName="Dejavu Sans Mono", fontPathName=os.path.join("assets", "fonts", "DejaVuSansMono.ttf"), fontSize=8):
self._brushes, self._font, self._lastBrush, self._lastPen, self._pens = None, None, None, None, None self._brushes, self._font, self._lastBrush, self._lastPen, self._pens = None, None, None, None, None
self.canvasBitmap, self.cellSize, self.fontName, self.fontPathName = None, None, fontName, fontPathName self.canvasBitmap, self.cellSize, self.fontName, self.fontPathName, self.fontSize = None, None, fontName, fontPathName, fontSize
if platform.system() == "Windows": if platform.system() == "Windows":
WinDLL("gdi32.dll").AddFontResourceW(self.fontPathName.encode("utf16")) WinDLL("gdi32.dll").AddFontResourceW(self.fontPathName.encode("utf16"))
self._initBrushesAndPens(); self.resize(canvasSize, cellSize); self._initBrushesAndPens(); self.resize(canvasSize);
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -146,7 +146,7 @@ class GuiFrame(wx.Frame):
def loadToolBars(self, toolBars): def loadToolBars(self, toolBars):
for toolBar in toolBars: for toolBar in toolBars:
self.toolBars.append(wx.lib.agw.aui.AuiToolBar(self.panelSkin, -1)) self.toolBars.append(wx.lib.agw.aui.AuiToolBar(self, -1))
self.toolBars[-1].SetArtProvider(GuiToolBarArtProvider()) self.toolBars[-1].SetArtProvider(GuiToolBarArtProvider())
self.toolBars[-1].SetToolBitmapSize((16, 16)) self.toolBars[-1].SetToolBitmapSize((16, 16))
for toolBarItem in toolBar: for toolBarItem in toolBar:
@ -170,13 +170,16 @@ class GuiFrame(wx.Frame):
else: else:
self.toolBars[-1].EnableTool(toolBarItem.attrDict["id"], toolBarItem.attrDict["initialState"]) self.toolBars[-1].EnableTool(toolBarItem.attrDict["id"], toolBarItem.attrDict["initialState"])
self.toolBars[-1].Refresh() self.toolBars[-1].Refresh()
self.toolBarPanes, row = [], 0
for toolBar in self.toolBars: for toolBar in self.toolBars:
self.sizerSkin.Add(toolBar, 0, wx.ALIGN_LEFT | wx.ALL, 3)
toolBar.Realize(); toolBar.Fit(); toolBar.Realize(); toolBar.Fit();
self.toolBarPanes += [wx.lib.agw.aui.AuiPaneInfo().ToolbarPane().CaptionVisible(False).CloseButton(False).Dockable(True).Floatable(True).Gripper(True).Row(row).Top()]
self.auiManager.AddPane(toolBar, self.toolBarPanes[-1]); row += 1;
self.auiManager.Update()
def addWindow(self, window, border=14, expand=False): def addWindow(self, window):
flags = wx.ALL; flags = flags | wx.EXPAND if expand else flags; self.auiManager.AddPane(window, wx.lib.agw.aui.AuiPaneInfo().CaptionVisible(False).Centre().CloseButton(False).Dockable(False).Floatable(False).Gripper(False))
self.sizerSkin.Add(window, 0, flags, border); self.sizerSkin.Fit(self.panelSkin); self.auiManager.Update()
def onChar(self, event): def onChar(self, event):
event.Skip() event.Skip()
@ -193,11 +196,10 @@ class GuiFrame(wx.Frame):
def __init__(self, iconPathName, size, parent=None, title=""): def __init__(self, iconPathName, size, parent=None, title=""):
super().__init__(parent, wx.ID_ANY, title, size=size) super().__init__(parent, wx.ID_ANY, title, size=size)
self.itemsById, self.menuItemsById, self.toolBarItemsById = {}, {}, {} self.auiManager = wx.lib.agw.aui.AuiManager(); self.auiManager.SetManagedWindow(self);
self.panelSkin, self.sizerSkin, self.toolBars = wx.Panel(self, wx.ID_ANY), wx.BoxSizer(wx.VERTICAL), [] self.itemsById, self.menuItemsById, self.toolBarItemsById, self.toolBars = {}, {}, {}, []
self.sizerSkin.AddSpacer(5); self.panelSkin.SetSizer(self.sizerSkin); self.panelSkin.SetAutoLayout(1);
self._initIcon(iconPathName); self.statusBar = self.CreateStatusBar(); self._initIcon(iconPathName); self.statusBar = self.CreateStatusBar();
self.sizerSkin.Fit(self.panelSkin); self.SetFocus(); self.Show(True); self.SetFocus(); self.Show(True);
for event, f in ((wx.EVT_CHAR, self.onChar), (wx.EVT_MENU, self.onMenu), (wx.EVT_MOUSEWHEEL, self.onMouseWheel)): for event, f in ((wx.EVT_CHAR, self.onChar), (wx.EVT_MENU, self.onMenu), (wx.EVT_MOUSEWHEEL, self.onMouseWheel)):
self.Bind(event, f) self.Bind(event, f)

View File

@ -8,8 +8,8 @@ import wx
class GuiWindow(wx.ScrolledWindow): class GuiWindow(wx.ScrolledWindow):
def _updateScrollBars(self): def _updateScrollBars(self):
if self.size != None: if (self.scrollStep != None) and (self.size != None):
clientSize = self.GetClientSize() self.SetScrollRate(*self.scrollStep); clientSize = self.GetClientSize();
if (self.size[0] > clientSize[0]) or (self.size[1] > clientSize[1]): if (self.size[0] > clientSize[0]) or (self.size[1] > clientSize[1]):
self.scrollFlag = True; super().SetVirtualSize(self.size); self.scrollFlag = True; super().SetVirtualSize(self.size);
elif self.scrollFlag \ elif self.scrollFlag \
@ -48,16 +48,16 @@ class GuiWindow(wx.ScrolledWindow):
while curWindow != None: while curWindow != None:
curWindow.Layout(); curWindow = curWindow.GetParent(); curWindow.Layout(); curWindow = curWindow.GetParent();
def __init__(self, parent, pos, scrollStep, style=0): def __init__(self, parent, pos, style=0):
super().__init__(parent, pos=pos, style=style) if style != 0 else super().__init__(parent, pos=pos) super().__init__(parent, pos=pos, style=style) if style != 0 else super().__init__(parent, pos=pos)
self.parent = parent self.parent = parent
self.pos, self.scrollFlag, self.scrollStep, self.size = pos, False, scrollStep, None self.pos, self.scrollFlag, self.scrollStep, self.size = pos, False, None, None
for eventType, f in ( for eventType, f in (
(wx.EVT_CHAR, self.onKeyboardInput), (wx.EVT_CLOSE, self.onClose), (wx.EVT_ENTER_WINDOW, self.onEnterWindow), (wx.EVT_CHAR, self.onKeyboardInput), (wx.EVT_CLOSE, self.onClose), (wx.EVT_ENTER_WINDOW, self.onEnterWindow),
(wx.EVT_LEAVE_WINDOW, self.onLeaveWindow), (wx.EVT_LEFT_DOWN, self.onMouseInput), (wx.EVT_MOTION, self.onMouseInput), (wx.EVT_LEAVE_WINDOW, self.onLeaveWindow), (wx.EVT_LEFT_DOWN, self.onMouseInput), (wx.EVT_MOTION, self.onMouseInput),
(wx.EVT_PAINT, self.onPaint), (wx.EVT_RIGHT_DOWN, self.onMouseInput), (wx.EVT_SCROLLWIN_LINEDOWN, self.onScroll), (wx.EVT_PAINT, self.onPaint), (wx.EVT_RIGHT_DOWN, self.onMouseInput), (wx.EVT_SCROLLWIN_LINEDOWN, self.onScroll),
(wx.EVT_SCROLLWIN_LINEUP, self.onScroll), (wx.EVT_SIZE, self.onSize)): (wx.EVT_SCROLLWIN_LINEUP, self.onScroll), (wx.EVT_SIZE, self.onSize)):
self.Bind(eventType, f) self.Bind(eventType, f)
self.SetScrollRate(*self.scrollStep); self._updateScrollBars(); self._updateScrollBars()
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -6,13 +6,26 @@
from Operator import Operator from Operator import Operator
# TODO <https://en.wikipedia.org/wiki/Box_Drawing_(Unicode_block)>
class OperatorFlipHorizontal(Operator): class OperatorFlipHorizontal(Operator):
name = "Flip horizontally" name = "Flip horizontally"
flipPairs = {
"/":"\\", "":"",
"":"", "":"", "":"", "":"",
"":"", "":"", "":"",
}
def apply(self, region): def apply(self, region):
region.reverse(); return region; region.reverse()
for numRow in range(len(region)):
for numCol in range(len(region[numRow])):
if region[numRow][numCol][3] in self.flipPairs:
region[numRow][numCol][3] = self.flipPairs[region[numRow][numCol][3]]
return region
def __init__(self, *args): def __init__(self, *args):
pass for flipPairKey in list(self.flipPairs.keys()):
self.flipPairs[self.flipPairs[flipPairKey]] = flipPairKey
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -6,15 +6,15 @@
from Operator import Operator from Operator import Operator
# TODO <https://en.wikipedia.org/wiki/Box_Drawing_(Unicode_block)>
class OperatorFlipVertical(Operator): class OperatorFlipVertical(Operator):
name = "Flip" name = "Flip"
flipPairs = { flipPairs = {
"(":")", ")":"(", "(":")", "/":"\\", "":"", "[":"]", "{":"}", "<":">", "`":"'",
"/":"\\", "\\":"/", "":"", "":"",
"\[":"]", "]":"\[", "":"", "":"",
"\{":"\}", "\}":"\{", "":"", "":"", "":"",
"<":">", ">":"<",
"`":"'",
} }
def apply(self, region): def apply(self, region):
@ -26,6 +26,7 @@ class OperatorFlipVertical(Operator):
return region return region
def __init__(self, *args): def __init__(self, *args):
pass for flipPairKey in list(self.flipPairs.keys()):
self.flipPairs[self.flipPairs[flipPairKey]] = flipPairKey
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -86,6 +86,28 @@ class RoarAssetsWindow(GuiMiniFrame):
with open(localConfFileName, "r", encoding="utf-8") as inFile: with open(localConfFileName, "r", encoding="utf-8") as inFile:
self.lastDir = inFile.read().rstrip("\r\n") self.lastDir = inFile.read().rstrip("\r\n")
def _removeAsset(self, idx):
del self.canvasList[idx]; self.listView.DeleteItem(idx);
itemCount = self.listView.GetItemCount()
if itemCount > 0:
self.listView.Select(self.currentIndex, on=0)
for numCanvas in [n for n in sorted(self.canvasList.keys()) if n >= idx]:
self.canvasList[numCanvas - 1] = self.canvasList[numCanvas]; del self.canvasList[numCanvas];
[self.listView.SetColumnWidth(col, wx.LIST_AUTOSIZE) for col in (0, 1)]
if (idx == 0) or (idx >= itemCount):
idx = 0 if itemCount > 0 else None
else:
idx = idx if idx < itemCount else None
self.currentIndex = idx
if self.currentIndex != None:
self.listView.Select(self.currentIndex, on=1)
self.drawCanvas(self.canvasList[self.currentIndex][0])
else:
self.currentIndex = None
[self.listView.SetColumnWidth(col, wx.LIST_AUTOSIZE_USEHEADER) for col in (0, 1)]
self.drawCanvas(Canvas((0, 0)))
return self.currentIndex
def _storeLastDir(self, pathName): def _storeLastDir(self, pathName):
localConfFileName = getLocalConfPathName("RecentAssetsDir.txt") localConfFileName = getLocalConfPathName("RecentAssetsDir.txt")
with open(localConfFileName, "w", encoding="utf-8") as outFile: with open(localConfFileName, "w", encoding="utf-8") as outFile:
@ -106,12 +128,12 @@ class RoarAssetsWindow(GuiMiniFrame):
self.scrollFlag = False; super(wx.ScrolledWindow, self.panelCanvas).SetVirtualSize((0, 0)); self.scrollFlag = False; super(wx.ScrolledWindow, self.panelCanvas).SetVirtualSize((0, 0));
def drawCanvas(self, canvas): def drawCanvas(self, canvas):
panelSize = [a * b for a, b in zip(canvas.size, self.cellSize)] panelSize = [a * b for a, b in zip(canvas.size, self.backend.cellSize)]
self.panelCanvas.SetMinSize(panelSize); self.panelCanvas.SetSize(wx.DefaultCoord, wx.DefaultCoord, *panelSize); self.panelCanvas.SetMinSize(panelSize); self.panelCanvas.SetSize(wx.DefaultCoord, wx.DefaultCoord, *panelSize);
curWindow = self.panelCanvas curWindow = self.panelCanvas
while curWindow != None: while curWindow != None:
curWindow.Layout(); curWindow = curWindow.GetParent(); curWindow.Layout(); curWindow = curWindow.GetParent();
self.backend.resize(canvas.size, self.cellSize) self.backend.resize(canvas.size)
eventDc = self.backend.getDeviceContext(self.panelCanvas.GetClientSize(), self.panelCanvas) eventDc = self.backend.getDeviceContext(self.panelCanvas.GetClientSize(), self.panelCanvas)
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0); eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
patches = [] patches = []
@ -144,12 +166,12 @@ class RoarAssetsWindow(GuiMiniFrame):
oldSize = [0, 0] if canvas.map == None else canvas.size oldSize = [0, 0] if canvas.map == None else canvas.size
deltaSize = [b - a for a, b in zip(oldSize, newSize)] deltaSize = [b - a for a, b in zip(oldSize, newSize)]
if canvas.resize(newSize, False): if canvas.resize(newSize, False):
panelSize = [a * b for a, b in zip(canvas.size, self.cellSize)] panelSize = [a * b for a, b in zip(canvas.size, self.backend.cellSize)]
self.panelCanvas.SetMinSize(panelSize); self.panelCanvas.SetSize(wx.DefaultCoord, wx.DefaultCoord, *panelSize); self.panelCanvas.SetMinSize(panelSize); self.panelCanvas.SetSize(wx.DefaultCoord, wx.DefaultCoord, *panelSize);
curWindow = self.panelCanvas curWindow = self.panelCanvas
while curWindow != None: while curWindow != None:
curWindow.Layout(); curWindow = curWindow.GetParent(); curWindow.Layout(); curWindow = curWindow.GetParent();
self.backend.resize(newSize, self.cellSize) self.backend.resize(newSize)
eventDc = self.backend.getDeviceContext(self.panelCanvas.GetClientSize(), self.panelCanvas) eventDc = self.backend.getDeviceContext(self.panelCanvas.GetClientSize(), self.panelCanvas)
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0); eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
patches = [] patches = []
@ -193,14 +215,27 @@ class RoarAssetsWindow(GuiMiniFrame):
else: else:
event.Skip() event.Skip()
def onClearList(self, event):
while len(self.canvasList):
self._removeAsset(list(self.canvasList.keys())[0])
def onListViewChar(self, event): def onListViewChar(self, event):
index, rc = self.listView.GetFirstSelected(), False keyCode = event.GetKeyCode()
if index != -1: if (event.GetModifiers() == wx.MOD_NONE) \
keyChar, keyModifiers = event.GetKeyCode(), event.GetModifiers() and (keyCode in (wx.WXK_DOWN, wx.WXK_UP)) \
if (keyChar, keyModifiers) == (wx.WXK_DELETE, wx.MOD_NONE): and (self.currentIndex != None):
self.currentIndex, rc = index, True; self.onRemove(None); self.listView.Select(self.currentIndex, on=0)
if not rc: id = +1 if keyCode == wx.WXK_DOWN else -1
event.Skip() self.currentIndex = (self.currentIndex + id) % len(self.canvasList)
self.listView.Select(self.currentIndex, on=1)
else:
index, rc = self.listView.GetFirstSelected(), False
if index != -1:
keyChar, keyModifiers = event.GetKeyCode(), event.GetModifiers()
if (keyChar, keyModifiers) == (wx.WXK_DELETE, wx.MOD_NONE):
self.currentIndex, rc = index, True; self.onRemove(None);
if not rc:
event.Skip()
def onListViewItemSelected(self, event): def onListViewItemSelected(self, event):
self.currentIndex = event.GetItem().GetId() self.currentIndex = event.GetItem().GetId()
@ -217,6 +252,10 @@ class RoarAssetsWindow(GuiMiniFrame):
self.contextMenuItems[4].Enable(False) self.contextMenuItems[4].Enable(False)
else: else:
self.contextMenuItems[4].Enable(True) self.contextMenuItems[4].Enable(True)
if len(self.canvasList) == 0:
self.contextMenuItems[7].Enable(False)
else:
self.contextMenuItems[7].Enable(True)
self.PopupMenu(self.contextMenu, eventPoint) self.PopupMenu(self.contextMenu, eventPoint)
def onLoad(self, event): def onLoad(self, event):
@ -256,23 +295,15 @@ class RoarAssetsWindow(GuiMiniFrame):
self._load_list(pathName) self._load_list(pathName)
def onRemove(self, event): def onRemove(self, event):
del self.canvasList[self.currentIndex]; self.listView.DeleteItem(self.currentIndex); items = [self.listView.GetFirstSelected()]
itemCount = self.listView.GetItemCount() while True:
if itemCount > 0: item = self.listView.GetNextSelected(items[-1])
for numCanvas in [n for n in sorted(self.canvasList.keys()) if n >= self.currentIndex]: if item != -1:
self.canvasList[numCanvas - 1] = self.canvasList[numCanvas]; del self.canvasList[numCanvas]; items += [item]
[self.listView.SetColumnWidth(col, wx.LIST_AUTOSIZE) for col in (0, 1)]
if (self.currentIndex == 0) or (self.currentIndex >= itemCount):
self.currentIndex = 0 if itemCount > 0 else None
else: else:
self.currentIndex = self.currentIndex if self.currentIndex < itemCount else None break
if self.currentIndex != None: while len(items):
self.listView.Select(self.currentIndex, on=1) self._removeAsset(items[0]); del items[0]; items = [i - 1 for i in items];
self.drawCanvas(self.canvasList[self.currentIndex][0])
else:
self.currentIndex = None
[self.listView.SetColumnWidth(col, wx.LIST_AUTOSIZE_USEHEADER) for col in (0, 1)]
self.drawCanvas(Canvas((0, 0)))
def onSaveList(self, event): def onSaveList(self, event):
rc = True rc = True
@ -293,12 +324,12 @@ class RoarAssetsWindow(GuiMiniFrame):
with wx.MessageDialog(self, "Error: {}".format(error), "", wx.OK | wx.OK_DEFAULT) as dialog: with wx.MessageDialog(self, "Error: {}".format(error), "", wx.OK | wx.OK_DEFAULT) as dialog:
dialogChoice = dialog.ShowModal() dialogChoice = dialog.ShowModal()
def __init__(self, backend, cellSize, parent, pos=None, size=(400, 400), title="Assets"): def __init__(self, backend, parent, pos=None, size=(400, 400), title="Assets"):
if pos == None: if pos == None:
parentRect = parent.GetScreenRect(); pos = (parentRect.x + parentRect.width, parentRect.y); parentRect = parent.GetScreenRect(); pos = (parentRect.x + parentRect.width, parentRect.y);
super().__init__(parent, size, title, pos=pos) super().__init__(parent, size, title, pos=pos)
self.backend, self.canvasList, self.lastDir = backend((0, 0), cellSize), {}, None self.backend, self.canvasList, self.lastDir = backend((0, 0)), {}, None
self.cellSize, self.currentIndex, self.leftDown, self.parent, self.scrollFlag = cellSize, None, False, parent, False self.currentIndex, self.leftDown, self.parent, self.scrollFlag = None, False, parent, False
self.Bind(wx.EVT_CHAR, self.onChar) self.Bind(wx.EVT_CHAR, self.onChar)
self._loadLastDir() self._loadLastDir()
@ -311,7 +342,9 @@ class RoarAssetsWindow(GuiMiniFrame):
("&Remove", self.onRemove), ("&Remove", self.onRemove),
(None, None), (None, None),
("Load from l&ist...", self.onLoadList), ("Load from l&ist...", self.onLoadList),
("Sa&ve as list...", self.onSaveList),): ("Sa&ve as list...", self.onSaveList),
(None, None),
("Cl&ear list", self.onClearList),):
if (text, f) == (None, None): if (text, f) == (None, None):
self.contextMenu.AppendSeparator() self.contextMenu.AppendSeparator()
else: else:
@ -325,7 +358,8 @@ class RoarAssetsWindow(GuiMiniFrame):
self.listView.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onListViewItemSelected) self.listView.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onListViewItemSelected)
self.listView.Bind(wx.EVT_RIGHT_DOWN, self.onListViewRightDown) self.listView.Bind(wx.EVT_RIGHT_DOWN, self.onListViewRightDown)
self.panelCanvas = GuiWindow(self, (0, 0), cellSize, wx.BORDER_SUNKEN) self.panelCanvas = GuiWindow(self, (0, 0), wx.BORDER_SUNKEN)
self.panelCanvas.Bind(wx.EVT_CHAR, self.onChar)
self.panelCanvas.Bind(wx.EVT_LEFT_DOWN, self.onPanelLeftDown) self.panelCanvas.Bind(wx.EVT_LEFT_DOWN, self.onPanelLeftDown)
self.panelCanvas.Bind(wx.EVT_PAINT, self.onPanelPaint) self.panelCanvas.Bind(wx.EVT_PAINT, self.onPanelPaint)
self.panelCanvas.Bind(wx.EVT_SIZE, self.onPanelSize) self.panelCanvas.Bind(wx.EVT_SIZE, self.onPanelSize)

View File

@ -123,7 +123,9 @@ class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCan
self.canvasUndo, self.canvasRedo, NID_TOOLBAR_HSEP, self.canvasUndo, self.canvasRedo, NID_TOOLBAR_HSEP,
self.canvasCut, self.canvasCopy, self.canvasPaste, self.canvasDelete, NID_TOOLBAR_HSEP, self.canvasCut, self.canvasCopy, self.canvasPaste, self.canvasDelete, NID_TOOLBAR_HSEP,
self.canvasAssetsWindowHide, self.canvasAssetsWindowShow, NID_TOOLBAR_HSEP, self.canvasAssetsWindowHide, self.canvasAssetsWindowShow, NID_TOOLBAR_HSEP,
self.canvasTool(self.canvasTool, 1), self.canvasTool(self.canvasTool, 7), self.canvasTool(self.canvasTool, 0), self.canvasTool(self.canvasTool, 3), self.canvasTool(self.canvasTool, 4), self.canvasTool(self.canvasTool, 8), self.canvasTool(self.canvasTool, 5), self.canvasTool(self.canvasTool, 2), self.canvasTool(self.canvasTool, 6), ])
toolBars.append(
[self.canvasTool(self.canvasTool, 1), self.canvasTool(self.canvasTool, 7), self.canvasTool(self.canvasTool, 0), self.canvasTool(self.canvasTool, 3), self.canvasTool(self.canvasTool, 4), self.canvasTool(self.canvasTool, 8), self.canvasTool(self.canvasTool, 5), self.canvasTool(self.canvasTool, 2), self.canvasTool(self.canvasTool, 6),
]) ])
toolBars.append( toolBars.append(
[self.canvasColour(self.canvasColour, 0), self.canvasColour(self.canvasColour, 1), self.canvasColour(self.canvasColour, 2), self.canvasColour(self.canvasColour, 3), [self.canvasColour(self.canvasColour, 0), self.canvasColour(self.canvasColour, 1), self.canvasColour(self.canvasColour, 2), self.canvasColour(self.canvasColour, 3),

View File

@ -7,14 +7,14 @@
from GuiFrame import GuiCommandDecorator, NID_MENU_SEP from GuiFrame import GuiCommandDecorator, NID_MENU_SEP
from RoarWindowAbout import RoarWindowAbout from RoarWindowAbout import RoarWindowAbout
from RoarWindowMelp import RoarWindowMelp from RoarWindowMelp import RoarWindowMelp
import webbrowser import webbrowser, wx
class RoarCanvasCommandsHelp(): class RoarCanvasCommandsHelp():
@GuiCommandDecorator("About roar", "&About roar", None, None, True) @GuiCommandDecorator("About roar", "&About roar", None, None, True)
def canvasAbout(self, event): def canvasAbout(self, event):
RoarWindowAbout(self.parentFrame) RoarWindowAbout(self.parentFrame)
@GuiCommandDecorator("View melp?", "View &melp?", None, None, True) @GuiCommandDecorator("View melp?", "View &melp?", None, [wx.MOD_NONE, wx.WXK_F1], True)
def canvasMelp(self, event): def canvasMelp(self, event):
RoarWindowMelp(self.parentFrame) RoarWindowMelp(self.parentFrame)

View File

@ -212,12 +212,12 @@ class RoarCanvasWindow(GuiWindow):
def onMouseWheel(self, event): def onMouseWheel(self, event):
if event.GetModifiers() == wx.MOD_CONTROL: if event.GetModifiers() == wx.MOD_CONTROL:
cd = +1 if event.GetWheelRotation() >= event.GetWheelDelta() else -1 fd = +1 if event.GetWheelRotation() >= event.GetWheelDelta() else -1
newCellSize = [cs + cd for cs in self.backend.cellSize] newFontSize = self.backend.fontSize + fd
if (newCellSize[0] > 0) and (newCellSize[1] > 0): if newFontSize > 0:
self.backend.cellSize = newCellSize self.backend.fontSize = newFontSize
self.backend.resize(self.canvas.size)
super().resize([a * b for a, b in zip(self.canvas.size, self.backend.cellSize)]) super().resize([a * b for a, b in zip(self.canvas.size, self.backend.cellSize)])
self.backend.resize(self.canvas.size, self.backend.cellSize)
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self) eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0); eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
patches = [] patches = []
@ -239,8 +239,8 @@ class RoarCanvasWindow(GuiWindow):
oldSize = [0, 0] if self.canvas.map == None else self.canvas.size oldSize = [0, 0] if self.canvas.map == None else self.canvas.size
deltaSize = [b - a for a, b in zip(oldSize, newSize)] deltaSize = [b - a for a, b in zip(oldSize, newSize)]
if self.canvas.resize(newSize, commitUndo): if self.canvas.resize(newSize, commitUndo):
self.backend.resize(newSize); self.scrollStep = self.backend.cellSize;
super().resize([a * b for a, b in zip(newSize, self.backend.cellSize)]) super().resize([a * b for a, b in zip(newSize, self.backend.cellSize)])
self.backend.resize(newSize, self.backend.cellSize)
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self) eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0); eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
patches = [] patches = []
@ -268,10 +268,10 @@ class RoarCanvasWindow(GuiWindow):
self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False) self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False)
eventDc.SetDeviceOrigin(*eventDcOrigin) eventDc.SetDeviceOrigin(*eventDcOrigin)
def __init__(self, backend, canvas, cellSize, commands, parent, parentFrame, pos, scrollStep, size): def __init__(self, backend, canvas, commands, parent, pos, size):
super().__init__(parent, pos, scrollStep) super().__init__(parent, pos)
self.size = size self.size = size
self.backend, self.canvas, self.cellSize, self.commands, self.parentFrame = backend(self.size, cellSize), canvas, cellSize, commands(self, parentFrame), parentFrame self.backend, self.canvas, self.commands, self.parentFrame = backend(self.size), canvas, commands(self, parent), parent
self.brushColours, self.brushPos, self.brushSize, self.dirty, self.lastCellState = [4, 1], [0, 0], [1, 1], False, None self.brushColours, self.brushPos, self.brushSize, self.dirty, self.lastCellState = [4, 1], [0, 0], [1, 1], False, None
self.popupEventDc = None self.popupEventDc = None
self.dropTarget = RoarCanvasWindowDropTarget(self) self.dropTarget = RoarCanvasWindowDropTarget(self)

View File

@ -39,13 +39,10 @@ class RoarClient(GuiFrame):
if closeFlag: if closeFlag:
event.Skip(); event.Skip();
def onSize(self, event): def __init__(self, parent, defaultCanvasPos=(0, 75), defaultCanvasSize=(100, 30), size=(840, 640), title=""):
self.canvasPanel.SetMinSize(self.GetSize()); self.canvasPanel.SetSize(wx.DefaultCoord, wx.DefaultCoord, *self.GetSize()); event.Skip();
def __init__(self, parent, defaultCanvasPos=(0, 75), defaultCanvasSize=(100, 30), defaultCellSize=(7, 14), size=(840, 640), title=""):
super().__init__(self._getIconPathName(), size, parent, title) super().__init__(self._getIconPathName(), size, parent, title)
self.canvas = Canvas(defaultCanvasSize) self.canvas = Canvas(defaultCanvasSize)
self.canvasPanel = RoarCanvasWindow(GuiCanvasWxBackend, self.canvas, defaultCellSize, RoarCanvasCommands, self.panelSkin, self, defaultCanvasPos, defaultCellSize, defaultCanvasSize) self.canvasPanel = RoarCanvasWindow(GuiCanvasWxBackend, self.canvas, RoarCanvasCommands, self, defaultCanvasPos, defaultCanvasSize)
self.loadAccels(self.canvasPanel.commands.accels, self.canvasPanel.commands.menus, self.canvasPanel.commands.toolBars) self.loadAccels(self.canvasPanel.commands.accels, self.canvasPanel.commands.menus, self.canvasPanel.commands.toolBars)
self.loadMenus(self.canvasPanel.commands.menus) self.loadMenus(self.canvasPanel.commands.menus)
self._initToolBitmaps(self.canvasPanel.commands.toolBars) self._initToolBitmaps(self.canvasPanel.commands.toolBars)
@ -54,8 +51,8 @@ class RoarClient(GuiFrame):
self.canvasPanel.commands.canvasNew(None) self.canvasPanel.commands.canvasNew(None)
self.canvasPanel.commands.canvasTool(self.canvasPanel.commands.canvasTool, 1)(None) self.canvasPanel.commands.canvasTool(self.canvasPanel.commands.canvasTool, 1)(None)
self.canvasPanel.commands.update(brushSize=self.canvasPanel.brushSize, colours=self.canvasPanel.brushColours) self.canvasPanel.commands.update(brushSize=self.canvasPanel.brushSize, colours=self.canvasPanel.brushColours)
self.addWindow(self.canvasPanel, expand=True) self.addWindow(self.canvasPanel)
self.assetsWindow = RoarAssetsWindow(GuiCanvasWxBackend, defaultCellSize, self) self.assetsWindow = RoarAssetsWindow(GuiCanvasWxBackend, self)
self.canvasPanel.commands.canvasAssetsWindowShow(None) self.canvasPanel.commands.canvasAssetsWindowShow(None)
self.canvasPanel.operatorsMenu = wx.Menu() self.canvasPanel.operatorsMenu = wx.Menu()
@ -67,6 +64,6 @@ class RoarClient(GuiFrame):
menuItemWindow = self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].Append(self.canvasPanel.commands.canvasClearRecent.attrDict["id"], self.canvasPanel.commands.canvasClearRecent.attrDict["label"], self.canvasPanel.commands.canvasClearRecent.attrDict["caption"]) menuItemWindow = self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].Append(self.canvasPanel.commands.canvasClearRecent.attrDict["id"], self.canvasPanel.commands.canvasClearRecent.attrDict["label"], self.canvasPanel.commands.canvasClearRecent.attrDict["caption"])
self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].Bind(wx.EVT_MENU, self.canvasPanel.commands.canvasClearRecent, menuItemWindow) self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].Bind(wx.EVT_MENU, self.canvasPanel.commands.canvasClearRecent, menuItemWindow)
self.Bind(wx.EVT_CLOSE, self.onClose) self.Bind(wx.EVT_CLOSE, self.onClose)
self.Bind(wx.EVT_SIZE, self.onSize) self.toolBarPanes[0].BestSize(0, 0).Right(); self.toolBarPanes[1].BestSize(0, 0).Right(); self.auiManager.Update();
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -111,7 +111,7 @@ class ToolText(Tool):
else: else:
brushPos[0], brushPos[1] = 0, 0 brushPos[0], brushPos[1] = 0, 0
rc = True; patchesCursor += [[*brushPos, *brushColours, 0, "_"]]; rc = True; patchesCursor += [[*brushPos, *brushColours, 0, "_"]];
else: elif not (keyModifiers in (wx.MOD_ALT, wx.MOD_ALTGR, wx.MOD_CONTROL)):
rc, patches_ = self._processKeyChar(brushColours, brushPos, canvas, keyChar, keyModifiers) rc, patches_ = self._processKeyChar(brushColours, brushPos, canvas, keyChar, keyModifiers)
patches += patches_ patches += patches_
if rc: if rc: