mirror of https://github.com/buggins/dlangui.git
ML parser improvements; allow specifying percent size for layoutWidth, layoutHeight in percents
This commit is contained in:
parent
2877cba890
commit
f0a615ed82
|
@ -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
|
||||
|
|
|
@ -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 |
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue