<file_sep>#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk

class _ManyButtonsCreater:
    def __init__(self, master):
        self.__master = master

    def addButton(self, **kw):
        return tk.Button(self.__master, **kw)


class _ButtonCanBeSelected(_ManyButtonsCreater):

    def deselectAll():
        pass


def _selectButton(btn):
    btn['state'] = 'disable'


def _deselectButton(btn):
    btn['state'] = 'active'


class OnlyOneButtonCanBeSelected(_ButtonCanBeSelected):
    def __init__(self, master):
        super().__init__(master)
        self.__selected = None

    def __buttonClicked(self, btn):
        if self.__selected != None:
            _deselectButton(self.__selected)
        self.__selected = btn
        _selectButton(btn)

    def __clickCommand(self, btn, cmd):
        self.__buttonClicked(btn)
        if cmd is not  None:
            cmd()

    def addButton(self, **kw):
        if 'command' in kw:
            cmd = kw.pop('command')
        else:
            cmd = None
        btn = super().addButton(**kw)
        btn['command'] = lambda: self.__clickCommand(btn, cmd)
        return btn

    def deselectAll(self):
        if self.__selected is not None:
            _deselectButton(self.__selected)
            self.__selected = None


class OnlyTowButtonCanBeSelected(_ButtonCanBeSelected):
    def __init__(self, master: tk.Widget):
        super().__init__(master)
        self.__selected = []

    def __buttonClicked(self, btn):
        self.__selected.append(btn)
        _selectButton(btn)

    def __clickCommand(self, btn, cmd):
        if len(self.__selected) < 2:
            self.__buttonClicked(btn)
            if cmd is not None:
                cmd()

    def addButton(self, **kw):
        if 'command' in kw:
            cmd = kw.pop('command')
        else:
            cmd = None
        btn = super().addButton(**kw)
        btn['command'] = lambda: self.__clickCommand(btn, cmd)
        return btn

    def deselectAll(self):
        while self.__selected:
            _deselectButton(self.__selected.pop())

    @property
    def count(self):
        return len(self.__selected)

<file_sep>#!/usr/bin/env python3

import tkinter as tk
import tkinter.ttk as ttk

PAD = 3

class ManyBuutonsPacker:
    def __init__(self, width):
        self.__width = width
        self.__counter = 0

    def pack(self, w: tk.Widget):
        rtn = w.grid(padx=PAD, pady=PAD, row=int(self.__counter/self.__width), column=self.__counter%self.__width)
        self.__counter += 1
        return rtn

class ScrollableFrame(ttk.Frame):
    def __init__(self, container, bar_x = True, bar_y = True):
        super().__init__(container)
        self.canvas = tk.Canvas(self, width=1280, height=720)
        self.scrollable_frame = ttk.Frame(self.canvas)
        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(
                scrollregion=self.canvas.bbox("all")
            )
        )
        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        if bar_y:
            self.scrollbar_y = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
            self.scrollbar_y.pack(side=tk.RIGHT, fill="y")
            self.canvas.configure(yscrollcommand=self.scrollbar_y.set)
        if bar_x:
            self.scrollbar_x = ttk.Scrollbar(self, orient="horizontal", command=self.canvas.xview)
            self.scrollbar_x.pack(side=tk.BOTTOM, fill="x")
            self.canvas.configure(xscrollcommand=self.scrollbar_x.set)
        self.canvas.pack(side=tk.LEFT, fill="both", expand=True)

class FrameMaker:
    def __init__(self, master):

        u = tk.Frame(master)
        u.pack(padx=PAD, pady=PAD, side=tk.TOP)

        d = ScrollableFrame(master)
        d.pack(padx=PAD, pady=PAD, side=tk.TOP)

        ul = tk.Frame(u)
        ul.pack(padx=PAD, pady=PAD, side=tk.LEFT)

        ur = tk.Frame(u)
        ur.pack(padx=PAD, pady=PAD, side=tk.LEFT)

        self.__upperleft = ul
        self.__upperright = ur
        self.__down = d.scrollable_frame

    @property
    def upperleft(self):
        return self.__upperleft

    @property
    def upperright(self):
        return self.__upperright

    @property
    def down(self):
        return self.__down

