With university term over, I've been able to do some more work on my screen editor. The major changes are:- Preliminary support for Company of Heroes (I'm testing against 2.602).
- Massive internal rewrite of the code responsible for loading and manipulating (and in future, saving) of screen files and their contents.
- Support for the following types of widget has been added: ComboBox, ProgressBar, CustomListBox, TextListBox, ScrollBar.
- The following types of widget should support mouse interactivity: Button, CheckButton, RadioButton.
- Beginnings of UI relating to editing rather than just viewing (though very much unfinished).
With regard to the last item, I wouldn't normally release something this unfinished, but I'm going on holiday for a while, and feel that CoH support justifies a release now. Due to this unfinishedness, I'm still calling this an alpha version.

Download: http://www.corsix.org/cdse/ScreenEditor_Alpha.exe
As an aside, people may also be interested in my current schema for screen files:
Code:
struct D2D1_POINT_2F @Predefined
{
float x @Lua(1) = 0.f;
float y @Lua(2) = 0.f;
};
struct D2D1_SIZE_F @Predefined
{
float width @Lua(1) = 1.f;
float height @Lua(2) = 1.f;
};
struct Range
{
float minimum @Lua(1) = 0.f;
float maximum @Lua(2) = 1.f;
};
enum States @CPrefix(State_) : int
{
Unknown @Default,
Disabled,
Normal,
Hover,
Active,
CheckedDisabled,
Checked,
CheckedHover,
CheckedActive,
};
enum ButtonType
{
Unknown @Default,
ClickOnRelease,
ClickOnPress,
};
struct Art @Window
{
string type = nullptr;
int id = 0;
bool[States] states = false;
D2D1_POINT_2F position @Get(getPosition()) @Set(repositionFromLua(..., getSize()));
D2D1_SIZE_F size @NotifyAs(position) @Get(getSize()) @Set(repositionFromLua(getPosition(), ...));
};
struct D2D1_COLOR_F @Predefined @SceneFromString(.getArtCache().loadColour)
{
float r @Lua(1) @Normalise(255.f) = 0.f;
float g @Lua(2) @Normalise(255.f) = 0.f;
float b @Lua(3) @Normalise(255.f) = 0.f;
float a @Lua(4) @Normalise(255.f) = 1.f;
};
struct GraphicArt : Art
{
string texture = "art/";
bool flip_horz @Lua(flipHorizontal) = false;
bool flip_vert @Lua(flipVertical) = false;
D2D1_COLOR_F colour;
};
enum DWRITE_TEXT_ALIGNMENT @Predefined
{
LEADING @Lua(Left) @Default,
CENTER @Lua(Centre),
TRAILING @Lua(Right),
};
enum DWRITE_PARAGRAPH_ALIGNMENT @Predefined
{
NEAR @Lua(Top),
CENTER @Lua(Centre) @Default,
FAR @Lua(Bottom),
};
struct TextArt : Art
{
D2D1_COLOR_F colour_top @NotifySelf(Colour) @Lua(textColourTop);
D2D1_COLOR_F colour_bottom @NotifySelf(Colour) @Lua(textColourBottom);
string fontname @NotifySelf(Font) = "";
bool is_multiline @NotifySelf(Font) @Lua(multiline) = true;
bool has_dropshadow @Lua(dropShadow) = false;
DWRITE_TEXT_ALIGNMENT horz_align @NotifySelf(Font) @Lua(horzAlign);
DWRITE_PARAGRAPH_ALIGNMENT vert_align @NotifySelf(Font) @Lua(vertAlign);
};
enum RectangleType @CPrefix(RT_)
{
Solid @Default,
Border,
};
struct RectangleArt : Art
{
D2D1_COLOR_F colour @NotifySelf;
RectangleType rectangle_type @Lua(rectangleType);
};
struct SwfArt : Art
{
string swf @NotifySelf = "no file";
float alpha = 1.f;
};
struct LineArt : Art
{
D2D1_COLOR_F colour @NotifySelf;
D2D1_POINT_2F p1 @NotifyAs(endpoint);
D2D1_POINT_2F p2 @NotifyAs(endpoint);
};
struct Style @Predefined
{
string sheetname @Lua(1) = nullptr;
string stylename @Lua(2) = nullptr;
};
struct Presentation
{
Art[] Art;
};
struct Widget @Window(UI::WindowWithChildren)
{
string type = nullptr;
string name @RegistryToSelf = "Untitled";
Style style @Style;
D2D1_POINT_2F position @Get(getPosition()) @Set(repositionFromLua(..., getSize()));
D2D1_SIZE_F size @Styled @NotifyAs(position) @Get(getSize()) @Set(repositionFromLua(getPosition(), ...));
Presentation Presentation @Styled;
bool is_visible @Lua(visible) = true;
string text @Ucs = nullptr;
string tooltip @Lua(tooltip_text) @SceneBeforeChange(.setTooltip(nullptr, nullptr)) @Ucs = "";
Widget tooltip_widget @Lua(tooltip_name) @RegistryLookup @NotChild;
};
struct GroupWidget : Widget
{
Widget[] Children;
};
struct CustomListBoxItem : GroupWidget
{
};
struct ComboBoxWidget : Widget
{
Widget ListBox @Styled;
Widget Label @Styled;
Widget ArrowButton @Styled;
};
struct CustomWidget : Widget
{
string tag @Lua(customProperties) = "";
};
struct ProgressBarWidget : Widget
{
Widget Progress @Styled;
Range range @Styled;
float step_size @Lua(stepSize) @Styled = 0.1f;
};
struct CustomListBoxWidget : Widget
{
Widget ItemsGroup @Styled;
Widget ItemTemplate @Styled;
Widget ScrollBar @Styled;
int maxItems @Styled = INT_MAX;
};
struct TextListBoxWidget : Widget
{
Widget ItemsGroup @Styled;
Widget ItemTemplate @Styled;
Widget ScrollBar @Styled;
};
struct ScrollBarWidget : Widget
{
Range range @Styled;
Widget ButtonIncrement;
Widget ButtonTrack;
Widget ButtonDecrement;
};
struct ButtonWidget : Widget
{
ButtonType button_type @Lua(buttonType);
bool want_alternate @Lua(wantAlternate) = false;
bool enabled = true;
};
struct CheckButtonWidget : ButtonWidget
{
};
struct RadioButtonWidget : CheckButtonWidget
{
};