import pandas as pd
import numpy as np
import pathlib as pl
import seaborn as sns
import matplotlib.pyplot as plt

from tqdm import tqdm
from scipy.stats import median_abs_deviation
from sklearn.metrics import roc_auc_score
from typing import Tuple, Optional, Dict

from utils.plotting import transform_plot_ax
from .adVMP_crossval import format_p
from .adVMP_discovery import order_heatmap

def get_significance(
    data: pd.DataFrame,
    clin: pd.DataFrame,
    union_cpgs: np.ndarray,
    background_cpgs: Optional[np.ndarray] = None,
    nadj: bool = True,
    hit_limit: float = 2,
    risk_col: str = "Ad_risk",
    exclude_one: bool = True,
    n_iter: int = 500,
    order: str = "Hit fraction",
) -> Tuple[np.ndarray, np.ndarray]:
    rdn_scores = []
    higher = []
    for i in tqdm(range(n_iter)):
        if background_cpgs is None:
            rdn_cpgs = np.random.choice(
                data.columns,
                size=(len(data.columns.intersection(union_cpgs))),
                replace=False,
            )
        else:
            rdn_cpgs = np.random.choice(
                data.columns.intersection(background_cpgs),
                size=(len(data.columns.intersection(union_cpgs))),
                replace=False,
            )
        selcpgs = rdn_cpgs

        healthy_pat = clin[risk_col] == 0

        # median_test = data.loc[:, data.columns.intersection(selcpgs)].median()
        median_test = data.loc[healthy_pat, data.columns.intersection(selcpgs)].median()
        # mad_test = median_abs_deviation(data.loc[:, data.columns.intersection(selcpgs)])
        mad_test = median_abs_deviation(
            data.loc[healthy_pat, data.columns.intersection(selcpgs)]
        )
        mad_test = pd.Series(mad_test, index=data.columns.intersection(selcpgs))

        test_z_score = data[data.columns.intersection(selcpgs)]
        test_z_score = (test_z_score - median_test) / mad_test

        hit_test = (test_z_score.abs() > hit_limit).astype(int)
        hit_fraction = hit_test.sum(axis=1) / hit_test.shape[1]
        hit_fraction.name = "Hit fraction"

        heatmap_df = pd.concat([test_z_score, clin[risk_col], hit_fraction], axis=1)

        heatmap_df = order_heatmap(heatmap_df=heatmap_df)

        if nadj:
            red_df = heatmap_df[heatmap_df[risk_col].isin([0, 1])]
        else:
            red_df = heatmap_df.copy()
            if exclude_one:
                red_df = red_df[red_df[risk_col] != 1]
            else:
                red_df[risk_col] = red_df[risk_col].replace({i: 0 for i in range(2)})
            red_df[risk_col] = red_df[risk_col].replace(
                {i: 1 for i in range(2, int(red_df[risk_col].max()) + 1)}
            )

        rdn_scores.append(
            roc_auc_score(
                y_true=red_df[risk_col].ravel(), y_score=red_df[order].ravel()
            )
        )

    return rdn_scores

def get_comparison_rdn_val(
    background_cpgs: np.ndarray,
    figdir: pl.Path,
    ref: float,
    phenotypes: np.ndarray,
    union_cpgs: Dict,
    data: pd.DataFrame,
    clin: pd.DataFrame,
    n_iter: int = 100,
    nadj: bool = True,
    hit_limit: int = 4,
    risk_col: str = "Ad_risk",
    exclude_one: bool = True,
    age_col: Optional[str] = "Age at visit",
    order: str = "Hit fraction",
) -> None:
    avg_perf = get_significance(
        data=data,
        clin=clin,
        union_cpgs=union_cpgs,
        background_cpgs=None,
        nadj=nadj,
        hit_limit=hit_limit,
        risk_col=risk_col,
        exclude_one=exclude_one,
        n_iter=n_iter,
        order=order,
    )
    avg_perf_back = get_significance(
        data=data,
        clin=clin,
        union_cpgs=union_cpgs,
        background_cpgs=background_cpgs,
        nadj=nadj,
        hit_limit=hit_limit,
        risk_col=risk_col,
        exclude_one=exclude_one,
        n_iter=n_iter,
        order=order,
    )

    pval_rdn = np.sum(ref < np.array(avg_perf)) / len(avg_perf)
    pval_rdn_bck = np.sum(ref < np.array(avg_perf_back)) / len(avg_perf_back)
    df = pd.concat(
        [
            pd.DataFrame(avg_perf, columns=["Random CpGs"]),
            pd.DataFrame(avg_perf_back, columns=["Random Highly Variable CpGs"]),
        ],
        axis=1,
    )

    if age_col is not None:
        if nadj:
            patloc = np.where((phenotypes == 0) | (phenotypes == 1))[0]
            cdf = clin.iloc[patloc]
            age_ref = roc_auc_score(
                y_score=cdf[age_col].ravel(), y_true=phenotypes[patloc]
            )
        else:
            if exclude_one:
                tokeep = np.where(phenotypes != 1)[0]
                cdf = clin.iloc[tokeep].copy()
                redphen = phenotypes[tokeep]
                redphen = pd.Series(redphen).replace(
                    {i: 1 for i in range(2, int(np.max(phenotypes)) + 1)}
                )
                age_ref = roc_auc_score(y_score=cdf[age_col].ravel(), y_true=redphen)
            else:
                redphen = phenotypes
                redphen = pd.Series(redphen).replace({i: 0 for i in range(2)}).ravel()
                redphen = (
                    pd.Series(redphen)
                    .replace({i: 1 for i in range(2, int(np.max(phenotypes)) + 1)})
                    .ravel()
                )
                age_ref = roc_auc_score(y_score=clin[age_col].ravel(), y_true=redphen)

    fig, ax = plt.subplots(1, 1)
    sns.boxplot(data=df, ax=ax, palette="bright")
    ax.set_ylim([0.4, 1])
    xmin, xmax = ax.get_xlim()
    # vertical lines
    ax.hlines(y=0.5, xmin=xmin, xmax=xmax, colors="r", lw=2, label="Random")
    if age_col is not None:
        ax.hlines(
            y=age_ref, xmin=xmin, xmax=xmax, colors="orange", ls="--", lw=2, label="Age"
        )
    ax.hlines(y=ref, xmin=xmin, xmax=xmax, colors="b", ls="--", lw=2, label="adVMP")

    ax.text(-0.1, 1.1 * ref, format_p(pval_rdn, len(avg_perf)), fontdict={"size": 15})
    ax.text(
        0.9,
        min(1.1 * ref, 0.8),
        format_p(pval_rdn_bck, len(avg_perf_back)),
        fontdict={"size": 15},
    )

    transform_plot_ax(ax, legend_title="")
    fig.savefig(figdir / "comparison_rdn_cpgs.svg", bbox_inches="tight")


import xlrd, xlwt

def get_new_count_product(file_name):
    counts = []
    with open(f"{file_name}.txt", 'r') as filename:
        try:
            for info in filename:
                info = info.strip()
                product, count = info.split(':')
                counts.append(count)
        except:
            pass

    return counts

def get_data_in_exele_file(file_name, new_count):
    rb = xlrd.open_workbook(f'{file_name}.xls', formatting_info=True)
    sheet = rb.sheet_by_index(0)
    vals = [sheet.row_values(rownum) for rownum in range(sheet.nrows)]

    new_data = []

    for number, val in enumerate(vals):
        try:
            val.append(new_count[number])
            new_data.append(val)
        except:
            pass
    return new_data

def read_first_exele_file(name_file):
    wb = xlwt.Workbook()
    ws = wb.add_sheet('main', cell_overwrite_ok=True)
    ws._cell_overwrite_ok = True

    with open(f'{name_file}.txt', 'r') as file:
        nrow = 0
        for info in file:
            collum = 0
            try:
                data = []
                info = info.strip()
                product, count = info.split(':')
                data.append([product, count])

                for dt in data[0]:
                    ws.write(nrow, collum, dt)
                    collum += 1
                nrow += 1
            except Exception as e:
                print(e)
    wb.save(f'{name_file}.xls')

def read_new_exele_file(name_file):
    new_count = get_new_count_product(name_file)
    data = get_data_in_exele_file(name_file, new_count)

    wb = xlwt.Workbook()
    ws = wb.add_sheet('main', cell_overwrite_ok=True)
    ws._cell_overwrite_ok = True
    try:
        nrow = 0
        for dt in data:
            collum = 0
            for d in dt:
                ws.write(nrow, collum, d)
                collum += 1
            nrow += 1
    except Exception as e:
        print(e)

    wb.save(f'{name_file}.xls')

# получение последнего колва продукта всех столбцов по колву
def get_last_count_product(file_name):
    rb = xlrd.open_workbook(f'{file_name}.xls', formatting_info=True)
    count = []
    sheet = rb.sheet_by_index(0)
    vals = [sheet.row_values(rownum) for rownum in range(sheet.nrows)]

    for val in vals:
        count_object_in_val = len(val)
        catcount = []
        for l in range(count_object_in_val-1):
            catcount.append([val[l+1]])
        count.append(catcount)
    return count

def get_phinish_count(file_name):
    counts_list = get_last_count_product(file_name)
    print(counts_list[0])
    data_list_count = []

    for counts in counts_list:
        two = counts[1][0]
        one = counts[0][0]
        try:
            count_phinish = int(two) - int(one)
            data_list_count.append(count_phinish)
        except Exception as e:
            try:
                counts_phinish_ = float(two) - float(one)
                data_list_count.append(counts_phinish_)
            except:
                data_list_count.append(one)

    return data_list_count

def read_last_exele_file(name_file):
    counts = get_phinish_count(name_file)
    data = get_data_in_exele_file(name_file, counts)

    wb = xlwt.Workbook()
    ws = wb.add_sheet('main', cell_overwrite_ok=True)
    ws._cell_overwrite_ok = True
    try:
        nrow = 0
        for dt in data:
            collum = 0
            for d in dt:
                ws.write(nrow, collum, d)
                collum += 1
            nrow += 1
    except Exception as e:
        print(e)

    wb.save(f'{name_file}.xls')


#!/usr/bin/python3

import click
from Bio import SeqIO
@click.command()
@click.argument('inputfilename')

def remove_small_contigs(inputfilename):
    """remove contigs smaller than 300bp (store in separate .fa file)"""

    smaller_than_300bp = []
    larger_than_300bp = []
    for record in SeqIO.parse(inputfilename, "fasta"):
        if len(record.seq) <= 300:
            smaller_than_300bp.append(record)
        elif 300 < len(record.seq):
            larger_than_300bp.append(record)

    SeqIO.write(smaller_than_300bp, "contigs_smaller_than_300bp.fa", "fasta")
    SeqIO.write(larger_than_300bp, "contigs_larger_than_300bp.fa", "fasta")

if __name__ == '__main__':
    remove_small_contigs()


# -*- coding: utf-8 -*-
from scrapy import Request, Spider, Selector
import datetime

from FirstSpider.items import *

def parse_index(response):
    items = response.xpath('//li[@class="js-smallCards _box"]')
    for item in items:
        bcy_item = BcyItem()
        bcy_item['author'] = item.xpath('a[@class="db posr ovf"]/@title').extract_first()
        bcy_item['pic_url'] = item.xpath('a/img/@src').extract_first().replace('/2X3', '')
        yield bcy_item

class BcySpider(Spider):
    name = 'bcy'
    allowed_domains = ['bcy.net']

    index_url = 'https://bcy.net/illust/toppost100?type=lastday&date={d}'

    ajax_url = 'https://bcy.net/illust/index/ajaxloadtoppost?p=1&type=lastday&date={d}'

    date_list = []  # 日期范围列表

    ajax_headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/68.0.3440.106 Safari/537.36',
        'Host': 'bcy.net',
        'Origin': 'https://bcy.net',
        'X-Requested-With': 'XMLHttpRequest'
    }

    def start_requests(self):
        self.init_date_list()
        for date in self.date_list:
            yield Request(self.index_url.format(d=date), callback=parse_index)
        for date in self.date_list:
            yield Request(self.ajax_url.format(d=date), callback=parse_index)

    # 构造一个日期列表
    def init_date_list(self):
        begin_date = datetime.datetime.strptime("20150918", "%Y%m%d")
        end_date = datetime.datetime.strptime("20180827", "%Y%m%d")
        while begin_date <= end_date:
            date_str = begin_date.strftime("%Y%m%d")
            self.date_list.append(date_str)
            begin_date += datetime.timedelta(days=1)


import random
import uuid
from Crypto.Util.Padding import pad, unpad
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA
from rsa import rsaKeyServer
import socket
import time

"""Helper Functions"""

# Returns current time in milliseconds from epoch (INT)
def returnCurrentTime():
    return int(time.time_ns() / 1000)

# Verifies incoming timestamps are within 10 seconds
def timestampGate(ts, s):
    if(returnCurrentTime() - ts > 10000 or s is None):
            s.send("Timed out!")
            s.close()
            exit(-1)

# Inititate Private and public RSA key
user_public_key = rsaKeyServer()

my_email = "dstingaciu@ryerson.ca"

delim = ";==;"
class key_exchange_with_org_key_server:
    def __init__(self):
        self.s = socket.socket()
        self.ksPort = 60000
        self.orgServer = "127.0.0.1"

    def initConnection(self):
        # Initiate connection to org key server
        self.s.connect((self.orgServer, self.ksPort))

        # Receive public key string and org name
        orgPubStr, orgName = self.s.recv(1024).decode().split(delim)
        print("Welcome to " + orgName)

        # Convert public key string to usable public key
        self.orgPub = PKCS1_v1_5.new(RSA.import_key(orgPubStr))

        # Prepare client key string and TS response
        clientPubKeyStr = user_public_key.key.public_key().export_key().decode()
        firstClientResponse = f"{clientPubKeyStr}{delim}{returnCurrentTime()}".encode()

        # Send client key
        self.s.send(firstClientResponse)

        self.beginKeyExchangeVerification()

    def beginKeyExchangeVerification(self):
        # Generate random N1
        N1 = uuid.uuid4().hex

        # Prepare N1 Str and encrypt with org public key
        N1Str = f"{N1}{delim}{returnCurrentTime()}"
        N1_enc = self.orgPub.encrypt(str.encode(N1Str))

        # Send encrypted N1 Str
        self.s.send(N1_enc)

        # Receive N1, N2, TS Str and split message
        N1N2_enc = self.s.recv(2048)
        N1_check, N2, TS = user_public_key.decryptMessage(N1N2_enc).split(delim)

        # Check N1
        if(N1_check != N1):
            self.s.send("N1 unverified, closing socket!")
            self.s.close()
            return

        # Verify time stamp is within 10 seconds
        timestampGate(int(TS), self.s)

        # Prepare N2 string
        N2Str = f"{N2}{delim}{returnCurrentTime()}"

        # Send N2 String
        self.s.send(self.orgPub.encrypt(str.encode(N2Str)))

        self.sendUserEmailToKs()

    def sendUserEmailToKs(self):
        # Setup email string
        email_str = f"{my_email}{delim}{returnCurrentTime()}"
        self.s.send(self.orgPub.encrypt(str.encode(email_str)))

        ack_enc = self.s.recv(1024)
        ack_str = user_public_key.decryptMessage(ack_enc)

        if(ack_str.strip() == "added"):
            print("Added session key!")

        self.s.close()

ks_ex = key_exchange_with_org_key_server()
ks_ex.initConnection()


import enum
import os
import shared
import sys

from pathlib import Path

parser = shared.create_parser()
parser.add_argument(
    '--minimize-location',
    help='location to minimize windows to in the MDI area',
    default='BottomLeft',
    choices=['TopLeft', 'TopRight', 'BottomLeft', 'BottomRight'],
)
parser.add_argument(
    '--border-width',
    help='width of the subwindow borders',
    type=int,
    choices=range(0, 6),
    default=1,
)
parser.add_argument(
    '--default-window-frame',
    help='use the default title bars',
    action='store_true',
)
parser.add_argument(
    '--status-bar',
    help='use a top-level status bar',
    action='store_true',
)
parser.add_argument(
    '--window-help',
    help='add a top-level context help button',
    action='store_true',
)
parser.add_argument(
    '--window-shade',
    help='add a top-level shade/unshade button',
    action='store_true',
)
parser.add_argument(
    '--wayland-testing',
    help='debug with a custom titlebar on wayland',
    action='store_true',
)
args, unknown = shared.parse_args(parser)
QtCore, QtGui, QtWidgets = shared.import_qt(args)
compat = shared.get_compat_definitions(args)
colors = shared.get_colors(args, compat)
ICON_MAP = shared.get_icon_map(args, compat)
# 100ms between repaints, so we avoid over-repainting.
# Allows us to avoid glitchy motion during drags/
REPAINT_TIMER = 100
TRACK_TIMER = 20
CLICK_TIMER = 20
# Make the titlebar size too large, so we can get the real value with min.
TITLEBAR_HEIGHT = 2**16
# QWIDGETSIZE_MAX isn't exported, which is needed to remove fixedSize constraints.
QWIDGETSIZE_MAX = (1 << 24) - 1

# Determine the Linux display server protocol we're using.
# Use `XDG_SESSION_TYPE`, since we can override it for X11.
IS_WAYLAND = os.environ.get('XDG_SESSION_TYPE') == 'wayland'
IS_XWAYLAND = os.environ.get('XDG_SESSION_TYPE') == 'xwayland'
IS_X11 = os.environ.get('XDG_SESSION_TYPE') == 'x11'
# We can run X11 on Wayland, but this doesn't support certain
# features like mouse grabbing, so we don't use it here.
IS_TRUE_WAYLAND = 'WAYLAND_DISPLAY' in os.environ
USE_WAYLAND_FRAME = IS_WAYLAND and not args.wayland_testing

# Add a warning if we're using Wayland with a custom titlebar.
if not args.default_window_frame and USE_WAYLAND_FRAME:
    print('WARNING: Wayland does not support custom title bars.', file=sys.stderr)
    print('Applications in Wayland cannot set their own position.', file=sys.stderr)
    print('Defaulting to the system title bar instead.', file=sys.stderr)

class MinimizeLocation(enum.IntEnum):
    '''Location where to place minimized widgets.'''

    TopLeft = 0
    TopRight = 1
    BottomLeft = 2
    BottomRight = 3

class WindowEdge(enum.IntEnum):
    '''Enumerations for window edge positions.'''

    NoEdge = 0
    Top = 1
    Bottom = 2
    Left = 3
    Right = 4
    TopLeft = 5
    TopRight = 6
    BottomLeft = 7
    BottomRight = 8

MINIMIZE_LOCATION = getattr(MinimizeLocation, args.minimize_location)
TOP_EDGES = (WindowEdge.Top, WindowEdge.TopLeft, WindowEdge.TopRight)
BOTTOM_EDGES = (WindowEdge.Bottom, WindowEdge.BottomLeft, WindowEdge.BottomRight)
LEFT_EDGES = (WindowEdge.Left, WindowEdge.TopLeft, WindowEdge.BottomLeft)
RIGHT_EDGES = (WindowEdge.Right, WindowEdge.TopRight, WindowEdge.BottomRight)

def standard_icon(widget, icon):
    '''Get a standard icon.'''
    return shared.standard_icon(args, widget, icon, ICON_MAP)

def menu_icon(widget):
    '''Get the menu icon depending on the stylesheet.'''
    return standard_icon(widget, compat.SP_TitleBarMenuButton)

def minimize_icon(widget):
    '''Get the minimize icon depending on the stylesheet.'''
    return standard_icon(widget, compat.SP_TitleBarMinButton)

def maximize_icon(widget):
    '''Get the maximize icon depending on the stylesheet.'''
    return standard_icon(widget, compat.SP_TitleBarMaxButton)

def restore_icon(widget):
    '''Get the restore icon depending on the stylesheet.'''
    return standard_icon(widget, compat.SP_TitleBarNormalButton)

def help_icon(widget):
    '''Get the help icon depending on the stylesheet.'''
    return standard_icon(widget, compat.SP_TitleBarContextHelpButton)

def shade_icon(widget):
    '''Get the shade icon depending on the stylesheet.'''
    return standard_icon(widget, compat.SP_TitleBarShadeButton)

def unshade_icon(widget):
    '''Get the unshade icon depending on the stylesheet.'''
    return standard_icon(widget, compat.SP_TitleBarUnshadeButton)

def close_icon(widget):
    '''Get the close icon depending on the stylesheet.'''
    return standard_icon(widget, compat.SP_TitleBarCloseButton)

def transparent_icon(widget):
    '''Create a transparent icon.'''
    return QtGui.QIcon()

def action(text, parent=None, icon=None, checkable=None):
    '''Create a custom QAction.'''

    value = compat.QAction(text, parent)
    if icon is not None:
        value.setIcon(icon)
    if checkable is not None:
        value.setCheckable(checkable)

    return value

def size_greater(x, y):
    '''Compare 2 sizes, determining if any bounds of x are greater than y.'''
    return x.width() > y.width() or x.height() > y.height()

def size_less(x, y):
    '''Compare 2 sizes, determining if any bounds of x are less than y.'''
    return x.width() < y.width() or x.height() < y.height()

# UI WIDGETS
# These are just to populate the views: these could be anything.

class LargeTable(QtWidgets.QTableWidget):
    '''Table with a large number of elements.'''

    def __init__(self, parent=None):
        super().__init__(parent)

        self.setColumnCount(100)
        self.setRowCount(100)
        for index in range(100):
            row = QtWidgets.QTableWidgetItem(f'Row {index + 1}')
            self.setVerticalHeaderItem(index, row)
            column = QtWidgets.QTableWidgetItem(f'Column {index + 1}')
            self.setHorizontalHeaderItem(index, column)