def destroy_child(frame: tk.Frame):
    children = frame.winfo_children()
    for child in children:
        child.destroy()
<file_sep>#!/usr/bin/env python3

import tkinter as tk
import functools as ft

from . import _utils as utils

class _ManyCheckbuttonCreater:
    def __init__(self, master):
        self.__master = master

    def addCheckbutton(self, **kw):
        return tk.Checkbutton(self.__master, **kw)

    def cleanFrame(self):
        utils.destroy_child(self.__master)


class _CheckbuttonCanBeSelected(_ManyCheckbuttonCreater):
    pass


def _selectCheckbutton(cb: tk.Checkbutton):
    cb.select()

def _deselectCheckbutton(cb: tk.Checkbutton):
    cb.deselect()


class OnlyOneCheckbuttonCanBeSelected(_CheckbuttonCanBeSelected):
    def __init__(self, master):
        super().__init__(master)
        self.__selected = None

    def __checkbuttonSelected(self, cb):
        if self.__selected != None:
            _deselectCheckbutton(self.__selected)
        self.__selected = cb

    def __selectCommand(self, cb, cmd):
        self.__checkbuttonSelected(cb)
        if cmd is not  None:
            cmd()

    def addCheckbutton(self, **kw):
        if 'command' in kw:
            cmd = kw.pop('command')
        else:
            cmd = None
        cb = super().addCheckbutton(**kw)
        # cb['command'] = lambda: self.__selectCommand(cb, cmd)
        cb['command'] = ft.partial(self.__selectCommand, cb, cmd)
        return cb

    def cleanFrame(self):
        self.__selected = None
        super().cleanFrame()

class OnlyTowCheckbuttonCanBeSelected(_CheckbuttonCanBeSelected):
    def __init__(self, master: tk.Widget):
        super().__init__(master)
        self.__selected = list()

    def __checkbuttonSelected(self, cb):
        self.__selected.append(cb)

    def __checkbuttonDeselected(self, cb):
        _deselectCheckbutton(cb)
        self.__selected.remove(cb)

    def __selectCommand(self, cb, cmd):
        if len(self.__selected) < 2:
            self.__checkbuttonSelected(cb)
            if cmd is not None:
                cmd()
        else:
            _deselectCheckbutton(cb)

    def __deselectCommand(self, cb, cmd):
        self.__checkbuttonDeselected(cb)
        if cmd is not None:
            cmd()

    def __command(self, cb, cmd):
        if cb in self.__selected:
            self.__deselectCommand(cb, cmd)
        else:
            self.__selectCommand(cb, cmd)

    def addCheckbutton(self, **kw):
        if 'command' in kw:
            cmd = kw.pop('command')
        else:
            cmd = None
        cb = super().addCheckbutton(**kw)
        # cb['command'] = lambda: self.__command(cb, cmd)
        cb['command'] = ft.partial(self.__command, cb, cmd)
        return cb

    def cleanFrame(self):
        self.__selected.clear()
        super().cleanFrame()


    @property
    def count(self):
        return len(self.__selected)

    @property
    def selected(self):
        return tuple([i['text'] for i in self.__selected])

<file_sep>#!/usr/bin/env python3

import tkinter as tk
from tkinter import ttk

from ._utils import *
from ._ButtonCanBeSelected import *
import ui._CheckboxCanBeSelected as ccbs

<file_sep>#!/usr/bin/env python3

from .main import *

import sqlite3
from os.path import expanduser

class MyScene(list):
    def __init__(self, obs: ObsControl, scene_name: str, scene_id: str, *items):
        super().__init__(*items)
        self.__obs = obs
        self.__name = scene_name
        self.__id = scene_id

    @property
    def name(self):
        return self.__name

    @property
    def id(self):
        return self.__id


