Conworld Codex 2018-05-03

By Max Woerner Chase

In this post:


I messed around in Lua a bit, started implementing the logic to store the setting data, and I decided that what I'd like to try to have is, a GUI app backed by SQLite or something. I'm not up for doing that in Lua, but I'm aware of libraries for that in Python. I was contemplating using one of them, SQLAlchemy, for Homunculus, and I've used the other, wxPython, in a project that didn't get off the ground.

The basic idea is to represent all of the relations I have in mind using annotated adjacency tables. I don't have a great idea of what the GUI should be like, but I'm going to focus on that first, because I have plenty of experience with ORM code from my day job.

The big break my attempts to follow the tutorial are going to have with what the tutorials say is, I'm really leery of subclassing framework classes, aside from stuff like ORM code.

Let's adapt the Hello World example to my taste, and... hm.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python3

import contextlib

import wx

_WX_APP = None
_WX_COUNTER = 0


@contextlib.contextmanager
def wx_app():
    global _WX_APP
    global _WX_COUNTER
    if _WX_APP is None:
        _WX_APP = wx.App(False)
    try:
        _WX_COUNTER += 1
        yield _WX_APP
    finally:
        _WX_COUNTER -= 1
        if _WX_COUNTER == 0:
            _WX_APP.MainLoop()


def main():
    with wx_app():
        frame = wx.Frame(None, wx.ID_ANY, "Hello World")
        frame.Show(True)


if __name__ == '__main__':
    main()

I'll need to use this code more to tell whether some of this is, like, actually a good idea or not.

Text editor:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/env python3

import contextlib
import typing

import wx

_WX_APP = None
_WX_COUNTER = 0


@contextlib.contextmanager
def wx_app():
    global _WX_APP
    global _WX_COUNTER
    if _WX_APP is None:
        _WX_APP = wx.App(False)
    try:
        _WX_COUNTER += 1
        yield _WX_APP
    finally:
        _WX_COUNTER -= 1
        if _WX_COUNTER == 0:
            _WX_APP.MainLoop()


class MyFrame(typing.NamedTuple):

    frame: wx.Frame
    control: wx.TextCtrl

    @classmethod
    def new(cls, parent, title):
        frame = wx.Frame(parent, title=title, size=(200, 100))
        control = wx.TextCtrl(frame, style=wx.TE_MULTILINE)
        return cls(frame, control)


def main():
    with wx_app():
        frame = MyFrame.new(None, 'Small editor')
        frame.frame.Show(True)


if __name__ == '__main__':
    main()

Maybe in a larger project I could prove my assumptions about what makes sense, but for now, I'm sorry, Larry Wall, but I'm not feeling the hubris yet.

Hm. I adapted more tutorial code, and something is wrong.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/usr/bin/env python3

import contextlib
import typing

import wx

_WX_APP = None
_WX_COUNTER = 0


@contextlib.contextmanager
def wx_app():
    global _WX_APP
    global _WX_COUNTER
    if _WX_APP is None:
        _WX_APP = wx.App(False)
    try:
        _WX_COUNTER += 1
        yield _WX_APP
    finally:
        _WX_COUNTER -= 1
        if _WX_COUNTER == 0:
            _WX_APP.MainLoop()


class MainWindow(typing.NamedTuple):

    frame: wx.Frame
    control: wx.TextCtrl

    @classmethod
    def new(cls, parent, title):
        frame = wx.Frame(parent, title=title, size=(200, 100))
        control = wx.TextCtrl(frame, style=wx.TE_MULTILINE)
        frame.CreateStatusBar()

        filemenu = wx.Menu()
        filemenu.Append(
            wx.ID_ABOUT, "&About", " Information about this program")
        filemenu.AppendSeparator()
        filemenu.Append(wx.ID_EXIT, "E&xit", " Terminate the program")

        menubar = wx.MenuBar()
        menubar.Append(filemenu, "&File")
        frame.SetMenuBar(menubar)

        return cls(frame, control)


def main():
    with wx_app():
        frame = MainWindow.new(None, 'Sample editor')
        frame.frame.Show(True)


if __name__ == '__main__':
    main()

The file menu doesn't open for me. I should look into this, try to figure out what's wrong. Oh, this is a Mac thing.

I've added some callbacks, and now it's at...

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/env python3

import contextlib
import typing

import wx

_WX_APP = None
_WX_COUNTER = 0


@contextlib.contextmanager
def wx_app():
    global _WX_APP
    global _WX_COUNTER
    if _WX_APP is None:
        _WX_APP = wx.App(False)
    try:
        _WX_COUNTER += 1
        yield _WX_APP
    finally:
        _WX_COUNTER -= 1
        if _WX_COUNTER == 0:
            _WX_APP.MainLoop()


class MainWindow(typing.NamedTuple):

    frame: wx.Frame
    control: wx.TextCtrl

    @classmethod
    def new(cls, parent, title):
        frame = wx.Frame(parent, title=title, size=(200, 100))
        control = wx.TextCtrl(frame, style=wx.TE_MULTILINE)
        frame.CreateStatusBar()

        filemenu = wx.Menu()
        menu_about = filemenu.Append(
            wx.ID_ABOUT, "&About", " Information about this program")
        filemenu.AppendSeparator()
        menu_exit = filemenu.Append(
            wx.ID_EXIT, "E&xit", " Terminate the program")

        menubar = wx.MenuBar()
        menubar.Append(filemenu, "&File")
        frame.SetMenuBar(menubar)

        self = cls(frame, control)

        frame.Bind(wx.EVT_MENU, self.on_about, menu_about)
        frame.Bind(wx.EVT_MENU, self.on_exit, menu_exit)

        return self

    def on_about(self, e):
        dlg = wx.MessageDialog(
            self.frame, "A small text editor", "About Sample Editor", wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def on_exit(self, e):
        self.frame.Close(True)


def main():
    with wx_app():
        frame = MainWindow.new(None, 'Sample editor')
        frame.frame.Show(True)


if __name__ == '__main__':
    main()

This is all very serviceable, though I am coming to the conclusion that the context manager was a bad idea. HOWEVER, I've got some new shininess I want to try out.

The new shininess works. I don't feel like pasting the code here though, because it is completely normal and not at all strange. Everything is fine.


Next week, I'll aim to write code more relevant to conworlds and codexing.