class SortableTree(QtWidgets.QTreeWidget):
    '''Tree with checkboxes and a sort indicator on the header.'''

    def __init__(self, parent=None):
        super().__init__(parent)

        self.item0 = QtWidgets.QTreeWidgetItem(self)
        self.item1 = QtWidgets.QTreeWidgetItem(self)
        self.item2 = QtWidgets.QTreeWidgetItem(self.item1)
        self.item2.setText(0, 'subitem')
        self.item3 = QtWidgets.QTreeWidgetItem(self.item2, ['Row 2.1'])
        self.item3.setFlags(self.item3.flags() | compat.ItemIsUserCheckable)
        self.item3.setCheckState(0, compat.Unchecked)
        self.item4 = QtWidgets.QTreeWidgetItem(self.item2, ['Row 2.2'])
        self.item5 = QtWidgets.QTreeWidgetItem(self.item4, ['Row 2.2.1'])
        self.item6 = QtWidgets.QTreeWidgetItem(self.item5, ['Row 2.2.1.1'])
        self.item7 = QtWidgets.QTreeWidgetItem(self.item5, ['Row 2.2.1.2'])
        self.item3.setFlags(self.item7.flags() | compat.ItemIsUserCheckable)
        self.item7.setCheckState(0, compat.Checked)
        self.item8 = QtWidgets.QTreeWidgetItem(self.item2, ['Row 2.3'])
        self.item8.setFlags(self.item8.flags() | compat.ItemIsUserTristate)
        self.item8.setCheckState(0, compat.PartiallyChecked)
        self.item9 = QtWidgets.QTreeWidgetItem(self, ['Row 3'])
        self.item10 = QtWidgets.QTreeWidgetItem(self.item9, ['Row 3.1'])
        self.item11 = QtWidgets.QTreeWidgetItem(self, ['Row 4'])

        self.headerItem().setText(0, 'qdz')
        self.setSortingEnabled(False)
        self.topLevelItem(0).setText(0, 'qzd')
        self.topLevelItem(1).setText(0, 'effefe')
        self.setSortingEnabled(True)

class SettingTabs(QtWidgets.QTabWidget):
    '''Sample setting widget with a tab view.'''

    def __init__(self, parent=None):
        super().__init__(parent)

        self.setTabPosition(compat.North)
        self.general = QtWidgets.QWidget()
        self.addTab(self.general, 'General')
        self.addTab(QtWidgets.QWidget(), 'Colors')
        self.general_layout = QtWidgets.QGridLayout(self.general)
        self.general_layout.setColumnStretch(3, 10)
        for row in range(1, 10):
            self.general_layout.setRowStretch(row, 1)
        self.general_layout.setRowStretch(7, 10)

        # Add the data folder hboxlayout
        self.general_layout.addWidget(QtWidgets.QLabel('Data Folder'), 0, 0)
        self.data_folder = QtWidgets.QLineEdit(str(Path.home()))
        self.general_layout.addWidget(self.data_folder, 0, 1, 1, 3)
        self.file_dialog = QtWidgets.QPushButton('...', checkable=False)
        self.general_layout.addWidget(self.file_dialog, 0, 4)
        self.file_dialog.clicked.connect(self.launch_filedialog)

        # Add default font.
        app = QtWidgets.QApplication.instance()
        self.general_layout.addWidget(QtWidgets.QLabel('Default Font'), 1, 0)
        self.font_value = QtWidgets.QLineEdit(app.font().family())
        self.general_layout.addWidget(self.font_value, 1, 1, 1, 3)
        self.font_dialog = QtWidgets.QPushButton('...', checkable=False)
        self.general_layout.addWidget(self.font_dialog, 1, 4)
        self.font_dialog.clicked.connect(lambda _: self.launch_fontdialog(self.font_value))

        # Add item label font
        self.general_layout.addWidget(QtWidgets.QLabel('Item Label Font'), 2, 0)
        self.item_label_value = QtWidgets.QLineEdit(app.font().family())
        self.general_layout.addWidget(self.item_label_value, 2, 1, 1, 3)
        self.item_label_dialog = QtWidgets.QPushButton('...', checkable=False)
        self.general_layout.addWidget(self.item_label_dialog, 2, 4)
        self.item_label_dialog.clicked.connect(lambda _: self.launch_fontdialog(self.item_label_value))

        # Add the "Show Grid" QCheckbox.
        self.grid = QtWidgets.QCheckBox('Show grid', self.general)
        self.general_layout.addWidget(self.grid, 3, 2, 1, 1)

        # Grid square size.
        self.grid_size = QtWidgets.QLabel('Grid Square Size', self.general)
        self.general_layout.addWidget(self.grid_size, 4, 0, 1, 2)
        self.grid_spin = QtWidgets.QSpinBox(self.general)
        self.grid_spin.setValue(16)
        self.general_layout.addWidget(self.grid_spin, 4, 2, 1, 1)

        # Add units of measurement
        self.units = QtWidgets.QLabel('Default length unit of measurement', self.general)
        self.general_layout.addWidget(self.units, 5, 0, 1, 2)
        self.units_combo = QtWidgets.QComboBox()
        self.units_combo.addItem('Inches')
        self.units_combo.addItem('Foot')
        self.units_combo.addItem('Meter')
        self.general_layout.addWidget(self.units_combo, 5, 2, 1, 1)

        # Add the alignment options
        self.align_combo = QtWidgets.QComboBox()
        self.align_combo.addItem('Align Top')
        self.align_combo.addItem('Align Bottom')
        self.align_combo.addItem('Align Left')
        self.align_combo.addItem('Align Right')
        self.align_combo.addItem('Align Center')
        self.general_layout.addWidget(self.align_combo, 6, 0, 1, 2)
        self.word_wrap = QtWidgets.QCheckBox('Word Wrap', self.general)
        self.general_layout.addWidget(self.word_wrap, 6, 2, 1, 1)

    def launch_filedialog(self):
        '''Launch the file dialog and store the folder.'''

        dialog = QtWidgets.QFileDialog()
        dialog.setFileMode(compat.Directory)
        dialog.setOption(compat.FileDontUseNativeDialog)
        dialog.setDirectory(self.data_folder.text())
        if shared.execute(args, dialog):
            self.data_folder.setText(dialog.selectedFiles()[0])

    def launch_fontdialog(self, edit):
        initial = QtGui.QFont()
        initial.setFamily(edit.text())
        font, ok = QtWidgets.QFontDialog.getFont(initial)
        if ok:
            edit.setText(font.family())

# RESIZE HELPERS

def border_size(self):
    '''Get the size of the border, regardless if present.'''
    return QtCore.QSize(2 * self._border, 2 * self._border)

def minimized_content_size(self):
    '''Get the minimum content size of the widget.'''
    return self._titlebar_size

def minimized_size(self):
    '''Get the minimum size of the widget, with the size grips hidden.'''

    size = self.minimized_content_size
    if self._border:
        size = size + self.border_size
    return size

def minimum_size(self):
    '''Get the minimum size for the widget.'''

    size = self.minimized_size
    if getattr(self, '_sizegrip', None) is not None and self._sizegrip.isVisible():
        # Don't modify in place: percolates later.
        size = size + self._sizegrip_size

    if getattr(self, '_statusbar', None) is not None and self._statusbar.isVisible():
        size = size + self._statusbar_size

    return size

def get_larger_size(x, y):
    '''Get the larger of the two sizes, for both the height and width.'''
    return QtCore.QSize(max(x.width(), y.width()), max(x.height(), y.height()))

def set_minimum_size(self):
    '''Sets the minimum size of the window and the titlebar, with clobbering.'''

    self._old_minimum_size = self.minimumSize()
    self._titlebar.set_minimum_size()
    self._titlebar_size = self._titlebar.minimumSize()
    self.setMinimumSize(self.minimum_size)

def set_larger_minimum_size(self):
    '''Sets the minimum size of the window and the titlebar, without clobbering.'''

    if self._old_minimum_size is not None:
        self.setMinimumSize(self._old_minimum_size)
    self._titlebar.set_minimum_size()
    self._titlebar_size = self._titlebar.minimumSize()
    size = get_larger_size(self.minimum_size, self.minimumSize())
    self.setMinimumSize(size)

def move_to(self, position):
    '''Move the window to the desired position'''

    # Also updates the stored previous subwindow position, if applicable.
    # This means shading/unshading uses the new position of the window,
    # but the old sizes, rather than jump the window back.
    # NOTICE: this fails on Wayland. Worse, using `QMainWindow::move` on
    # Wayland causes the cursor position to be incorrect, causing issues
    # with other events.
    if IS_WAYLAND and self.window() == self:
        return

    self.move(position)
    rect = self._titlebar._window_rect
    if rect is not None:
        rect.moveTo(position)

def set_geometry(self, rect):
    '''Set the window geometry.'''

    # See `move_to` for documentation.
    self.resize(rect.size())
    window_rect = self._titlebar._window_rect
    if window_rect is not None:
        window_rect.setSize(rect.size())

    move_to(self, rect.topLeft())

def shade(self, size, grip_type):
    '''Shade the window, hiding the main widget and size grip.'''

    self._widget.hide()
    if getattr(self, f'_{grip_type}') is not None:
        getattr(self, f'_{grip_type}').hide()
    self.set_minimum_size()
    self.resize(size)

def unshade(self, rect, grip_type):
    '''Unshade the window, showing the main widget and size grip.'''

    self._widget.show()
    if getattr(self, f'_{grip_type}') is not None:
        getattr(self, f'_{grip_type}').show()
    self.set_larger_minimum_size()
    self.set_geometry(rect)

def start_drag(self, event, window_type):
    '''Start the window drag state.'''
    setattr(self, f'_{window_type}_drag', event.pos())

def handle_drag(self, event, window, window_type):
    '''Handle the window drag event.'''

    position = event.pos() - getattr(self, f'_{window_type}_drag')
    window.move_to(window.mapToParent(position))

def end_drag(self, window_type):
    '''End the window drag state.'''
    setattr(self, f'_{window_type}_drag', None)

def start_move(self, widget, window_type):
    '''Start the window move state.'''

    setattr(self, f'_{window_type}_move', widget)
    widget.menu_move_to(QtGui.QCursor.pos())

def handle_move(self, position, window_type):
    '''Handle the window move event.'''
    getattr(self, f'_{window_type}_move').menu_move_to(position)

def end_move(self, window_type):
    '''End the window move state.'''
    setattr(self, f'_{window_type}_move', None)

def start_resize(self, window, window_type):
    '''Start the window resize state.'''

    # NOTE: We can't use a rubber band with mouse tracking,
    # since mouse events only occurs if the user is holding
    # down the house. Simulating a mouse click isn't enough,
    # even if it sends a mouse press without a release.
    setattr(self, f'_{window_type}_resize', window)
    self.window().setCursor(compat.SizeFDiagCursor)
    self.menu_size_to(QtGui.QCursor.pos())

    # Grab the mouse so we can intercept the click event,
    # and track hover events outside the app. This doesn't
    # work on Wayland or on macOS.
    #   https://doc.qt.io/qt-5/qwidget.html#grabMouse
    if not IS_TRUE_WAYLAND and not sys.platform == 'darwin':
        self.window().grabMouse()

def handle_resize(self, position):
    '''Handle the window resize event.'''
    self.menu_size_to(position)

def end_resize(self, window_type):
    '''End the window resize state.'''

    window = getattr(self, f'_{window_type}_resize')
    if window is None:
        return

    setattr(self, f'_{window_type}_resize', None)
    window.window().unsetCursor()
    if not IS_TRUE_WAYLAND and not sys.platform == 'darwin':
        self.window().releaseMouse()

def start_frame(self, frame, window_type):
    '''Start the window frame resize state.'''
    setattr(self, f'_{window_type}_frame', frame)