class MyItem:
    def __init__(self, obs: ObsControl, scene_id: str, item_name: str, item_id: str, source_id: str,
            position_x: int, position_y: int, size_width: int, size_height: int):
        self.__obs = obs
        self.__scene_id = scene_id
        self.__name = item_name
        self.__item_id = item_id
        self.__source_id = source_id
        self.__position_x = position_x
        self.__position_y = position_y
        self.__size_width = size_width
        self.__size_height = size_height

    @property
    def scene_id(self):
        return self.__scene_id

    @property
    def name(self):
        return self.__name

    @property
    def item_id(self):
        return self.__item_id

    @property
    def source_id(self):
        return self.__source_id

    def align(self):
        self.__obs.set_sceneitem_size(self.scene_id, self.item_id, self.__size_width, self.__size_height)
        self.__obs.set_sceneitem_position(self.scene_id, self.item_id, self.__position_x, self.__position_y)


def read_db(db_file: str = expanduser('~/myobs.sqlite3')):
    ret = dict()
    obs = ObsControl()
    conn = sqlite3.connect(db_file)
    cur = conn.cursor()

    cur.execute('select name, id from scene')
    for row in cur:
        scene_name, scene_id = row
        ret[scene_name] = MyScene(obs, scene_name, scene_id)

    cur.execute('select scene.name, scene_id, item_name, item_id, source_id, position_x, position_y, size_width, size_height from item innner join scene on scene_id = scene.id')
    for row in cur:
        scene_name = row[0]
        newitem = MyItem(obs, *row[1:])
        ret[scene_name].append(newitem)

    conn.close()
    return ret
<file_sep>#!/usr/bin/env python3

from .main import *
from .read_from_sqlite3 import *
<file_sep>#!/usr/bin/env python3

import subprocess

class SLManager:
    def __init__(self):
        self.__slset = {}

    def start(self, desc, url):
        proc = subprocess.Popen(['streamlink', url, '720p,720p60,480p,best' , '--player-external-http', '--player-external-http-port', str(desc), '--twitch-disable-ads'])
        self.stop(desc)
        self.__slset[desc] = proc

    def stop(self, desc):
        if desc in self.__slset:
            proc = self.__slset.pop(desc)
            proc.kill()

if __name__ == '__main__':
    slm = SLManager()
    slm.start(49152, 'https://www.youtube.com/watch?v=IBflp1YeR3k')
    input()
    slm.stop(49152)
<file_sep>#!/usr/bin/env python3

from .main import *

# __all__ = []
<file_sep>#!/usr/bin/env python3

import obscontrol
import streamlinkwrapper

slm = streamlinkwrapper.SLManager()

class _FewStreamManager:
    def __init__(self, basedesc, quantity):
        self.__basedesc = basedesc
        self.__quantity = quantity
        self.__count = 0

    def setURL(self, *urls):
        for url in urls:
            if url is not None:
                slm.start(self.__basedesc+self.__count, url)
                self.__count += 1

    def reset(self):
        while self.__count > 0:
            self.__count -= 1
            slm.stop(self.__basedesc+self.__count)
            print('Stopped {0}'.format(self.__basedesc+self.__count))

class _ManySteamManager:
    def __init__(self, basedesc, quantity1, quantity2):
        self.__waiting = list()
        for i in range(quantity1):
            self.__waiting.append(_FewStreamManager(basedesc+(i*quantity2), quantity2))
        self.__used = dict()

    def setURL(self, key, *urls):
        if key not in self.__used:
            self.__used[key] = self.__waiting.pop()
        self.__used[key].reset()
        self.__used[key].setURL(*urls)

    def reset(self):
        for k in reversed(list(self.__used)):
            self.__used[k].reset()
            self.__waiting.append(self.__used.pop(k))
<file_sep>#!/usr/bin/env python3

import ParticipantManager
import ui
import delivery
import obscontrol
import copy
import utils

import functools as ft
import copy as cp


def trainsition(scene: list):
    for item in scene:
        item.align()


