<commit_before>#!/usr/bin/env python
#coding=utf8

from whacked4 import utils
from whacked4.dehacked import statefilter
from whacked4.ui import editormixin, windows
from whacked4.ui.dialogs import statepreviewdialog

import whacked4.config as config

import copy
import wx


class ThingsFrame(editormixin.EditorMixin, windows.ThingsFrameBase):
    """
    Things editor window.
    """

    # Text control to internal key mappings.
    PROPS_VALUES = {
        windows.THING_VAL_ID: 'id',
        windows.THING_VAL_HEALTH: 'health',
        windows.THING_VAL_GIBHEALTH: 'gibHealth',
        windows.THING_VAL_SPEED: 'speed',
        windows.THING_VAL_RADIUS: 'radius',
        windows.THING_VAL_HEIGHT: 'height',
        windows.THING_VAL_DAMAGE: 'damage',
        windows.THING_VAL_REACTIONTIME: 'reactionTime',
        windows.THING_VAL_PAINCHANCE: 'painChance',
        windows.THING_VAL_MASS: 'mass',
        windows.THING_VAL_GAME: 'game',
        windows.THING_VAL_SPAWNID: 'spawnId',
        windows.THING_VAL_RESPAWNTIME: 'respawnTime',
        windows.THING_VAL_RENDERSTYLE: 'renderStyle',
        windows.THING_VAL_ALPHA: 'alpha',
        windows.THING_VAL_SCALE: 'scale',
        windows.THING_VAL_DECAL: 'decal',
        windows.THING_VAL_DAMAGEFACTOR: 'damageFactor',
        windows.THING_VAL_GRAVITY: 'gravity',
    }

    # Value types for text control validation.
    PROPS_VALUE_TYPES = {
        windows.THING_VAL_ID: 'int',
        windows.THING_VAL_HEALTH: 'int',
        windows.THING_VAL_GIBHEALTH: 'int',
        windows.THING_VAL_SPEED: 'int',
        windows.THING_VAL_RADIUS: 'fixed',
        windows.THING_VAL_HEIGHT: 'fixed',
        windows.THING_VAL_DAMAGE: 'int',
        windows.THING_VAL_REACTIONTIME: 'int',
        windows.THING_VAL_PAINCHANCE: 'int',
        windows.THING_VAL_MASS: 'int',
        windows.THING_VAL_GAME: 'int',
        windows.THING_VAL_SPAWNID: 'int',
        windows.THING_VAL_RESPAWNTIME: 'int',
        windows.THING_VAL_RENDERSTYLE: 'int',
        windows.THING_VAL_ALPHA: 'float',
        windows.THING_VAL_SCALE: 'float',
        windows.THING_VAL_DECAL: 'str',
        windows.THING_VAL_DAMAGEFACTOR: 'float',
        windows.THING_VAL_GRAVITY: 'float',
    }

    # State text control to partial internal key mappings.
    PROPS_STATES = {
        windows.THING_STATE_SPAWN: 'Spawn',
        windows.THING_STATE_WALK: 'Walk',
        windows.THING_STATE_PAIN: 'Pain',
        windows.THING_STATE_MELEE: 'Melee',
        windows.THING_STATE_ATTACK: 'Attack',
        windows.THING_STATE_DEATH: 'Death',
        windows.THING_STATE_EXPLODE: 'Explode',
        windows.THING_STATE_RAISE: 'Raise',
        windows.THING_STATE_CRASH: 'Crash',
        windows.THING_STATE_FREEZE: 'Freeze',
        windows.THING_STATE_BURN: 'Burn'
    }

    # State name label to partial internal key mappings.
    PROPS_STATENAMES = {
        windows.THING_STATENAME_SPAWN: 'Spawn',
        windows.THING_STATENAME_WALK: 'Walk',
        windows.THING_STATENAME_PAIN: 'Pain',
        windows.THING_STATENAME_MELEE: 'Melee',
        windows.THING_STATENAME_ATTACK: 'Attack',
        windows.THING_STATENAME_DEATH: 'Death',
        windows.THING_STATENAME_EXPLODE: 'Explode',
        windows.THING_STATENAME_RAISE: 'Raise',
        windows.THING_STATENAME_CRASH: 'Crash',
        windows.THING_STATENAME_FREEZE: 'Freeze',
        windows.THING_STATENAME_BURN: 'Burn'
    }

    # State set button to partial internal key mappings.
    PROPS_STATESET = {
        windows.THING_STATESET_SPAWN: windows.THING_STATE_SPAWN,
        windows.THING_STATESET_WALK: windows.THING_STATE_WALK,
        windows.THING_STATESET_PAIN: windows.THING_STATE_PAIN,
        windows.THING_STATESET_MELEE: windows.THING_STATE_MELEE,
        windows.THING_STATESET_ATTACK: windows.THING_STATE_ATTACK,
        windows.THING_STATESET_DEATH: windows.THING_STATE_DEATH,
        windows.THING_STATESET_EXPLODE: windows.THING_STATE_EXPLODE,
        windows.THING_STATESET_RAISE: windows.THING_STATE_RAISE,
        windows.THING_STATESET_CRASH: windows.THING_STATE_CRASH,
        windows.THING_STATESET_FREEZE: windows.THING_STATE_FREEZE,
        windows.THING_STATESET_BURN: windows.THING_STATE_BURN
    }

    # Sound text control to partial internal key mappings.
    PROPS_SOUNDS = {
        windows.THING_SOUND_ALERT: 'Alert',
        windows.THING_SOUND_ATTACK: 'Attack',
        windows.THING_SOUND_PAIN: 'Pain',
        windows.THING_SOUND_DEATH: 'Death',
        windows.THING_SOUND_ACTIVE: 'Active'
    }

    # Sound set button to partial internal key mappings.
    PROPS_SOUNDSET = {
        windows.THING_SOUNDSET_ALERT: windows.THING_SOUND_ALERT,
        windows.THING_SOUNDSET_ATTACK: windows.THING_SOUND_ATTACK,
        windows.THING_SOUNDSET_PAIN: windows.THING_SOUND_PAIN,
        windows.THING_SOUNDSET_DEATH: windows.THING_SOUND_DEATH,
        windows.THING_SOUNDSET_ACTIVE: windows.THING_SOUND_ACTIVE
    }

    # State name label to partial internal key mappings.
    PROPS_SOUNDNAMES = {
        windows.THING_SOUNDNAME_ALERT: 'Alert',
        windows.THING_SOUNDNAME_ATTACK: 'Attack',
        windows.THING_SOUNDNAME_PAIN: 'Pain',
        windows.THING_SOUNDNAME_DEATH: 'Death',
        windows.THING_SOUNDNAME_ACTIVE: 'Active'
    }

    # Fixed point unit divisor for certain thing properties.
    FIXED_UNIT = 0x10000

    def __init__(self, params):
        windows.ThingsFrameBase.__init__(self, params)
        editormixin.EditorMixin.__init__(self)

        self.SetIcon(wx.Icon('res/editor-things.ico'))

        self.patch = None
        self.pwads = None
        self.clipboard = None
        self.preview_dialog = None

        self.selected_index = 0
        self.thing_is_projectile = False

        self.thingflag_mnemonics = None

        for prop in self.PROPS_STATENAMES.keys():
            item = self.FindWindowById(prop)
            item.SetFont(config.FONT_MONOSPACED_BOLD)

        for prop in self.PROPS_SOUNDNAMES.keys():
            item = self.FindWindowById(prop)
            item.SetFont(config.FONT_MONOSPACED_BOLD)

    def build(self, patch):
        """
        @see EditorMixin.build
        """

        self.patch = patch
        self.pwads = self.GetParent().pwads
        self.clipboard = None
        self.preview_dialog = statepreviewdialog.StatePreviewDialog(self.GetParent())

        self.selected_index = 0

        self.thingflag_mnemonics = None

        self.set_feature_visibility()
        self.flaglist_build()
        self.thinglist_build()
        self.game_build()
        self.renderstyle_build()

    def update(self):
        """
        @see: EditorMixin.update
        """

        self.pwads = self.GetParent().pwads

    def set_feature_visibility(self):
        """
        Sets the visibility of controls based on enabled engine features.
        """

        features = self.patch.engine.features

        self.PanelDamageFactor.Show(('thing.damageFactor' in features))
        self.PanelGravity.Show(('thing.gravity' in features))
        self.PanelGame.Show(('thing.game' in features))
        self.PanelGibHealth.Show(('thing.gibHealth' in features))
        self.PanelSpawnID.Show(('thing.spawnId' in features))
        self.PanelRespawnTime.Show(('thing.respawnTime' in features))
        self.PanelRenderStyle.Show(('thing.renderStyle' in features))
        self.PanelAlpha.Show(('thing.alpha' in features))
        self.PanelScale.Show(('thing.scale' in features))
        self.PanelDecal.Show(('thing.decal' in features))

        self.PanelStateCrash.Show(('thing.stateCrash' in features))
        self.PanelStateFreeze.Show(('thing.stateFreeze' in features))
        self.PanelStateBurn.Show(('thing.stateBurn' in features))

        self.Layout()

    def game_build(self):
        """
        Builds the list of game types.
        """

        self.ThingGame.Clear()
        self.ThingGame.AppendItems([
            'Any',
            'Doom',
            'Heretic',
            'Hexen',
            'Raven'
        ])

    def renderstyle_build(self):
        """
        Builds the list of render styles.
        """

        self.ThingRenderStyle.Clear()
        self.ThingRenderStyle.AppendItems(list(self.patch.engine.render_styles.values()))

    def thinglist_build(self):
        """
        Builds the thing names list from scratch.
        """

        self.ThingList.ClearAll()

        if self.ThingList.GetColumnCount() == 0:
            self.ThingList.InsertColumn(0, '', width=36)
            self.ThingList.InsertColumn(1, 'Name', width=225)
            self.ThingList.InsertColumn(2, 'ID', width=46)
            if 'thing.game' in self.patch.engine.features:
                self.ThingList.InsertColumn(3, 'Game', width=50)

        for index in range(len(self.patch.things.names)):
            self.ThingList.InsertItem(index, '')
            self.thinglist_update_row(index)

        self.list_autosize(self.ThingList)
        self.ThingList.Select(0, True)

    def thinglist_update_row(self, row_index):
        """
        Updates a thing name in the list.
        """

        thing = self.patch.things[row_index]
        thing_name = self.patch.things.names[row_index]

        self.ThingList.SetItemText(row_index, str(row_index + 1))
        self.ThingList.SetItem(row_index, 1, thing_name)
        self.ThingList.SetItem(row_index, 2, str(thing['id']))
        if 'thing.game' in self.patch.engine.features:
            self.ThingList.SetItem(row_index, 3, thing['game'])

    def thinglist_resize(self, event):
        """
        Resizes the thing name column to match the control's width.
        """

        # ioanch 20160124: check bounds
        col_count = self.ThingList.GetColumnCount()
        columns_width = self.ThingList.GetColumnWidth(0) if col_count > 0 else 0
        if col_count > 3:
            columns_width += self.ThingList.GetColumnWidth(2) + self.ThingList.GetColumnWidth(3)

        width = self.ThingList.GetClientSize()[0] - columns_width - 4
        if col_count > 1:
            self.ThingList.SetColumnWidth(1, width)