def handle_frame(self, window, event, window_type):
    '''Handle the window frame resize event.'''

    # Check if use size grips, return early.
    frame = getattr(window, '_sizeframe', None)
    if frame is None:
        return
    self.frame_event(event, frame)

    # Store if the frame state is active.
    if frame.is_active and not getattr(self, f'_{window_type}_frame'):
        start_frame(self, frame, window_type)
    elif not frame.is_active and getattr(self, f'_{window_type}_frame'):
        end_frame(self, window_type)

def end_frame(self, window_type):
    '''End the window frame resize state.'''
    setattr(self, f'_{window_type}_frame', None)

# EVENT HANDLES

def window_resize_event(self, event):
    '''Ensure titlebar text elides normally.'''

    # Need to trigger the titlebar title resize. Need to handle it
    # here, since the SizeFrame resizes won't always trigger a
    # Label::resizeEvent, which can cause the text to stay elided.
    title_timer = self._titlebar._title._timer
    title_timer.start(REPAINT_TIMER)

    super(type(self), self).resizeEvent(event)

def window_show_event(self, event, grip_type):
    '''Set the minimum size policies once the widgets are shown.'''

    # Until shown, the size grip has inaccurate sizes.
    # Set the minimum size policy of the widget.
    # The show event occurs just after everything is shown,
    # so the widget sizes (and isVisible) are accurate.
    self._titlebar_size = self._titlebar.minimumSize()
    if getattr(self, f'_{grip_type}') is not None:
        grip_size = getattr(self, f'_{grip_type}').sizeHint()
        setattr(self, f'_{grip_type}_size', QtCore.QSize(0, grip_size.height()))
    size = get_larger_size(self.minimum_size, self.minimumSize())
    self.setMinimumSize(size)

    super(type(self), self).showEvent(event)

def window_mouse_double_click_event(self, event):
    '''Override the mouse double click, and don't call the press event.'''

    # By default, the flowchart for titlebar double clicks is as follows:
    #   1. If minimized, restore
    #   2. If maximized, restore
    #   3. If no state and can shade, shade
    #   4. If no state and cannot shade, maximize
    #   5. If shaded, unshade.
    widget = self._titlebar
    if not widget.underMouse() or event.button() != compat.LeftButton:
        return super(type(self), self).mouseDoubleClickEvent(event)
    if widget._is_shaded:
        widget.unshade()
    elif widget.isMinimized() or widget.isMaximized():
        widget.restore()
    elif widget._has_shade:
        widget.shade()
    else:
        widget.maximize()

def window_mouse_press_event(self, event, window, window_type):
    '''Override a mouse click on the titlebar to allow a move.'''

    widget = self._titlebar
    if widget.underMouse():
        # `self.window()._subwindow_move` cannot be set, since we're inside
        # the global event filter here. We handle conflicts here,
        # so only one of the 4 states can be set. We can't move
        # minimized widgets, so don't try.
        is_left = event.button() == compat.LeftButton
        is_minimized = self.isMinimized() and not widget._is_shaded
        has_frame = getattr(window, f'_{window_type}_frame') is not None
        if is_left and not is_minimized and not has_frame:
            start_drag(self.window(), event, window_type)
        elif event.button() == compat.RightButton:
            position = shared.single_point_global_position(args, event)
            shared.execute(args, widget._main_menu, position)
    return super(type(self), self).mousePressEvent(event)

def window_mouse_move_event(self, event, window, window_type):
    '''Reposition the window on the move event.'''

    if getattr(window, f'_{window_type}_frame') is not None:
        end_drag(window, window_type)
    if getattr(window, f'_{window_type}_drag') is not None:
        handle_drag(window, event, self, window_type)
    return super(type(self), self).mouseMoveEvent(event)

def window_mouse_release_event(self, event, window, window_type):
    '''End the drag event.'''

    end_drag(window, window_type)
    return super(type(self), self).mouseReleaseEvent(event)

# WINDOW WIDGETS

class Label(QtWidgets.QLabel):
    '''Custom QLabel-like class that allows text elision.'''

    def __init__(
        self,
        text='',
        parent=None,
        elide=compat.ElideNone,
        width_cb=None,
    ):
        super().__init__(text, parent)
        self._text = text
        self._elide = elide
        self._width_cb = width_cb
        self._timer = QtCore.QTimer()
        self._timer.setSingleShot(True)
        self._timer.timeout.connect(self.elide)

    def text(self):
        '''Get the internal text for the label.'''
        return self._text

    def setText(self, text):
        '''Override the set text event to store the text internally.'''

        # Need to set the text first, otherwise
        # the `width()` might be too small.
        self._text = text
        super().setText(text)
        self.elide()

    def elideMode(self):
        '''Get the elide mode for the label.'''
        return self._elide

    def setElideMode(self, elide):
        self._elide = elide

    def elide(self):
        '''Elide the text in the QLabel.'''

        # The width estimate might not be valid: check the callback.
        width = self.width()
        if self._width_cb is not None:
            width = self._width_cb()

        metrics = QtGui.QFontMetrics(self.font())
        elided = metrics.elidedText(self._text, self._elide, width)
        super().setText(elided)

class TitleButton(QtWidgets.QToolButton):
    '''An icon-only button, without borders, for the titlebar.'''

    def __init__(self, icon, parent=None):
        super().__init__()
        self.setIcon(icon)
        self.setAutoRaise(True)