def onlyOne(teams, u, desc, text, scene):
    d = delivery._FewStreamManager(desc, 1)

    tab = u.addTab(text)
    fr = ui.FrameDesignerD(tab, d.reset, ft.partial(trainsition, scene))

    for i in teams:
        for j in teams[i]:
            url = teams[i][j].videoURL
            cmd = d.reset if url is None else utils.fpf(d.reset, ft.partial(d.setURL, cp.copy(url)))
            fr.add(text = '{0} - {1}'.format(i, j), command = cmd)

    return tab


def OnevOne(teams, u, desc, text, scene):
    d = delivery._FewStreamManager(desc, 2)

    tab = u.addTab(text)
    fr = ui.FrameDesignerB(tab, d.reset, ft.partial(trainsition, scene))

    for i in teams:
        for j in teams[i]:
            url = teams[i][j].videoURL
            if url is not None:
                cmd = ft.partial(d.setURL, cp.copy(url))
            fr.add(text = '{0} - {1}'.format(i, j), command = cmd)

    return tab


def OneTeam(teams, u, desc, text, scene):
    d = delivery._FewStreamManager(desc, 3)

    tab = u.addTab(text)
    fr = ui.FrameDesignerB(tab, d.reset, ft.partial(trainsition, scene))

    for i in teams:
        urls = [teams[i][j].videoURL for j in teams[i] if teams[i][j] is not None]
        cmd = utils.fpf(d.reset, ft.partial(d.setURL, *cp.copy(urls)))
        fr.add(text = i, command=cmd)

    return tab


def TowvTow(teams, u, desc, text, scene):
    d = delivery._ManySteamManager(desc, 2, 2)

    tab = u.addTab(text)
    fr = ui.FrameDesignerA(tab, d.reset, ft.partial(trainsition, scene))

    for i in teams:

        mem = teams[i].keys()

        def cmd(team, *selmem):
            print(selmem)
            d.setURL(id(team), *[team[j].videoURL for j in selmem])

        fr.add(text=i, command=ft.partial(cmd, cp.copy(teams[i])), member=mem)


    return tab

def OptionTab(u: ui.UI, text: str, listreload):
    tab = u.addTab(text)
    fr = ui.FrameDesignerC(tab)

    fr.add(text='リスト再読込', command = listreload)

    return tab

def imptabCreate(teams: ParticipantManager.Participant, u: ui.tk.Widget):

    imptab = list()
    db = obscontrol.read_db()

    imptab.append(onlyOne(teams, u, 49513, '一人視点 A', db['1a']))
    imptab.append(onlyOne(teams, u, 49514, '一人視点 B', db['1b']))

    imptab.append(OnevOne(teams, u, 49515, '1vs1 A', db['2a']))
    imptab.append(OnevOne(teams, u, 49517, '1vs1 B', db['2b']))

    imptab.append(OnevOne(teams, u, 49519, '収容所 A', db['ga']))
    imptab.append(OnevOne(teams, u, 49521, '収容所 B', db['gb']))

    imptab.append(OneTeam(teams, u, 49523, '1チーム視点 A', db['3a']))
    imptab.append(OneTeam(teams, u, 49526, '1チーム視点 B', db['3b']))

    TowvTow(teams, u, 49529, '2vs2 A', db['4a'])
    TowvTow(teams, u, 49533, '2vs2 B', db['4b'])

    return imptab

def main():
    teams = ParticipantManager.readFile()
    u = ui.UI()

    imptab = imptabCreate(teams, u)

    def listreload():
        teams = ParticipantManager.readFile()
        u.destroy()
        main()
    OptionTab(u, 'オプション', listreload)

    u.mainloop()


if __name__ == '__main__':
    main()
<file_sep>#!/usr/bin/env python3

import pyslobs as slobs
import asyncio