<commit_msg>Rewrite thing list column resizing to work with any amount of columns.<commit_after>#!/usr/bin/env python
#coding=utf8

from whacked4 import utils
from whacked4.dehacked import statefilter
from whacked4.ui import editormixin, windows
from whacked4.ui.dialogs import statepreviewdialog

import whacked4.config as config

import copy
import wx


class ThingsFrame(editormixin.EditorMixin, windows.ThingsFrameBase):
    """
    Things editor window.
    """

    # Text control to internal key mappings.
    PROPS_VALUES = {
        windows.THING_VAL_ID: 'id',
        windows.THING_VAL_HEALTH: 'health',
        windows.THING_VAL_GIBHEALTH: 'gibHealth',
        windows.THING_VAL_SPEED: 'speed',
        windows.THING_VAL_RADIUS: 'radius',
        windows.THING_VAL_HEIGHT: 'height',
        windows.THING_VAL_DAMAGE: 'damage',
        windows.THING_VAL_REACTIONTIME: 'reactionTime',
        windows.THING_VAL_PAINCHANCE: 'painChance',
        windows.THING_VAL_MASS: 'mass',
        windows.THING_VAL_GAME: 'game',
        windows.THING_VAL_SPAWNID: 'spawnId',
        windows.THING_VAL_RESPAWNTIME: 'respawnTime',
        windows.THING_VAL_RENDERSTYLE: 'renderStyle',
        windows.THING_VAL_ALPHA: 'alpha',
        windows.THING_VAL_SCALE: 'scale',
        windows.THING_VAL_DECAL: 'decal',
        windows.THING_VAL_DAMAGEFACTOR: 'damageFactor',
        windows.THING_VAL_GRAVITY: 'gravity',
    }

    # Value types for text control validation.
    PROPS_VALUE_TYPES = {
        windows.THING_VAL_ID: 'int',
        windows.THING_VAL_HEALTH: 'int',
        windows.THING_VAL_GIBHEALTH: 'int',
        windows.THING_VAL_SPEED: 'int',
        windows.THING_VAL_RADIUS: 'fixed',
        windows.THING_VAL_HEIGHT: 'fixed',
        windows.THING_VAL_DAMAGE: 'int',
        windows.THING_VAL_REACTIONTIME: 'int',
        windows.THING_VAL_PAINCHANCE: 'int',
        windows.THING_VAL_MASS: 'int',
        windows.THING_VAL_GAME: 'int',
        windows.THING_VAL_SPAWNID: 'int',
        windows.THING_VAL_RESPAWNTIME: 'int',
        windows.THING_VAL_RENDERSTYLE: 'int',
        windows.THING_VAL_ALPHA: 'float',
        windows.THING_VAL_SCALE: 'float',
        windows.THING_VAL_DECAL: 'str',
        windows.THING_VAL_DAMAGEFACTOR: 'float',
        windows.THING_VAL_GRAVITY: 'float',
    }

    # State text control to partial internal key mappings.
    PROPS_STATES = {
        windows.THING_STATE_SPAWN: 'Spawn',
        windows.THING_STATE_WALK: 'Walk',
        windows.THING_STATE_PAIN: 'Pain',
        windows.THING_STATE_MELEE: 'Melee',
        windows.THING_STATE_ATTACK: 'Attack',
        windows.THING_STATE_DEATH: 'Death',
        windows.THING_STATE_EXPLODE: 'Explode',
        windows.THING_STATE_RAISE: 'Raise',
        windows.THING_STATE_CRASH: 'Crash',
        windows.THING_STATE_FREEZE: 'Freeze',
        windows.THING_STATE_BURN: 'Burn'
    }

    # State name label to partial internal key mappings.
    PROPS_STATENAMES = {
        windows.THING_STATENAME_SPAWN: 'Spawn',
        windows.THING_STATENAME_WALK: 'Walk',
        windows.THING_STATENAME_PAIN: 'Pain',
        windows.THING_STATENAME_MELEE: 'Melee',
        windows.THING_STATENAME_ATTACK: 'Attack',
        windows.THING_STATENAME_DEATH: 'Death',
        windows.THING_STATENAME_EXPLODE: 'Explode',
        windows.THING_STATENAME_RAISE: 'Raise',
        windows.THING_STATENAME_CRASH: 'Crash',
        windows.THING_STATENAME_FREEZE: 'Freeze',
        windows.THING_STATENAME_BURN: 'Burn'
    }

    # State set button to partial internal key mappings.
    PROPS_STATESET = {
        windows.THING_STATESET_SPAWN: windows.THING_STATE_SPAWN,
        windows.THING_STATESET_WALK: windows.THING_STATE_WALK,
        windows.THING_STATESET_PAIN: windows.THING_STATE_PAIN,
        windows.THING_STATESET_MELEE: windows.THING_STATE_MELEE,
        windows.THING_STATESET_ATTACK: windows.THING_STATE_ATTACK,
        windows.THING_STATESET_DEATH: windows.THING_STATE_DEATH,
        windows.THING_STATESET_EXPLODE: windows.THING_STATE_EXPLODE,
        windows.THING_STATESET_RAISE: windows.THING_STATE_RAISE,
        windows.THING_STATESET_CRASH: windows.THING_STATE_CRASH,
        windows.THING_STATESET_FREEZE: windows.THING_STATE_FREEZE,
        windows.THING_STATESET_BURN: windows.THING_STATE_BURN
    }

    # Sound text control to partial internal key mappings.
    PROPS_SOUNDS = {
        windows.THING_SOUND_ALERT: 'Alert',
        windows.THING_SOUND_ATTACK: 'Attack',
        windows.THING_SOUND_PAIN: 'Pain',
        windows.THING_SOUND_DEATH: 'Death',
        windows.THING_SOUND_ACTIVE: 'Active'
    }

    # Sound set button to partial internal key mappings.
    PROPS_SOUNDSET = {
        windows.THING_SOUNDSET_ALERT: windows.THING_SOUND_ALERT,
        windows.THING_SOUNDSET_ATTACK: windows.THING_SOUND_ATTACK,
        windows.THING_SOUNDSET_PAIN: windows.THING_SOUND_PAIN,
        windows.THING_SOUNDSET_DEATH: windows.THING_SOUND_DEATH,
        windows.THING_SOUNDSET_ACTIVE: windows.THING_SOUND_ACTIVE
    }

    # State name label to partial internal key mappings.
    PROPS_SOUNDNAMES = {
        windows.THING_SOUNDNAME_ALERT: 'Alert',
        windows.THING_SOUNDNAME_ATTACK: 'Attack',
        windows.THING_SOUNDNAME_PAIN: 'Pain',
        windows.THING_SOUNDNAME_DEATH: 'Death',
        windows.THING_SOUNDNAME_ACTIVE: 'Active'
    }

    # Fixed point unit divisor for certain thing properties.
    FIXED_UNIT = 0x10000

    def __init__(self, params):
        windows.ThingsFrameBase.__init__(self, params)
        editormixin.EditorMixin.__init__(self)

        self.SetIcon(wx.Icon('res/editor-things.ico'))

        self.patch = None
        self.pwads = None
        self.clipboard = None
        self.preview_dialog = None

        self.selected_index = 0
        self.thing_is_projectile = False

        self.thingflag_mnemonics = None

        for prop in self.PROPS_STATENAMES.keys():
            item = self.FindWindowById(prop)
            item.SetFont(config.FONT_MONOSPACED_BOLD)

        for prop in self.PROPS_SOUNDNAMES.keys():
            item = self.FindWindowById(prop)
            item.SetFont(config.FONT_MONOSPACED_BOLD)

    def build(self, patch):
        """
        @see EditorMixin.build
        """

        self.patch = patch
        self.pwads = self.GetParent().pwads
        self.clipboard = None
        self.preview_dialog = statepreviewdialog.StatePreviewDialog(self.GetParent())

        self.selected_index = 0

        self.thingflag_mnemonics = None

        self.set_feature_visibility()
        self.flaglist_build()
        self.thinglist_build()
        self.game_build()
        self.renderstyle_build()

    def update(self):
        """
        @see: EditorMixin.update
        """

        self.pwads = self.GetParent().pwads

    def set_feature_visibility(self):
        """
        Sets the visibility of controls based on enabled engine features.
        """

        features = self.patch.engine.features

        self.PanelDamageFactor.Show(('thing.damageFactor' in features))
        self.PanelGravity.Show(('thing.gravity' in features))
        self.PanelGame.Show(('thing.game' in features))
        self.PanelGibHealth.Show(('thing.gibHealth' in features))
        self.PanelSpawnID.Show(('thing.spawnId' in features))
        self.PanelRespawnTime.Show(('thing.respawnTime' in features))
        self.PanelRenderStyle.Show(('thing.renderStyle' in features))
        self.PanelAlpha.Show(('thing.alpha' in features))
        self.PanelScale.Show(('thing.scale' in features))
        self.PanelDecal.Show(('thing.decal' in features))

        self.PanelStateCrash.Show(('thing.stateCrash' in features))
        self.PanelStateFreeze.Show(('thing.stateFreeze' in features))
        self.PanelStateBurn.Show(('thing.stateBurn' in features))

        self.Layout()

    def game_build(self):
        """
        Builds the list of game types.
        """

        self.ThingGame.Clear()
        self.ThingGame.AppendItems([
            'Any',
            'Doom',
            'Heretic',
            'Hexen',
            'Raven'
        ])

    def renderstyle_build(self):
        """
        Builds the list of render styles.
        """

        self.ThingRenderStyle.Clear()
        self.ThingRenderStyle.AppendItems(list(self.patch.engine.render_styles.values()))

    def thinglist_build(self):
        """
        Builds the thing names list from scratch.
        """

        self.ThingList.ClearAll()

        if self.ThingList.GetColumnCount() == 0:
            self.ThingList.InsertColumn(0, '', width=36)
            self.ThingList.InsertColumn(1, 'Name', width=225)
            self.ThingList.InsertColumn(2, 'ID', width=46)
            if 'thing.game' in self.patch.engine.features:
                self.ThingList.InsertColumn(3, 'Game', width=50)

        for index in range(len(self.patch.things.names)):
            self.ThingList.InsertItem(index, '')
            self.thinglist_update_row(index)

        self.list_autosize(self.ThingList)
        self.ThingList.Select(0, True)

    def thinglist_update_row(self, row_index):
        """
        Updates a thing name in the list.
        """

        thing = self.patch.things[row_index]
        thing_name = self.patch.things.names[row_index]

        self.ThingList.SetItemText(row_index, str(row_index + 1))
        self.ThingList.SetItem(row_index, 1, thing_name)
        self.ThingList.SetItem(row_index, 2, str(thing['id']))
        if 'thing.game' in self.patch.engine.features:
            self.ThingList.SetItem(row_index, 3, thing['game'])

    def thinglist_resize(self, event):
        """
        Resizes the thing name column to match the control's width.
        """

        if not self.ThingList.GetColumnCount():
            return

        columns_width = 0
        for column in range(self.ThingList.GetColumnCount()):
            if column == 1:
                continue
            columns_width += self.ThingList.GetColumnWidth(column)

        name_width = self.ThingList.GetClientSize()[0] - columns_width - 4
        self.ThingList.SetColumnWidth(1, name_width)

{'fraction_non_alphanumeric': 0.10020287990499283, 'fraction_numerical': 0.004403978425454006, 'mean_word_length': 2.718491260349586, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3001697', 'n_tokens_mistral': 6805, 'n_tokens_neox': 6588, 'n_words': 1073}