diff --git a/README.md b/README.md index b5b38e28..570b438e 100644 --- a/README.md +++ b/README.md @@ -188,8 +188,9 @@ Third party components used * DerelictGL3 - for OpenGL support * DerelictFT + FreeType library support under linux and optionally under Windows. * DerelictFI + FreeImage library support for decoding of images +* DerelictSDL2 + SDL2 for cross platform support * WindowsAPI bindings from http://www.dsource.org/projects/bindings/wiki/WindowsApi (patched) -* XCB and X11 bindings (patched) TODO: provide links +* XCB and X11 bindings (patched) when SDL2 is not used; TODO: provide links Hello World diff --git a/dlanguilib.visualdproj b/dlanguilib.visualdproj index 466a77aa..5e780b00 100644 --- a/dlanguilib.visualdproj +++ b/dlanguilib.visualdproj @@ -66,7 +66,7 @@ 0 0 - Unicode USE_OPENGL USE_SDL + Unicode USE_SDL 0 0 1 @@ -217,14 +217,6 @@ - - - - - - - - @@ -234,6 +226,14 @@ + + + + + + + + diff --git a/examples/example1/example1.visualdproj b/examples/example1/example1.visualdproj index 03c3ef63..b04fc227 100644 --- a/examples/example1/example1.visualdproj +++ b/examples/example1/example1.visualdproj @@ -66,7 +66,7 @@ 0 0 - Unicode USE_OPENGL USE_SDL + Unicode USE_SDL 0 3 0 diff --git a/examples/example1/src/main.d b/examples/example1/src/main.d index bb8f316c..0cc34d45 100644 --- a/examples/example1/src/main.d +++ b/examples/example1/src/main.d @@ -158,7 +158,95 @@ extern (C) int UIAppMain(string[] args) { tabs.addTab(list, "Long List"d); } - tabs.addTab((new TextWidget()).id("tab3").textColor(0x00802000).text("Tab 3 contents"), "Tab 3"d); + { + LinearLayout layout3 = new LinearLayout("tab3"); + layout3.addChild(new TextWidget(null, "Buttons in HorizontalLayout"d)); + WidgetGroup buttons1 = new HorizontalLayout(); + buttons1.addChild(new Button("btn1", "Button 1"d)); + buttons1.addChild(new Button("btn2", "Button 2"d)); + buttons1.addChild(new Button("btn3", "Button 3"d)); + buttons1.addChild(new Button("btn4", "Button 4"d)); + layout3.addChild(buttons1); + layout3.addChild(new VSpacer()); + layout3.addChild(new TextWidget(null, "CheckBoxes in HorizontalLayout"d)); + WidgetGroup buttons2 = new HorizontalLayout(); + buttons2.addChild(new CheckBox("btn1", "CheckBox 1"d)); + buttons2.addChild(new CheckBox("btn2", "CheckBox 2"d)); + buttons2.addChild(new CheckBox("btn3", "CheckBox 3"d)); + buttons2.addChild(new CheckBox("btn4", "CheckBox 4"d)); + layout3.addChild(buttons2); + + layout3.addChild(new VSpacer()); + layout3.addChild(new TextWidget(null, "RadioButtons in HorizontalLayout"d)); + WidgetGroup buttons3 = new HorizontalLayout(); + buttons3.addChild(new RadioButton("btn1", "RadioButton 1"d)); + buttons3.addChild(new RadioButton("btn2", "RadioButton 2"d)); + buttons3.addChild(new RadioButton("btn3", "RadioButton 3"d)); + buttons3.addChild(new RadioButton("btn4", "RadioButton 4"d)); + layout3.addChild(buttons3); + + layout3.addChild(new VSpacer()); + layout3.addChild(new TextWidget(null, "ImageButtons HorizontalLayout"d)); + WidgetGroup buttons4 = new HorizontalLayout(); + buttons4.addChild(new ImageButton("btn1", "fileclose")); + buttons4.addChild(new ImageButton("btn2", "fileopen")); + buttons4.addChild(new ImageButton("btn3", "exit")); + layout3.addChild(buttons4); + + layout3.addChild(new VSpacer()); + layout3.addChild(new TextWidget(null, "In vertical layouts:"d)); + HorizontalLayout hlayout2 = new HorizontalLayout(); + hlayout2.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); + + buttons1 = new VerticalLayout(); + buttons1.addChild(new TextWidget(null, "Buttons"d)); + buttons1.addChild(new Button("btn1", "Button 1"d)); + buttons1.addChild(new Button("btn2", "Button 2"d)); + buttons1.addChild((new Button("btn3", "Button 3 - disabled"d)).enabled(false)); + buttons1.addChild(new Button("btn4", "Button 4"d)); + hlayout2.addChild(buttons1); + hlayout2.addChild(new HSpacer()); + + buttons2 = new VerticalLayout(); + buttons2.addChild(new TextWidget(null, "CheckBoxes"d)); + buttons2.addChild(new CheckBox("btn1", "CheckBox 1"d)); + buttons2.addChild(new CheckBox("btn2", "CheckBox 2"d)); + buttons2.addChild(new CheckBox("btn3", "CheckBox 3"d)); + buttons2.addChild(new CheckBox("btn4", "CheckBox 4"d)); + hlayout2.addChild(buttons2); + hlayout2.addChild(new HSpacer()); + + buttons3 = new VerticalLayout(); + buttons3.addChild(new TextWidget(null, "RadioButtons"d)); + buttons3.addChild(new RadioButton("btn1", "RadioButton 1"d)); + buttons3.addChild(new RadioButton("btn2", "RadioButton 2"d)); + buttons3.addChild(new RadioButton("btn3", "RadioButton 3"d)); + buttons3.addChild(new RadioButton("btn4", "RadioButton 4"d)); + hlayout2.addChild(buttons3); + hlayout2.addChild(new HSpacer()); + + buttons4 = new VerticalLayout(); + buttons4.addChild(new TextWidget(null, "ImageButtons"d)); + buttons4.addChild(new ImageButton("btn1", "fileclose")); + buttons4.addChild(new ImageButton("btn2", "fileopen")); + buttons4.addChild(new ImageButton("btn3", "exit")); + hlayout2.addChild(buttons4); + hlayout2.addChild(new HSpacer()); + + WidgetGroup buttons5 = new VerticalLayout(); + buttons5.addChild(new TextWidget(null, "ImageTextButtons"d)); + buttons5.addChild(new ImageTextButton("btn1", "fileclose", "Close"d)); + buttons5.addChild(new ImageTextButton("btn2", "fileopen", "Open"d)); + buttons5.addChild(new ImageTextButton("btn3", "exit", "Exit"d)); + hlayout2.addChild(buttons5); + + + layout3.addChild(hlayout2); + + layout3.addChild(new VSpacer()); + layout3.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); + tabs.addTab(layout3, "Buttons"d); + } tabs.addTab((new TextWidget()).id("tab4").textColor(0x00802000).text("Tab 4 contents some long string"), "Tab 4"d); tabs.addTab((new TextWidget()).id("tab5").textColor(0x00802000).text("Tab 5 contents"), "Tab 5"d); @@ -201,7 +289,7 @@ extern (C) int UIAppMain(string[] args) { //========================================================================== - tabs.selectTab("tab1"); + tabs.selectTab("tab3"); contentLayout.addChild(tabs); window.mainWidget = contentLayout; diff --git a/res/mdpi/btn_default_small_normal.9.png b/res/mdpi/btn_default_small_normal.9.png index 5dddd464..ca9bfd6f 100644 Binary files a/res/mdpi/btn_default_small_normal.9.png and b/res/mdpi/btn_default_small_normal.9.png differ diff --git a/res/mdpi/btn_default_small_normal_disable.9.png b/res/mdpi/btn_default_small_normal_disable.9.png index 6ab5c4a2..83d9af53 100644 Binary files a/res/mdpi/btn_default_small_normal_disable.9.png and b/res/mdpi/btn_default_small_normal_disable.9.png differ diff --git a/res/mdpi/btn_default_small_normal_disable_focused.9.png b/res/mdpi/btn_default_small_normal_disable_focused.9.png index c65bace3..f57bb3df 100644 Binary files a/res/mdpi/btn_default_small_normal_disable_focused.9.png and b/res/mdpi/btn_default_small_normal_disable_focused.9.png differ diff --git a/res/mdpi/btn_default_small_pressed.9.png b/res/mdpi/btn_default_small_pressed.9.png index 43e82f97..c9a14601 100644 Binary files a/res/mdpi/btn_default_small_pressed.9.png and b/res/mdpi/btn_default_small_pressed.9.png differ diff --git a/res/mdpi/btn_default_small_selected.9.png b/res/mdpi/btn_default_small_selected.9.png index 7a376a97..ee71e01d 100644 Binary files a/res/mdpi/btn_default_small_selected.9.png and b/res/mdpi/btn_default_small_selected.9.png differ diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d index 8181617e..64f258a0 100644 --- a/src/dlangui/platforms/sdl/sdlapp.d +++ b/src/dlangui/platforms/sdl/sdlapp.d @@ -2,7 +2,6 @@ module src.dlangui.platforms.sdl.sdlapp; version(USE_SDL) { import core.runtime; - import std.string; import std.conv; import std.string; import std.utf; @@ -13,7 +12,7 @@ version(USE_SDL) { import dlangui.core.logger; import dlangui.core.events; import dlangui.graphics.drawbuf; - import dlangui.graphics.fonts; + import dlangui.graphics.fonts; import dlangui.graphics.ftfonts; import dlangui.graphics.resources; import dlangui.widgets.styles; @@ -21,13 +20,13 @@ version(USE_SDL) { import dlangui.platforms.common.platform; import derelict.sdl2.sdl; + import derelict.opengl3.gl3; version (USE_OPENGL) { + import dlangui.graphics.gldrawbuf; import dlangui.graphics.glsupport; } - import derelict.opengl3.gl3; - import derelict.opengl3.glx; // pragma(lib, "xcb"); // pragma(lib, "xcb-shm"); @@ -49,22 +48,67 @@ version(USE_SDL) { debug Log.d("Destroying SDL window"); if (_renderer) SDL_DestroyRenderer(_renderer); + version(USE_OPENGL) { + if (_context) + SDL_GL_DeleteContext(_context); + } if (_win) SDL_DestroyWindow(_win); } - + + version(USE_OPENGL) { + static private bool _gl3Reloaded = false; + private SDL_GLContext _context; + } + bool create() { - _win = SDL_CreateWindow(_caption.toStringz, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 700, 500, SDL_WINDOW_RESIZABLE); + uint windowFlags = SDL_WINDOW_RESIZABLE; + version(USE_OPENGL) { + if (_enableOpengl) + windowFlags |= SDL_WINDOW_OPENGL; + } + _win = SDL_CreateWindow(_caption.toStringz, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + 700, 500, + windowFlags); + version(USE_OPENGL) { + if (!_win) { + if (_enableOpengl) { + Log.e("SDL_CreateWindow failed - cannot create OpenGL window: ", fromStringz(SDL_GetError())); + _enableOpengl = false; + // recreate w/o OpenGL + windowFlags &= ~SDL_WINDOW_OPENGL; + _win = SDL_CreateWindow(_caption.toStringz, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + 700, 500, + windowFlags); + } + } + } if (!_win) { Log.e("SDL2: Failed to create window"); return false; } - _renderer = SDL_CreateRenderer(_win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - if (!_renderer) { - Log.e("SDL2: Failed to create renderer"); - return false; - } - //windowCaption = _caption; + version(USE_OPENGL) { + if (_enableOpengl) { + _context = SDL_GL_CreateContext(_win); // Create the actual context and make it current + if (!_context) { + Log.e("SDL_GL_CreateContext failed: ", fromStringz(SDL_GetError())); + _enableOpengl = false; + } else if (!_gl3Reloaded) { + DerelictGL3.reload(); + _gl3Reloaded = true; + if (!initShaders()) + _enableOpengl = false; + } + } + } + if (!_enableOpengl) { + _renderer = SDL_CreateRenderer(_win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (!_renderer) { + Log.e("SDL2: Failed to create renderer"); + return false; + } + } + windowCaption = _caption; return true; } @@ -75,7 +119,6 @@ version(USE_SDL) { } - bool _derelictgl3Reloaded; override void show() { Log.d("SDLWindow.show()"); SDL_ShowWindow(_win); @@ -127,20 +170,35 @@ version(USE_SDL) { //Log.e("Widget instance count in SDLWindow.redraw: ", Widget.instanceCount()); // check if size has been changed int w, h; - SDL_GetWindowSize(_win, - &w, - &h); + SDL_GetWindowSize(_win, &w, &h); onResize(w, h); - if (_enableOpengl) { version(USE_OPENGL) { + SDL_GL_MakeCurrent(_win, _context); + glDisable(GL_DEPTH_TEST); + glViewport(0, 0, _dx, _dy); + float a = 1.0f; + float r = ((_backgroundColor >> 16) & 255) / 255.0f; + float g = ((_backgroundColor >> 8) & 255) / 255.0f; + float b = ((_backgroundColor >> 0) & 255) / 255.0f; + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); + GLDrawBuf buf = new GLDrawBuf(_dx, _dy, false); + buf.beforeDrawing(); + onDraw(buf); + buf.afterDrawing(); + SDL_GL_SwapWindow(_win); + destroy(buf); } } else { - // Select the color for drawing. It is set to red here. - //SDL_SetRenderDrawColor(_renderer, 255, 0, 0, 255); + // Select the color for drawing. + ubyte r = cast(ubyte)((_backgroundColor >> 16) & 255); + ubyte g = cast(ubyte)((_backgroundColor >> 8) & 255); + ubyte b = cast(ubyte)((_backgroundColor >> 0) & 255); + SDL_SetRenderDrawColor(_renderer, r, g, b, 255); // Clear the entire screen to our selected color. - //SDL_RenderClear(_renderer); + SDL_RenderClear(_renderer); if (!_drawbuf) _drawbuf = new ColorDrawBuf(_dx, _dy); @@ -446,12 +504,6 @@ version(USE_SDL) { } bool connect() { - try { - //DerelictGL3.load(); - _enableOpengl = false; - } catch (Exception e) { - Log.e("Cannot load opengl library", e); - } return true; } @@ -698,13 +750,6 @@ version(USE_SDL) { string[] args = splitCmdLine(cmdline); Log.i("Command line params: ", args); - try { - // Load the SDL 2 library. - DerelictSDL2.load(); - } catch (Exception e) { - Log.e("Cannot load SDL2 library", e); - return 1; - } //_cmdShow = iCmdShow; //_hInstance = hInstance; @@ -721,22 +766,6 @@ version(USE_SDL) { setStderrLogger(); setLogLevel(LogLevel.Trace); - try { - // Load the SDL 2 library. - DerelictSDL2.load(); - } catch (Exception e) { - Log.e("Cannot load SDL2 library", e); - return 1; - } - - SDL_DisplayMode displayMode; - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS) != 0) { - Log.e("Cannot init SDL2"); - return 2; - } - scope(exit)SDL_Quit(); - int request = SDL_GetDesktopDisplayMode(0,&displayMode); - FreeTypeFontManager ft = new FreeTypeFontManager(); // TODO: use FontConfig @@ -750,6 +779,40 @@ version(USE_SDL) { int sdlmain(string[] args) { currentTheme = createDefaultTheme(); + try { + // Load the SDL 2 library. + DerelictSDL2.load(); + } catch (Exception e) { + Log.e("Cannot load SDL2 library", e); + return 1; + } + + version(USE_OPENGL) { + try { + DerelictGL3.load(); + _enableOpengl = true; + } catch (Exception e) { + Log.e("Cannot load opengl library", e); + } + } + + SDL_DisplayMode displayMode; + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS) != 0) { + Log.e("Cannot init SDL2"); + return 2; + } + scope(exit)SDL_Quit(); + int request = SDL_GetDesktopDisplayMode(0,&displayMode); + + version(USE_OPENGL) { + // we want OpenGL 3.3 + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,2); + // Set OpenGL attributes + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + } + SDLPlatform sdl = new SDLPlatform(); if (!sdl.connect()) { return 1; diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index 88d1eadb..730dd198 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -35,15 +35,21 @@ import dlangui.widgets.layouts; /// vertical spacer to fill empty space in vertical layouts class VSpacer : Widget { this() { - styleId = "VSpacer"; + styleId = "VSPACER"; } + //override void measure(int parentWidth, int parentHeight) { + // measuredContent(parentWidth, parentHeight, 8, 8); + //} } /// horizontal spacer to fill empty space in horizontal layouts class HSpacer : Widget { this() { - styleId = "HSpacer"; + styleId = "HSPACER"; } + //override void measure(int parentWidth, int parentHeight) { + // measuredContent(parentWidth, parentHeight, 8, 8); + //} } /// static text widget @@ -291,6 +297,22 @@ class Button : Widget { focusable = true; trackHover = true; } + this(string ID, dstring label) { + super(ID); + _text = label; + styleId = "BUTTON"; + clickable = true; + focusable = true; + trackHover = true; + } + this(string ID, string labelResourceId) { + super(ID); + _text = labelResourceId; + styleId = "BUTTON"; + clickable = true; + focusable = true; + trackHover = true; + } override void measure(int parentWidth, int parentHeight) { FontRef font = font();