class TitleBar(QtWidgets.QFrame):
    '''Custom instance of a QTitlebar'''

    def __init__(self, window, parent=None, flags=None):
        super().__init__(parent)

        # Get and set some properties.
        self.setProperty('isTitlebar', True)
        self._window = window
        self._window_type = 'window'
        if isinstance(self._window, SubWindow):
            self._window_type = 'subwindow'
        self._state = compat.WindowNoState
        self._window_rect = None
        self._has_help = False
        self._has_shade = False
        self._is_shaded = False
        self._has_shown = False
        self._title_column = None
        self._move_timer = QtCore.QTimer()
        self._move_timer.setSingleShot(True)
        self._move_timer.timeout.connect(self.menu_move)
        self._size_timer = QtCore.QTimer()
        self._size_timer.setSingleShot(True)
        self._size_timer.timeout.connect(self.menu_size)
        if flags is not None:
            self._has_help = bool(flags & compat.WindowContextHelpButtonHint)
            self._has_shade = bool(flags & compat.WindowShadeButtonHint)

        # Create our widgets.
        self._layout = QtWidgets.QGridLayout(self)
        self._menu = TitleButton(menu_icon(self))
        self._title = Label('', self, compat.ElideRight, self.title_width)
        self._min = TitleButton(minimize_icon(self))
        self._max = TitleButton(maximize_icon(self))
        self._restore= TitleButton(restore_icon(self))
        self._close = TitleButton(close_icon(self))
        if self._has_help:
            self._help = TitleButton(help_icon(self))
        if self._has_shade:
            self._shade = TitleButton(shade_icon(self))
            self._unshade = TitleButton(unshade_icon(self))

        # Add actions to our menu.
        self._menu.setPopupMode(compat.InstantPopup)
        self._main_menu = menu = QtWidgets.QMenu(self)
        self._restore_action = action('&Restore', self, restore_icon(self))
        self._restore_action.triggered.connect(self.restore)
        self._move_action = action('&Move', self, transparent_icon(self))
        self._move_action.triggered.connect(self.move_timer)
        self._size_action = action('&Size', self, transparent_icon(self))
        self._size_action.triggered.connect(self.size_timer)
        self._min_action = action('Mi&nimize', self, minimize_icon(self))
        self._min_action.triggered.connect(self.minimize)
        self._max_action = action('Ma&ximize', self, maximize_icon(self))
        self._max_action.triggered.connect(self.maximize)
        self._top_action = action('Stay on &Top', self, checkable=True)
        self._top_action.toggled.connect(self.toggle_keep_above)
        self._close_action = action('&Close', self, close_icon(self))
        self._close_action.triggered.connect(self._window.close)
        self._main_menu.addActions([
            self._restore_action,
            self._move_action,
            self._size_action,
            self._min_action,
            self._max_action,
            self._top_action,
        ])
        self._main_menu.addSeparator()
        self._main_menu.addAction(self._close_action)
        self._menu.setMenu(self._main_menu)

        # Customize the enabled items.
        self._restore_action.setEnabled(False)

        # Create our layout.
        col = 0
        self._layout.addWidget(self._menu, 0, col)
        col += 1
        self._layout.addWidget(self._title, 0, col, compat.AlignHCenter)
        self._layout.setColumnStretch(col, 1)
        self._title_column = col
        col += 1
        if self._has_help:
            self._layout.addWidget(self._help, 0, col)
            col += 1
        self._layout.addWidget(self._min, 0, col)
        self._state1_column = col
        col += 1
        self._layout.addWidget(self._max, 0, col)
        self._state2_column = col
        col += 1
        if self._has_shade:
            self._layout.addWidget(self._shade, 0, col)
            col += 1
        self._layout.addWidget(self._close, 0, col)
        self._close_column = col
        self._restore.hide()
        if self._has_shade:
            self._unshade.hide()

        # Add in our event triggers.
        self._min.clicked.connect(self.minimize)
        self._max.clicked.connect(self.maximize)
        self._restore.clicked.connect(self.restore)
        self._close.clicked.connect(self._window.close)
        if self._has_help:
            self._help.clicked.connect(self.help)
        if self._has_shade:
            self._shade.clicked.connect(self.shade)
            self._unshade.clicked.connect(self.unshade)

    # PROPERTIES

    @property
    def minimum_width(self):
        '''Get the height (in pixels) for the minimum title bar width.'''

        app = QtWidgets.QApplication.instance()
        icon_width = self._menu.iconSize().width()
        font_size = app.font().pointSizeF()

        # We can have 4-6 icons, which with padding means we need
        # room for at least 10 characters.
        return 6 * icon_width + int(16 * font_size)

    @property
    def minimum_height(self):
        '''Get the height (in pixels) for the minimum title bar height.'''
        return TITLEBAR_HEIGHT

    @property
    def minimum_size(self):
        '''Get the minimum dimensions for the title bar.'''
        return QtCore.QSize(self.minimum_width, self.minimum_height)

    def title_width(self):
        '''Get the width of the title based on the grid layout.'''
        return self._layout.cellRect(0, self._title_column).width()

    # QT-LIKE PROPERTIES

    def windowTitle(self):
        '''Get the titlebar's window title.'''
        return self._title.text()

    def setWindowTitle(self, title):
        '''Get the titlebar's window title.'''
        self._title.setText(title)

    def isNormal(self):
        '''Get if the titlebar and therefore window has no state.'''
        return self._state == compat.WindowNoState

    def isMinimized(self):
        '''Get if the titlebar and therefore window is minimized.'''
        return self._state == compat.WindowMinimized

    def isMaximized(self):
        '''Get if the titlebar and therefore window is maximized.'''
        return self._state == compat.WindowMaximized

    # QT EVENTS

    def showEvent(self, event):
        '''Set the minimum size policies once the widgets are shown.'''

        global TITLEBAR_HEIGHT
        if not self._has_shown:
            TITLEBAR_HEIGHT = min(self.height(), TITLEBAR_HEIGHT)
            self._has_shown = True

        # Set some size policies.
        self.setMinimumSize(self.minimum_width, self.minimum_height)

        super().showEvent(event)

    # ACTIONS

    def set_minimum_size(self):
        '''Set the minimum size of the titlebar.'''
        self.setMinimumSize(self.minimum_width, self.minimum_height)

    def move_timer(self):
        '''Start timer to invoke menu_move.'''

        # We use a timer since the clicks on the menu can invoke the
        # MousePressEvent, which instantly cancels the move event.
        self._move_timer.start(CLICK_TIMER)

    def menu_move(self):
        '''Start a manually trigger move.'''
        start_move(self.window(), self, self._window_type)

    def menu_move_to(self, global_position):
        '''
        Move the subwindow so that the position is in the center bottom
        of the title bar. The position is given in global coordinates.
        '''

        # Move it so the position is right below the bottom and the center.
        position = self.mapFromGlobal(global_position)
        rect = self.geometry()
        x = position.x() - rect.width() // 2
        y = position.y()
        rect.moveBottomLeft(QtCore.QPoint(x, y))

        window = self._window
        window.move_to(window.mapToParent(rect.topLeft()))

    def size_timer(self):
        '''Start timer to invoke menu_size.'''

        # We use a timer since the clicks on the menu can invoke the
        # MousePressEvent, which instantly cancels the size event.
        self._size_timer.start(CLICK_TIMER)

    def menu_size(self):
        '''Start a manually triggered resize event.'''

        window = self.window()
        start_resize(window, self._window, self._window_type)

    def minimize(self):
        '''Minimize the current window.'''

        if self.isNormal():
            self._window_rect = self._window.geometry()
        self.set_minimized()
        self.set_shaded()

        # Toggle state
        self._state = compat.WindowMinimized
        self._is_shaded = False
        self._window.minimize(self._window.minimized_size)

        # Toggle the menu actions
        # Minimized windows should not be movable, resizable, or minimizable.
        self._restore_action.setEnabled(True)
        self._move_action.setEnabled(False)
        self._size_action.setEnabled(False)
        self._min_action.setEnabled(False)
        self._max_action.setEnabled(True)

    def maximize(self):
        '''Maximize the current window.'''

        if self.isNormal():
            self._window_rect = self._window.geometry()
        elif self.isMinimized() and not self._is_shaded:
            self._window.unminimize()
        size = self._window.maximum_size
        rect = QtCore.QRect(0, 0, size.width(), size.height())
        self.set_maximized()
        self.set_unshaded()

        # Toggle state
        self._state = compat.WindowMaximized
        self._is_shaded = False
        self._window.maximize(rect)

        # Toggle the menu actions
        self._restore_action.setEnabled(True)
        self._move_action.setEnabled(False)
        self._size_action.setEnabled(False)
        self._min_action.setEnabled(True)
        self._max_action.setEnabled(False)

    def restore(self):
        '''Restore the current window (set to no state).'''

        if self.isMinimized() and not self._is_shaded:
            self._window.unminimize()
        self.set_restored()
        self.set_unshaded()

        # Toggle state
        self._state = compat.WindowNoState
        self._is_shaded = False
        self._window.restore(self._window_rect)

        # Toggle the menu actions
        self._restore_action.setEnabled(False)
        self._move_action.setEnabled(True)
        self._size_action.setEnabled(True)
        self._min_action.setEnabled(True)
        self._max_action.setEnabled(True)

    def shade(self):
        '''Shade the current window.'''

        # Shaded windows are treated as if they have minimized state, and
        # if the window is maximized, it sets the previous window rect
        # to the maximized geometry.
        self.set_shaded()
        self.set_minimized()

        # Toggle state
        self._state = compat.WindowMinimized
        self._is_shaded = True
        self._window_rect = self._window.geometry()
        width = self._window.width()
        height = self._window.minimized_size.height()
        self._window.shade(QtCore.QSize(width, height))

        # Toggle the menu actions
        # Shaded windows should be movable, but not resizable or minimizable.
        self._restore_action.setEnabled(True)
        self._move_action.setEnabled(True)
        self._size_action.setEnabled(False)
        self._min_action.setEnabled(False)
        self._max_action.setEnabled(True)

    def unshade(self):
        '''Unshade the current window.'''

        if self.isMinimized() and not self._is_shaded:
            self._window.unminimize()

        # If the window is minimized, it restores to the previous
        # window state and position.
        self.set_unshaded()
        self.set_restored()

        # Toggle state
        self._state = compat.WindowNoState
        self._is_shaded = False
        self._window.unshade(self._window_rect)

        # Toggle the menu actions
        # Unshaded windows have no state: they are restored.
        self._restore_action.setEnabled(False)
        self._move_action.setEnabled(True)
        self._size_action.setEnabled(True)
        self._min_action.setEnabled(True)
        self._max_action.setEnabled(True)

    def toggle_keep_above(self, checked):
        '''Toggle whether to keep the window above others.'''

        # If we have a top-level widget, changing the window
        # flags causes `setParent` to be called, causing the
        # widget to hide and then re-appear. This causes major
        # visual delay, so we just ignore the hide event, then
        # set the flags, re-show the window, and unignore hides.
        # Finally, this can change the geometry of the window,
        # so we need to store the geometry and reset it.
        if self._window.window() == self._window:
            self._window._ignore_hide = True
            rect = self.window().geometry()

        flags = self._window.windowFlags()
        if checked:
            flags |= compat.WindowStaysOnTopHint
        else:
            flags &= ~compat.WindowStaysOnTopHint
        self._window.setWindowFlags(flags)

        if self._window.window() == self._window:
            self._window._ignore_hide = False
            self.window().show()
            self.window().set_geometry(rect)

    def help(self):
        '''Enter what's this mode.'''
        QtWidgets.QWhatsThis.enterWhatsThisMode()

    # VIEW

    def set_minimized(self):
        '''Show the restore and maximize icons.'''

        if self.isMinimized():
            return

        item1 = self._layout.itemAtPosition(0, self._state1_column)
        item2 = self._layout.itemAtPosition(0, self._state2_column)
        self._layout.removeItem(item1)
        self._layout.removeItem(item2)
        self._layout.addWidget(self._restore, 0, self._state1_column)
        self._layout.addWidget(self._max, 0, self._state2_column)
        self._min.hide()
        self._restore.show()
        self._max.show()

    def set_maximized(self):
        '''Show the minimize and restore icons.'''

        if self.isMaximized():
            return

        item1 = self._layout.itemAtPosition(0, self._state1_column)
        item2 = self._layout.itemAtPosition(0, self._state2_column)
        self._layout.removeItem(item1)
        self._layout.removeItem(item2)
        self._layout.addWidget(self._min, 0, self._state1_column)
        self._layout.addWidget(self._restore, 0, self._state2_column)
        self._max.hide()
        self._min.show()
        self._restore.show()

    def set_restored(self):
        '''Show the minimize and maximize icons.'''

        if self.isNormal():
            return

        item1 = self._layout.itemAtPosition(0, self._state1_column)
        item2 = self._layout.itemAtPosition(0, self._state2_column)
        self._layout.removeItem(item1)
        self._layout.removeItem(item2)
        self._layout.addWidget(self._min, 0, self._state1_column)
        self._layout.addWidget(self._max, 0, self._state2_column)
        self._restore.hide()
        self._min.show()
        self._max.show()

    def set_shaded(self):
        '''Show the unshade icon (and hide the shade icon).'''

        if self._has_shade and not (self.isMinimized() or self._is_shaded):
            self._layout.replaceWidget(self._shade, self._unshade)
            self._shade.hide()
            self._unshade.show()

    def set_unshaded(self):
        '''Show the shade icon (and hide the unshade icon).'''

        if self._has_shade and (self.isMinimized() or self._is_shaded):
            self._layout.replaceWidget(self._unshade, self._shade)
            self._unshade.hide()
            self._shade.show()