async def set_sceneitem_size(conn, scene_id, item_id, width, height):
    ss = slobs.ScenesService(conn)
    scene = await ss.get_scene(scene_id)
    item = await scene.get_item(item_id)
    source = await item.get_source()
    if source.width != 0 and source.height !=0:
        x_scale = float(width) / float(source.width)
        y_scale = float(height) / float(source.height)
        await item.set_scale(slobs.IVec2(x_scale, y_scale))
    await conn.close()


async def set_sceneitem_position(conn, scene_id, item_id, x_pos, y_pos):
    ss = slobs.ScenesService(conn)
    scene = await ss.get_scene(scene_id)
    item = await scene.get_item(item_id)

    old_transform = item.transform
    new_transform = slobs.ITransform(
            crop=old_transform.crop,
            scale=old_transform.scale,
            position=slobs.IVec2(
                x=x_pos,
                y=y_pos,
                ),
            rotation=old_transform.rotation,
            )

    await item.set_transform(new_transform)
    await conn.close()


async def stadio_mode(conn: slobs.SlobsConnection):
    ts = slobs.TransitionsService(conn)
    await ts.enable_studio_mode()
    await conn.close()


async def transiton(conn: slobs.SlobsConnection):
    ts = slobs.TransitionsService(conn)
    await ts.execute_studio_mode_transition()
    await conn.close()


async def make_active(conn: slobs.SlobsConnection, scene_id: str):
    ss = slobs.ScenesService(conn)
    await ss.make_scene_active(scene_id)
    await conn.close()


async def get_settings(conn: slobs.SlobsConnection, source_id: str):
    ss = slobs.SourcesService(conn)
    source = await ss.get_source(source_id)
    settings = await source.get_settings()
    print(settings)
    await conn.close()


async def change_source_file(conn: slobs.SlobsConnection, source_id: str, filename: str):
    ss = slobs.SourcesService(conn)
    source = await ss.get_source(source_id)
    await source.update_settings({'file': filename})
    await conn.close()


async def change_source_input(conn: slobs.SlobsConnection, source_id: str, inputname: str):
    ss = slobs.SourcesService(conn)
    source = await ss.get_source(source_id)
    await source.update_settings({'input': inputname})
    await conn.close()


async def print_settings(conn: slobs.SlobsConnection, source_id: str):
    ss = slobs.SourcesService(conn)
    source = await ss.get_source(source_id)
    settings = await source.get_settings()
    print(settings)
    await conn.close()


class ObsControl:

    def set_sceneitem_size(self, scene_id, item_id, width, height):
        conn = slobs.SlobsConnection(slobs.config_from_ini())
        async def main():
            await asyncio.gather(conn.background_processing(),
                    set_sceneitem_size(conn, scene_id, item_id, width, height))
        asyncio.run(main())

    def set_sceneitem_position(self, scene_id, item_id, x_pos, y_pos):
        conn = slobs.SlobsConnection(slobs.config_from_ini())
        async def main():
            await asyncio.gather(conn.background_processing(),
                    set_sceneitem_position(conn, scene_id, item_id, x_pos, y_pos))
        asyncio.run(main())

    def stadio_mode(self):
        conn = slobs.SlobsConnection(slobs.config_from_ini())
        async def main():
            await asyncio.gather(conn.background_processing(), stadio_mode(conn))
        asyncio.run(main())

    def transition(self):
        conn = slobs.SlobsConnection(slobs.config_from_ini())
        async def main():
            await asyncio.gather(conn.background_processing(), transiton(conn))
        asyncio.run(main())

    def make_active(self, scene_id: str):
        conn = slobs.SlobsConnection(slobs.config_from_ini())
        async def main():
            await asyncio.gather(conn.background_processing(), make_active(conn, scene_id))
        asyncio.run(main())

    def change_source_file(self, source_id: str, filename: str):
        conn = slobs.SlobsConnection(slobs.config_from_ini())
        async def main():
            await asyncio.gather(conn.background_processing(), change_source_file(conn, source_id, filename))
        asyncio.run(main())

    def change_source_input(self, source_id: str, inputname: str):
        conn = slobs.SlobsConnection(slobs.config_from_ini())
        async def main():
            await asyncio.gather(conn.background_processing(), change_source_input(conn, source_id, inputname))
        asyncio.run(main())

    def print_settings(self, source_id: str):
        conn = slobs.SlobsConnection(slobs.config_from_ini())
        async def main():
            await asyncio.gather(conn.background_processing(), print_settings(conn, source_id))
        asyncio.run(main())
