ML parser improvements; allow specifying percent size for layoutWidth, layoutHeight in percents

This commit is contained in:
Vadim Lopatin 2015-04-02 11:06:50 +03:00
parent 2877cba890
commit f0a615ed82
10 changed files with 215 additions and 19 deletions

View File

@ -34,6 +34,9 @@ EndProject
Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "dsfml", "..\DSFML\dsfml\dsfml.visualdproj", "{DB490C05-D9F8-431C-91DD-CEE646A64FDA}"
EndProject
Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "dmledit", "examples\dmledit\dmledit.visualdproj", "{06D73450-2919-48A8-B2C3-738B12505D74}"
ProjectSection(ProjectDependencies) = postProject
{5FF17402-9997-4D0E-8068-6D84B8769D98} = {5FF17402-9997-4D0E-8068-6D84B8769D98}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -4,13 +4,131 @@ import dlangui;
mixin APP_ENTRY_POINT;
// action codes
enum IDEActions : int {
//ProjectOpen = 1010000,
FileNew = 1010000,
FileOpen,
FileSave,
FileSaveAs,
FileSaveAll,
FileClose,
FileExit,
EditPreferences,
}
// actions
const Action ACTION_FILE_NEW = new Action(IDEActions.FileNew, "MENU_FILE_NEW"c, "document-new", KeyCode.KEY_N, KeyFlag.Control);
const Action ACTION_FILE_SAVE = (new Action(IDEActions.FileSave, "MENU_FILE_SAVE"c, "document-save", KeyCode.KEY_S, KeyFlag.Control)).disableByDefault();
const Action ACTION_FILE_SAVE_AS = (new Action(IDEActions.FileSaveAs, "MENU_FILE_SAVE_AS"c)).disableByDefault();
const Action ACTION_FILE_OPEN = new Action(IDEActions.FileOpen, "MENU_FILE_OPEN"c, "document-open", KeyCode.KEY_O, KeyFlag.Control);
const Action ACTION_FILE_EXIT = new Action(IDEActions.FileExit, "MENU_FILE_EXIT"c, "document-close"c, KeyCode.KEY_X, KeyFlag.Alt);
const Action ACTION_EDIT_COPY = (new Action(EditorActions.Copy, "MENU_EDIT_COPY"c, "edit-copy"c, KeyCode.KEY_C, KeyFlag.Control)).addAccelerator(KeyCode.INS, KeyFlag.Control).disableByDefault();
const Action ACTION_EDIT_PASTE = (new Action(EditorActions.Paste, "MENU_EDIT_PASTE"c, "edit-paste"c, KeyCode.KEY_V, KeyFlag.Control)).addAccelerator(KeyCode.INS, KeyFlag.Shift).disableByDefault();
const Action ACTION_EDIT_CUT = (new Action(EditorActions.Cut, "MENU_EDIT_CUT"c, "edit-cut"c, KeyCode.KEY_X, KeyFlag.Control)).addAccelerator(KeyCode.DEL, KeyFlag.Shift).disableByDefault();
const Action ACTION_EDIT_UNDO = (new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c, "edit-undo"c, KeyCode.KEY_Z, KeyFlag.Control)).disableByDefault();
const Action ACTION_EDIT_REDO = (new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo"c, KeyCode.KEY_Y, KeyFlag.Control)).addAccelerator(KeyCode.KEY_Z, KeyFlag.Control|KeyFlag.Shift).disableByDefault();
const Action ACTION_EDIT_INDENT = (new Action(EditorActions.Indent, "MENU_EDIT_INDENT"c, "edit-indent"c, KeyCode.TAB, 0)).addAccelerator(KeyCode.KEY_BRACKETCLOSE, KeyFlag.Control).disableByDefault();
const Action ACTION_EDIT_UNINDENT = (new Action(EditorActions.Unindent, "MENU_EDIT_UNINDENT"c, "edit-unindent", KeyCode.TAB, KeyFlag.Shift)).addAccelerator(KeyCode.KEY_BRACKETOPEN, KeyFlag.Control).disableByDefault();
const Action ACTION_EDIT_TOGGLE_LINE_COMMENT = (new Action(EditorActions.ToggleLineComment, "MENU_EDIT_TOGGLE_LINE_COMMENT"c, null, KeyCode.KEY_DIVIDE, KeyFlag.Control)).disableByDefault();
const Action ACTION_EDIT_TOGGLE_BLOCK_COMMENT = (new Action(EditorActions.ToggleBlockComment, "MENU_EDIT_TOGGLE_BLOCK_COMMENT"c, null, KeyCode.KEY_DIVIDE, KeyFlag.Control|KeyFlag.Shift)).disableByDefault();
const Action ACTION_EDIT_PREFERENCES = (new Action(IDEActions.EditPreferences, "MENU_EDIT_PREFERENCES"c, null)).disableByDefault();
class EditFrame : AppFrame {
MenuItem mainMenuItems;
override protected void init() {
_appName = "DMLEdit";
super.init();
}
/// create main menu
override protected MainMenu createMainMenu() {
return new MainMenu(new MenuItem());
mainMenuItems = new MenuItem();
MenuItem fileItem = new MenuItem(new Action(1, "MENU_FILE"));
fileItem.add(ACTION_FILE_NEW, ACTION_FILE_OPEN,
ACTION_FILE_EXIT);
MenuItem editItem = new MenuItem(new Action(2, "MENU_EDIT"));
editItem.add(ACTION_EDIT_COPY, ACTION_EDIT_PASTE,
ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO,
ACTION_EDIT_INDENT, ACTION_EDIT_UNINDENT, ACTION_EDIT_TOGGLE_LINE_COMMENT, ACTION_EDIT_TOGGLE_BLOCK_COMMENT);
editItem.add(ACTION_EDIT_PREFERENCES);
MainMenu mainMenu = new MainMenu(mainMenuItems);
return mainMenu;
}
/// create app toolbars
override protected ToolBarHost createToolbars() {
ToolBarHost res = new ToolBarHost();
ToolBar tb;
tb = res.getOrAddToolbar("Standard");
tb.addButtons(ACTION_FILE_NEW, ACTION_FILE_OPEN, ACTION_FILE_SAVE);
tb = res.getOrAddToolbar("Edit");
tb.addButtons(ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT, ACTION_SEPARATOR,
ACTION_EDIT_UNDO, ACTION_EDIT_REDO, ACTION_EDIT_INDENT, ACTION_EDIT_UNINDENT);
return res;
}
/// create app body widget
override protected Widget createBody() {
VerticalLayout bodyWidget = new VerticalLayout();
bodyWidget.layoutWidth = FILL_PARENT;
bodyWidget.layoutHeight = FILL_PARENT;
HorizontalLayout hlayout = new HorizontalLayout();
hlayout.layoutWidth = makePercentSize(50);
hlayout.layoutHeight = FILL_PARENT;
SourceEdit editor = new SourceEdit();
hlayout.addChild(editor);
ScrollWidget preview = new ScrollWidget();
preview.layoutWidth = FILL_PARENT;
preview.layoutHeight = FILL_PARENT;
hlayout.addChild(preview);
bodyWidget.addChild(hlayout);
return bodyWidget;
}
}
/// entry point for dlangui based application
extern (C) int UIAppMain(string[] args) {
// embed non-standard resources listed in views/resources.list into executable
embeddedResourceList.addResources(embedResourcesFromList!("resources.list")());
// create window
Window window = Platform.instance.createWindow("DlangUI example - HelloWorld", null);
Window window = Platform.instance.createWindow("DlangUI ML editor"d, null, WindowFlag.Resizable, 700, 470);
// create some widget to show in window
window.mainWidget = (new Button()).text("Hello, world!"d).margins(Rect(20,20,20,20));
window.windowIcon = drawableCache.getImage("dlangui-logo1");
// create some widget to show in window
window.mainWidget = new EditFrame();
/*
parseML(q{
VerticalLayout {
id: vlayout
margins: Rect { left: 5; right: 3; top: 2; bottom: 4 }
padding: Rect { 5, 4, 3, 2 } // same as Rect { left: 5; top: 4; right: 3; bottom: 2 }
TextWidget {
id: myLabel1
text: "Some text"; padding: 5
enabled: false
}
TextWidget {
id: myLabel2
text: SOME_TEXT_RESOURCE_ID; margins: 5
enabled: true
}
}
});
*/
// show window
window.show();

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

View File

@ -2,6 +2,7 @@ res/i18n/en.ini
res/i18n/ru.ini
res/mdpi/cr3_logo.png
res/mdpi/document-close.png
res/mdpi/document-new.png
res/mdpi/document-open-recent.png
res/mdpi/document-open.png
res/mdpi/document-properties.png

View File

@ -1,3 +1,18 @@
// Written in the D programming language.
/**
This module is DML (DlangUI Markup Language) parser - similar to QML in QtQuick
Synopsis:
----
// helloworld
----
Copyright: Vadim Lopatin, 2015
License: Boost License 1.0
Authors: Vadim Lopatin, coolreader.org@gmail.com
*/
module dlangui.core.parser;
import dlangui.core.linestream;
@ -21,7 +36,7 @@ class ParserException : Exception {
@property int pos() { return _pos; }
this(string msg, string file, int line, int pos) {
super(msg ~ " at " ~ _file ~ " line " ~ to!string(line) ~ " column " ~ to!string(pos));
super(msg ~ " at " ~ file ~ " line " ~ to!string(line) ~ " column " ~ to!string(pos));
_msg = msg;
_file = file;
_line = line;
@ -29,6 +44,28 @@ class ParserException : Exception {
}
}
/// parser exception - unknown (unregistered) widget name
class UnknownWidgetException : ParserException {
protected string _objectName;
@property string objectName() { return _objectName; }
this(string msg, string objectName, string file, int line, int pos) {
super(msg is null ? "Unknown widget name: " ~ objectName : msg, file, line, pos);
_objectName = objectName;
}
}
/// parser exception - unknown property for widget
class UnknownPropertyException : UnknownWidgetException {
protected string _propName;
@property string propName() { return _propName; }
this(string msg, string objectName, string propName, string file, int line, int pos) {
super(msg is null ? "Unknown property " ~ objectName ~ "." ~ propName : msg, objectName, file, line, pos);
}
}
enum TokenType : ushort {
/// end of file
@ -406,6 +443,14 @@ class Tokenizer {
throw new ParserException(msg ~ getContextSource(), _filename, _token.line, _token.pos);
}
void emitUnknownPropertyError(string objectName, string propName) {
throw new UnknownPropertyException("Unknown property " ~ objectName ~ "." ~ propName ~ getContextSource(), objectName, propName, _filename, _token.line, _token.pos);
}
void emitUnknownObjectError(string objectName) {
throw new UnknownWidgetException("Unknown widget type " ~ objectName ~ getContextSource(), objectName, _filename, _token.line, _token.pos);
}
void emitError(string msg, ref const Token token) {
throw new ParserException(msg, _filename, token.line, token.pos);
}
@ -481,6 +526,14 @@ class MLParser {
_tokenizer.emitError(msg);
}
protected void unknownObjectError(string objectName) {
_tokenizer.emitUnknownObjectError(objectName);
}
protected void unknownPropertyError(string objectName, string propName) {
_tokenizer.emitUnknownPropertyError(objectName, propName);
}
Widget createWidget(string name) {
auto metadata = findWidgetMetadata(name);
if (!metadata)

View File

@ -215,6 +215,29 @@ int makePercentSize(int percent) {
return (percent * 100) | SIZE_IN_PERCENTS_FLAG;
}
/// make size value with SIZE_IN_PERCENTS_FLAG set
int makePercentSize(double percent) {
return cast(int)(percent * 100) | SIZE_IN_PERCENTS_FLAG;
}
/// returns true for WRAP_CONTENT, WRAP_CONTENT, SIZE_UNSPECIFIED
bool isSpecialSize(int sz) {
// don't forget to update if more special constants added
return (sz & (WRAP_CONTENT | FILL_PARENT | SIZE_UNSPECIFIED)) != 0;
}
/// returns true if size has SIZE_IN_PERCENTS_FLAG bit set
bool isPercentSize(int size) {
return (size & SIZE_IN_PERCENTS_FLAG) != 0;
}
/// if size has SIZE_IN_PERCENTS_FLAG bit set, returns percent of baseSize, otherwise returns size unchanged
int fromPercentSize(int size, int baseSize) {
if (isPercentSize(size))
return cast(int)(cast(long)(size & ~SIZE_IN_PERCENTS_FLAG) * baseSize / 10000);
return size;
}
/// screen dots per inch
private __gshared int PRIVATE_SCREEN_DPI = 96;

View File

@ -71,6 +71,7 @@ public import dlangui.widgets.popup;
public import dlangui.widgets.appframe;
public import dlangui.widgets.statusline;
public import dlangui.widgets.docks;
public import dlangui.widgets.toolbars;
public import dlangui.platforms.common.platform;
public import dlangui.core.parser;

View File

@ -80,6 +80,13 @@ class AppFrame : VerticalLayout, MenuItemClickHandler, MenuItemActionHandler {
protected ulong _currentBackgroundOperationTimer;
this() {
super("APP_FRAME");
layoutWidth = FILL_PARENT;
layoutHeight = FILL_PARENT;
_appName = "dlangui";
init();
}
protected string _appName;
/// override to return some identifier for app, e.g. to use as settings directory name
@ -210,14 +217,6 @@ class AppFrame : VerticalLayout, MenuItemClickHandler, MenuItemActionHandler {
/// body widget
@property Widget frameBody() { return _body; }
this() {
super("APP_FRAME");
layoutWidth = FILL_PARENT;
layoutHeight = FILL_PARENT;
_appName = "dlangui";
init();
}
/// map key to action
override Action findKeyAction(uint keyCode, uint flags) {
if (_mainMenu) {

View File

@ -205,12 +205,6 @@ immutable uint TEXT_FLAGS_USE_PARENT = uint.max - 1;
/// to take layout weight from parent
immutable int WEIGHT_UNSPECIFIED = -1;
/// returns true for WRAP_CONTENT, WRAP_CONTENT, SIZE_UNSPECIFIED
bool isSpecialSize(int sz) {
// don't forget to update if more special constants added
return sz >= WRAP_CONTENT;
}
/// Align option bit constants
enum Align : ubyte {
/// alignment is not specified

View File

@ -1223,9 +1223,13 @@ class Widget {
// check for fixed size set in layoutWidth, layoutHeight
int lh = layoutHeight;
int lw = layoutWidth;
if (!isSpecialSize(lh))
if (isPercentSize(lh) && parentHeight != SIZE_UNSPECIFIED)
dy = fromPercentSize(lh, parentHeight);
else if (!isSpecialSize(lh))
dy = lh;
if (!isSpecialSize(lw))
if (isPercentSize(lw) && parentWidth != SIZE_UNSPECIFIED)
dy = fromPercentSize(lw, parentWidth);
else if (!isSpecialSize(lw))
dx = lw;
// apply min/max width and height constraints
int minw = minWidth;