class SizeFrame(QtCore.QObject):
    '''An invisible frame for resizing events around a window.'''

    def __init__(self, window=None, border_width=3):
        super().__init__(window)

        self._window = window
        self._border_width = border_width
        self._band = QtWidgets.QRubberBand(compat.RubberBandRectangle)

        self._pressed = False
        self._cursor = None
        self._press_edge = WindowEdge.NoEdge
        self._move_edge = WindowEdge.NoEdge

        self._window.setMouseTracking(True)
        self._window.setWindowFlag(compat.FramelessWindowHint, True)
        self._window.setAttribute(compat.WA_Hover)

    @property
    def is_active(self):
        '''Get if the SizeFrame resize event is active.'''
        return self._pressed

    def is_on_top(self, pos, rect):
        '''Determine if the cursor is on the top of the widget.'''
        return (
            pos.x() >= rect.x() + self._border_width and
            pos.x() <= rect.x() + rect.width() - self._border_width and
            pos.y() >= rect.y() and
            pos.y() <= rect.y() + self._border_width
        )

    def is_on_bottom(self, pos, rect):
        '''Determine if the cursor is on the bottom of the widget.'''
        return (
            pos.x() >= rect.x() + self._border_width and
            pos.x() <= rect.x() + rect.width() - self._border_width and
            pos.y() >= rect.y() + rect.height() - self._border_width and
            pos.y() <= rect.y() + rect.height()
        )

    def is_on_left(self, pos, rect):
        '''Determine if the cursor is on the left of the widget.'''
        return (
            pos.x() >= rect.x() - self._border_width and
            pos.x() <= rect.x() + self._border_width and
            pos.y() >= rect.y() + self._border_width and
            pos.y() <= rect.y() + rect.height() - self._border_width
        )

    def is_on_right(self, pos, rect):
        '''Determine if the cursor is on the right of the widget.'''
        return (
            pos.x() >= rect.x() + rect.width() - self._border_width and
            pos.x() <= rect.x() + rect.width() and
            pos.y() >= rect.y() + self._border_width and
            pos.y() <= rect.y() + rect.height() - self._border_width
        )

    def is_on_top_left(self, pos, rect):
        '''Determine if the cursor is on the top left of the widget.'''
        return (
            pos.x() >= rect.x() and
            pos.x() <= rect.x() + self._border_width and
            pos.y() >= rect.y() and
            pos.y() <= rect.y() + self._border_width
        )

    def is_on_top_right(self, pos, rect):
        '''Determine if the cursor is on the top right of the widget.'''
        return (
            pos.x() >= rect.x() + rect.width() - self._border_width and
            pos.x() <= rect.x() + rect.width() and
            pos.y() >= rect.y() and
            pos.y() <= rect.y() + self._border_width
        )

    def is_on_bottom_left(self, pos, rect):
        '''Determine if the cursor is on the bottom left of the widget.'''
        return (
            pos.x() >= rect.x() and
            pos.x() <= rect.x() + self._border_width and
            pos.y() >= rect.y() + rect.height() - self._border_width and
            pos.y() <= rect.y() + rect.height()
        )

    def is_on_bottom_right(self, pos, rect):
        '''Determine if the cursor is on the bottom right of the widget.'''
        return (
            pos.x() >= rect.x() + rect.width() - self._border_width and
            pos.x() <= rect.x() + rect.width() and
            pos.y() >= rect.y() + rect.height() - self._border_width and
            pos.y() <= rect.y() + rect.height()
        )

    def cursor_position(self, pos, rect):
        '''Calculate the cursor position inside the window.'''

        if self.is_on_left(pos, rect):
            return WindowEdge.Left
        elif self.is_on_right(pos, rect):
            return WindowEdge.Right
        elif self.is_on_bottom(pos, rect):
            return WindowEdge.Bottom
        elif self.is_on_top(pos, rect):
            return WindowEdge.Top
        elif self.is_on_bottom_left(pos, rect):
            return WindowEdge.BottomLeft
        elif self.is_on_bottom_right(pos, rect):
            return WindowEdge.BottomRight
        elif self.is_on_top_right(pos, rect):
            return WindowEdge.TopRight
        elif self.is_on_top_left(pos, rect):
            return WindowEdge.TopLeft

        return WindowEdge.NoEdge

    def top_left(self, rect):
        '''Get the top/left position of the window in global coordinates.'''

        # Calculate the top left bounds of our window to get our frame.
        # We want our frame in global coordinates, but our window
        # might be a subwindow. If it has a parent, then it's a subwindow
        # and we need to map our coordinates.
        point = rect.topLeft()
        if self._window.window() != self._window:
            point = self._window.parent().mapToGlobal(point)

        return point

    def frame_geometry(self):
        '''Calculate the frame geometry of our window in global coordinates.'''

        rect = self._window.frameGeometry()
        return QtCore.QRect(self.top_left(rect), self._window.frameSize())

    def geometry(self):
        '''Calculate the geometry of our window in global coordinates.'''

        rect = self._window.geometry()
        return QtCore.QRect(self.top_left(rect), self._window.size())

    def update_cursor(self, position):
        '''Update the cursor shape depending on the cursor position.'''

        if self._window.isMaximized() or self._window.isFullScreen():
            self.unset_cursor()
            return

        if self._pressed:
            return

        rect = self.frame_geometry()
        self._move_edge = self.cursor_position(position, rect)
        if self._move_edge == WindowEdge.NoEdge:
            self.unset_cursor()
            return
        if self._move_edge in (WindowEdge.Top, WindowEdge.Bottom):
            self._cursor = compat.SizeVerCursor
        elif self._move_edge in (WindowEdge.Left, WindowEdge.Right):
            self._cursor = compat.SizeHorCursor
        elif self._move_edge in (WindowEdge.TopLeft, WindowEdge.BottomRight):
            self._cursor = compat.SizeFDiagCursor
        elif self._move_edge in (WindowEdge.TopRight, WindowEdge.BottomLeft):
            self._cursor = compat.SizeBDiagCursor

        self._window.setCursor(self._cursor)

    def resize(self, position, rect):
        '''Resize our window to the adjusted dimensions.'''

        # Get our new frame dimensions.
        if self._press_edge == WindowEdge.NoEdge:
            return
        elif self._press_edge == WindowEdge.Top:
            rect.setTop(position.y())
        elif self._press_edge == WindowEdge.Bottom:
            rect.setBottom(position.y())
        elif self._press_edge == WindowEdge.Left:
            rect.setLeft(position.x())
        elif self._press_edge == WindowEdge.Right:
            rect.setRight(position.x())
        elif self._press_edge == WindowEdge.TopLeft:
            rect.setTopLeft(position)
        elif self._press_edge == WindowEdge.TopRight:
            rect.setTopRight(position)
        elif self._press_edge == WindowEdge.BottomLeft:
            rect.setBottomLeft(position)
        elif self._press_edge == WindowEdge.BottomRight:
            rect.setBottomRight(position)

        # Ensure we don't drag the widgets if we go below min sizes.
        if rect.width() < self._window.minimumWidth():
            if self._press_edge in LEFT_EDGES:
                rect.setLeft(rect.right() - self._window.minimumWidth())
            elif self._press_edge in RIGHT_EDGES:
                rect.setRight(rect.left() + self._window.minimumWidth())
        if rect.height() < self._window.minimumHeight():
            if self._press_edge in TOP_EDGES:
                rect.setTop(rect.bottom() - self._window.minimumHeight())
            elif self._press_edge in BOTTOM_EDGES:
                rect.setBottom(rect.top() + self._window.minimumHeight())

        # Calculate our rect for our widget.
        size = rect.size()
        point = rect.topLeft()
        if self._window.window() != self._window:
            point = self._window.parent().mapFromGlobal(point)
        local_rect = QtCore.QRect(point, size)

        # If we have a subwindow, need to limit to the MDI area rect.
        if self._window.window() != self._window:
            area_rect = self._window.mdiArea().contentsRect()
            # Need to calculate our shifts here.
            dx1 = max(local_rect.left(), area_rect.left()) - local_rect.left()
            dy1 = max(local_rect.top(), area_rect.top()) - local_rect.top()
            dx2 = min(local_rect.right(), area_rect.right()) - local_rect.right()
            dy2 = min(local_rect.bottom(), area_rect.bottom()) - local_rect.bottom()
            rect.adjust(dx1, dy1, dx2, dy2)
            # NOTE: Do not remove this. I have tried everything.
            # This does not work unless you keep it. There's a weird
            # bug where the window (only for QMdiSubWindow) now has
            # a bug where if you click on the title bar, it re-enters
            # a resize mode, which is independent of this. Shifting
            # the position by 1 pixel undoes this. Nothing else works,
            # and I have tried:
            #   - Not due to custom drag/move/resize/frame states.
            #   - Not due to lingering pressed/press_edge/move_edge.
            #   - Not due to a lingering cursor.
            #   - Not due to change event.
            #   - Not due to resize/show event.
            #   - Not due to mouse press/double click/release/move event.
            #   - Not due to the event filter.
            #   - Not due to the QMainWindow-level custom title bar.
            #   - `setFixedSize` on the window on the mouse release
            #       and then undoing on the next resize event eats
            #       the mouse click, but still enters the same mode
            #       (just the window can't be resized).
            #   - Not due to the window-level widgets or margins.
            #   - `setFixedSize` on the title bar just fixes title bar size.
            #   - No previous versions work if we use the local_rect.
            #   - Unsetting the band and use the window directly does nothing.
            #   - Using `setGeometry(rect)` then `setGeometry(local_rect)`.
            #   - Unsetting the band geometry in `mouse_release` event.
            #   - Simulating mouse press+release in `mouse_release`.
            #   - Simulating mouse press+release in `end_frame`.
            #   - Ignoring the subsequent mousePressEvent on the title bar.
            #       - This causes the window to disappear entirely.
            #   - Hide+show inside `mouse_release` causes window to hide.
            #   - Hide+show inside `end_frame` causes window to hide.
            #   - Not due to minimum rect size checks.
            #   - Not due to MDI area limit checks.
            #   - Not related to custom restore/min/max/shade/unshade code.
            #   - Not due to custom hide/setVisible overrides.
            #
            # This is almost certain a bug in QMdiArea, but this is a
            # workaround that produces almost is almost imperceptible,
            # since the widget is being actively resized.
            #
            # I love mess.... but not this.
            if dx1 == 0 and dy1 == 0 and dx2 == 0 and dy2 == 0:
                dx1 += 1
                dy1 += 1
                dx2 += 1
                dy2 += 1
            local_rect.adjust(dx1, dy1, dx2, dy2)

        self._window.set_geometry(local_rect)
        self._band.setGeometry(rect)

    def unset_cursor(self):
        '''Unset the custom cursor.'''

        if self._cursor:
            self._window.unsetCursor()
        self._cursor = None

    def enter(self, event):
        '''Handle the enterEvent of the window.'''

        position = shared.single_point_position(args, event)
        self.update_cursor(self._window.mapToGlobal(position))

    def leave(self, event):
        '''Handle the leaveEvent of the window.'''

        if not self._pressed:
            self.unset_cursor()

    def mouse_move(self, event):
        '''Handle the mouseMoveEvent of the window.'''

        position = shared.single_point_global_position(args, event)
        if not self._pressed:
            self.update_cursor(position)
            return

        self.resize(position, self._band.geometry())

    def mouse_press(self, event):
        '''Handle the mousePressEvent of the window.'''

        if event.button() == compat.LeftButton:
            position = shared.single_point_global_position(args, event)
            rect = self.frame_geometry()
            self._press_edge = self.cursor_position(position, rect)
            # We want to separately handle drags, so only
            # set this if we are pressing on the edge.
            if self._press_edge != WindowEdge.NoEdge:
                self._pressed = True
                self._band.setGeometry(self.geometry())

    def mouse_release(self, event):
        '''Handle the mouseReleaseEvent of the window.'''

        if event.button() == compat.LeftButton and self._pressed:
            self._pressed = False

    def hover_move(self, event):
        '''Handle the hoverMoveEvent of the window.'''

        position = shared.single_point_position(args, event)
        self.update_cursor(self._window.mapToGlobal(position))

class SubWindow(QtWidgets.QMdiSubWindow):
    '''Base subclass for a QMdiSubwindow.'''

    def __init__(self, parent=None, flags=QtCore.Qt.WindowType(0)):
        super().__init__(parent, flags=flags)
        super().setWidget(QtWidgets.QWidget())

class DefaultSubWindow(SubWindow):
    '''Default subwindow with a window frame.'''

    def __init__(
        self,
        parent=None,
        flags=QtCore.Qt.WindowType(0),
        sizegrip=False,
    ):
        super().__init__(parent, flags=flags)