<file_sep>#!/usr/bin/env python3

import tkinter as tk
import functools as ft

from . import _utils as utils
from . import _ButtonCanBeSelected as bcbs
from . import _CheckbuttonCanBeSelected as ccbs

class CheckbuttonFromButtons:
    def __init__(self, btnframe, cbframe1, cbframe2):
        self.__bcbs = bcbs.OnlyTowButtonCanBeSelected(btnframe)
        self.__ccbs1 = ccbs.OnlyTowCheckbuttonCanBeSelected(cbframe1)
        self.__ccbs2 = ccbs.OnlyTowCheckbuttonCanBeSelected(cbframe2)

    def __buttonCommand(self, cmd, mem):
        kw = dict()

        if self.__bcbs.count == 1:
            kw['command'] = lambda: cmd(*self.__ccbs1.selected)
            targetframe = self.__ccbs1
        else:
            kw['command'] = lambda: cmd(*self.__ccbs2.selected)
            targetframe = self.__ccbs2

        for i in mem:
            kw['text'] = i
            bln = tk.BooleanVar()
            bln.set(False)
            kw['variable'] = bln
            targetframe.addCheckbutton(**kw).pack()

    def addButton(self, **kw):

        cmd = kw.pop('command') if 'command' in kw else None
        mem = kw.pop('member') if 'member' in kw else tuple()
        kw['command'] = ft.partial(self.__buttonCommand, cmd, mem)

        return self.__bcbs.addButton(**kw)

    def reset(self):
        self.__ccbs1.cleanFrame()
        self.__ccbs2.cleanFrame()
        self.__bcbs.deselectAll()

<file_sep>#!/usr/bin/env python3

import csv
import os.path

class Player:
    def __init__(self, videourl = ''):
        self.__videourl = videourl

    @property
    def videoURL(self):
        return self.__videourl

    @videoURL.setter
    def videoURL(self, videourl):
        self.__videourl = videourl

class Team(dict[str,Player]):
    pass

class Participant(dict[str,Team]):
    pass

def readFile(filepath = os.path.expanduser('~/ParticipantList.txt')):
    ret = Participant()

    with open(filepath, 'r',encoding="utf-8_sig") as fd:
        reader = csv.DictReader(fd, skipinitialspace = True)

        for part in reader:
            ret.setdefault(part['TeamName'], Team())
            ret[part['TeamName']][part['PlayerName']] = Player(videourl = part['VideoURL'])

    return ret

<file_sep>#!/usr/bin/env python3

import tkinter as tk
import functools as ft

from ._utils import *
from ._ButtonCanBeSelected import *

from . import _CheckbuttonFromButtons as cbfb

RESETBUTTONTEXT = 'リセット'
TRANSITIONBUTTONTEXT = 'トランジション'

class FrameDesignerA:
    '''
    ボタンを押すと左上にチェックボタンが現れます。ボタンは2個まで押せます。
    '''

    def __init__(self, master, resetfunc, transfunc):

        self.__packer = ManyBuutonsPacker(12)

        frames = FrameMaker(master)

        cbframe1 = tk.Frame(frames.upperleft)
        cbframe1.pack(side=tk.LEFT)

        cbframe2 = tk.Frame(frames.upperleft)
        cbframe2.pack(side=tk.LEFT)

        self.__cbfb = cbfb.CheckbuttonFromButtons(frames.down, cbframe1, cbframe2)

        def reset():
            resetfunc()
            self.__cbfb.reset()
        resetbutton = tk.Button(frames.upperright, text=RESETBUTTONTEXT, command=reset, height=3)
        resetbutton.pack(padx=PAD, pady=PAD, side=tk.LEFT)

        transbutton = tk.Button(frames.upperright, text=TRANSITIONBUTTONTEXT, command=transfunc, height=3)
        transbutton.pack(padx=PAD, pady=PAD, side=tk.LEFT)


    def add(self, **kw):

        kw.setdefault('width', 12)

        btn = self.__cbfb.addButton(**kw)
        self.__packer.pack(btn)

