diff --git a/README.md b/README.md
index b7c8e885..4635cd6e 100644
--- a/README.md
+++ b/README.md
@@ -229,6 +229,7 @@ Clone dependency libraries to dlangui/deps directory
git clone https://github.com/DerelictOrg/DerelictSDL2.git
git clone https://github.com/gecko0307/dlib.git
git clone https://github.com/Dav1dde/gl3n.git
+ git clone https://github.com/nomad-software/x11.git
Open solution file with Mono-D
diff --git a/dlangui-monod-linux.dproj b/dlangui-monod-linux.dproj
index 85e014e9..af1cea46 100644
--- a/dlangui-monod-linux.dproj
+++ b/dlangui-monod-linux.dproj
@@ -139,6 +139,33 @@
-Jviews/res
-Jviews/res/i18n
-Jviews/res/mdpi
+-Jviews/res/hdpi
+ false
+ libdlangui-monod-linux
+ StaticLibrary
+ true
+ 0
+
+
+ bin\DebugX11
+
+
+ USE_X11
+ USE_FREETYPE
+ EmbedStandardResources
+
+
+ obj/DebugX11
+ false
+
+
+ X
+
+
+ -Jviews
+-Jviews/res
+-Jviews/res/i18n
+-Jviews/res/mdpi
-Jviews/res/hdpi
false
libdlangui-monod-linux
@@ -277,5 +304,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dlangui-monod-osx.dproj b/dlangui-monod-osx.dproj
index 6a96d47d..16cd0ae6 100644
--- a/dlangui-monod-osx.dproj
+++ b/dlangui-monod-osx.dproj
@@ -43,6 +43,15 @@
StaticLibrary
true
0
+ -Jviews -Jviews/res -Jviews/res/i18n -Jviews/res/mdpi -Jviews/res/hdpi
+
+
+ USE_SDL
+ USE_OPENGL
+ USE_FREETYPE
+ EmbedStandardResources
+
+
true
@@ -54,6 +63,15 @@
Executable
true
0
+ -Jviews -Jviews/res -Jviews/res/i18n -Jviews/res/mdpi -Jviews/res/hdpi
+
+
+ USE_SDL
+ USE_OPENGL
+ USE_FREETYPE
+ EmbedStandardResources
+
+
diff --git a/examples/derelictcocoatest-monod-osx/derelictcocoatest-monod-osx.dproj b/examples/derelictcocoatest-monod-osx/derelictcocoatest-monod-osx.dproj
index 6c640c5e..67b8eda5 100644
--- a/examples/derelictcocoatest-monod-osx/derelictcocoatest-monod-osx.dproj
+++ b/examples/derelictcocoatest-monod-osx/derelictcocoatest-monod-osx.dproj
@@ -2,7 +2,7 @@
Debug
- AnyCPU
+ x64
{1F050D82-5245-4B51-A554-473194EA0DE9}
DMD2
true
@@ -26,17 +26,6 @@
-
- true
- bin\Debug
- obj/Debug
- false
- false
- derelictcocoatest-monod-osx
- Executable
- true
- 0
-
bin\Release
obj/Release
@@ -58,6 +47,25 @@
true
0
+
+ true
+ bin\Debug
+
+
+ USE_SDL
+ USE_OPENGL
+ USE_FREETYPE
+ EmbedStandardResources
+
+
+ obj/Debug
+ false
+ false
+ derelictcocoatest-monod-osx
+ Executable
+ true
+ 0
+
diff --git a/examples/derelictcocoatest-monod-osx/src/cocoatest.d b/examples/derelictcocoatest-monod-osx/src/cocoatest.d
index a88f6db9..ed820bac 100644
--- a/examples/derelictcocoatest-monod-osx/src/cocoatest.d
+++ b/examples/derelictcocoatest-monod-osx/src/cocoatest.d
@@ -1,43 +1,748 @@
module cocoatest;
+version(OSX):
import derelict.cocoa;
import dlangui.core.logger;
+import dlangui.core.types;
+import dlangui.core.events;
+import dlangui.graphics.drawbuf;
+import std.uuid;
+import core.stdc.stdlib;
+import std.string;
void main(string[] args)
{
Log.setStderrLogger();
Log.setLogLevel(LogLevel.Trace);
DerelictCocoa.load();
-
- NSString appName = NSProcessInfo.processInfo().processName();
- Log.i("appName = %s", appName);
- //writefln("appName = %s", appName);
-
- auto pool = new NSAutoreleasePool;
-
- auto NSApp = NSApplication.sharedApplication;
-
- NSApp.setActivationPolicy(NSApplicationActivationPolicyRegular);
-
- NSMenu menubar = NSMenu.alloc;
- menubar.init_();
- NSMenuItem appMenuItem = NSMenuItem.alloc();
- appMenuItem.init_();
- menubar.addItem(appMenuItem);
- NSApp.setMainMenu(menubar);
-
- NSWindow window = NSWindow.alloc();
- window.initWithContentRect(NSMakeRect(10, 10, 200, 200),
- NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask, //NSBorderlessWindowMask,
- NSBackingStoreBuffered, NO);
- window.makeKeyAndOrderFront();
- NSView parentView;
- parentView = window.contentView();
-
- NSApp.activateIgnoringOtherApps(YES);
- NSApp.run();
+
+
+ static if (true) {
+ auto pool = new NSAutoreleasePool;
+ NSString appName = NSProcessInfo.processInfo().processName();
+ Log.i("appName = %s", appName);
+
+ CocoaWindow window = new CocoaWindow(cast(void*)null, new IWindowListenerLogger(), 300, 300);
+ Log.d("");
+ } else {
+
+
+ NSString appName = NSProcessInfo.processInfo().processName();
+ Log.i("appName = %s", appName);
+ //writefln("appName = %s", appName);
+
+ auto pool = new NSAutoreleasePool;
+
+ auto NSApp = NSApplication.sharedApplication;
+
+ NSApp.setActivationPolicy(NSApplicationActivationPolicyRegular);
+
+ NSMenu menubar = NSMenu.alloc;
+ menubar.init_();
+ NSMenuItem appMenuItem = NSMenuItem.alloc();
+ appMenuItem.init_();
+ menubar.addItem(appMenuItem);
+ NSApp.setMainMenu(menubar);
+
+ NSWindow window = NSWindow.alloc();
+ window.initWithContentRect(NSMakeRect(10, 10, 200, 200),
+ NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask, //NSBorderlessWindowMask,
+ NSBackingStoreBuffered, NO);
+ window.makeKeyAndOrderFront();
+
+ NSView parentView;
+ parentView = window.contentView();
+
+ Log.i("parentView=", parentView);
+
+ NSApp.activateIgnoringOtherApps(YES);
+
+ // string uuid = randomUUID().toString();
+ // DlanguiCocoaView.customClassName = "DlanguiCocoaView_" ~ uuid;
+ // DlanguiCocoaView.registerSubclass();
+ //
+ // _view = DlanguiCocoaView.alloc();
+ // _view.initialize(this, width, height);
+ //
+ // parentView.addSubview(_view);
+
+
+ NSApp.run();
+ }
DerelictCocoa.unload();
}
+
+interface IWindowListener {
+ void onMouseWheel(int x, int y, int deltaX, int deltaY, MouseState state);
+ void onKeyDown(uint key);
+ void onKeyUp(uint key);
+ void onMouseMove(int x, int y, int deltaX, int deltaY,
+ MouseState mouseState);
+ void onMouseRelease(int x, int y, MouseButton mb, MouseState mouseState);
+ void onMouseClick(int x, int y, MouseButton mb, bool isDoubleClick, MouseState mouseState);
+ void recomputeDirtyAreas();
+ void onResized(int width, int height);
+ void onAnimate(double dt, double time);
+ Rect getDirtyRectangle();
+}
+
+class IWindowListenerLogger : IWindowListener {
+ override void onMouseWheel(int x, int y, int deltaX, int deltaY, MouseState state) {
+ Log.d("onMouseWheel");
+ }
+ override void onKeyDown(uint key) {
+ Log.d("onKeyDown");
+ }
+ override void onKeyUp(uint key) {
+ Log.d("onKeyUp");
+ }
+ override void onMouseMove(int x, int y, int deltaX, int deltaY,
+ MouseState mouseState) {
+ Log.d("onMouseMove");
+ }
+ override void onMouseRelease(int x, int y, MouseButton mb, MouseState mouseState) {
+ Log.d("onMouseRelease");
+ }
+ override void onMouseClick(int x, int y, MouseButton mb, bool isDoubleClick, MouseState mouseState) {
+ Log.d("onMouseClick");
+ }
+ override void recomputeDirtyAreas() {
+ //Log.d("recomputeDirtyAreas");
+ }
+ override void onResized(int width, int height) {
+ Log.d("onResized");
+ }
+ override void onAnimate(double dt, double time) {
+ //Log.d("onAnimate");
+ }
+ override Rect getDirtyRectangle() {
+ return Rect(0, 0, 100, 100);
+ }
+}
+
+struct MouseState {
+ bool leftButtonDown;
+ bool rightButtonDown;
+ bool middleButtonDown;
+ bool ctrlPressed;
+ bool shiftPressed;
+ bool altPressed;
+}
+
+enum MouseButton : int {
+ left,
+ right,
+ middle
+}
+
+final class CocoaWindow
+{
+private:
+ IWindowListener _listener;
+
+ // Stays null in the case of a plugin, but exists for a stand-alone program
+ // For testing purpose.
+ NSWindow _cocoaWindow = null;
+ NSApplication _cocoaApplication;
+
+ NSColorSpace _nsColorSpace;
+ CGColorSpaceRef _cgColorSpaceRef;
+ NSData _imageData;
+ NSString _logFormatStr;
+
+ ColorDrawBuf _drawBuf;
+
+ DPlugCustomView _view = null;
+
+ bool _terminated = false;
+
+ int _lastMouseX, _lastMouseY;
+ bool _firstMouseMove = true;
+
+ int _width;
+ int _height;
+
+ ubyte* _buffer = null;
+
+ uint _timeAtCreationInMs;
+ uint _lastMeasturedTimeInMs;
+ bool _dirtyAreasAreNotYetComputed;
+
+public:
+
+ this(void* parentWindow, IWindowListener listener, int width, int height)
+ {
+ _listener = listener;
+
+ DerelictCocoa.load();
+ NSApplicationLoad(); // to use Cocoa in Carbon applications
+ bool parentViewExists = parentWindow !is null;
+ NSView parentView;
+ if (!parentViewExists)
+ {
+ // create a NSWindow to hold our NSView
+ _cocoaApplication = NSApplication.sharedApplication;
+ _cocoaApplication.setActivationPolicy(NSApplicationActivationPolicyRegular);
+
+ NSWindow window = NSWindow.alloc();
+ window.initWithContentRect(NSMakeRect(100, 100, width, height),
+ NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask,
+ NSBackingStoreBuffered,
+ NO);
+ window.makeKeyAndOrderFront();
+
+ parentView = window.contentView();
+
+ _cocoaApplication.activateIgnoringOtherApps(YES);
+ }
+ else
+ parentView = NSView(cast(id)parentWindow);
+
+
+
+ _width = 0;
+ _height = 0;
+
+ _nsColorSpace = NSColorSpace.sRGBColorSpace();
+ // hopefully not null else the colors will be brighter
+ _cgColorSpaceRef = _nsColorSpace.CGColorSpace();
+
+ _logFormatStr = NSString.stringWith("%@");
+
+ _timeAtCreationInMs = getTimeMs();
+ _lastMeasturedTimeInMs = _timeAtCreationInMs;
+
+ _dirtyAreasAreNotYetComputed = true;
+
+ string uuid = randomUUID().toString();
+ DPlugCustomView.customClassName = "DPlugCustomView_" ~ uuid;
+ DPlugCustomView.registerSubclass();
+
+ _view = DPlugCustomView.alloc();
+ _view.initialize(this, width, height);
+
+ parentView.addSubview(_view);
+
+ if (_cocoaApplication)
+ _cocoaApplication.run();
+
+
+ }
+
+ ~this()
+ {
+ if (_view)
+ {
+ //debug ensureNotInGC("CocoaWindow");
+ _terminated = true;
+
+ {
+ _view.killTimer();
+ }
+
+ _view.removeFromSuperview();
+ _view.release();
+ _view = DPlugCustomView(null);
+
+ DPlugCustomView.unregisterSubclass();
+
+ if (_buffer != null)
+ {
+ free(_buffer);
+ _buffer = null;
+ }
+
+ DerelictCocoa.unload();
+ }
+ }
+
+ // Implements IWindow
+ void waitEventAndDispatch()
+ {
+ assert(false); // not implemented in Cocoa, since we don't have a NSWindow
+ }
+
+ bool terminated()
+ {
+ return _terminated;
+ }
+
+ void debugOutput(string s)
+ {
+ import core.stdc.stdio;
+ fprintf(stderr, toStringz(s));
+ }
+
+ uint getTimeMs()
+ {
+ return cast(uint)(NSDate.timeIntervalSinceReferenceDate() * 1000.0);
+ }
+
+private:
+
+ MouseState getMouseState(NSEvent event)
+ {
+ // not working
+ MouseState state;
+ uint pressedMouseButtons = event.pressedMouseButtons();
+ if (pressedMouseButtons & 1)
+ state.leftButtonDown = true;
+ if (pressedMouseButtons & 2)
+ state.rightButtonDown = true;
+ if (pressedMouseButtons & 4)
+ state.middleButtonDown = true;
+
+ NSEventModifierFlags mod = event.modifierFlags();
+ if (mod & NSControlKeyMask)
+ state.ctrlPressed = true;
+ if (mod & NSShiftKeyMask)
+ state.shiftPressed = true;
+ if (mod & NSAlternateKeyMask)
+ state.altPressed = true;
+
+ return state;
+ }
+
+ void handleMouseWheel(NSEvent event)
+ {
+ int deltaX = cast(int)(0.5 + 10 * event.deltaX);
+ int deltaY = cast(int)(0.5 + 10 * event.deltaY);
+ Point mousePos = getMouseXY(_view, event, _height);
+ _listener.onMouseWheel(mousePos.x, mousePos.y, deltaX, deltaY, getMouseState(event));
+ }
+
+ void handleKeyEvent(NSEvent event, bool released)
+ {
+ uint keyCode = event.keyCode();
+ uint key;
+ switch (keyCode)
+ {
+ case kVK_ANSI_Keypad0: key = KeyCode.KEY_0; break;
+ case kVK_ANSI_Keypad1: key = KeyCode.KEY_1; break;
+ case kVK_ANSI_Keypad2: key = KeyCode.KEY_2; break;
+ case kVK_ANSI_Keypad3: key = KeyCode.KEY_3; break;
+ case kVK_ANSI_Keypad4: key = KeyCode.KEY_4; break;
+ case kVK_ANSI_Keypad5: key = KeyCode.KEY_5; break;
+ case kVK_ANSI_Keypad6: key = KeyCode.KEY_6; break;
+ case kVK_ANSI_Keypad7: key = KeyCode.KEY_7; break;
+ case kVK_ANSI_Keypad8: key = KeyCode.KEY_8; break;
+ case kVK_ANSI_Keypad9: key = KeyCode.KEY_9; break;
+ case kVK_Return: key = KeyCode.RETURN; break;
+ case kVK_Escape: key = KeyCode.ESCAPE; break;
+ case kVK_LeftArrow: key = KeyCode.LEFT; break;
+ case kVK_RightArrow: key = KeyCode.RIGHT; break;
+ case kVK_DownArrow: key = KeyCode.DOWN; break;
+ case kVK_UpArrow: key = KeyCode.UP; break;
+ default: key = 0;
+ }
+
+ if (released)
+ _listener.onKeyDown(key);
+ else
+ _listener.onKeyUp(key);
+ }
+
+ void handleMouseMove(NSEvent event)
+ {
+ Point mousePos = getMouseXY(_view, event, _height);
+
+ if (_firstMouseMove)
+ {
+ _firstMouseMove = false;
+ _lastMouseX = mousePos.x;
+ _lastMouseY = mousePos.y;
+ }
+
+ _listener.onMouseMove(mousePos.x, mousePos.y, mousePos.x - _lastMouseX, mousePos.y - _lastMouseY,
+ getMouseState(event));
+
+ _lastMouseX = mousePos.x;
+ _lastMouseY = mousePos.y;
+ }
+
+ void handleMouseClicks(NSEvent event, MouseButton mb, bool released)
+ {
+ Point mousePos = getMouseXY(_view, event, _height);
+
+ if (released)
+ _listener.onMouseRelease(mousePos.x, mousePos.y, mb, getMouseState(event));
+ else
+ {
+ int clickCount = event.clickCount();
+ bool isDoubleClick = clickCount >= 2;
+ _listener.onMouseClick(mousePos.x, mousePos.y, mb, isDoubleClick, getMouseState(event));
+ }
+ }
+
+ enum scanLineAlignment = 4; // could be anything
+
+ // given a width, how long in bytes should scanlines be
+ int byteStride(int width)
+ {
+ int widthInBytes = width * 4;
+ return (widthInBytes + (scanLineAlignment - 1)) & ~(scanLineAlignment-1);
+ }
+
+ void drawRect(NSRect rect)
+ {
+ NSGraphicsContext nsContext = NSGraphicsContext.currentContext();
+
+ CIContext ciContext = nsContext.getCIContext();
+
+ // update internal buffers in case of startup/resize
+ {
+ NSRect boundsRect = _view.bounds();
+ int width = cast(int)(boundsRect.size.width); // truncating down the dimensions of bounds
+ int height = cast(int)(boundsRect.size.height);
+ updateSizeIfNeeded(width, height);
+ }
+
+ // The first drawRect callback occurs before the timer triggers.
+ // But because recomputeDirtyAreas() wasn't called before there is nothing to draw.
+ // Hence, do it.
+ if (_dirtyAreasAreNotYetComputed)
+ {
+ _dirtyAreasAreNotYetComputed = false;
+ _listener.recomputeDirtyAreas();
+ }
+
+ // draw buffers
+// ImageRef!RGBA wfb;
+// wfb.w = _width;
+// wfb.h = _height;
+// wfb.pitch = byteStride(_width);
+// wfb.pixels = cast(RGBA*)_buffer;
+// _listener.onDraw(wfb, WindowPixelFormat.ARGB8);
+ _drawBuf.fill(0x8090B0);
+ _drawBuf.fillRect(Rect(20, 20, 120, 120), 0xFFBBBB);
+
+ size_t sizeNeeded = byteStride(_width) * _height;
+ _imageData = NSData.dataWithBytesNoCopy(cast(ubyte*)_drawBuf.scanLine(0), sizeNeeded, false);
+
+ CIImage image = CIImage.imageWithBitmapData(_imageData,
+ byteStride(_width),
+ CGSize(_width, _height),
+ kCIFormatARGB8,
+ _cgColorSpaceRef);
+
+ ciContext.drawImage(image, rect, rect);
+ }
+
+ /// Returns: true if window size changed.
+ bool updateSizeIfNeeded(int newWidth, int newHeight)
+ {
+ // only do something if the client size has changed
+ if ( (newWidth != _width) || (newHeight != _height) )
+ {
+ // Extends buffer
+ if (_buffer != null)
+ {
+ free(_buffer);
+ _buffer = null;
+ }
+
+ size_t sizeNeeded = byteStride(newWidth) * newHeight;
+ _buffer = cast(ubyte*) malloc(sizeNeeded);
+ _width = newWidth;
+ _height = newHeight;
+ if (_drawBuf is null)
+ _drawBuf = new ColorDrawBuf(_width, _height);
+ else if (_drawBuf.width != _width || _drawBuf.height != _height)
+ _drawBuf.resize(_width, _height);
+ _listener.onResized(_width, _height);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ void doAnimation()
+ {
+ uint now = getTimeMs();
+ double dt = (now - _lastMeasturedTimeInMs) * 0.001;
+ double time = (now - _timeAtCreationInMs) * 0.001; // hopefully no plug-in will be open more than 49 days
+ _lastMeasturedTimeInMs = now;
+ _listener.onAnimate(dt, time);
+ }
+
+ void onTimer()
+ {
+ // Deal with animation
+ doAnimation();
+
+ _listener.recomputeDirtyAreas();
+ _dirtyAreasAreNotYetComputed = false;
+ Rect dirtyRect = _listener.getDirtyRectangle();
+ if (!dirtyRect.empty())
+ {
+
+ NSRect boundsRect = _view.bounds();
+ int height = cast(int)(boundsRect.size.height);
+ NSRect r = NSMakeRect(dirtyRect.left,
+ height - dirtyRect.top - dirtyRect.height,
+ dirtyRect.width,
+ dirtyRect.height);
+ _view.setNeedsDisplayInRect(r);
+ }
+ }
+}
+
+struct DPlugCustomView
+{
+ // This class uses a unique class name for each plugin instance
+ static string customClassName = null;
+
+ NSView parent;
+ alias parent this;
+
+ // create from an id
+ this (id id_)
+ {
+ this._id = id_;
+ }
+
+ /// Allocates, but do not init
+ static DPlugCustomView alloc()
+ {
+ alias fun_t = extern(C) id function (id obj, SEL sel);
+ return DPlugCustomView( (cast(fun_t)objc_msgSend)(getClassID(), sel!"alloc") );
+ }
+
+ static Class getClass()
+ {
+ return cast(Class)( getClassID() );
+ }
+
+ static id getClassID()
+ {
+ assert(customClassName !is null);
+ return objc_getClass(customClassName);
+ }
+
+private:
+
+ CocoaWindow _window;
+ NSTimer _timer = null;
+
+ void initialize(CocoaWindow window, int width, int height)
+ {
+ // Warning: taking this address is fishy since DPlugCustomView is a struct and thus could be copied
+ // we rely on the fact it won't :|
+ void* thisPointer = cast(void*)(&this);
+ object_setInstanceVariable(_id, "this", thisPointer);
+
+ this._window = window;
+
+ NSRect r = NSRect(NSPoint(0, 0), NSSize(width, height));
+ initWithFrame(r);
+
+ _timer = NSTimer.timerWithTimeInterval(1 / 60.0, this, sel!"onTimer:", null, true);
+ NSRunLoop.currentRunLoop().addTimer(_timer, NSRunLoopCommonModes);
+ }
+
+ static Class clazz;
+
+ static void registerSubclass()
+ {
+ clazz = objc_allocateClassPair(cast(Class) lazyClass!"NSView", toStringz(customClassName), 0);
+
+ class_addMethod(clazz, sel!"keyDown:", cast(IMP) &keyDown, "v@:@");
+ class_addMethod(clazz, sel!"keyUp:", cast(IMP) &keyUp, "v@:@");
+ class_addMethod(clazz, sel!"mouseDown:", cast(IMP) &mouseDown, "v@:@");
+ class_addMethod(clazz, sel!"mouseUp:", cast(IMP) &mouseUp, "v@:@");
+ class_addMethod(clazz, sel!"rightMouseDown:", cast(IMP) &rightMouseDown, "v@:@");
+ class_addMethod(clazz, sel!"rightMouseUp:", cast(IMP) &rightMouseUp, "v@:@");
+ class_addMethod(clazz, sel!"otherMouseDown:", cast(IMP) &otherMouseDown, "v@:@");
+ class_addMethod(clazz, sel!"otherMouseUp:", cast(IMP) &otherMouseUp, "v@:@");
+ class_addMethod(clazz, sel!"mouseMoved:", cast(IMP) &mouseMoved, "v@:@");
+ class_addMethod(clazz, sel!"mouseDragged:", cast(IMP) &mouseMoved, "v@:@");
+ class_addMethod(clazz, sel!"rightMouseDragged:", cast(IMP) &mouseMoved, "v@:@");
+ class_addMethod(clazz, sel!"otherMouseDragged:", cast(IMP) &mouseMoved, "v@:@");
+ class_addMethod(clazz, sel!"acceptsFirstResponder", cast(IMP) &acceptsFirstResponder, "b@:");
+ class_addMethod(clazz, sel!"isOpaque", cast(IMP) &isOpaque, "b@:");
+ class_addMethod(clazz, sel!"acceptsFirstMouse:", cast(IMP) &acceptsFirstMouse, "b@:@");
+ class_addMethod(clazz, sel!"viewDidMoveToWindow", cast(IMP) &viewDidMoveToWindow, "v@:");
+ class_addMethod(clazz, sel!"drawRect:", cast(IMP) &drawRect, "v@:" ~ encode!NSRect);
+ class_addMethod(clazz, sel!"onTimer:", cast(IMP) &onTimer, "v@:@");
+
+ // This ~ is to avoid a strange DMD ICE. Didn't succeed in isolating it.
+ class_addMethod(clazz, sel!("scroll" ~ "Wheel:") , cast(IMP) &scrollWheel, "v@:@");
+
+ // very important: add an instance variable for the this pointer so that the D object can be
+ // retrieved from an id
+ class_addIvar(clazz, "this", (void*).sizeof, (void*).sizeof == 4 ? 2 : 3, "^v");
+
+ objc_registerClassPair(clazz);
+ }
+
+ static void unregisterSubclass()
+ {
+ // For some reason the class need to continue to exist, so we leak it
+ // objc_disposeClassPair(clazz);
+ // TODO: remove this crap
+ }
+
+ void killTimer()
+ {
+ if (_timer)
+ {
+ _timer.invalidate();
+ _timer = NSTimer(null);
+ }
+ }
+}
+
+DPlugCustomView getInstance(id anId)
+{
+ // strange thing: object_getInstanceVariable definition is odd (void**)
+ // and only works for pointer-sized values says SO
+ void* thisPointer = null;
+ Ivar var = object_getInstanceVariable(anId, "this", &thisPointer);
+ assert(var !is null);
+ assert(thisPointer !is null);
+ return *cast(DPlugCustomView*)thisPointer;
+}
+
+Point getMouseXY(NSView view, NSEvent event, int windowHeight)
+{
+ NSPoint mouseLocation = event.locationInWindow();
+ mouseLocation = view.convertPoint(mouseLocation, NSView(null));
+ int px = cast(int)(mouseLocation.x) - 2;
+ int py = windowHeight - cast(int)(mouseLocation.y) - 3;
+ return Point(px, py);
+}
+
+// Overridden function gets called with an id, instead of the self pointer.
+// So we have to get back the D class object address.
+// Big thanks to Mike Ash (@macdev)
+extern(C)
+{
+ void keyDown(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.handleKeyEvent(NSEvent(event), false);
+ }
+
+ void keyUp(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.handleKeyEvent(NSEvent(event), true);
+ }
+
+ void mouseDown(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.handleMouseClicks(NSEvent(event), MouseButton.left, false);
+ }
+
+ void mouseUp(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.handleMouseClicks(NSEvent(event), MouseButton.left, true);
+ }
+
+ void rightMouseDown(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.handleMouseClicks(NSEvent(event), MouseButton.right, false);
+ }
+
+ void rightMouseUp(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.handleMouseClicks(NSEvent(event), MouseButton.right, true);
+ }
+
+ void otherMouseDown(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ auto nsEvent = NSEvent(event);
+ if (nsEvent.buttonNumber == 2)
+ view._window.handleMouseClicks(nsEvent, MouseButton.middle, false);
+ }
+
+ void otherMouseUp(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ auto nsEvent = NSEvent(event);
+ if (nsEvent.buttonNumber == 2)
+ view._window.handleMouseClicks(nsEvent, MouseButton.middle, true);
+ }
+
+ void mouseMoved(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.handleMouseMove(NSEvent(event));
+ }
+
+ void scrollWheel(id self, SEL selector, id event)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.handleMouseWheel(NSEvent(event));
+ }
+
+ bool acceptsFirstResponder(id self, SEL selector)
+ {
+ return YES;
+ }
+
+ bool acceptsFirstMouse(id self, SEL selector, id pEvent)
+ {
+ return YES;
+ }
+
+ bool isOpaque(id self, SEL selector)
+ {
+ return YES;
+ }
+
+ void viewDidMoveToWindow(id self, SEL selector)
+ {
+ DPlugCustomView view = getInstance(self);
+ NSWindow parentWindow = view.window();
+ if (parentWindow)
+ {
+ parentWindow.makeFirstResponder(view);
+ parentWindow.setAcceptsMouseMovedEvents(true);
+ }
+ }
+
+ void drawRect(id self, SEL selector, NSRect rect)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.drawRect(rect);
+ }
+
+ void onTimer(id self, SEL selector, id timer)
+ {
+ //FPControl fpctrl;
+ //fpctrl.initialize();
+ DPlugCustomView view = getInstance(self);
+ view._window.onTimer();
+ }
+}
\ No newline at end of file
diff --git a/examples/dmledit/dmledit-monod-linux.dproj b/examples/dmledit/dmledit-monod-linux.dproj
index 216af14d..26668157 100644
--- a/examples/dmledit/dmledit-monod-linux.dproj
+++ b/examples/dmledit/dmledit-monod-linux.dproj
@@ -162,6 +162,22 @@
-Jviews/res/hdpi
-Jviews/res/mdpi
-Jviews/res/i18n
+
+ false
+ dmledit-monod-linux
+ Executable
+ true
+ 0
+
+
+ bin\DebugX11
+ obj/DebugX11
+ false
+ -Jviews
+-Jviews/res
+-Jviews/res/hdpi
+-Jviews/res/mdpi
+-Jviews/res/i18n
false
dmledit-monod-linux
diff --git a/examples/dmledit/src/dmledit.d b/examples/dmledit/src/dmledit.d
index be60ad80..f87c3254 100644
--- a/examples/dmledit/src/dmledit.d
+++ b/examples/dmledit/src/dmledit.d
@@ -146,17 +146,32 @@ class EditFrame : AppFrame {
}
}
+ void saveSourceFile(string filename) {
+ if (filename.length == 0)
+ filename = _filename;
+ import std.file;
+ _filename = filename;
+ window.windowCaption = toUTF32(filename);
+ _editor.save(filename);
+ }
+
bool onCanClose() {
// todo
return true;
}
- FileDialog createFileDialog(UIString caption) {
- FileDialog dlg = new FileDialog(caption, window, null);
+ FileDialog createFileDialog(UIString caption, bool fileMustExist = true) {
+ uint flags = DialogFlag.Modal | DialogFlag.Resizable;
+ if (fileMustExist)
+ flags |= FileDialogFlag.FileMustExist;
+ FileDialog dlg = new FileDialog(caption, window, null, flags);
dlg.filetypeIcons[".d"] = "text-dml";
return dlg;
}
+ void saveAs() {
+ }
+
/// override to handle specific actions
override bool handleAction(const Action a) {
if (a) {
@@ -169,7 +184,40 @@ class EditFrame : AppFrame {
window.showMessageBox(UIString("About DlangUI ML Editor"d),
UIString("DLangIDE\n(C) Vadim Lopatin, 2015\nhttp://github.com/buggins/dlangui\nSimple editor for DML code"d));
return true;
- case IDEActions.FileOpen:
+ case IDEActions.FileNew:
+ UIString caption;
+ caption = "Create new DML file"d;
+ FileDialog dlg = createFileDialog(caption, false);
+ dlg.addFilter(FileFilterEntry(UIString("DML files"d), "*.dml"));
+ dlg.addFilter(FileFilterEntry(UIString("All files"d), "*.*"));
+ dlg.onDialogResult = delegate(Dialog dlg, const Action result) {
+ if (result.id == ACTION_OPEN.id) {
+ string filename = result.stringParam;
+ _editor.text=""d;
+ saveSourceFile(filename);
+ }
+ };
+ dlg.show();
+ return true;
+ case IDEActions.FileSave:
+ if (_filename.length) {
+ saveSourceFile(_filename);
+ return true;
+ }
+ UIString caption;
+ caption = "Save DML File as"d;
+ FileDialog dlg = createFileDialog(caption, false);
+ dlg.addFilter(FileFilterEntry(UIString("DML files"d), "*.dml"));
+ dlg.addFilter(FileFilterEntry(UIString("All files"d), "*.*"));
+ dlg.onDialogResult = delegate(Dialog dlg, const Action result) {
+ if (result.id == ACTION_OPEN.id) {
+ string filename = result.stringParam;
+ saveSourceFile(filename);
+ }
+ };
+ dlg.show();
+ return true;
+ case IDEActions.FileOpen:
UIString caption;
caption = "Open DML File"d;
FileDialog dlg = createFileDialog(caption);
@@ -196,7 +244,23 @@ class EditFrame : AppFrame {
return false;
}
- void updatePreview() {
+ /// override to handle specific actions state (e.g. change enabled state for supported actions)
+ override bool handleActionStateRequest(const Action a) {
+ switch (a.id) {
+ case IDEActions.HelpAbout:
+ case IDEActions.FileNew:
+ case IDEActions.FileSave:
+ case IDEActions.FileOpen:
+ case IDEActions.DebugStart:
+ case IDEActions.EditPreferences:
+ a.state = ACTION_STATE_ENABLED;
+ return true;
+ default:
+ return super.handleActionStateRequest(a);
+ }
+ }
+
+ void updatePreview() {
dstring dsource = _editor.text;
string source = toUTF8(dsource);
try {
diff --git a/examples/example1/example1-monod-linux.dproj b/examples/example1/example1-monod-linux.dproj
index e3a5e646..d2281597 100644
--- a/examples/example1/example1-monod-linux.dproj
+++ b/examples/example1/example1-monod-linux.dproj
@@ -161,6 +161,22 @@
-Jviews/res/hdpi
-Jviews/res/mdpi
-Jviews/res/i18n
+
+ false
+ example1-monod-linux
+ Executable
+ true
+ 0
+
+
+ bin\DebugX11
+ obj/DebugX11
+ false
+ -Jviews
+-Jviews/res
+-Jviews/res/hdpi
+-Jviews/res/mdpi
+-Jviews/res/i18n
false
example1-monod-linux
diff --git a/examples/example1/example1-monod-osx.dproj b/examples/example1/example1-monod-osx.dproj
index 8e3c2b71..f65fc79b 100644
--- a/examples/example1/example1-monod-osx.dproj
+++ b/examples/example1/example1-monod-osx.dproj
@@ -44,7 +44,7 @@
Executable
true
0
- -v
+ false
bin\Release
@@ -64,6 +64,7 @@
Executable
true
0
+ -v
true
@@ -84,6 +85,7 @@
Executable
true
0
+ -v
diff --git a/examples/helloworld/helloworld-monod-linux.dproj b/examples/helloworld/helloworld-monod-linux.dproj
index 76660d6e..c4144341 100644
--- a/examples/helloworld/helloworld-monod-linux.dproj
+++ b/examples/helloworld/helloworld-monod-linux.dproj
@@ -129,6 +129,27 @@
true
0
+
+ bin\DebugX11
+
+
+ USE_X11
+ USE_FREETYPE
+
+
+ obj/DebugX11
+ true
+ false
+ helloworld-monod-linux
+ Executable
+ true
+ 0
+
+
+ -L-lX11
+
+
+
diff --git a/examples/tetris/tetris-monod-linux.dproj b/examples/tetris/tetris-monod-linux.dproj
index 14c6be1a..caefd800 100644
--- a/examples/tetris/tetris-monod-linux.dproj
+++ b/examples/tetris/tetris-monod-linux.dproj
@@ -161,6 +161,22 @@
-Jviews/res/hdpi
-Jviews/res/mdpi
-Jviews/res/i18n
+
+ false
+ tetris-monod-linux
+ Executable
+ true
+ 0
+
+
+ bin\DebugX11
+ obj/DebugX11
+ false
+ -Jviews
+-Jviews/res
+-Jviews/res/hdpi
+-Jviews/res/mdpi
+-Jviews/res/i18n
false
tetris-monod-linux
diff --git a/src/dlangui/dialogs/settingsdialog.d b/src/dlangui/dialogs/settingsdialog.d
index b7b403f0..775cfb8c 100644
--- a/src/dlangui/dialogs/settingsdialog.d
+++ b/src/dlangui/dialogs/settingsdialog.d
@@ -197,6 +197,28 @@ class NumberEditItem : SettingsItem {
}
}
+class StringEditItem : SettingsItem {
+ string _defaultValue;
+ this(string id, UIString label, string defaultValue) {
+ super(id, label);
+ _defaultValue = defaultValue;
+ }
+ /// create setting widget
+ override Widget[] createWidgets(Setting settings) {
+ TextWidget lbl = new TextWidget(_id ~ "-label", _label);
+ EditLine ed = new EditLine(_id ~ "-edit", _label);
+ Setting setting = settings.settingByPath(_id, SettingType.STRING);
+ string value = setting.strDef(_defaultValue);
+ setting.str = value;
+ ed.text = toUTF32(value);
+ ed.onContentChangeListener = delegate(EditableContent content) {
+ string value = toUTF8(content.text);
+ setting.str = value;
+ };
+ return [lbl, ed];
+ }
+}
+
/// settings page - item of settings tree, can edit several settings
class SettingsPage {
protected SettingsPage _parent;
@@ -261,7 +283,14 @@ class SettingsPage {
return res;
}
- StringComboBoxItem addStringComboBox(string id, UIString label, StringListValue[] items) {
+ /// add EditLine to edit string
+ StringEditItem addStringEdit(string id, UIString label, string defaultValue = "") {
+ StringEditItem res = new StringEditItem(id, label, defaultValue);
+ addItem(res);
+ return res;
+ }
+
+ StringComboBoxItem addStringComboBox(string id, UIString label, StringListValue[] items) {
StringComboBoxItem res = new StringComboBoxItem(id, label, items);
addItem(res);
return res;
diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d
index 822010a3..c5149fdf 100644
--- a/src/dlangui/graphics/glsupport.d
+++ b/src/dlangui/graphics/glsupport.d
@@ -27,6 +27,22 @@ import std.conv;
import std.string;
import std.array;
+derelict.util.exception.ShouldThrow gl3MissingSymFunc( string symName ) {
+ import std.algorithm : equal;
+ foreach(s; ["glGetError", "glShaderSource", "glCompileShader",
+ "glGetShaderiv", "glGetShaderInfoLog", "glGetString",
+ "glCreateProgram", "glUseProgram", "glDeleteProgram",
+ "glDeleteShader", "glEnable", "glDisable", "glBlendFunc",
+ "glUniformMatrix4fv", "glGetAttribLocation", "glGetUniformLocation",
+ "glGenVertexArrays", "glBindVertexArray", "glBufferData",
+ "glBindBuffer", "glBufferSubData"]) {
+ if (symName.equal(s)) // Symbol is used
+ return derelict.util.exception.ShouldThrow.Yes;
+ }
+ // Don't throw for unused symbol
+ return derelict.util.exception.ShouldThrow.No;
+}
+
// utility function to fill 4-float array of vertex colors with converted CR 32bit color
private void LVGLFillColor(uint color, float * buf, int count) {
float r = ((color >> 16) & 255) / 255.0f;
@@ -85,8 +101,11 @@ class GLProgram {
}
private void compatibilityFixes(ref char[] code, GLuint type) {
- if (glslversionInt < 150)
+ if (glslversionInt < 150) {
code = replace(code, " texture(", " texture2D(");
+ code = replace(code, "in ", "");
+ code = replace(code, "out ", "");
+ }
}
private GLuint compileShader(string src, GLuint type) {
@@ -277,11 +296,17 @@ class SolidFillProgram : GLProgram {
matrixLocation = glGetUniformLocation(program, "matrix");
checkError("glGetUniformLocation matrix");
+ if (matrixLocation == 0)
+ Log.e("glGetUniformLocation failed for matrixLocation");
vertexLocation = glGetAttribLocation(program, "vertex");
checkError("glGetAttribLocation vertex");
- colAttrLocation = glGetAttribLocation(program, "colAttr");
+ if (vertexLocation == 0)
+ Log.e("glGetUniformLocation failed for vertexLocation");
+ colAttrLocation = glGetAttribLocation(program, "colAttr");
checkError("glGetAttribLocation colAttr");
- return res && matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0;
+ if (colAttrLocation == 0)
+ Log.e("glGetUniformLocation failed for colAttrLocation");
+ return res && matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0;
}
bool execute(float[] vertices, float[] colors) {
diff --git a/src/dlangui/platforms/common/platform.d b/src/dlangui/platforms/common/platform.d
index 399f342d..39ac1471 100644
--- a/src/dlangui/platforms/common/platform.d
+++ b/src/dlangui/platforms/common/platform.d
@@ -32,6 +32,10 @@ private import std.algorithm;
private import core.sync.mutex;
private import std.string;
+/// entry point - declare such function to use as main for dlangui app
+extern(C) int UIAppMain(string[] args);
+
+
// specify debug=DebugMouseEvents for logging mouse handling
// specify debug=DebugRedraw for logging drawing and layouts handling
// specify debug=DebugKeys for logging of key events
@@ -175,6 +179,10 @@ class Window {
if (_mainWidget !is null)
_mainWidget.window = this;
}
+
+ // Abstract methods : override in platform implementatino
+
+ /// show window
abstract void show();
/// returns window caption
abstract @property dstring windowCaption();
@@ -1370,6 +1378,9 @@ version (Windows) {
/// put "mixin APP_ENTRY_POINT;" to main module of your dlangui based app
mixin template APP_ENTRY_POINT() {
version (linux) {
+ version(USE_X11) {
+ pragma(lib, "X11");
+ }
version (USE_XCB) {
//pragma(lib, "png");
pragma(lib, "xcb");
@@ -1404,217 +1415,12 @@ mixin template APP_ENTRY_POINT() {
}
}
-version (Windows) {
-
- /// initialize font manager - default implementation
- /// On win32 - first it tries to init freetype, and falls back to win32 fonts.
- /// On linux/mac - tries to init freetype with some hardcoded font paths
- bool initFontManager() {
- import win32.windows;
- import std.utf;
- import dlangui.platforms.windows.win32fonts;
- try {
- /// testing freetype font manager
- version(USE_FREETYPE) {
- Log.v("Trying to init FreeType font manager");
-
- import dlangui.graphics.ftfonts;
- // trying to create font manager
- Log.v("Creating FreeTypeFontManager");
- FreeTypeFontManager ftfontMan = new FreeTypeFontManager();
-
- import win32.shlobj;
- string fontsPath = "c:\\Windows\\Fonts\\";
- static if (true) { // SHGetFolderPathW not found in shell32.lib
- WCHAR[MAX_PATH] szPath;
- static if (false) {
- const CSIDL_FLAG_NO_ALIAS = 0x1000;
- const CSIDL_FLAG_DONT_UNEXPAND = 0x2000;
- if(SUCCEEDED(SHGetFolderPathW(NULL,
- CSIDL_FONTS|CSIDL_FLAG_NO_ALIAS|CSIDL_FLAG_DONT_UNEXPAND,
- NULL,
- 0,
- szPath.ptr)))
- {
- fontsPath = toUTF8(fromWStringz(szPath));
- }
- } else {
- if (GetWindowsDirectory(szPath.ptr, MAX_PATH - 1)) {
- fontsPath = toUTF8(fromWStringz(szPath));
- Log.i("Windows directory: ", fontsPath);
- fontsPath ~= "\\Fonts\\";
- Log.i("Fonts directory: ", fontsPath);
- }
- }
- }
- Log.v("Registering fonts");
- ftfontMan.registerFont(fontsPath ~ "arial.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "arialbd.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Bold);
- ftfontMan.registerFont(fontsPath ~ "arialbi.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Bold);
- ftfontMan.registerFont(fontsPath ~ "ariali.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "cour.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "courbd.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Bold);
- ftfontMan.registerFont(fontsPath ~ "courbi.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Bold);
- ftfontMan.registerFont(fontsPath ~ "couri.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "times.ttf", FontFamily.Serif, "Times New Roman", false, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "timesbd.ttf", FontFamily.Serif, "Times New Roman", false, FontWeight.Bold);
- ftfontMan.registerFont(fontsPath ~ "timesbi.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Bold);
- ftfontMan.registerFont(fontsPath ~ "timesi.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "consola.ttf", FontFamily.MonoSpace, "Consolas", false, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "consolab.ttf", FontFamily.MonoSpace, "Consolas", false, FontWeight.Bold);
- ftfontMan.registerFont(fontsPath ~ "consolai.ttf", FontFamily.MonoSpace, "Consolas", true, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "consolaz.ttf", FontFamily.MonoSpace, "Consolas", true, FontWeight.Bold);
- ftfontMan.registerFont(fontsPath ~ "verdana.ttf", FontFamily.SansSerif, "Verdana", false, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "verdanab.ttf", FontFamily.SansSerif, "Verdana", false, FontWeight.Bold);
- ftfontMan.registerFont(fontsPath ~ "verdanai.ttf", FontFamily.SansSerif, "Verdana", true, FontWeight.Normal);
- ftfontMan.registerFont(fontsPath ~ "verdanaz.ttf", FontFamily.SansSerif, "Verdana", true, FontWeight.Bold);
- if (ftfontMan.registeredFontCount()) {
- FontManager.instance = ftfontMan;
- } else {
- Log.w("No fonts registered in FreeType font manager. Disabling FreeType.");
- destroy(ftfontMan);
- }
- }
- } catch (Exception e) {
- Log.e("Cannot create FreeTypeFontManager - falling back to win32");
- }
-
- // use Win32 font manager
- if (FontManager.instance is null) {
- FontManager.instance = new Win32FontManager();
- }
- return true;
- }
-
-} else {
- import dlangui.graphics.ftfonts;
- bool registerFonts(FreeTypeFontManager ft, string path) {
- import std.file;
- if (!exists(path) || !isDir(path))
- return false;
- ft.registerFont(path ~ "DejaVuSans.ttf", FontFamily.SansSerif, "DejaVuSans", false, FontWeight.Normal);
- ft.registerFont(path ~ "DejaVuSans-Bold.ttf", FontFamily.SansSerif, "DejaVuSans", false, FontWeight.Bold);
- ft.registerFont(path ~ "DejaVuSans-Oblique.ttf", FontFamily.SansSerif, "DejaVuSans", true, FontWeight.Normal);
- ft.registerFont(path ~ "DejaVuSans-BoldOblique.ttf", FontFamily.SansSerif, "DejaVuSans", true, FontWeight.Bold);
- ft.registerFont(path ~ "DejaVuSansMono.ttf", FontFamily.MonoSpace, "DejaVuSansMono", false, FontWeight.Normal);
- ft.registerFont(path ~ "DejaVuSansMono-Bold.ttf", FontFamily.MonoSpace, "DejaVuSansMono", false, FontWeight.Bold);
- ft.registerFont(path ~ "DejaVuSansMono-Oblique.ttf", FontFamily.MonoSpace, "DejaVuSansMono", true, FontWeight.Normal);
- ft.registerFont(path ~ "DejaVuSansMono-BoldOblique.ttf", FontFamily.MonoSpace, "DejaVuSansMono", true, FontWeight.Bold);
- return true;
- }
-
- /// initialize font manager - default implementation
- /// On win32 - first it tries to init freetype, and falls back to win32 fonts.
- /// On linux/mac - tries to init freetype with some hardcoded font paths
- bool initFontManager() {
- FreeTypeFontManager ft = new FreeTypeFontManager();
-
- if (!registerFontConfigFonts(ft)) {
- // TODO: use FontConfig
- Log.w("No fonts found using FontConfig. Trying hardcoded paths.");
- ft.registerFonts("/usr/share/fonts/truetype/dejavu/");
- ft.registerFonts("/usr/share/fonts/TTF/");
- ft.registerFonts("/usr/share/fonts/dejavu/");
- ft.registerFonts("/usr/share/fonts/truetype/ttf-dejavu/"); // let it compile on Debian Wheezy
- version(OSX) {
- ft.registerFont("/Library/Fonts/Arial.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Arial Bold.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Bold);
- ft.registerFont("/Library/Fonts/Arial Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Arial Bold Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Bold);
- ft.registerFont("/Library/Fonts/Arial Narrow.ttf", FontFamily.SansSerif, "Arial Narrow", false, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Arial Narrow Bold.ttf", FontFamily.SansSerif, "Arial Narrow", false, FontWeight.Bold);
- ft.registerFont("/Library/Fonts/Arial Narrow Italic.ttf", FontFamily.SansSerif, "Arial Narrow", true, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Arial Narrow Bold Italic.ttf", FontFamily.SansSerif, "Arial Narrow", true, FontWeight.Bold);
- ft.registerFont("/Library/Fonts/Courier New.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Courier New Bold.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Bold);
- ft.registerFont("/Library/Fonts/Courier New Italic.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Courier New Bold Italic.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Bold);
- ft.registerFont("/Library/Fonts/Georgia.ttf", FontFamily.SansSerif, "Georgia", false, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Georgia Bold.ttf", FontFamily.SansSerif, "Georgia", false, FontWeight.Bold);
- ft.registerFont("/Library/Fonts/Georgia Italic.ttf", FontFamily.SansSerif, "Georgia", true, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Georgia Bold Italic.ttf", FontFamily.SansSerif, "Georgia", true, FontWeight.Bold);
- ft.registerFont("/Library/Fonts/Georgia.ttf", FontFamily.SansSerif, "Georgia", false, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Georgia Bold.ttf", FontFamily.SansSerif, "Georgia", false, FontWeight.Bold);
- ft.registerFont("/Library/Fonts/Georgia Italic.ttf", FontFamily.SansSerif, "Georgia", true, FontWeight.Normal);
- ft.registerFont("/Library/Fonts/Georgia Bold Italic.ttf", FontFamily.SansSerif, "Georgia", true, FontWeight.Bold);
- }
- }
-
- if (!ft.registeredFontCount)
- return false;
-
- FontManager.instance = ft;
- return true;
- }
-}
-
-/// call this when all resources are supposed to be freed to report counts of non-freed resources by type
-void releaseResourcesOnAppExit() {
-
- //
- debug setAppShuttingDownFlag();
-
- debug {
- if (Widget.instanceCount() > 0) {
- Log.e("Non-zero Widget instance count when exiting: ", Widget.instanceCount);
- }
- }
-
- currentTheme = null;
- drawableCache = null;
- imageCache = null;
- FontManager.instance = null;
-
- debug {
- if (DrawBuf.instanceCount > 0) {
- Log.e("Non-zero DrawBuf instance count when exiting: ", DrawBuf.instanceCount);
- }
- if (Style.instanceCount > 0) {
- Log.e("Non-zero Style instance count when exiting: ", Style.instanceCount);
- }
- if (ImageDrawable.instanceCount > 0) {
- Log.e("Non-zero ImageDrawable instance count when exiting: ", ImageDrawable.instanceCount);
- }
- if (Drawable.instanceCount > 0) {
- Log.e("Non-zero Drawable instance count when exiting: ", Drawable.instanceCount);
- }
- version (USE_FREETYPE) {
- import dlangui.graphics.ftfonts;
- if (FreeTypeFontFile.instanceCount > 0) {
- Log.e("Non-zero FreeTypeFontFile instance count when exiting: ", FreeTypeFontFile.instanceCount);
- }
- if (FreeTypeFont.instanceCount > 0) {
- Log.e("Non-zero FreeTypeFont instance count when exiting: ", FreeTypeFont.instanceCount);
- }
- }
- }
-}
-
+/// initialize font manager on startup
+extern(C) bool initFontManager();
/// initialize logging (for win32 - to file ui.log, for other platforms - stderr; log level is TRACE for debug builds, and WARN for release builds)
-void initLogs() {
- version (Windows) {
- debug {
- Log.setFileLogger(new std.stdio.File("ui.log", "w"));
- } else {
- // no logging unless version ForceLogs is set
- version(ForceLogs) {
- Log.setFileLogger(new std.stdio.File("ui.log", "w"));
- Log.i("Logging to file ui.log");
- }
- }
- } else {
- Log.setStderrLogger();
- }
- debug {
- Log.setLogLevel(LogLevel.Trace);
- } else {
- version(ForceLogs) {
- Log.setLogLevel(LogLevel.Trace);
- Log.i("Log level: trace");
- } else {
- Log.setLogLevel(LogLevel.Warn);
- Log.i("Log level: warn");
- }
- }
- Log.i("Logger is initialized");
-}
+extern(C) void initLogs();
+/// call this when all resources are supposed to be freed to report counts of non-freed resources by type
+extern(C) void releaseResourcesOnAppExit();
+
+
+
diff --git a/src/dlangui/platforms/common/startup.d b/src/dlangui/platforms/common/startup.d
new file mode 100644
index 00000000..5b0a1bfe
--- /dev/null
+++ b/src/dlangui/platforms/common/startup.d
@@ -0,0 +1,223 @@
+module dlangui.platforms.common.startup;
+
+public import dlangui.core.events;
+public import dlangui.widgets.styles;
+public import dlangui.graphics.fonts;
+public import dlangui.graphics.resources;
+public import dlangui.widgets.widget;
+
+version(USE_FREETYPE) {
+ public import dlangui.graphics.ftfonts;
+}
+
+version (Windows) {
+
+ /// initialize font manager - default implementation
+ /// On win32 - first it tries to init freetype, and falls back to win32 fonts.
+ /// On linux/mac - tries to init freetype with some hardcoded font paths
+ extern(C) bool initFontManager() {
+ import win32.windows;
+ import std.utf;
+ import dlangui.platforms.windows.win32fonts;
+ try {
+ /// testing freetype font manager
+ version(USE_FREETYPE) {
+ Log.v("Trying to init FreeType font manager");
+
+ import dlangui.graphics.ftfonts;
+ // trying to create font manager
+ Log.v("Creating FreeTypeFontManager");
+ FreeTypeFontManager ftfontMan = new FreeTypeFontManager();
+
+ import win32.shlobj;
+ string fontsPath = "c:\\Windows\\Fonts\\";
+ static if (true) { // SHGetFolderPathW not found in shell32.lib
+ WCHAR[MAX_PATH] szPath;
+ static if (false) {
+ const CSIDL_FLAG_NO_ALIAS = 0x1000;
+ const CSIDL_FLAG_DONT_UNEXPAND = 0x2000;
+ if(SUCCEEDED(SHGetFolderPathW(NULL,
+ CSIDL_FONTS|CSIDL_FLAG_NO_ALIAS|CSIDL_FLAG_DONT_UNEXPAND,
+ NULL,
+ 0,
+ szPath.ptr)))
+ {
+ fontsPath = toUTF8(fromWStringz(szPath));
+ }
+ } else {
+ if (GetWindowsDirectory(szPath.ptr, MAX_PATH - 1)) {
+ fontsPath = toUTF8(fromWStringz(szPath));
+ Log.i("Windows directory: ", fontsPath);
+ fontsPath ~= "\\Fonts\\";
+ Log.i("Fonts directory: ", fontsPath);
+ }
+ }
+ }
+ Log.v("Registering fonts");
+ ftfontMan.registerFont(fontsPath ~ "arial.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "arialbd.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Bold);
+ ftfontMan.registerFont(fontsPath ~ "arialbi.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Bold);
+ ftfontMan.registerFont(fontsPath ~ "ariali.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "cour.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "courbd.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Bold);
+ ftfontMan.registerFont(fontsPath ~ "courbi.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Bold);
+ ftfontMan.registerFont(fontsPath ~ "couri.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "times.ttf", FontFamily.Serif, "Times New Roman", false, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "timesbd.ttf", FontFamily.Serif, "Times New Roman", false, FontWeight.Bold);
+ ftfontMan.registerFont(fontsPath ~ "timesbi.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Bold);
+ ftfontMan.registerFont(fontsPath ~ "timesi.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "consola.ttf", FontFamily.MonoSpace, "Consolas", false, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "consolab.ttf", FontFamily.MonoSpace, "Consolas", false, FontWeight.Bold);
+ ftfontMan.registerFont(fontsPath ~ "consolai.ttf", FontFamily.MonoSpace, "Consolas", true, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "consolaz.ttf", FontFamily.MonoSpace, "Consolas", true, FontWeight.Bold);
+ ftfontMan.registerFont(fontsPath ~ "verdana.ttf", FontFamily.SansSerif, "Verdana", false, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "verdanab.ttf", FontFamily.SansSerif, "Verdana", false, FontWeight.Bold);
+ ftfontMan.registerFont(fontsPath ~ "verdanai.ttf", FontFamily.SansSerif, "Verdana", true, FontWeight.Normal);
+ ftfontMan.registerFont(fontsPath ~ "verdanaz.ttf", FontFamily.SansSerif, "Verdana", true, FontWeight.Bold);
+ if (ftfontMan.registeredFontCount()) {
+ FontManager.instance = ftfontMan;
+ } else {
+ Log.w("No fonts registered in FreeType font manager. Disabling FreeType.");
+ destroy(ftfontMan);
+ }
+ }
+ } catch (Exception e) {
+ Log.e("Cannot create FreeTypeFontManager - falling back to win32");
+ }
+
+ // use Win32 font manager
+ if (FontManager.instance is null) {
+ FontManager.instance = new Win32FontManager();
+ }
+ return true;
+ }
+
+} else {
+ import dlangui.graphics.ftfonts;
+ bool registerFonts(FreeTypeFontManager ft, string path) {
+ import std.file;
+ if (!exists(path) || !isDir(path))
+ return false;
+ ft.registerFont(path ~ "DejaVuSans.ttf", FontFamily.SansSerif, "DejaVuSans", false, FontWeight.Normal);
+ ft.registerFont(path ~ "DejaVuSans-Bold.ttf", FontFamily.SansSerif, "DejaVuSans", false, FontWeight.Bold);
+ ft.registerFont(path ~ "DejaVuSans-Oblique.ttf", FontFamily.SansSerif, "DejaVuSans", true, FontWeight.Normal);
+ ft.registerFont(path ~ "DejaVuSans-BoldOblique.ttf", FontFamily.SansSerif, "DejaVuSans", true, FontWeight.Bold);
+ ft.registerFont(path ~ "DejaVuSansMono.ttf", FontFamily.MonoSpace, "DejaVuSansMono", false, FontWeight.Normal);
+ ft.registerFont(path ~ "DejaVuSansMono-Bold.ttf", FontFamily.MonoSpace, "DejaVuSansMono", false, FontWeight.Bold);
+ ft.registerFont(path ~ "DejaVuSansMono-Oblique.ttf", FontFamily.MonoSpace, "DejaVuSansMono", true, FontWeight.Normal);
+ ft.registerFont(path ~ "DejaVuSansMono-BoldOblique.ttf", FontFamily.MonoSpace, "DejaVuSansMono", true, FontWeight.Bold);
+ return true;
+ }
+
+ /// initialize font manager - default implementation
+ /// On win32 - first it tries to init freetype, and falls back to win32 fonts.
+ /// On linux/mac - tries to init freetype with some hardcoded font paths
+ extern(C) bool initFontManager() {
+ FreeTypeFontManager ft = new FreeTypeFontManager();
+
+ if (!registerFontConfigFonts(ft)) {
+ // TODO: use FontConfig
+ Log.w("No fonts found using FontConfig. Trying hardcoded paths.");
+ ft.registerFonts("/usr/share/fonts/truetype/dejavu/");
+ ft.registerFonts("/usr/share/fonts/TTF/");
+ ft.registerFonts("/usr/share/fonts/dejavu/");
+ ft.registerFonts("/usr/share/fonts/truetype/ttf-dejavu/"); // let it compile on Debian Wheezy
+ version(OSX) {
+ ft.registerFont("/Library/Fonts/Arial.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Normal);
+ ft.registerFont("/Library/Fonts/Arial Bold.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Bold);
+ ft.registerFont("/Library/Fonts/Arial Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Normal);
+ ft.registerFont("/Library/Fonts/Arial Bold Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Bold);
+ //ft.registerFont("/Library/Fonts/Arial Narrow.ttf", FontFamily.SansSerif, "Arial Narrow", false, FontWeight.Normal);
+ //ft.registerFont("/Library/Fonts/Arial Narrow Bold.ttf", FontFamily.SansSerif, "Arial Narrow", false, FontWeight.Bold);
+ //ft.registerFont("/Library/Fonts/Arial Narrow Italic.ttf", FontFamily.SansSerif, "Arial Narrow", true, FontWeight.Normal);
+ //ft.registerFont("/Library/Fonts/Arial Narrow Bold Italic.ttf", FontFamily.SansSerif, "Arial Narrow", true, FontWeight.Bold);
+ ft.registerFont("/Library/Fonts/Courier New.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Normal);
+ ft.registerFont("/Library/Fonts/Courier New Bold.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Bold);
+ ft.registerFont("/Library/Fonts/Courier New Italic.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Normal);
+ ft.registerFont("/Library/Fonts/Courier New Bold Italic.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Bold);
+ ft.registerFont("/Library/Fonts/Georgia.ttf", FontFamily.Serif, "Georgia", false, FontWeight.Normal);
+ ft.registerFont("/Library/Fonts/Georgia Bold.ttf", FontFamily.Serif, "Georgia", false, FontWeight.Bold);
+ ft.registerFont("/Library/Fonts/Georgia Italic.ttf", FontFamily.Serif, "Georgia", true, FontWeight.Normal);
+ ft.registerFont("/Library/Fonts/Georgia Bold Italic.ttf", FontFamily.Serif, "Georgia", true, FontWeight.Bold);
+ }
+ }
+
+ if (!ft.registeredFontCount)
+ return false;
+
+ FontManager.instance = ft;
+ return true;
+ }
+}
+
+
+/// initialize logging (for win32 - to file ui.log, for other platforms - stderr; log level is TRACE for debug builds, and WARN for release builds)
+extern (C) void initLogs() {
+ version (Windows) {
+ debug {
+ Log.setFileLogger(new std.stdio.File("ui.log", "w"));
+ } else {
+ // no logging unless version ForceLogs is set
+ version(ForceLogs) {
+ Log.setFileLogger(new std.stdio.File("ui.log", "w"));
+ Log.i("Logging to file ui.log");
+ }
+ }
+ } else {
+ Log.setStderrLogger();
+ }
+ debug {
+ Log.setLogLevel(LogLevel.Trace);
+ } else {
+ version(ForceLogs) {
+ Log.setLogLevel(LogLevel.Trace);
+ Log.i("Log level: trace");
+ } else {
+ Log.setLogLevel(LogLevel.Warn);
+ Log.i("Log level: warn");
+ }
+ }
+ Log.i("Logger is initialized");
+}
+
+/// call this when all resources are supposed to be freed to report counts of non-freed resources by type
+extern (C) void releaseResourcesOnAppExit() {
+
+ //
+ debug setAppShuttingDownFlag();
+
+ debug {
+ if (Widget.instanceCount() > 0) {
+ Log.e("Non-zero Widget instance count when exiting: ", Widget.instanceCount);
+ }
+ }
+
+ currentTheme = null;
+ drawableCache = null;
+ imageCache = null;
+ FontManager.instance = null;
+
+ debug {
+ if (DrawBuf.instanceCount > 0) {
+ Log.e("Non-zero DrawBuf instance count when exiting: ", DrawBuf.instanceCount);
+ }
+ if (Style.instanceCount > 0) {
+ Log.e("Non-zero Style instance count when exiting: ", Style.instanceCount);
+ }
+ if (ImageDrawable.instanceCount > 0) {
+ Log.e("Non-zero ImageDrawable instance count when exiting: ", ImageDrawable.instanceCount);
+ }
+ if (Drawable.instanceCount > 0) {
+ Log.e("Non-zero Drawable instance count when exiting: ", Drawable.instanceCount);
+ }
+ version (USE_FREETYPE) {
+ import dlangui.graphics.ftfonts;
+ if (FreeTypeFontFile.instanceCount > 0) {
+ Log.e("Non-zero FreeTypeFontFile instance count when exiting: ", FreeTypeFontFile.instanceCount);
+ }
+ if (FreeTypeFont.instanceCount > 0) {
+ Log.e("Non-zero FreeTypeFont instance count when exiting: ", FreeTypeFont.instanceCount);
+ }
+ }
+ }
+}
diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d
index 91710b41..f8be874f 100644
--- a/src/dlangui/platforms/sdl/sdlapp.d
+++ b/src/dlangui/platforms/sdl/sdlapp.d
@@ -175,7 +175,8 @@ class SDLWindow : Window {
version(USE_OPENGL) {
if (_enableOpengl) {
Log.i("Trying to create OpenGL 3.2 context");
- _context = SDL_GL_CreateContext(_win); // Create the actual context and make it current
+ createContext(3, 2);
+ //_context = SDL_GL_CreateContext(_win); // Create the actual context and make it current
if (!_context) {
Log.e("SDL_GL_CreateContext failed: ", fromStringz(SDL_GetError()));
Log.w("trying other versions of OpenGL");
@@ -190,11 +191,17 @@ class SDLWindow : Window {
}
}
if (_context && !_gl3Reloaded) {
- DerelictGL3.reload();
- _gl3Reloaded = true;
- if (!glSupport.valid && !glSupport.initShaders())
- _enableOpengl = false;
- fixSize();
+ try {
+ DerelictGL3.missingSymbolCallback = &gl3MissingSymFunc;
+ DerelictGL3.reload(GLVersion.GL21, GLVersion.GL40);
+ _gl3Reloaded = true;
+ if (!glSupport.valid && !glSupport.initShaders())
+ _enableOpengl = false;
+ fixSize();
+ } catch (derelict.util.exception.SymbolLoadException e) {
+ Log.e("Exception in DerelictGL3.reload ", e);
+ _enableOpengl = false;
+ }
}
}
}
@@ -1074,7 +1081,7 @@ class SDLPlatform : Platform {
case SDL_KEYDOWN:
SDLWindow w = getWindow(event.key.windowID);
if (w) {
- w.processKeyEvent(KeyAction.KeyDown, event.key.keysym.sym, event.key.keysym.mod);
+ w.processKeyEvent(KeyAction.KeyDown, event.key.keysym.sym, event.key.keysym.mod);
SDL_StartTextInput();
}
break;
@@ -1177,9 +1184,6 @@ class SDLPlatform : Platform {
protected SDLWindow[uint] _windowMap;
}
-// entry point
-extern(C) int UIAppMain(string[] args);
-
version (Windows) {
import win32.windows;
import dlangui.platforms.windows.win32fonts;
@@ -1266,9 +1270,6 @@ version (Windows) {
extern(C) int DLANGUImain(string[] args)
{
-
- initLogs();
-
return sdlmain(args);
}
}
@@ -1301,6 +1302,7 @@ int sdlmain(string[] args) {
version(USE_OPENGL) {
try {
+ DerelictGL3.missingSymbolCallback = &gl3MissingSymFunc;
DerelictGL3.load();
_enableOpengl = true;
} catch (Exception e) {
@@ -1309,7 +1311,7 @@ int sdlmain(string[] args) {
}
SDL_DisplayMode displayMode;
- if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS) != 0) {
+ if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS|SDL_INIT_NOPARACHUTE) != 0) {
Log.e("Cannot init SDL2");
return 2;
}
@@ -1336,7 +1338,8 @@ int sdlmain(string[] args) {
if (!sdl.connect()) {
return 1;
}
- Platform.setInstance(sdl);
+
+ Platform.setInstance(sdl);
int res = 0;
diff --git a/src/dlangui/platforms/x11/x11app.d b/src/dlangui/platforms/x11/x11app.d
new file mode 100644
index 00000000..2b99130a
--- /dev/null
+++ b/src/dlangui/platforms/x11/x11app.d
@@ -0,0 +1,252 @@
+module dlangui.platforms.x11.x11app;
+
+version (USE_X11):
+
+import dlangui.core.logger;
+import dlangui.core.events;
+import dlangui.core.files;
+import dlangui.graphics.drawbuf;
+import dlangui.graphics.fonts;
+import dlangui.graphics.ftfonts;
+import dlangui.graphics.resources;
+import dlangui.widgets.styles;
+import dlangui.widgets.widget;
+import dlangui.platforms.common.platform;
+
+import x11.Xlib;
+import x11.Xutil;
+import x11.Xtos;
+import x11.X;
+
+pragma(lib, "X11");
+
+private __gshared Display * x11display;
+private __gshared int x11screen;
+
+class X11Window : dlangui.platforms.common.platform.Window {
+ protected X11Platform _platform;
+ protected dstring _caption;
+ protected x11.Xlib.Window _win;
+ protected GC _gc;
+
+ this(X11Platform platform, dstring caption, dlangui.platforms.common.platform.Window parent, uint flags, uint width = 0, uint height = 0) {
+ _platform = platform;
+ _caption = caption;
+ debug Log.d("Creating SDL window");
+ _dx = width;
+ _dy = height;
+ //create(flags);
+
+ /* get the colors black and white (see section for details) */
+ ulong black, white;
+ black = BlackPixel(x11display, x11screen); /* get color black */
+ white = WhitePixel(x11display, x11screen); /* get color white */
+
+ /* once the display is initialized, create the window.
+ This window will be have be 200 pixels across and 300 down.
+ It will have the foreground white and background black
+ */
+ _win = XCreateSimpleWindow(x11display, DefaultRootWindow(x11display), 0, 0,
+ _dx, _dy, 5, white, black);
+
+ /* here is where some properties of the window can be set.
+ The third and fourth items indicate the name which appears
+ at the top of the window and the name of the minimized window
+ respectively.
+ */
+ XSetStandardProperties(x11display, _win, cast(char*)"My Window".ptr, cast(char*)"HI!".ptr, None, cast(char**)null, 0, cast(XSizeHints*)null);
+
+ /* this routine determines which types of input are allowed in
+ the input. see the appropriate section for details...
+ */
+ XSelectInput(x11display, _win, ExposureMask|ButtonPressMask|KeyPressMask);
+
+ /* create the Graphics Context */
+ _gc = XCreateGC(x11display, _win, 0, cast(XGCValues*)null);
+
+ /* here is another routine to set the foreground and background
+ colors _currently_ in use in the window.
+ */
+ XSetBackground(x11display, _gc, white);
+ XSetForeground(x11display, _gc, black);
+
+ /* clear the window and bring it on top of the other windows */
+ XClearWindow(x11display, _win);
+ }
+
+ ~this() {
+ if (_gc)
+ XFreeGC(x11display, _gc);
+ if (_win)
+ XDestroyWindow(x11display, _win);
+ }
+
+ /// show window
+ override void show() {
+ XMapRaised(x11display, _win);
+ }
+
+ override @property dstring windowCaption() {
+ return _caption;
+ }
+
+ override @property void windowCaption(dstring caption) {
+ _caption = caption;
+ //if (_win)
+ // SDL_SetWindowTitle(_win, toUTF8(_caption).toStringz);
+ }
+
+ /// sets window icon
+ override @property void windowIcon(DrawBufRef icon) {
+ }
+ /// request window redraw
+ override void invalidate() {
+ }
+
+ /// close window
+ override void close() {
+ }
+}
+
+class X11Platform : Platform {
+
+ this() {
+ }
+
+ /**
+ * create window
+ * Args:
+ * windowCaption = window caption text
+ * parent = parent Window, or null if no parent
+ * flags = WindowFlag bit set, combination of Resizable, Modal, Fullscreen
+ * width = window width
+ * height = window height
+ *
+ * Window w/o Resizable nor Fullscreen will be created with size based on measurement of its content widget
+ */
+ override dlangui.platforms.common.platform.Window createWindow(dstring windowCaption, dlangui.platforms.common.platform.Window parent, uint flags = WindowFlag.Resizable, uint width = 0, uint height = 0) {
+ int newwidth = width;
+ int newheight = height;
+ X11Window window = new X11Window(this, windowCaption, parent, flags, newwidth, newheight);
+ return window;
+ }
+
+ /**
+ * close window
+ *
+ * Closes window earlier created with createWindow()
+ */
+ override void closeWindow(dlangui.platforms.common.platform.Window w) {
+ }
+
+ /**
+ * Starts application message loop.
+ *
+ * When returned from this method, application is shutting down.
+ */
+ override int enterMessageLoop() {
+ XEvent event; /* the XEvent declaration !!! */
+ KeySym key; /* a dealie-bob to handle KeyPress Events */
+ char[255] text; /* a char buffer for KeyPress Events */
+
+ /* look for events forever... */
+ while(1) {
+ /* get the next event and stuff it into our event variable.
+ Note: only events we set the mask for are detected!
+ */
+ XNextEvent(x11display, &event);
+
+ if (event.type==Expose && event.xexpose.count==0) {
+ /* the window was exposed redraw it! */
+ //redraw();
+ }
+ if (event.type == KeyPress &&
+ XLookupString(&event.xkey, text.ptr, 255, &key, cast(XComposeStatus*)null) == 1) {
+ /* use the XLookupString routine to convert the invent
+ KeyPress data into regular text. Weird but necessary...
+ */
+ if (text[0]=='q') {
+ break;
+ //close_x();
+ }
+ Log.d("You pressed the key", text[0]);
+ }
+ if (event.type==ButtonPress) {
+ /* tell where the mouse Button was Pressed */
+ Log.d("You pressed a button at ",
+ event.xbutton.x, ", ", event.xbutton.y);
+ }
+ }
+ return 0;
+ }
+
+ /// retrieves text from clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
+ override dstring getClipboardText(bool mouseBuffer = false) {
+ return "";
+ }
+
+ /// sets text to clipboard (when mouseBuffer == true, use mouse selection clipboard - under linux)
+ override void setClipboardText(dstring text, bool mouseBuffer = false) {
+ // todo
+ }
+
+ /// calls request layout for all windows
+ override void requestLayout() {
+ // todo
+ }
+}
+
+extern(C) int DLANGUImain(string[] args)
+{
+ initLogs();
+
+ if (!initFontManager()) {
+ Log.e("******************************************************************");
+ Log.e("No font files found!!!");
+ Log.e("Currently, only hardcoded font paths implemented.");
+ Log.e("Probably you can modify sdlapp.d to add some fonts for your system.");
+ Log.e("TODO: use fontconfig");
+ Log.e("******************************************************************");
+ assert(false);
+ }
+
+
+ /* use the information from the environment variable DISPLAY
+ to create the X connection:
+ */
+ x11display = XOpenDisplay(null);
+ if (!x11display) {
+ Log.e("Cannot open X11 display");
+ return 1;
+ }
+
+ x11screen = DefaultScreen(x11display);
+
+
+ currentTheme = createDefaultTheme();
+
+ X11Platform x11platform = new X11Platform();
+
+ Platform.setInstance(x11platform);
+
+ int res = 0;
+
+ version (unittest) {
+ } else {
+ res = UIAppMain(args);
+ }
+
+ //Log.e("Widget instance count after UIAppMain: ", Widget.instanceCount());
+
+ Log.d("Destroying X11 platform");
+ Platform.setInstance(null);
+
+ releaseResourcesOnAppExit();
+
+
+ XCloseDisplay(x11display);
+
+ Log.d("Exiting main width result=", res);
+
+ return res;
+}
diff --git a/src/dlangui/widgets/srcedit.d b/src/dlangui/widgets/srcedit.d
index 80cac927..d012a4de 100644
--- a/src/dlangui/widgets/srcedit.d
+++ b/src/dlangui/widgets/srcedit.d
@@ -54,4 +54,19 @@ class SourceEdit : EditBox {
_filename = null;
return false;
}
+
+ bool save(string fn) {
+ if (content.save(fn)) {
+ _filename = fn;
+ requestLayout();
+ window.update();
+ return true;
+ }
+ // failed
+ requestLayout();
+ window.update();
+ _filename = null;
+ return false;
+ }
+
}
diff --git a/src/dlangui/widgets/styles.d b/src/dlangui/widgets/styles.d
index 74495bc4..96821a98 100644
--- a/src/dlangui/widgets/styles.d
+++ b/src/dlangui/widgets/styles.d
@@ -827,8 +827,8 @@ class Theme : Style {
_fontSize = 9 | SIZE_IN_POINTS_FLAG; // TODO: from settings or screen properties / DPI
_fontStyle = FONT_STYLE_NORMAL;
_fontWeight = 400;
- //_fontFace = "Arial"; // TODO: from settings
- _fontFace = "Verdana"; // TODO: from settings
+ _fontFace = "Arial"; // TODO: from settings
+ //_fontFace = "Verdana"; // TODO: from settings
_fontFamily = FontFamily.SansSerif;
_minHeight = 0;
_minWidth = 0;
diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d
index f1d77d33..9b11e522 100644
--- a/src/dlangui/widgets/widget.d
+++ b/src/dlangui/widgets/widget.d
@@ -1579,7 +1579,7 @@ class Widget {
alpha = cast(ushort)value;
return true;
}
- mixin(generatePropertySetters("minWidth", "maxWidth", "minHeight", "maxHeight", "layoutWidth", "layoutHeight", "textColor", "backgroundColor", "fontSize", "fontWeight"));
+ mixin(generatePropertySetters("minWidth", "maxWidth", "minHeight", "maxHeight", "layoutWidth", "layoutHeight", "layoutWeight", "textColor", "backgroundColor", "fontSize", "fontWeight"));
if (name.equal("margins")) { // use same value for all sides
margins = Rect(value, value, value, value);
return true;