class FramelessSubWindow(SubWindow):
    '''Custom subwindow instance without a window frame.'''

    def __init__(
        self,
        parent=None,
        flags=QtCore.Qt.WindowType(0),
        sizegrip=False,
    ):
        super().__init__(parent, flags=flags | compat.FramelessWindowHint)

        # Create our widgets. Sizeframe and sizegrip are mutually exclusive.
        self._central = QtWidgets.QFrame(super().widget())
        self._central.setLayout(QtWidgets.QVBoxLayout())
        self._titlebar = TitleBar(self, self._central, flags)
        self._widget = QtWidgets.QWidget(self._central)
        self._widget.setLayout(QtWidgets.QVBoxLayout())
        self._sizeframe = None
        self._sizegrip = None
        self._border = args.border_width
        self._titlebar_size = QtCore.QSize()
        self._sizegrip_size = QtCore.QSize()
        self._old_minimum_size = None
        if sizegrip:
            self._sizegrip = QtWidgets.QSizeGrip(self._central)
        else:
            self._sizeframe = SizeFrame(self, border_width=5)

        # Add our titlebar, then our central widgets, etc.
        # Make sure we have our titlebar compacted to fit.
        # The trick here is quite simple: have no spacing
        # on the parent layout (so the titlebar goes on the
        # absolute top), and all 3 widgets, with the main
        # widget expanding to the view, and make it seem like
        # it's the central widget for the layout, as is its layout.

        # Align the size grip to the bottom right, without stretch, so
        # it compacts and has the natural placement. For the titlebar,
        # align it top so when the sizegrip is hidden (as is the widget),
        # it does not have a border/padding on the top.
        bottom_right = compat.AlignBottom | compat.AlignRight
        super().layout().setSpacing(0)
        super().layout().addWidget(self._central, 10)
        self._central.layout().setSpacing(0)
        self._central.layout().addWidget(self._titlebar, 0, compat.AlignTop)
        self._central.layout().addWidget(self._widget, 10)
        if self._sizegrip is not None:
            self._central.layout().addWidget(self._sizegrip, 0, bottom_right)

        # Set the border properties.
        self._central.layout().setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
        self._central.setProperty('isWindow', True)
        if self._border > 0:
            self._central.setProperty('windowFrame', min(self._border, 5))
            self._central.setFrameShape(compat.Box)
            self._central.setFrameShadow(compat.Raised)

        # Ensure our titlebar gets highest priority.
        self._titlebar.raise_()
        self._widget.lower()

    # PROPERTIES

    @property
    def border_size(self):
        '''Get the size of the border, regardless if present.'''
        return border_size(self)

    @property
    def minimized_content_size(self):
        '''Get the minimum content size of the widget.'''
        return minimized_content_size(self)

    @property
    def minimized_size(self):
        '''Get the minimum size of the widget, with the size grips hidden.'''
        return minimized_size(self)

    @property
    def minimum_size(self):
        '''Get the minimum size for the widget.'''
        return minimum_size(self)

    @property
    def maximum_size(self):
        '''Get the maximum size for the widget.'''
        return self.mdiArea().size()

    # RESIZE

    def move_to(self, position):
        '''Move the window to the desired position'''
        move_to(self, position)

    def set_geometry(self, rect):
        '''Set the window geometry.'''
        set_geometry(self, rect)

    def set_minimum_size(self):
        '''Sets the minimum size of the window and the titlebar, with clobbering.'''
        set_minimum_size(self)

    def set_larger_minimum_size(self):
        '''Sets the minimum size of the window and the titlebar, without clobbering.'''
        set_larger_minimum_size(self)

    def minimize(self, size):
        '''Minimize the window, hiding the main widget and size grip.'''

        self._widget.hide()
        if self._sizegrip is not None:
            self._sizegrip.hide()
        self.set_minimum_size()
        self.resize(size)
        self.mdiArea().minimize(self)

    def maximize(self, rect):
        '''Maximize the window, showing the main widget and hiding size grip.'''

        self._widget.show()
        if self._sizegrip is not None:
            self._sizegrip.hide()
        self.set_larger_minimum_size()
        self.set_geometry(rect)

    def restore(self, rect):
        '''Restore the window, showing the main widget and size grip.'''

        self._widget.show()
        if self._sizegrip is not None:
            self._sizegrip.show()
        self.set_larger_minimum_size()
        self.set_geometry(rect)

    def shade(self, size):
        '''Shade the window, hiding the main widget and size grip.'''
        shade(self, size, 'sizegrip')

    def unshade(self, rect):
        '''Unshade the window, showing the main widget and size grip.'''
        unshade(self, rect, 'sizegrip')

    def unminimize(self):
        '''Unminimize a minimized subwindow.'''
        self.mdiArea().unminimize(self)

    # QT EVENTS

    def resizeEvent(self, event):
        '''Handle widget resize events here.'''
        window_resize_event(self, event)

    def showEvent(self, event):
        '''Set the minimum size policies once the widgets are shown.'''
        window_show_event(self, event, 'sizegrip')

    def mouseDoubleClickEvent(self, event):
        '''Override the mouse double click, and don't call the press event.'''
        window_mouse_double_click_event(self, event)

    def mousePressEvent(self, event):
        '''Override a mouse click on the titlebar to allow a move.'''
        return window_mouse_press_event(self, event, self.window(), 'subwindow')

    def mouseMoveEvent(self, event):
        '''Reposition the window on the move event.'''
        return window_mouse_move_event(self, event, self.window(), 'subwindow')

    def mouseReleaseEvent(self, event):
        '''End the drag event.'''
        return window_mouse_release_event(self, event, self.window(), 'subwindow')

    # QT-LIKE PROPERTIES

    def windowTitle(self):
        '''Get the window title from the titlebar.'''
        return self._titlebar.windowTitle()

    def setWindowTitle(self, title):
        '''Get the window title from the titlebar.'''
        self._titlebar.setWindowTitle(title)

    def layout(self):
        '''Get the subwindow layout (mapped to self._widget)'''
        return self._widget.layout()

    def setLayout(self, layout):
        '''Set the subwindow layout (mapped to self._widget)'''
        self._widget.setLayout(layout)

    def widget(self):
        '''Get the subwindow widget (mapped to self._widget)'''
        return self._widget

    def setWidget(self, widget):
        '''Set the subwindow widget (mapped to self._widget)'''

        super().layout().replaceWidget(self._widget, widget)
        self._widget = widget

    def isMinimized(self):
        '''Overload since we use a custom minimized for our subwindow.'''
        return self._titlebar.isMinimized()

    def isMaximized(self):
        '''Overload since we use a custom maximized for our subwindow.'''
        return self._titlebar.isMaximized()