class FrameDesignerB:
    '''
    ボタンを2個まで押せます。
    '''

    def __init__(self, master, resetfunc, transfunc):
        self.__packer = ManyBuutonsPacker(6)
        self.__resetfunc = resetfunc
        self.__transfnuc = transfunc

        frames = FrameMaker(master)

        resetbutton = tk.Button(frames.upperright, text=RESETBUTTONTEXT, command=self.reset, height=3)
        resetbutton.pack(padx=PAD, pady=PAD, side=tk.LEFT)

        transbutton = tk.Button(frames.upperright, text=TRANSITIONBUTTONTEXT, command=transfunc, height=3)
        transbutton.pack(padx=PAD, pady=PAD, side=tk.LEFT)

        self.__mbc = OnlyTowButtonCanBeSelected(frames.down)

    def __buttonCommand(self, cmd):
        if cmd is not None:
            cmd()

    def add(self, **kw):

        kw.setdefault('width', 27)

        btn = self.__mbc.addButton(**kw)
        self.__packer.pack(btn)

    def reset(self):
        self.__resetfunc()
        self.__mbc.deselectAll()


class FrameDesignerC:
    def __init__(self, master):
        self.__master = master

    def add(self, **kw):
        btn = tk.Button(self.__master, **kw)
        btn.pack()

class FrameDesignerD:
    '''
    ボタンは1個しか押せません。
    '''

    def __init__(self, master, resetfunc, transfunc):
        self.__packer = ManyBuutonsPacker(6)
        self.__resetfunc = resetfunc
        self.__transfnuc = transfunc

        frames = FrameMaker(master)

        resetbutton = tk.Button(frames.upperright, text=RESETBUTTONTEXT, command=self.reset, height=3)
        resetbutton.pack(padx=PAD, pady=PAD, side=tk.LEFT)

        transbutton = tk.Button(frames.upperright, text=TRANSITIONBUTTONTEXT, command=transfunc, height=3)
        transbutton.pack(padx=PAD, pady=PAD, side=tk.LEFT)

        self.__mbc = OnlyOneButtonCanBeSelected(frames.down)

    def __buttonCommand(self, cmd):
        if cmd is not None:
            cmd()

    def add(self, **kw):

        kw.setdefault('width', 27)

        btn = self.__mbc.addButton(**kw)
        self.__packer.pack(btn)

    def reset(self):
        self.__resetfunc()
        self.__mbc.deselectAll()


class UI(tk.Tk):
    '''
    タブ付きウィンドウを作る
    '''

    def __init__(self):
        super().__init__()
        self.__notebook = ttk.Notebook(self)
        self.__notebook.pack()
        self.__cmdlist = {}
        def tab_changed(_):
            if len(self.__cmdlist) != 0:
                cmd = self.__cmdlist[self.__notebook.select()]
                if cmd is not None:
                    cmd()
        self.bind('<<NotebookTabChanged>>', tab_changed)
        self.__openingtab = None

    def addTab(self, text = '', openfunc = None, closefunc = None):
        frame = tk.Frame(self.__notebook)
        self.__notebook.add(frame, text = text)
        self.__cmdlist[self.__notebook.tabs()[self.__notebook.index('end')-1]] = openfunc
        return frame

<file_sep>#!/usr/bin/env python3

class _fpf:
    def __init__(self, f1, f2):
        self.__f1 = f1
        self.__f2 = f2

    def __func(self):
        self.__f1()
        self.__f2()

    def func(self):
        return lambda: self.__func()

def fpf(f1, f2):
    '''
    関数同士をつなぎ合わせるだけ
    '''
    return _fpf(f1,f2).func()