class MdiArea(QtWidgets.QMdiArea):
    '''Override the QMdiArea for window minimization and background color.'''

    def __init__(self, parent=None, location=MINIMIZE_LOCATION):
        super().__init__(parent)
        self._minimized = []
        self._location = location
        self._timer = QtCore.QTimer()
        self._timer.setSingleShot(True)
        self._timer.timeout.connect(self.move_minimized)

        # Set the background color
        background = self.background()
        background.setColor(colors.ViewBackground)
        self.setBackground(background)

    def resizeEvent(self, event):
        '''Handle moving minimized windows without glitchy motion.'''

        self._timer.start(REPAINT_TIMER)
        super().resizeEvent(event)

    def minimize(self, subwindow):
        '''Minimize a subwindow and reposition it.'''

        self._minimized.append(subwindow)
        self.move_minimized()

    def unminimize(self, subwindow):
        '''Unminimize a subwindow.'''

        self._minimized.remove(subwindow)
        self.move_minimized()

    def move_minimized(self):
        '''Move the minimized windows.'''

        # No need to set the geometry of our minimized windows.
        if not self._minimized:
            return

        # Get the geometry of the elements, and calculate the windows per row.
        window = self._minimized[0]
        has_border = any(i._border for i in self._minimized)
        size = window.minimized_content_size
        if has_border:
            size = size + window.border_size
        width = size.width()
        height = size.height()
        width += max(int(0.01 * width), 1)
        height += max(int(0.01 * height), 1)
        total_size = self.size()
        minimized_count = len(self._minimized)
        row_count = max(total_size.width() // width, 1)
        rows = minimized_count // row_count
        if minimized_count % row_count != 0:
            rows += 1

        # Get how we shift our elements. Start our elements so
        # the first iteration will shift them into place.
        # We never want to place elements at a negative index,
        # so our right always starts at least at 1.
        # For our bottom, we want the last element to be placed at (_, 0)
        # if it would overflow to the top, we place it at 0 instead.
        left_x = 0
        right_x = max(total_size.width() - width, 0)
        top_y = 0
        bottom_y = max(total_size.height() - height, (rows - 1) * height)
        if self._location == MinimizeLocation.TopLeft:
            point = QtCore.QPoint(left_x, top_y)
            new_column = lambda p: QtCore.QPoint(left_x, p.y() + height)
            shift_row = lambda p, w: p + QtCore.QPoint(w, 0)
        elif self._location == MinimizeLocation.TopRight:
            point = QtCore.QPoint(right_x, top_y)
            new_column = lambda p: QtCore.QPoint(right_x, p.y() + height)
            shift_row = lambda p, w: p - QtCore.QPoint(w, 0)
        elif self._location == MinimizeLocation.BottomLeft:
            point = QtCore.QPoint(left_x, bottom_y)
            new_column = lambda p: QtCore.QPoint(left_x, p.y() - height)
            shift_row = lambda p, w: p + QtCore.QPoint(w, 0)
        else:
            point = QtCore.QPoint(right_x, bottom_y)
            new_column = lambda p: QtCore.QPoint(right_x, p.y() - height)
            shift_row = lambda p, w: p - QtCore.QPoint(w, 0)

        # Now, need to place them accordingly.
        # Need to handle unshifts, if they occur, due to the
        for index in range(len(self._minimized)):
            # Calculate our new column, only storing if it is a new column.
            window = self._minimized[index]
            is_new_column = index % row_count == 0
            if index != 0 and is_new_column:
                point = new_column(point)

            window.move(point)
            point = shift_row(point, width)

class Window(QtWidgets.QMainWindow):
    '''Base subclass for a QMainWindow.'''

    def __init__(self, parent=None, flags=QtCore.Qt.WindowType(0)):
        super().__init__(parent, flags)

        # Tracking for move and resize events.
        # Click and drag title bar move.
        self._subwindow_drag = None
        # Context menu move.
        self._subwindow_move = None
        # Context menu resize.
        self._subwindow_resize = None
        # SizeFrame resize.
        self._subwindow_frame = None

    def setup(self):
        '''Setup the main UI.'''

        subwindow_class = FramelessSubWindow
        if args.default_window_frame:
            subwindow_class = DefaultSubWindow

        self.resize(1068, 824)
        self.setWindowTitle('Custom SubWindow Style.')

        flags = compat.SubWindow
        self.area = MdiArea(self._widget)
        self.window1 = subwindow_class(flags=flags, sizegrip=True)
        self.window1.setWindowTitle('Short Title')
        self.area.addSubWindow(self.window1)
        self.table = LargeTable(self.window1.widget())
        self.window1.layout().addWidget(self.table)

        flags = compat.SubWindow
        flags |= compat.WindowContextHelpButtonHint
        flags |= compat.WindowShadeButtonHint
        self.window2 = subwindow_class(flags=flags)
        self.window2.setWindowTitle('Example of a very, very long title')
        self.area.addSubWindow(self.window2)
        self.tree = SortableTree(self.window2.widget())
        self.window2.layout().addWidget(self.tree)

        flags = compat.SubWindow
        flags |= compat.WindowShadeButtonHint
        self.window3 = subwindow_class(flags=flags, sizegrip=True)
        self.window3.setWindowTitle('Medium length title')
        self.area.addSubWindow(self.window3)
        self._widget.layout().addWidget(self.area)
        self.tab = SettingTabs(self.window3.widget())
        self.window3.layout().addWidget(self.tab)

    # PROPERTIES

    @property
    def maximum_size(self):
        '''Get the maximum size for the window.'''
        # Unused since we use the window flags anyway.
        return self.maximumSize()

    # ACTIONS

    def menu_size_to(self, point):
        '''
        Size the window so that the position is in the center bottom
        of the title bar. The position is given in global coordinates.
        '''

        window = getattr(self, '_window_resize', None)
        if window is None:
            window = self._subwindow_resize
        rect = window.geometry()
        # We add a trivial amount so we avoid a bug where we are
        # exactly on the sizegrip, which keeps us in resize mode
        # unless we do another button click, we weirdly doesn't
        # work well when simulated.
        point += QtCore.QPoint(2, 2)

        # If we have a subwindow, need to limit to the MDI area rect.
        if window.window() != window:
            point = window.parent().mapFromGlobal(point)
            area_rect = window.mdiArea().contentsRect()
            point.setX(min(point.x(), area_rect.right()))
            point.setY(min(point.y(), area_rect.bottom()))

        # Need to ensure we didn't go past the top left.
        # Don't want to shift to negative values.
        top_left = rect.topLeft()
        point.setX(max(top_left.x(), point.x()))
        point.setY(max(top_left.y(), point.y()))

        # We add a trivial amount to simplify growing the window on Wayland.
        # Wayland cannot track outside of the application.
        if IS_TRUE_WAYLAND and window.window() == window:
            point += QtCore.QPoint(16, 16)
        rect.setBottomRight(point)
        window.set_geometry(rect)

        # Ensure we trigger the elide resize timer.
        titlebar = window._titlebar
        titlebar._title._timer.start(REPAINT_TIMER)

    def resolve_state(self):
        '''Handle theoretically possible conflicts in window state.'''

        # The _drag, _move, _resize, and _frame options are
        # mutually exclusive: only one can be active at a given time.
        # Since we use timers for `_move` and `_resize`, it's **possible**
        # multiple might be active here, but it's unlikely. So, we handle
        # those cases by playing favorites. _frame > _resize > _move > _drag.
        # We deal with the window-level widgets first, then the subwindow-level
        # widgets next. We use `getattr(obj, attr, None)` for the window-level
        # widgets since they might not be present (if using Wayland).

        has_state = False
        if has_state or getattr(self, f'_window_frame', None) is not None:
            end_resize(self, 'window')
            has_state = True
        if has_state or getattr(self, f'_window_resize', None) is not None:
            end_move(self, 'window')
            has_state = True
        if has_state or getattr(self, f'_window_move', None) is not None:
            end_drag(self, 'window')
            has_state = True
        if has_state or getattr(self, f'_window_drag', None) is not None:
            end_frame(self, 'window')
            has_state = True
        if has_state or self._subwindow_frame is not None:
            end_resize(self, 'subwindow')
            has_state = True
        if has_state or self._subwindow_resize is not None:
            end_move(self, 'subwindow')
            has_state = True
        if has_state or self._subwindow_move is not None:
            end_drag(self, 'subwindow')
            has_state = True

    def move_event(self, _, event, window_type):
        '''Handle window move events.'''

        if event.type() == compat.MouseMove:
            position = shared.single_point_global_position(args, event)
            handle_move(self, position, window_type)
        elif event.type() == compat.MouseButtonPress:
            end_move(self, window_type)

    def resize_event(self, obj, event, window_type):
        '''Handle window resize events.'''

        # NOTE: If we're on Wayland, we cant' track hover events outside the
        # main widget, and we can't guess intermittently since if the mouse
        # doesn't move, we won't get an `Enter` or `HoverEnter` event, and
        # `QCursor::pos` will always be the same. What this means is we
        # can't guess where we left the, and resize until we're back
        # in the bounds.
        if event.type() in (compat.MouseMove, compat.HoverMove):
            position = shared.single_point_global_position(args, event)
            handle_resize(self, position)
        elif event.type() == compat.MouseButtonPress:
            end_resize(self, window_type)

    def frame_event(self, event, frame):
        '''Handle size adjustments using the window frame.'''

        # No position for the event: we don't use it.
        if event.type() in (compat.Enter, compat.HoverEnter):
            frame.enter(event)
        elif event.type() in (compat.Leave, compat.HoverLeave):
            frame.leave(event)
        elif event.type() == compat.MouseMove:
            frame.mouse_move(event)
        elif event.type() == compat.MouseButtonPress:
            frame.mouse_press(event)
        elif event.type() == compat.MouseButtonRelease:
            frame.mouse_release(event)
        elif event.type() == compat.HoverMove:
            frame.hover_move(event)

    # QT EVENTS

    def eventFilter(self, obj, event):
        '''Custom event filter to handle move and resize events.'''

        self.resolve_state()
        if getattr(self, '_window_move', None) is not None:
            # Cannot occur while the size frame is active.
            self.move_event(obj, event, 'window')
        elif getattr(self, '_window_resize', None) is not None:
            self.resize_event(obj, event, 'window')
        elif isinstance(obj, Window) and not obj.isMinimized():
            handle_frame(self, obj, event, 'window')
        elif self._subwindow_move is not None:
            # Cannot occur while the size frame is active.
            self.move_event(obj, event, 'subwindow')
        elif self._subwindow_resize is not None:
            self.resize_event(obj, event, 'subwindow')
        elif isinstance(obj, SubWindow) and not obj.isMinimized():
            handle_frame(self, obj, event, 'subwindow')

        return super().eventFilter(obj, event)

class DefaultWindow(Window):
    '''Default main window with a window frame.'''

    def __init__(self, parent=None, flags=QtCore.Qt.WindowType(0)):
        if args.window_help:
            flags |= compat.WindowContextHelpButtonHint
        if args.window_shade:
            flags |= compat.WindowShadeButtonHint
        super().__init__(parent, flags)

        self._central = QtWidgets.QFrame(self)
        self._layout = QtWidgets.QVBoxLayout(self._central)
        self.setCentralWidget(self._central)
        self._widget = QtWidgets.QWidget(self._central)
        self._widget.setLayout(QtWidgets.QVBoxLayout())
        self._central.layout().addWidget(self._widget, 10)

        if args.status_bar:
            self._statusbar = QtWidgets.QStatusBar(self._central)
            self.setStatusBar(self._statusbar)

        self.setup()

class FramelessWindow(Window):
    '''Main window with a custom event filter for all events.'''

    def __init__(self, parent=None, flags=QtCore.Qt.WindowType(0)):
        # On X11, the `WindowStaysOnTopHint` hint supposedly doesn't
        # work unless you bypass the window manager, but this seems
        # to no longer be true. There's major downsides to bypassing
        # the window manager, so it's not worth it anyway.
        flags |= compat.FramelessWindowHint
        if args.window_help:
            flags |= compat.WindowContextHelpButtonHint
        if args.window_shade:
            flags |= compat.WindowShadeButtonHint
        super().__init__(parent, flags)

        # Create our widgets. Sizeframe and sizegrip are mutually exclusive.
        self._central = QtWidgets.QFrame(self)
        self._layout = QtWidgets.QVBoxLayout(self._central)
        self.setCentralWidget(self._central)
        self._titlebar = TitleBar(self, self._central, flags)
        self._widget = QtWidgets.QWidget(self._central)
        self._widget.setLayout(QtWidgets.QVBoxLayout())
        self._sizeframe = None
        self._statusbar = None
        self._border = args.border_width
        self._titlebar_size = QtCore.QSize()
        self._statusbar_size = QtCore.QSize()
        self._old_minimum_size = None
        if args.status_bar:
            self._statusbar = QtWidgets.QStatusBar(self._central)
            self.setStatusBar(self._statusbar)
        else:
            self._sizeframe = SizeFrame(self, border_width=5)

        self._central.layout().setSpacing(0)
        self._central.layout().addWidget(self._titlebar, 0, compat.AlignTop)
        self._central.layout().addWidget(self._widget, 10)

        # Tracking for move and resize events.
        # Click and drag title bar move.
        self._window_drag = None
        # Context menu move.
        self._window_move = None
        # Context menu resize.
        self._window_resize = None
        # SizeFrame resize.
        self._window_frame = None

        # For toggling window flags, which calls `setParent`, hiding the window.
        # Since an immediate show causes an unminimize/re-minimize, this
        # causes a serious visual lag.
        self._ignore_hide = False

        # Set the border properties.
        self._central.layout().setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
        self._central.setProperty('isWindow', True)
        if self._border > 0:
            self._central.setProperty('windowFrame', min(self._border, 5))
            self._central.setFrameShape(compat.Box)
            self._central.setFrameShadow(compat.Raised)

        # Ensure our titlebar gets highest priority.
        self._titlebar.raise_()
        self._widget.lower()

        self.setup()

    # HACKS

    def hide(self):
        '''Override the hide event to ignore it if desired.'''

        if self._ignore_hide:
            return
        super().hide()

    def setVisible(self, value):
        '''Override the hide event to ignore it if desired.'''

        if self._ignore_hide and not value:
            return
        super().setVisible(value)

    # PROPERTIES

    @property
    def border_size(self):
        '''Get the size of the border, regardless if present.'''
        return border_size(self)

    @property
    def minimized_content_size(self):
        '''Get the minimum content size of the widget.'''
        return minimized_content_size(self)

    @property
    def minimized_size(self):
        '''Get the minimum size of the widget, with the size grips hidden.'''
        return minimized_size(self)

    @property
    def minimum_size(self):
        '''Get the minimum size for the widget.'''
        return minimum_size(self)

    # QT-LIKE PROPERTIES

    def windowTitle(self):
        '''Get the window title from the titlebar.'''
        return self._titlebar.windowTitle()

    def setWindowTitle(self, title):
        '''Get the window title from the titlebar.'''
        self._titlebar.setWindowTitle(title)

    # RESIZE

    def move_to(self, position):
        '''Move the window to the desired position'''
        move_to(self, position)

    def set_geometry(self, rect):
        '''Set the window geometry.'''
        set_geometry(self, rect)

    def set_minimum_size(self):
        '''Sets the minimum size of the window and the titlebar, with clobbering.'''
        set_minimum_size(self)

    def set_larger_minimum_size(self):
        '''Sets the minimum size of the window and the titlebar, without clobbering.'''
        set_larger_minimum_size(self)

    def minimize(self, _):
        '''Minimize the window, using the actual OS to handle that.'''
        self.showMinimized()

    def maximize(self, _):
        '''Minimize the window, using the actual OS to handle that.'''
        self.showMaximized()

    def restore(self, _):
        '''Restore the window, showing the main widget and size grip.'''
        self.showNormal()

    def showNormal(self):
        super().showNormal()

    def shade(self, size):
        '''Shade the window, hiding the main widget and size grip.'''
        shade(self, size, 'statusbar')

    def unshade(self, rect):
        '''Unshade the window, showing the main widget and size grip.'''
        unshade(self, rect, 'statusbar')

    def unminimize(self):
        '''Unminimize a minimized window (unimplemented).'''

    # QT EVENTS

    def resizeEvent(self, event):
        '''Handle widget resize events here.'''
        window_resize_event(self, event)

    def showEvent(self, event):
        '''Set the minimum size policies once the widgets are shown.'''
        window_show_event(self, event, 'statusbar')

    def mouseDoubleClickEvent(self, event):
        '''Override the mouse double click, and don't call the press event.'''
        window_mouse_double_click_event(self, event)

    def mousePressEvent(self, event):
        '''Override a mouse click on the titlebar to allow a move.'''
        return window_mouse_press_event(self, event, self, 'window')

    def mouseMoveEvent(self, event):
        '''Reposition the window on the move event.'''
        return window_mouse_move_event(self, event, self, 'window')

    def mouseReleaseEvent(self, event):
        '''End the drag event.'''
        return window_mouse_release_event(self, event, self, 'window')

    def changeEvent(self, event):
        '''Catch state changes from outside our custom titlebar.'''

        super().changeEvent(event)

        # If we're restoring a top-level widget, need to ensure the
        # state is properly restored to the correct icons.
        if event.type() not in (compat.ActivationChange, compat.WindowStateChange):
            return

        # We have 3 states, and we can have combinations of some of them:
        #   - NoState
        #   - Minimized
        #   - Maximized
        #   - Minimized + Maximized (treat as Minimized).
        state = self.windowState()
        if state & compat.WindowMinimized:
            self._titlebar.minimize()
        elif state & compat.WindowMaximized:
            self._titlebar.maximize()
        else:
            self._titlebar.restore()

def main():
    'Application entry point'

    window_class = FramelessWindow
    # Wayland does not allow windows to reposition themselves: therefore,
    # we cannot use the custom titlebar at the application level.
    if args.default_window_frame or USE_WAYLAND_FRAME:
        window_class = DefaultWindow
    app, window = shared.setup_app(args, unknown, compat, window_class=window_class)
    app.installEventFilter(window)

    shared.set_stylesheet(args, app, compat)
    return shared.exec_app(args, app, window, compat)

if __name__ == '__main__':
    sys.exit(main())