diff --git a/dub.json b/dub.json index a6b24fcb..ff67b48f 100644 --- a/dub.json +++ b/dub.json @@ -34,8 +34,8 @@ "dependencies": { "inilike": "~>1.2.2", "icontheme": "~>1.2.3", - "arsd-official:dom": "~>11.1.0", - "arsd-official:image_files": "~>11.1.0" + "arsd-official:dom": "11.2.3", + "arsd-official:image_files": "11.2.3" }, "subPackages": [ diff --git a/examples/dminer/src/minermain.d b/examples/dminer/src/minermain.d index d3315814..9a3c5e55 100644 --- a/examples/dminer/src/minermain.d +++ b/examples/dminer/src/minermain.d @@ -40,12 +40,14 @@ import dminer.core.chunk; mixin APP_ENTRY_POINT; /// entry point for dlangui based application -extern (C) int UIAppMain(string[] args) { +extern (C) int UIAppMain(string[] args) +{ // embed resources listed in views/resources.list into executable embeddedResourceList.addResources(embedResourcesFromList!("resources.list")()); //embeddedResourceList.dumpEmbeddedResources(); - debug { + debug + { testPlanes(); } @@ -62,17 +64,22 @@ extern (C) int UIAppMain(string[] args) { return Platform.instance.enterMessageLoop(); } -class ChunkVisitCounter : ChunkVisitor { +class ChunkVisitCounter : ChunkVisitor +{ int count; - bool visit(World world, SmallChunk * chunk) { + bool visit(World world, SmallChunk* chunk) + { count++; return true; } } -class MinerDrawable : MaterialDrawableObject, ChunkVisitor { +class MinerDrawable : MaterialDrawableObject, ChunkVisitor +{ import dlangui.graphics.scene.node; + import core.sys.linux.input_event_codes; + private World _world; private ChunkDiamondVisitor _chunkVisitor; private VisibilityCheckIterator _chunkIterator; @@ -83,17 +90,27 @@ class MinerDrawable : MaterialDrawableObject, ChunkVisitor { private vec3 _camForwardVector; private bool _wireframe; - @property bool wireframe() { return _wireframe; } - @property void wireframe(bool flgWireframe) { _wireframe = flgWireframe; } + @property bool wireframe() + { + return _wireframe; + } + + @property void wireframe(bool flgWireframe) + { + _wireframe = flgWireframe; + } - this(World world, Material material, Camera cam) { + this(World world, Material material, Camera cam) + { super(material); _world = world; _cam = cam; } + int _skippedCount; int _drawnCount; - override void draw(Node3d node, bool wireframe) { + override void draw(Node3d node, bool wireframe) + { /// override it _node = node; //Log.d("drawing Miner scene"); @@ -109,7 +126,8 @@ class MinerDrawable : MaterialDrawableObject, ChunkVisitor { camVector.x = cast(int)(_camForwardVector.x * 256); camVector.y = cast(int)(_camForwardVector.y * 256); camVector.z = cast(int)(_camForwardVector.z * 256); - version (TEST_VISITOR_PERFORMANCE) { + version (TEST_VISITOR_PERFORMANCE) + { ChunkVisitCounter countVisitor = new ChunkVisitCounter(); _chunkIterator.start(_world, _world.camPosition.pos, MAX_VIEW_DISTANCE); _chunkIterator.visitVisibleChunks(countVisitor, camVector); @@ -118,15 +136,20 @@ class MinerDrawable : MaterialDrawableObject, ChunkVisitor { _chunkIterator.visitVisibleChunks(this, camVector); long duration = currentTimeMillis() - ts; Log.d("drawing of Miner scene finished in ", duration, " ms skipped:", _skippedCount, " drawn:", _drawnCount, " duration(noDraw)=", durationNoDraw); - } else { + } + else + { _chunkIterator.start(_world, _world.camPosition.pos, MAX_VIEW_DISTANCE); _chunkIterator.visitVisibleChunks(this, camVector); long duration = currentTimeMillis() - ts; Log.d("drawing of Miner scene finished in ", duration, " ms skipped:", _skippedCount, " drawn:", _drawnCount); } } - bool visit(World world, SmallChunk * chunk) { - if (chunk) { + + bool visit(World world, SmallChunk* chunk) + { + if (chunk) + { Vector3d p = chunk.position; vec3 chunkPos = vec3(p.x + 4, p.y + 4, p.z + 4); float camDist = (_camPosition - chunkPos).length; @@ -137,12 +160,14 @@ class MinerDrawable : MaterialDrawableObject, ChunkVisitor { threshold = 0.2; //Log.d("visit() chunkPos ", chunkPos, " chunkDir ", chunkDirection, " camDir ", " dot ", dot, " threshold ", threshold); - if (dot < threshold) { // cos(45) + if (dot < threshold) + { // cos(45) _skippedCount++; return false; } Mesh mesh = chunk.getMesh(world); - if (mesh) { + if (mesh) + { _material.bind(_node, mesh, lights(_node)); _material.drawMesh(mesh, _wireframe); _material.unbind(); @@ -154,13 +179,16 @@ class MinerDrawable : MaterialDrawableObject, ChunkVisitor { } } -class UiWidget : VerticalLayout { //, CellVisitor - this() { +class UiWidget : VerticalLayout +{ //, CellVisitor + this() + { super("OpenGLView"); layoutWidth = FILL_PARENT; layoutHeight = FILL_PARENT; alignment = Align.Center; - try { + try + { parseML(q{ { margins: 0 @@ -182,7 +210,9 @@ class UiWidget : VerticalLayout { //, CellVisitor } } }, "", this); - } catch (Exception e) { + } + catch (Exception e) + { Log.e("Failed to parse dml", e); } // assign OpenGL drawable to child widget background @@ -195,14 +225,17 @@ class UiWidget : VerticalLayout { //, CellVisitor _scene.activeCamera = _cam; - static if (true) { + static if (true) + { _scene.skyBox.setFaceTexture(SkyBox.Face.Right, "skybox_night_right1"); _scene.skyBox.setFaceTexture(SkyBox.Face.Left, "skybox_night_left2"); _scene.skyBox.setFaceTexture(SkyBox.Face.Top, "skybox_night_top3"); _scene.skyBox.setFaceTexture(SkyBox.Face.Bottom, "skybox_night_bottom4"); _scene.skyBox.setFaceTexture(SkyBox.Face.Front, "skybox_night_front5"); _scene.skyBox.setFaceTexture(SkyBox.Face.Back, "skybox_night_back6"); - } else { + } + else + { _scene.skyBox.setFaceTexture(SkyBox.Face.Right, "debug_right"); _scene.skyBox.setFaceTexture(SkyBox.Face.Left, "debug_left"); _scene.skyBox.setFaceTexture(SkyBox.Face.Top, "debug_top"); @@ -221,20 +254,20 @@ class UiWidget : VerticalLayout { //, CellVisitor dirLightNode.light.enabled = true; _scene.addChild(dirLightNode); - int x0 = 0; int y0 = 0; int z0 = 0; - - _minerMesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR, VertexElementType.TEXCOORD0)); + _minerMesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType + .COLOR, VertexElementType.TEXCOORD0)); _world = new World(); initWorldTerrain(_world); int cy0 = 3; for (int y = CHUNK_DY - 1; y > 0; y--) - if (!_world.canPass(Vector3d(0, y, 0))) { + if (!_world.canPass(Vector3d(0, y, 0))) + { cy0 = y; break; } @@ -245,7 +278,6 @@ class UiWidget : VerticalLayout { //, CellVisitor _world.setCell(5, cy0 + 5, -7, BlockId.face_test); _world.setCell(3, cy0 + 5, 13, BlockId.face_test); - //_world.makeCastleWall(Vector3d(25, cy0 - 5, 12), Vector3d(1, 0, 0), 12, 30, 4, BlockId.brick); _world.makeCastle(Vector3d(0, cy0, 60), 30, 12); @@ -254,7 +286,7 @@ class UiWidget : VerticalLayout { //, CellVisitor Material minerMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "blocks"); //Material minerMaterial = new Material(EffectId("colored.vert", "colored.frag", null), "blocks"); - minerMaterial.ambientColor = vec3(0.25,0.25,0.25); + minerMaterial.ambientColor = vec3(0.25, 0.25, 0.25); minerMaterial.textureLinear = false; minerMaterial.fogParams = new FogParams(vec4(0.01, 0.01, 0.01, 1), 12, 80); //minerMaterial.specular = 10; @@ -265,7 +297,6 @@ class UiWidget : VerticalLayout { //, CellVisitor //_minerDrawable.wireframe = true; _scene.addChild(minerNode); - focusable = true; } @@ -274,11 +305,14 @@ class UiWidget : VerticalLayout { //, CellVisitor int lastMouseX; int lastMouseY; /// process key event, return true if event is processed. - override bool onMouseEvent(MouseEvent event) { - if (event.action == MouseAction.ButtonDown) { + override bool onMouseEvent(MouseEvent event) + { + if (event.action == MouseAction.ButtonDown && false) + { lastMouseX = event.x; lastMouseY = event.y; - if (event.button == MouseButton.Left && false) { + if (event.button == MouseButton.Left) + { int x = event.x; int y = event.y; int xindex = 0; @@ -298,43 +332,47 @@ class UiWidget : VerticalLayout { //, CellVisitor 3 4 5 6 7 8 */ - switch(index) { - default: - case 1: - case 4: - //_world.camPosition.forward(1); - //updateCamPosition(); - startMoveAnimation(_world.camPosition.direction.forward); - break; - case 0: - case 3: - _world.camPosition.turnLeft(); - updateCamPosition(); - break; - case 2: - case 5: - _world.camPosition.turnRight(); - updateCamPosition(); - break; - case 7: - //_world.camPosition.backward(1); - //updateCamPosition(); - startMoveAnimation(-_world.camPosition.direction.forward); - break; - case 6: - //_world.camPosition.moveLeft(); - //updateCamPosition(); - startMoveAnimation(_world.camPosition.direction.left); - break; - case 8: - //_world.camPosition.moveRight(); - //updateCamPosition(); - startMoveAnimation(_world.camPosition.direction.right); - break; + switch (index) + { + default: + case 1: + case 4: + //_world.camPosition.forward(1); + //updateCamPosition(); + startMoveAnimation(_world.camPosition.direction.forward); + break; + case 0: + case 3: + _world.camPosition.turnLeft(); + updateCamPosition(); + break; + case 2: + case 5: + _world.camPosition.turnRight(); + updateCamPosition(); + break; + case 7: + //_world.camPosition.backward(1); + //updateCamPosition(); + startMoveAnimation(-_world.camPosition.direction.forward); + break; + case 6: + //_world.camPosition.moveLeft(); + //updateCamPosition(); + startMoveAnimation(_world.camPosition.direction.left); + break; + case 8: + //_world.camPosition.moveRight(); + //updateCamPosition(); + startMoveAnimation(_world.camPosition.direction.right); + break; } } - } else if (event.action == MouseAction.Move) { - if (event.lbutton.isDown) { + } + else if (event.action == MouseAction.Move) + { + if (event.lbutton.isDown) + { int deltaX = event.x - lastMouseX; int deltaY = event.y - lastMouseY; int maxshift = width > 100 ? width : 100; @@ -355,69 +393,82 @@ class UiWidget : VerticalLayout { //, CellVisitor newAngleY = 65; setYAngle(newAngleY, true); } - } else if (event.action == MouseAction.ButtonUp || event.action == MouseAction.Cancel) { + } + else if (event.action == MouseAction.ButtonUp || event.action == MouseAction.Cancel) + { stopMoveAnimation(); } return true; } /// process key event, return true if event is processed. - override bool onKeyEvent(KeyEvent event) { - if (event.action == KeyAction.KeyDown) { - switch(event.keyCode) with(KeyCode) { - case F1: - _minerDrawable.wireframe = !_minerDrawable.wireframe; - return true; - case KEY_W: - case UP: - _world.camPosition.forward(1); - updateCamPosition(); - return true; - case DOWN: - case KEY_S: - _world.camPosition.backward(1); - updateCamPosition(); - return true; - case KEY_A: - case LEFT: - _world.camPosition.turnLeft(); - updateCamPosition(); - return true; - case KEY_D: - case RIGHT: - _world.camPosition.turnRight(); - updateCamPosition(); - return true; - case HOME: - case KEY_E: - _world.camPosition.moveUp(); - updateCamPosition(); - return true; - case END: - case KEY_Q: - _world.camPosition.moveDown(); - updateCamPosition(); - return true; - case KEY_Z: - _world.camPosition.moveLeft(); - updateCamPosition(); - return true; - case KEY_C: - _world.camPosition.moveRight(); - updateCamPosition(); - return true; - case KEY_F: - flying = !flying; - if (!flying) - _world.camPosition.pos.y = CHUNK_DY - 3; - updateCamPosition(); - return true; - case KEY_U: - enableMeshUpdate = !enableMeshUpdate; - updateCamPosition(); - return true; - default: - return false; + override bool onKeyEvent(KeyEvent event) + { + if (event.action == KeyAction.KeyDown) + { + switch (event.keyCode) with (KeyCode) + { + case F1: + _minerDrawable.wireframe = !_minerDrawable.wireframe; + return true; + case KEY_W: + case UP: + _world.camPosition.forward(1); + updateCamPosition(); + return true; + case DOWN: + case KEY_S: + _world.camPosition.backward(1); + updateCamPosition(); + return true; + case KEY_A: + case LEFT: + _world.camPosition.turnLeft(); + updateCamPosition(); + return true; + case KEY_D: + case RIGHT: + _world.camPosition.turnRight(); + updateCamPosition(); + return true; + case HOME: + case KEY_E: + _world.camPosition.moveUp(); + updateCamPosition(); + return true; + case END: + case KEY_Q: + _world.camPosition.moveDown(); + updateCamPosition(); + return true; + case KEY_Z: + _world.camPosition.moveLeft(); + updateCamPosition(); + return true; + case KEY_C: + _world.camPosition.moveRight(); + updateCamPosition(); + return true; + case KEY_F: + flying = !flying; + if (!flying) + _world.camPosition.pos.y = CHUNK_DY - 3; + updateCamPosition(); + return true; + case KEY_U: + enableMeshUpdate = !enableMeshUpdate; + updateCamPosition(); + return true; + + case KEY_PERIOD: + int cx = _world.camPosition.pos.x; + int cy = _world.camPosition.pos.y; + int cz = _world.camPosition.pos.z; + + _world.setCell(cx+1, cy, cz+1, BlockId.clay); + return true; + default: + return false; } } return false; @@ -434,28 +485,34 @@ class UiWidget : VerticalLayout { //, CellVisitor bool enableMeshUpdate = true; Vector3d _moveAnimationDirection; - void animateMoving() { - if (_moveAnimationDirection != Vector3d(0,0,0)) { + void animateMoving() + { + if (_moveAnimationDirection != Vector3d(0, 0, 0)) + { Vector3d animPos = _world.camPosition.pos + _moveAnimationDirection; vec3 p = vec3(animPos.x + 0.5f, animPos.y + 0.5f, animPos.z + 0.5f); - if ((_animatingPosition - p).length < 2) { + if ((_animatingPosition - p).length < 2) + { _world.camPosition.pos += _moveAnimationDirection; updateCamPosition(true); } } } - void updateCamPosition(bool animateIt = true) { + void updateCamPosition(bool animateIt = true) + { import std.string; import std.conv : to; import std.utf : toUTF32; import std.format; - if (!flying) { + if (!flying) + { animateMoving(); - while(_world.canPass(_world.camPosition.pos + Vector3d(0, -1, 0))) + while (_world.canPass(_world.camPosition.pos + Vector3d(0, -1, 0))) _world.camPosition.pos += Vector3d(0, -1, 0); - if(!_world.canPass(_world.camPosition.pos + Vector3d(0, -1, 0))) { + if (!_world.canPass(_world.camPosition.pos + Vector3d(0, -1, 0))) + { if (_world.canPass(_world.camPosition.pos + Vector3d(0, 1, 0))) _world.camPosition.pos += Vector3d(0, 1, 0); else if (_world.canPass(_world.camPosition.pos + Vector3d(1, 0, 0))) @@ -466,7 +523,7 @@ class UiWidget : VerticalLayout { //, CellVisitor _world.camPosition.pos += Vector3d(0, 0, 1); else if (_world.canPass(_world.camPosition.pos + Vector3d(0, 0, -1))) _world.camPosition.pos += Vector3d(0, 0, -1); - while(_world.canPass(_world.camPosition.pos + Vector3d(0, -1, 0))) + while (_world.canPass(_world.camPosition.pos + Vector3d(0, -1, 0))) _world.camPosition.pos += Vector3d(0, -1, 0); } } @@ -477,28 +534,33 @@ class UiWidget : VerticalLayout { //, CellVisitor updatePositionMessage(); } - void updatePositionMessage() { + void updatePositionMessage() + { import std.string : format; + Widget w = childById("lblPosition"); string dir = _world.camPosition.direction.dir.to!string; - dstring s = format("pos(%d,%d) h=%d fps:%d %s [F]lying: %s [U]pdateMesh: %s [F1] wireframe: %s", _world.camPosition.pos.x, _world.camPosition.pos.z, _world.camPosition.pos.y, - _fps, - dir, - flying, - enableMeshUpdate, - _minerDrawable ? _minerDrawable.wireframe : false - ).toUTF32; + dstring s = format("pos(%d,%d) h=%d fps:%d %s [F]lying: %s [U]pdateMesh: %s [F1] wireframe: %s", _world.camPosition.pos.x, _world + .camPosition.pos.z, _world.camPosition.pos.y, + _fps, + dir, + flying, + enableMeshUpdate, + _minerDrawable ? _minerDrawable.wireframe : false + ).toUTF32; w.text = s; } int _fps = 0; - void startMoveAnimation(Vector3d direction) { + void startMoveAnimation(Vector3d direction) + { _moveAnimationDirection = direction; updateCamPosition(); } - void stopMoveAnimation() { + void stopMoveAnimation() + { _moveAnimationDirection = Vector3d(0, 0, 0); updateCamPosition(); } @@ -524,91 +586,121 @@ class UiWidget : VerticalLayout { //, CellVisitor float _animatingAngle; float _animatingYAngle; - void setPos(vec3 newPos, bool animateIt = false) { - if (animateIt) { + void setPos(vec3 newPos, bool animateIt = false) + { + if (animateIt) + { _position = newPos; - } else { + } + else + { _animatingPosition = newPos; _position = newPos; } } - void setAngle(float newAngle, bool animateIt = false) { - if (animateIt) { + void setAngle(float newAngle, bool animateIt = false) + { + if (animateIt) + { _angle = newAngle; - } else { + } + else + { _animatingAngle = newAngle; _angle = newAngle; } } - void setYAngle(float newAngle, bool animateIt = false) { - if (animateIt) { + void setYAngle(float newAngle, bool animateIt = false) + { + if (animateIt) + { _yAngle = newAngle; - } else { + } + else + { _animatingYAngle = newAngle; _yAngle = newAngle; } } /// returns true is widget is being animated - need to call animate() and redraw - @property override bool animating() { return true; } + @property override bool animating() + { + return true; + } /// animates window; interval is time left from previous draw, in hnsecs (1/10000000 of second) - override void animate(long interval) { + override void animate(long interval) + { //Log.d("animating"); - if (interval > 0) { + if (interval > 0) + { int newfps = cast(int)(10000000.0 / interval); - if (newfps < _fps - 3 || newfps > _fps + 3) { + if (newfps < _fps - 3 || newfps > _fps + 3) + { _fps = newfps; updatePositionMessage(); } } animateMoving(); - if (_animatingAngle != _angle) { + if (_animatingAngle != _angle) + { float delta = _angle - _animatingAngle; if (delta > 180) delta -= 360; else if (delta < -180) delta += 360; float dist = delta < 0 ? -delta : delta; - if (dist < 5) { + if (dist < 5) + { _animatingAngle = _angle; - } else { + } + else + { float speed = 360 / 2; float step = speed * interval / 10000000.0f; //Log.d("Rotate animation delta=", delta, " dist=", dist, " elapsed=", interval, " step=", step); if (step > dist) step = dist; - delta = delta * (step /dist); + delta = delta * (step / dist); _animatingAngle += delta; } } - if (_animatingYAngle != _yAngle) { + if (_animatingYAngle != _yAngle) + { float delta = _yAngle - _animatingYAngle; if (delta > 180) delta -= 360; else if (delta < -180) delta += 360; float dist = delta < 0 ? -delta : delta; - if (dist < 5) { + if (dist < 5) + { _animatingYAngle = _yAngle; - } else { + } + else + { float speed = 360 / 2; float step = speed * interval / 10000000.0f; //Log.d("Rotate animation delta=", delta, " dist=", dist, " elapsed=", interval, " step=", step); if (step > dist) step = dist; - delta = delta * (step /dist); + delta = delta * (step / dist); _animatingYAngle += delta; } } - if (_animatingPosition != _position) { + if (_animatingPosition != _position) + { vec3 delta = _position - _animatingPosition; float dist = delta.length; - if (dist < 0.01) { + if (dist < 0.01) + { _animatingPosition = _position; // done - } else { + } + else + { float speed = 8; if (dist > 2) speed = (dist - 2) * 3 + speed; @@ -622,22 +714,22 @@ class UiWidget : VerticalLayout { //, CellVisitor } invalidate(); } + float angle = 0; Scene3d _scene; Camera _cam; Mesh _minerMesh; - /// this is OpenGLDrawableDelegate implementation - private void doDraw(Rect windowRect, Rect rc) { + private void doDraw(Rect windowRect, Rect rc) + { _cam.setPerspective(rc.width, rc.height, 45.0f, 0.3, MAX_VIEW_DISTANCE); _cam.setIdentity(); _cam.translate(_animatingPosition); _cam.rotateY(_animatingAngle); _cam.rotateX(_yAngle); - dirLightNode.setIdentity(); dirLightNode.translate(_animatingPosition); dirLightNode.rotateY(_animatingAngle); @@ -655,7 +747,8 @@ class UiWidget : VerticalLayout { //, CellVisitor checkgl!glDisable(GL_CULL_FACE); } - ~this() { + ~this() + { destroy(_scene); destroy(_world); } diff --git a/examples/dmledit/src/dmledit.d b/examples/dmledit/src/dmledit.d index 548d04c9..0e1645d7 100644 --- a/examples/dmledit/src/dmledit.d +++ b/examples/dmledit/src/dmledit.d @@ -8,13 +8,15 @@ import dlangui.widgets.metadata; import std.array : replaceFirst; import std.algorithm; import std.stdio; +import std.string; import std.array; import std.file; mixin APP_ENTRY_POINT; // action codes -enum IDEActions : int { +enum IDEActions : int +{ //ProjectOpen = 1010000, FileNew = 1010000, FileOpen, @@ -29,27 +31,47 @@ enum IDEActions : int { } // 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(); -const Action ACTION_DEBUG_START = new Action(IDEActions.DebugStart, "MENU_DEBUG_UPDATE_PREVIEW"c, "debug-run"c, KeyCode.F5, 0); +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(); +const Action ACTION_DEBUG_START = new Action(IDEActions.DebugStart, "MENU_DEBUG_UPDATE_PREVIEW"c, "debug-run"c, KeyCode + .F5, 0); const Action ACTION_HELP_ABOUT = new Action(IDEActions.HelpAbout, "MENU_HELP_ABOUT"c); /// DIDE source file editor -class DMLSourceEdit : SourceEdit { - this(string ID) { +class DMLSourceEdit : SourceEdit +{ + this(string ID) + { super(ID); MenuItem editPopupItem = new MenuItem(null); editPopupItem.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_DEBUG_START); @@ -57,21 +79,23 @@ class DMLSourceEdit : SourceEdit { content.syntaxSupport = new DMLSyntaxSupport(""); setTokenHightlightColor(TokenCategory.Comment, 0x008000); // green setTokenHightlightColor(TokenCategory.Keyword, 0x0000FF); // blue - setTokenHightlightColor(TokenCategory.String, 0xa31515); // brown - setTokenHightlightColor(TokenCategory.Integer, 0xa315C0); // - setTokenHightlightColor(TokenCategory.Float, 0xa315C0); // - setTokenHightlightColor(TokenCategory.Error, 0xFF0000); // red + setTokenHightlightColor(TokenCategory.String, 0xa31515); // brown + setTokenHightlightColor(TokenCategory.Integer, 0xa315C0); // + setTokenHightlightColor(TokenCategory.Float, 0xa315C0); // + setTokenHightlightColor(TokenCategory.Error, 0xFF0000); // red setTokenHightlightColor(TokenCategory.Op, 0x503000); - setTokenHightlightColor(TokenCategory.Identifier_Class, 0x000080); // blue + setTokenHightlightColor(TokenCategory.Identifier_Class, 0x000080); // blue } - this() { + + this() + { this("DMLEDIT"); } } immutable dstring SAMPLE_SOURCE_CODE = -q{VerticalLayout { + 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 } @@ -99,27 +123,30 @@ q{VerticalLayout { // used to generate property lists once, then simply swap StringListAdapter[string] propListsAdapters; -class EditFrame : AppFrame { +class EditFrame : AppFrame +{ MenuItem mainMenuItems; - override protected void initialize() { + override protected void initialize() + { _appName = "DMLEdit"; super.initialize(); updatePreview(); } /// create main menu - override protected MainMenu createMainMenu() { + override protected MainMenu createMainMenu() + { mainMenuItems = new MenuItem(); MenuItem fileItem = new MenuItem(new Action(1, "MENU_FILE")); fileItem.add(ACTION_FILE_NEW, ACTION_FILE_OPEN, - ACTION_FILE_EXIT); + ACTION_FILE_EXIT); mainMenuItems.add(fileItem); 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, ACTION_DEBUG_START); + 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, ACTION_DEBUG_START); editItem.add(ACTION_EDIT_PREFERENCES); mainMenuItems.add(editItem); @@ -127,9 +154,9 @@ class EditFrame : AppFrame { return mainMenu; } - /// create app toolbars - override protected ToolBarHost createToolbars() { + override protected ToolBarHost createToolbars() + { ToolBarHost res = new ToolBarHost(); ToolBar tb; tb = res.getOrAddToolbar("Standard"); @@ -137,15 +164,18 @@ class EditFrame : AppFrame { 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); + ACTION_EDIT_UNDO, ACTION_EDIT_REDO, ACTION_EDIT_INDENT, ACTION_EDIT_UNINDENT); return res; } string _filename; - void openSourceFile(string filename) { + void openSourceFile(string filename) + { import std.file; + // TODO - if (exists(filename)) { + if (exists(filename)) + { _filename = filename; window.windowCaption = toUTF32(filename); _editor.load(filename); @@ -153,21 +183,25 @@ class EditFrame : AppFrame { } } - void saveSourceFile(string filename) { + void saveSourceFile(string filename) + { if (filename.length == 0) filename = _filename; import std.file; + _filename = filename; window.windowCaption = toUTF32(filename); _editor.save(filename); } - bool onCanClose() { + bool onCanClose() + { // todo return true; } - FileDialog createFileDialog(UIString caption, bool fileMustExist = true) { + FileDialog createFileDialog(UIString caption, bool fileMustExist = true) + { uint flags = DialogFlag.Modal | DialogFlag.Resizable; if (fileMustExist) flags |= FileDialogFlag.FileMustExist; @@ -176,107 +210,120 @@ class EditFrame : AppFrame { return dlg; } - void saveAs() { + void saveAs() + { } /// override to handle specific actions - override bool handleAction(const Action a) { - if (a) { - switch (a.id) { - case IDEActions.FileExit: - if (onCanClose()) - window.close(); - return true; - case IDEActions.HelpAbout: - window.showMessageBox(UIString.fromRaw("About DlangUI ML Editor"d), - UIString.fromRaw("DLangIDE\n(C) Vadim Lopatin, 2015\nhttp://github.com/buggins/dlangui\nSimple editor for DML code"d)); - return true; - case IDEActions.FileNew: - UIString caption; - caption = "Create new DML file"d; - FileDialog dlg = createFileDialog(caption, false); - dlg.addFilter(FileFilterEntry(UIString.fromRaw("DML files"d), "*.dml")); - dlg.addFilter(FileFilterEntry(UIString.fromRaw("All files"d), "*.*")); - dlg.dialogResult = 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; + override bool handleAction(const Action a) + { + if (a) + { + switch (a.id) + { + case IDEActions.FileExit: + if (onCanClose()) + window.close(); + return true; + case IDEActions.HelpAbout: + window.showMessageBox(UIString.fromRaw("About DlangUI ML Editor"d), + UIString.fromRaw( + "DLangIDE\n(C) Vadim Lopatin, 2015\nhttp://github.com/buggins/dlangui\nSimple editor for DML code"d)); + return true; + case IDEActions.FileNew: + UIString caption; + caption = "Create new DML file"d; + FileDialog dlg = createFileDialog(caption, false); + dlg.addFilter(FileFilterEntry(UIString.fromRaw("DML files"d), "*.dml")); + dlg.addFilter(FileFilterEntry(UIString.fromRaw("All files"d), "*.*")); + dlg.dialogResult = delegate(Dialog dlg, const Action result) { + if (result.id == ACTION_OPEN.id) + { + string filename = result.stringParam; + _editor.text = ""d; + saveSourceFile(filename); } - UIString caption; - caption = "Save DML File as"d; - FileDialog dlg = createFileDialog(caption, false); - dlg.addFilter(FileFilterEntry(UIString.fromRaw("DML files"d), "*.dml")); - dlg.addFilter(FileFilterEntry(UIString.fromRaw("All files"d), "*.*")); - dlg.dialogResult = 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); - dlg.addFilter(FileFilterEntry(UIString.fromRaw("DML files"d), "*.dml")); - dlg.addFilter(FileFilterEntry(UIString.fromRaw("All files"d), "*.*")); - dlg.dialogResult = delegate(Dialog dlg, const Action result) { - if (result.id == ACTION_OPEN.id) { - string filename = result.stringParam; - openSourceFile(filename); - } - }; - dlg.show(); - return true; - case IDEActions.DebugStart: - updatePreview(); - return true; - case IDEActions.EditPreferences: - //showPreferences(); + }; + dlg.show(); + return true; + case IDEActions.FileSave: + if (_filename.length) + { + saveSourceFile(_filename); return true; - default: - return super.handleAction(a); + } + UIString caption; + caption = "Save DML File as"d; + FileDialog dlg = createFileDialog(caption, false); + dlg.addFilter(FileFilterEntry(UIString.fromRaw("DML files"d), "*.dml")); + dlg.addFilter(FileFilterEntry(UIString.fromRaw("All files"d), "*.*")); + dlg.dialogResult = 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); + dlg.addFilter(FileFilterEntry(UIString.fromRaw("DML files"d), "*.dml")); + dlg.addFilter(FileFilterEntry(UIString.fromRaw("All files"d), "*.*")); + dlg.dialogResult = delegate(Dialog dlg, const Action result) { + if (result.id == ACTION_OPEN.id) + { + string filename = result.stringParam; + openSourceFile(filename); + } + }; + dlg.show(); + return true; + case IDEActions.DebugStart: + updatePreview(); + return true; + case IDEActions.EditPreferences: + //showPreferences(); + return true; + default: + return super.handleAction(a); } } return false; } /// 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.FileOpen: - case IDEActions.DebugStart: - case IDEActions.EditPreferences: - case IDEActions.FileSaveAs: + override bool handleActionStateRequest(const Action a) + { + switch (a.id) + { + case IDEActions.HelpAbout: + case IDEActions.FileNew: + case IDEActions.FileOpen: + case IDEActions.DebugStart: + case IDEActions.EditPreferences: + case IDEActions.FileSaveAs: + a.state = ACTION_STATE_ENABLED; + return true; + case IDEActions.FileSave: + if (_editor.content.modified) a.state = ACTION_STATE_ENABLED; - return true; - case IDEActions.FileSave: - if (_editor.content.modified) - a.state = ACTION_STATE_ENABLED; - else - a.state = ACTION_STATE_DISABLE; - return true; - default: - return super.handleActionStateRequest(a); + else + a.state = ACTION_STATE_DISABLE; + return true; + default: + return super.handleActionStateRequest(a); } } - void updatePreview() { + void updatePreview() + { dstring dsource = _editor.text; string source = toUTF8(dsource); - try { + try + { Widget w = parseML(source); if (statusLine) statusLine.setStatusText("No errors"d); @@ -287,7 +334,9 @@ class EditFrame : AppFrame { if (_highlightBackground) w.backgroundColor = 0xC0C0C0C0; _preview.contentWidget = w; - } catch (ParserException e) { + } + catch (ParserException e) + { if (statusLine) statusLine.setStatusText(toUTF32("ERROR: " ~ e.msg)); _editor.setCaretPos(e.line, e.pos); @@ -307,9 +356,11 @@ class EditFrame : AppFrame { protected bool _highlightBackground; protected DMLSourceEdit _editor; protected ScrollWidget _preview; + /// create app body widget override protected Widget createBody() { + string currentWidget; DockHost dockHost = new DockHost(); @@ -324,17 +375,18 @@ class EditFrame : AppFrame { auto registeredWidgetList = getRegisteredWidgetsList(); registeredWidgetList.sort!("a < b"); - foreach(const ref widget; registeredWidgetList) - { + foreach (const ref widget; registeredWidgetList) + { auto propertyListAdapter = new StringListAdapter(); - if ( auto meta = findWidgetMetadata(widget) ) + if (auto meta = findWidgetMetadata(widget)) { auto mp = meta.properties; mp.sort!("a.name < b.name"); - foreach(const ref prop; mp) + foreach (const ref prop; mp) { - propertyListAdapter.add(UIString.fromRaw(prop.name ~ " [" ~ to!string(prop.type) ~ "]" )); - propListsAdapters[widget] = propertyListAdapter; + propertyListAdapter.add(UIString.fromRaw( + prop.name ~ " [" ~ to!string(prop.type) ~ "]")); + propListsAdapters[widget] = propertyListAdapter; } } sla.add(UIString.fromRaw(widget)); @@ -342,15 +394,67 @@ class EditFrame : AppFrame { widgetsList.adapter = sla; + StringListAdapter origSla = new StringListAdapter(); + + for (int i = 0; i < sla.getItems.count; i++) + { + origSla.add(sla.items[i]); + } + + StringListAdapter origProps = new StringListAdapter(); + auto leftPanel = new VerticalLayout(); leftPanel.layoutHeight = FILL_PARENT; - widgetsList.minHeight=800; - propList.minHeight=600; + widgetsList.minHeight = 800; + propList.minHeight = 600; + + auto searchBox = new EditLine().text("").backgroundColor(0xffffff).minHeight(25); + searchBox.keyEvent = delegate(Widget w, KeyEvent e) { + string[] arr; + + foreach (s; origSla.getItems) + arr ~= s; + + arr = arr.filter!(x => x.toLower.canFind(searchBox.text.toLower)).array; + + sla.clear(); + + foreach (string k; arr) + sla.add(UIString.fromRaw(k)); - leftPanel.addChild(new TextWidget().text("Widgets").backgroundColor(0xdddddd).minHeight(50) ); + widgetsList.adapter = sla; + return false; + }; + + auto searchBoxProps = new EditLine().text("").backgroundColor(0xffffff).minHeight(25); + searchBoxProps.keyEvent = delegate(Widget w, KeyEvent e) { + if (currentWidget in propListsAdapters) + { + string[] arr; + + foreach (s; origProps.getItems) + arr ~= s; + + arr = arr.filter!(x => x.toLower.canFind(searchBoxProps.text.toLower)).array; + + StringListAdapter sla = new StringListAdapter(); + + foreach (string k; arr) + sla.add(UIString.fromRaw(k)); + + propList.adapter = sla; + } + return false; + }; + + leftPanel.addChild(searchBox); + leftPanel.addChild(new TextWidget().text("Widgets").backgroundColor(0xdddddd).minHeight(25)); leftPanel.addChild(widgetsList); - leftPanel.addChild(new TextWidget().text("Widget properties").backgroundColor(0xdddddd).minHeight(50)); + + leftPanel.addChild(searchBoxProps); + leftPanel.addChild(new TextWidget().text("Widget properties") + .backgroundColor(0xdddddd).minHeight(50)); leftPanel.addChild(propList); auto leftDockWin = new DockWindow("left dock"); @@ -364,6 +468,21 @@ class EditFrame : AppFrame { _editor = new DMLSourceEdit(); _editor.text = SAMPLE_SOURCE_CODE; + _editor.keyEvent = delegate(Widget w, KeyEvent e) { + if (e.action == KeyAction.KeyUp) + { + if ((e.keyCode == KeyCode.DEL) + || (e.flags == KeyFlag.LControl && e.keyCode == KeyCode.KEY_S) + || (e.flags == KeyFlag.LControl && e.keyCode == KeyCode.KEY_V) + || (e.flags == KeyFlag.LControl && e.keyCode == KeyCode.KEY_Z)) + { + updatePreview(); + } + } + + return false; + }; + auto editorDockWin = new DockWindow("editor"); editorDockWin.layoutWidth = makePercentSize(50); editorDockWin.bodyWidget = _editor; @@ -393,11 +512,13 @@ class EditFrame : AppFrame { updatePreview(); return true; }; - widgetsList.itemClick = delegate (Widget source, int itemIndex){ - propList.adapter = propListsAdapters[to!string(widgetsList.selectedItem)]; + widgetsList.itemClick = delegate(Widget source, int itemIndex) { + currentWidget = to!string(widgetsList.selectedItem); + origProps = propListsAdapters[currentWidget]; + propList.adapter = origProps; return true; }; - widgetsList.onItemDoubleClick = delegate (Widget source, int itemIndex) { + widgetsList.onItemDoubleClick = delegate(Widget source, int itemIndex) { auto caret = _editor.caretPos; auto widgetClassName = widgetsList.selectedItem; EditOperation op = new EditOperation(EditAction.Replace, caret, widgetClassName); @@ -428,15 +549,17 @@ class EditFrame : AppFrame { } } -alias onItemDoubleClickHandler = void delegate (Widget source, int itemIndex); +alias onItemDoubleClickHandler = void delegate(Widget source, int itemIndex); class WidgetsList : StringListWidget { onItemDoubleClickHandler onItemDoubleClick; - override bool onMouseEvent(MouseEvent event) { + override bool onMouseEvent(MouseEvent event) + { bool result = super.onMouseEvent(event); - if (event.doubleClick) { + if (event.doubleClick) + { if (onItemDoubleClick !is null) onItemDoubleClick(this, selectedItemIndex); } @@ -445,7 +568,8 @@ class WidgetsList : StringListWidget } /// entry point for dlangui based application -extern (C) int UIAppMain(string[] args) { +extern (C) int UIAppMain(string[] args) +{ // embed non-standard resources listed in views/resources.list into executable embeddedResourceList.addResources(embedResourcesFromList!("resources.list")()); diff --git a/src/dlangui/core/i18n.d b/src/dlangui/core/i18n.d index 40ca44c0..db363988 100644 --- a/src/dlangui/core/i18n.d +++ b/src/dlangui/core/i18n.d @@ -441,7 +441,7 @@ class UIStringTranslator { return s; if (fallbackValue.length > 0) return fallbackValue; - return "UNTRANSLATED: "d ~ toUTF32(id); + return toUTF32(id); } } diff --git a/src/dlangui/widgets/lists.d b/src/dlangui/widgets/lists.d index e508cd51..59a9aca2 100644 --- a/src/dlangui/widgets/lists.d +++ b/src/dlangui/widgets/lists.d @@ -24,15 +24,15 @@ import dlangui.widgets.scrollbar; import dlangui.widgets.layouts; import dlangui.core.signals; - /** interface - slot for onAdapterChangeListener */ -interface OnAdapterChangeHandler { +interface OnAdapterChangeHandler +{ void onAdapterChange(ListAdapter source); } - /// list widget adapter provides items for list widgets -interface ListAdapter { +interface ListAdapter +{ /// returns number of widgets in list @property int itemCount() const; /// return list item widget by item index @@ -66,141 +66,173 @@ interface ListAdapter { } /// List adapter for simple list of widget instances -class ListAdapterBase : ListAdapter { +class ListAdapterBase : ListAdapter +{ /** Handle items change */ protected Signal!OnAdapterChangeHandler adapterChanged; /// connect adapter change handler - override ListAdapter connect(OnAdapterChangeHandler handler) { + override ListAdapter connect(OnAdapterChangeHandler handler) + { adapterChanged.connect(handler); return this; } /// disconnect adapter change handler - override ListAdapter disconnect(OnAdapterChangeHandler handler) { + override ListAdapter disconnect(OnAdapterChangeHandler handler) + { adapterChanged.disconnect(handler); return this; } /// returns integer item id by index (if supported) - override int itemId(int index) const { + override int itemId(int index) const + { return 0; } /// returns string item id by index (if supported) - override string itemStringId(int index) const { + override string itemStringId(int index) const + { return null; } /// returns number of widgets in list - override @property int itemCount() const { + override @property int itemCount() const + { // override it return 0; } /// return list item widget by item index - override Widget itemWidget(int index) { + override Widget itemWidget(int index) + { // override it return null; } /// return list item's state flags - override uint itemState(int index) const { + override uint itemState(int index) const + { // override it return State.Enabled; } /// set one or more list item's state flags, returns updated state - override uint setItemState(int index, uint flags) { + override uint setItemState(int index, uint flags) + { return 0; } /// reset one or more list item's state flags, returns updated state - override uint resetItemState(int index, uint flags) { + override uint resetItemState(int index, uint flags) + { return 0; } /// remove all items - override void clear() { + override void clear() + { } /// notify listeners about list items changes - void updateViews() { + void updateViews() + { if (adapterChanged.assigned) adapterChanged.emit(this); } /// called when theme is changed - void onThemeChanged() { + void onThemeChanged() + { } /// return true to receive mouse events - override @property bool wantMouseEvents() { + override @property bool wantMouseEvents() + { return false; } /// return true to receive keyboard events - override @property bool wantKeyEvents() { + override @property bool wantKeyEvents() + { return false; } } /// List adapter for simple list of widget instances -class WidgetListAdapter : ListAdapterBase { +class WidgetListAdapter : ListAdapterBase +{ private WidgetList _widgets; /// list of widgets to display - @property ref const(WidgetList) widgets() { return _widgets; } + @property ref const(WidgetList) widgets() + { + return _widgets; + } /// returns number of widgets in list - @property override int itemCount() const { + @property override int itemCount() const + { return _widgets.count; } /// return list item widget by item index - override Widget itemWidget(int index) { + override Widget itemWidget(int index) + { return _widgets.get(index); } /// return list item's state flags - override uint itemState(int index) const { + override uint itemState(int index) const + { return _widgets.get(index).state; } /// set one or more list item's state flags, returns updated state - override uint setItemState(int index, uint flags) { + override uint setItemState(int index, uint flags) + { return _widgets.get(index).setState(flags).state; } /// reset one or more list item's state flags, returns updated state - override uint resetItemState(int index, uint flags) { + override uint resetItemState(int index, uint flags) + { return _widgets.get(index).resetState(flags).state; } /// add item - WidgetListAdapter add(Widget item, int index = -1) { + WidgetListAdapter add(Widget item, int index = -1) + { _widgets.insert(item, index); updateViews(); return this; } /// remove item - WidgetListAdapter remove(int index) { + WidgetListAdapter remove(int index) + { auto item = _widgets.remove(index); destroy(item); updateViews(); return this; } /// remove all items - override void clear() { + override void clear() + { _widgets.clear(); updateViews(); } /// called when theme is changed - override void onThemeChanged() { + override void onThemeChanged() + { super.onThemeChanged(); - foreach(w; _widgets) + foreach (w; _widgets) w.onThemeChanged(); } - ~this() { + + ~this() + { //Log.d("Destroying WidgetListAdapter"); } /// return true to receive mouse events - override @property bool wantMouseEvents() { + override @property bool wantMouseEvents() + { return true; } } /** List adapter providing strings only. */ -class StringListAdapterBase : ListAdapterBase { +class StringListAdapterBase : ListAdapterBase +{ protected UIStringCollection _items; protected uint[] _states; protected int[] _intIds; @@ -209,12 +241,14 @@ class StringListAdapterBase : ListAdapterBase { protected int _lastItemIndex; /** create empty string list adapter. */ - this() { + this() + { _lastItemIndex = -1; } /** Init with array of string resource IDs. */ - this(string[] items) { + this(string[] items) + { _items.addAll(items); _intIds.length = items.length; _stringIds.length = items.length; @@ -224,7 +258,8 @@ class StringListAdapterBase : ListAdapterBase { } /** Init with array of unicode strings. */ - this(dstring[] items) { + this(dstring[] items) + { _items.addAll(items); _intIds.length = items.length; _stringIds.length = items.length; @@ -234,11 +269,13 @@ class StringListAdapterBase : ListAdapterBase { } /** Init with array of StringListValue. */ - this(StringListValue[] items) { + this(StringListValue[] items) + { _intIds.length = items.length; _stringIds.length = items.length; _iconIds.length = items.length; - for (int i = 0; i < items.length; i++) { + for (int i = 0; i < items.length; i++) + { _items.add(items[i].label); _intIds[i] = items[i].intId; _stringIds[i] = items[i].stringId; @@ -249,17 +286,20 @@ class StringListAdapterBase : ListAdapterBase { } /// remove all items - override void clear() { + override void clear() + { _items.clear(); updateStatesLength(); updateViews(); } /// remove item by index - StringListAdapterBase remove(int index) { + StringListAdapterBase remove(int index) + { if (index < 0 || index >= _items.length) return this; - for (int i = 0; i < _items.length - 1; i++) { + for (int i = 0; i < _items.length - 1; i++) + { _intIds[i] = _intIds[i + 1]; _stringIds[i] = _stringIds[i + 1]; _iconIds[i] = _iconIds[i + 1]; @@ -275,7 +315,8 @@ class StringListAdapterBase : ListAdapterBase { } /// add new item - StringListAdapterBase add(UIString item, int index = -1) { + StringListAdapterBase add(UIString item, int index = -1) + { if (index < 0 || index > _items.length) index = _items.length; _items.add(item, index); @@ -283,7 +324,8 @@ class StringListAdapterBase : ListAdapterBase { _states.length = _items.length; _stringIds.length = items.length; _iconIds.length = items.length; - for (int i = _items.length - 1; i > index; i--) { + for (int i = _items.length - 1; i > index; i--) + { _intIds[i] = _intIds[i - 1]; _stringIds[i] = _stringIds[i - 1]; _iconIds[i] = _iconIds[i - 1]; @@ -297,25 +339,32 @@ class StringListAdapterBase : ListAdapterBase { return this; } /// add new string resource item - StringListAdapterBase add(string item, int index = -1) { + StringListAdapterBase add(string item, int index = -1) + { return add(UIString.fromId(item), index); } /// add new raw dstring item - StringListAdapterBase add(dstring item, int index = -1) { + StringListAdapterBase add(dstring item, int index = -1) + { return add(UIString.fromRaw(item), index); } /** Access to items collection. */ - @property ref const(UIStringCollection) items() { return _items; } + @property ref const(UIStringCollection) items() + { + return _items; + } /** Replace items collection. */ - @property StringListAdapterBase items(dstring[] values) { + @property StringListAdapterBase items(dstring[] values) + { _items = values; _intIds.length = items.length; _states.length = _items.length; _stringIds.length = items.length; _iconIds.length = items.length; - for (int i = 0; i < _items.length; i++) { + for (int i = 0; i < _items.length; i++) + { _intIds[i] = 0; _stringIds[i] = null; _iconIds[i] = null; @@ -326,13 +375,15 @@ class StringListAdapterBase : ListAdapterBase { } /** Replace items collection. */ - @property StringListAdapterBase items(UIString[] values) { + @property StringListAdapterBase items(UIString[] values) + { _items = values; _intIds.length = items.length; _states.length = _items.length; _stringIds.length = items.length; _iconIds.length = items.length; - for (int i = 0; i < _items.length; i++) { + for (int i = 0; i < _items.length; i++) + { _intIds[i] = 0; _stringIds[i] = null; _iconIds[i] = null; @@ -343,13 +394,15 @@ class StringListAdapterBase : ListAdapterBase { } /** Replace items collection. */ - @property StringListAdapterBase items(StringListValue[] values) { + @property StringListAdapterBase items(StringListValue[] values) + { _items = values; _intIds.length = items.length; _states.length = _items.length; _stringIds.length = items.length; _iconIds.length = items.length; - for (int i = 0; i < _items.length; i++) { + for (int i = 0; i < _items.length; i++) + { _intIds[i] = values[i].intId; _stringIds[i] = values[i].stringId; _iconIds[i] = values[i].iconId; @@ -360,23 +413,28 @@ class StringListAdapterBase : ListAdapterBase { } /// returns number of widgets in list - @property override int itemCount() const { + @property override int itemCount() const + { return _items.length; } /// returns integer item id by index (if supported) - override int itemId(int index) const { + override int itemId(int index) const + { return index >= 0 && index < _intIds.length ? _intIds[index] : 0; } /// returns string item id by index (if supported) - override string itemStringId(int index) const { + override string itemStringId(int index) const + { return index >= 0 && index < _stringIds.length ? _stringIds[index] : null; } - protected void updateStatesLength() { - if (_states.length < _items.length) { - int oldlen = cast(int)_states.length; + protected void updateStatesLength() + { + if (_states.length < _items.length) + { + int oldlen = cast(int) _states.length; _states.length = _items.length; for (int i = oldlen; i < _items.length; i++) _states[i] = State.Enabled; @@ -390,60 +448,85 @@ class StringListAdapterBase : ListAdapterBase { } /// return list item's state flags - override uint itemState(int index) const { + override uint itemState(int index) const + { if (index < 0 || index >= _items.length) return 0; return _states[index]; } /// set one or more list item's state flags, returns updated state - override uint setItemState(int index, uint flags) { + override uint setItemState(int index, uint flags) + { updateStatesLength(); _states[index] |= flags; return _states[index]; } /// reset one or more list item's state flags, returns updated state - override uint resetItemState(int index, uint flags) { + override uint resetItemState(int index, uint flags) + { updateStatesLength(); _states[index] &= ~flags; return _states[index]; } - ~this() { + ~this() + { } } /** List adapter providing strings only. */ -class StringListAdapter : StringListAdapterBase { +class StringListAdapter : StringListAdapterBase +{ protected TextWidget _widget; /** create empty string list adapter. */ - this() { + this() + { super(); } /** Init with array of string resource IDs. */ - this(string[] items) { + this(string[] items) + { super(items); } /** Init with array of unicode strings. */ - this(dstring[] items) { + this(dstring[] items) + { super(items); } /** Init with array of StringListValue. */ - this(StringListValue[] items) { + this(StringListValue[] items) + { super(items); } + string[] getItems() + { + import std.conv; + + string[] result; + + for (int i = 0; i < items.length; i++) + result ~= items[i].to!string; + + return result; + } + /// return list item widget by item index - override Widget itemWidget(int index) { + override Widget itemWidget(int index) + { updateStatesLength(); - if (_widget is null) { + if (_widget is null) + { _widget = new TextWidget("STRING_LIST_ITEM"); _widget.styleId = STYLE_LIST_ITEM; - } else { + } + else + { if (index == _lastItemIndex) return _widget; } @@ -455,73 +538,85 @@ class StringListAdapter : StringListAdapterBase { } /// called when theme is changed - override void onThemeChanged() { + override void onThemeChanged() + { super.onThemeChanged(); if (_widget) _widget.onThemeChanged(); } /// set one or more list item's state flags, returns updated state - override uint setItemState(int index, uint flags) { + override uint setItemState(int index, uint flags) + { uint res = super.setItemState(index, flags); if (_widget !is null && _lastItemIndex == index) _widget.state = res; return res; } - - /// reset one or more list item's state flags, returns updated state - override uint resetItemState(int index, uint flags) { + override uint resetItemState(int index, uint flags) + { uint res = super.resetItemState(index, flags); if (_widget !is null && _lastItemIndex == index) _widget.state = res; return res; } - ~this() { + ~this() + { if (_widget) destroy(_widget); } } /** List adapter providing strings with icons. */ -class IconStringListAdapter : StringListAdapterBase { +class IconStringListAdapter : StringListAdapterBase +{ protected HorizontalLayout _widget; protected TextWidget _textWidget; protected ImageWidget _iconWidget; /** create empty string list adapter. */ - this() { + this() + { super(); } /** Init with array of StringListValue. */ - this(StringListValue[] items) { + this(StringListValue[] items) + { super(items); } /// return list item widget by item index - override Widget itemWidget(int index) { + override Widget itemWidget(int index) + { updateStatesLength(); - if (_widget is null) { + if (_widget is null) + { _widget = new HorizontalLayout("ICON_STRING_LIST_ITEM"); _widget.styleId = STYLE_LIST_ITEM; _textWidget = new TextWidget("label"); _iconWidget = new ImageWidget("icon"); _widget.addChild(_iconWidget); _widget.addChild(_textWidget); - } else { + } + else + { if (index == _lastItemIndex) return _widget; } // update widget _textWidget.text = _items.get(index); _textWidget.state = _states[index]; - if (_iconIds[index]) { + if (_iconIds[index]) + { _iconWidget.visibility = Visibility.Visible; _iconWidget.drawableId = _iconIds[index]; - } else { + } + else + { _iconWidget.visibility = Visibility.Gone; } _lastItemIndex = index; @@ -529,16 +624,19 @@ class IconStringListAdapter : StringListAdapterBase { } /// called when theme is changed - override void onThemeChanged() { + override void onThemeChanged() + { super.onThemeChanged(); if (_widget) _widget.onThemeChanged(); } /// set one or more list item's state flags, returns updated state - override uint setItemState(int index, uint flags) { + override uint setItemState(int index, uint flags) + { uint res = super.setItemState(index, flags); - if (_widget !is null && _lastItemIndex == index) { + if (_widget !is null && _lastItemIndex == index) + { _widget.state = res; _textWidget.state = res; } @@ -546,34 +644,39 @@ class IconStringListAdapter : StringListAdapterBase { } /// reset one or more list item's state flags, returns updated state - override uint resetItemState(int index, uint flags) { + override uint resetItemState(int index, uint flags) + { uint res = super.resetItemState(index, flags); - if (_widget !is null && _lastItemIndex == index) { + if (_widget !is null && _lastItemIndex == index) + { _widget.state = res; _textWidget.state = res; } return res; } - ~this() { + ~this() + { if (_widget) destroy(_widget); } } /** interface - slot for onItemSelectedListener */ -interface OnItemSelectedHandler { +interface OnItemSelectedHandler +{ bool onItemSelected(Widget source, int itemIndex); } /** interface - slot for onItemClickListener */ -interface OnItemClickHandler { +interface OnItemClickHandler +{ bool onItemClick(Widget source, int itemIndex); } - /** List widget - shows content as hori*/ -class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { +class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler +{ /** Handle selection change. */ Signal!OnItemSelectedHandler itemSelected; @@ -582,9 +685,13 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { protected Orientation _orientation = Orientation.Vertical; /// returns linear layout orientation (Vertical, Horizontal) - @property Orientation orientation() { return _orientation; } + @property Orientation orientation() + { + return _orientation; + } /// sets linear layout orientation - @property ListWidget orientation(Orientation value) { + @property ListWidget orientation(Orientation value) + { _orientation = value; _scrollbar.orientation = value; requestLayout(); @@ -617,15 +724,23 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { /// when true, mouse hover selects underlying item protected bool _selectOnHover; /// when true, mouse hover selects underlying item - @property bool selectOnHover() { return _selectOnHover; } + @property bool selectOnHover() + { + return _selectOnHover; + } /// when true, mouse hover selects underlying item - @property ListWidget selectOnHover(bool select) { _selectOnHover = select; return this; } + @property ListWidget selectOnHover(bool select) + { + _selectOnHover = select; + return this; + } /// if true, generate itemClicked on mouse down instead mouse up event protected bool _clickOnButtonDown; /// returns rectangle for item (not scrolled, first item starts at 0,0) - Rect itemRectNoScroll(int index) { + Rect itemRectNoScroll(int index) + { if (index < 0 || index >= _itemRects.length) return Rect.init; Rect res; @@ -634,14 +749,18 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// returns rectangle for item (scrolled) - Rect itemRect(int index) { + Rect itemRect(int index) + { if (index < 0 || index >= _itemRects.length) return Rect.init; Rect res = itemRectNoScroll(index); - if (_orientation == Orientation.Horizontal) { + if (_orientation == Orientation.Horizontal) + { res.left -= _scrollPosition; res.right -= _scrollPosition; - } else { + } + else + { res.top -= _scrollPosition; res.bottom -= _scrollPosition; } @@ -649,7 +768,8 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// returns item index by 0-based offset from top/left of list content - int itemByPosition(int pos) { + int itemByPosition(int pos) + { return 0; } @@ -658,9 +778,13 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { protected bool _ownAdapter; /// get adapter - @property ListAdapter adapter() { return _adapter; } + @property ListAdapter adapter() + { + return _adapter; + } /// set adapter - @property ListWidget adapter(ListAdapter adapter) { + @property ListWidget adapter(ListAdapter adapter) + { if (_adapter is adapter) return this; // no changes if (_adapter) @@ -675,7 +799,8 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { return this; } /// set adapter, which will be owned by list (destroy will be called for adapter on widget destroy) - @property ListWidget ownAdapter(ListAdapter adapter) { + @property ListWidget ownAdapter(ListAdapter adapter) + { if (_adapter is adapter) return this; // no changes if (_adapter) @@ -691,32 +816,37 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// returns number of widgets in list - @property int itemCount() { + @property int itemCount() + { if (_adapter !is null) return _adapter.itemCount; return 0; } /// return list item widget by item index - Widget itemWidget(int index) { + Widget itemWidget(int index) + { if (_adapter !is null) return _adapter.itemWidget(index); return null; } /// returns true if item with corresponding index is enabled - bool itemEnabled(int index) { + bool itemEnabled(int index) + { if (_adapter !is null && index >= 0 && index < itemCount) return (_adapter.itemState(index) & State.Enabled) != 0; return false; } /// empty parameter list constructor - for usage by factory - this() { + this() + { this(null); } /// create with ID parameter - this(string ID, Orientation orientation = Orientation.Vertical) { + this(string ID, Orientation orientation = Orientation.Vertical) + { super(ID); _orientation = orientation; focusable = true; @@ -728,46 +858,57 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { addChild(_scrollbar); } - protected void setHoverItem(int index) { + protected void setHoverItem(int index) + { if (_hoverItemIndex == index) return; - if (_hoverItemIndex != -1) { + if (_hoverItemIndex != -1) + { _adapter.resetItemState(_hoverItemIndex, State.Hovered); invalidate(); } _hoverItemIndex = index; - if (_hoverItemIndex != -1) { + if (_hoverItemIndex != -1) + { _adapter.setItemState(_hoverItemIndex, State.Hovered); invalidate(); } } /// item list is changed - override void onAdapterChange(ListAdapter source) { + override void onAdapterChange(ListAdapter source) + { requestLayout(); } /// override to handle change of selection - protected void selectionChanged(int index, int previouslySelectedItem = -1) { + protected void selectionChanged(int index, int previouslySelectedItem = -1) + { if (itemSelected.assigned) itemSelected(this, index); } /// override to handle mouse up on item - protected void itemClicked(int index) { + protected void itemClicked(int index) + { if (itemClick.assigned) itemClick(this, index); } /// allow to override state for updating of items // currently used to treat main menu items with opened submenu as focused - @property protected uint overrideStateForItem() { + @property protected uint overrideStateForItem() + { return state; } - protected void updateSelectedItemFocus() { - if (_selectedItemIndex != -1) { - if ((_adapter.itemState(_selectedItemIndex) & State.Focused) != (overrideStateForItem & State.Focused)) { + protected void updateSelectedItemFocus() + { + if (_selectedItemIndex != -1) + { + if ((_adapter.itemState(_selectedItemIndex) & State.Focused) != ( + overrideStateForItem & State.Focused)) + { if (overrideStateForItem & State.Focused) _adapter.setItemState(_selectedItemIndex, State.Focused); else @@ -778,15 +919,18 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// override to handle focus changes - override protected void handleFocusChange(bool focused, bool receivedFocusFromKeyboard = false) { + override protected void handleFocusChange(bool focused, bool receivedFocusFromKeyboard = false) + { updateSelectedItemFocus(); } /// ensure selected item is visible (scroll if necessary) - void makeSelectionVisible() { + void makeSelectionVisible() + { if (_selectedItemIndex < 0) return; // no selection - if (needLayout) { + if (needLayout) + { _makeSelectionVisibleOnNextLayout = true; return; } @@ -795,7 +939,8 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { protected bool _makeSelectionVisibleOnNextLayout; /// ensure item is visible - void makeItemVisible(int itemIndex) { + void makeItemVisible(int itemIndex) + { if (itemIndex < 0 || itemIndex >= itemCount) return; // no selection @@ -804,12 +949,15 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { if (scrolledrc.isInsideOf(viewrc)) // completely visible return; int delta = 0; - if (_orientation == Orientation.Vertical) { + if (_orientation == Orientation.Vertical) + { if (scrolledrc.top < viewrc.top) delta = scrolledrc.top - viewrc.top; else if (scrolledrc.bottom > viewrc.bottom) delta = scrolledrc.bottom - viewrc.bottom; - } else { + } + else + { if (scrolledrc.left < viewrc.left) delta = scrolledrc.left - viewrc.left; else if (scrolledrc.right > viewrc.right) @@ -822,20 +970,25 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// move selection - bool moveSelection(int direction, bool wrapAround = true) { + bool moveSelection(int direction, bool wrapAround = true) + { if (itemCount <= 0) return false; int maxAttempts = itemCount - 1; int index = _selectedItemIndex; - for (int i = 0; i < maxAttempts; i++) { + for (int i = 0; i < maxAttempts; i++) + { int newIndex = 0; - if (index < 0) { + if (index < 0) + { // no previous selection if (direction > 0) newIndex = wrapAround ? 0 : itemCount - 1; else newIndex = wrapAround ? itemCount - 1 : 0; - } else { + } + else + { // step newIndex = index + direction; } @@ -843,8 +996,10 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { newIndex = wrapAround ? itemCount - 1 : 0; else if (newIndex >= itemCount) newIndex = wrapAround ? 0 : itemCount - 1; - if (newIndex != index) { - if (selectItem(newIndex)) { + if (newIndex != index) + { + if (selectItem(newIndex)) + { selectionChanged(_selectedItemIndex, index); return true; } @@ -854,12 +1009,14 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { return true; } - bool selectItem(int index, int disabledItemsSkipDirection) { + bool selectItem(int index, int disabledItemsSkipDirection) + { //debug Log.d("selectItem ", index, " skipDirection=", disabledItemsSkipDirection); if (index == -1 || disabledItemsSkipDirection == 0) return selectItem(index); int maxAttempts = itemCount; - for (int i = 0; i < maxAttempts; i++) { + for (int i = 0; i < maxAttempts; i++) + { if (selectItem(index)) return true; index += disabledItemsSkipDirection > 0 ? 1 : -1; @@ -872,37 +1029,45 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /** Selected item index. */ - @property int selectedItemIndex() { + @property int selectedItemIndex() + { return _selectedItemIndex; } - @property void selectedItemIndex(int index) { + @property void selectedItemIndex(int index) + { selectItem(index); } - bool selectItem(int index) { + bool selectItem(int index) + { //debug Log.d("selectItem ", index); - if (_selectedItemIndex == index) { + if (_selectedItemIndex == index) + { updateSelectedItemFocus(); makeSelectionVisible(); return true; } if (index != -1 && !itemEnabled(index)) return false; - if (_selectedItemIndex != -1) { + if (_selectedItemIndex != -1) + { _adapter.resetItemState(_selectedItemIndex, State.Selected | State.Focused); invalidate(); } _selectedItemIndex = index; - if (_selectedItemIndex != -1) { + if (_selectedItemIndex != -1) + { makeSelectionVisible(); - _adapter.setItemState(_selectedItemIndex, State.Selected | (overrideStateForItem & State.Focused)); + _adapter.setItemState(_selectedItemIndex, State.Selected | ( + overrideStateForItem & State.Focused)); invalidate(); } return true; } - ~this() { + ~this() + { if (_adapter) _adapter.disconnect(this); //Log.d("Destroying List ", _id); @@ -912,16 +1077,21 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// handle scroll event - override bool onScrollEvent(AbstractSlider source, ScrollEvent event) { + override bool onScrollEvent(AbstractSlider source, ScrollEvent event) + { int newPosition = _scrollPosition; - if (event.action == ScrollAction.SliderMoved) { + if (event.action == ScrollAction.SliderMoved) + { // scroll newPosition = event.position; - } else { + } + else + { // use default handler for page/line up/down events newPosition = event.defaultUpdatePosition(); } - if (_scrollPosition != newPosition) { + if (_scrollPosition != newPosition) + { _scrollPosition = newPosition; if (_scrollPosition > _maxScrollPosition) _scrollPosition = _maxScrollPosition; @@ -933,10 +1103,12 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// handle theme change: e.g. reload some themed resources - override void onThemeChanged() { + override void onThemeChanged() + { super.onThemeChanged(); _scrollbar.onThemeChanged(); - for (int i = 0; i < itemCount; i++) { + for (int i = 0; i < itemCount; i++) + { Widget w = itemWidget(i); w.onThemeChanged(); } @@ -945,28 +1117,34 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// sets minimum size for the list, override to change - Point minimumVisibleContentSize() { + Point minimumVisibleContentSize() + { if (_orientation == Orientation.Vertical) return Point(measureMinChildrenSize().x, 100); else return Point(100, measureMinChildrenSize().y); } - protected Point measureMinChildrenSize() { + protected Point measureMinChildrenSize() + { // measure children Point sz; - for (int i = 0; i < itemCount; i++) { + for (int i = 0; i < itemCount; i++) + { Widget w = itemWidget(i); if (w is null || w.visibility == Visibility.Gone) continue; w.measure(SIZE_UNSPECIFIED, SIZE_UNSPECIFIED); - if (_orientation == Orientation.Vertical) { + if (_orientation == Orientation.Vertical) + { // Vertical if (sz.x < w.measuredWidth) sz.x = w.measuredWidth; sz.y += w.measuredHeight; - } else { + } + else + { // Horizontal if (sz.y < w.measuredHeight) sz.y = w.measuredHeight; @@ -977,8 +1155,10 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// Measure widget according to desired width and height constraints. (Step 1 of two phase layout). - override void measure(int parentWidth, int parentHeight) { - if (visibility == Visibility.Gone) { + override void measure(int parentWidth, int parentHeight) + { + if (visibility == Visibility.Gone) + { _measuredWidth = _measuredHeight = 0; return; } @@ -1012,25 +1192,31 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { _lastMeasureWidth = pwidth; _lastMeasureHeight = pheight; - int sbsize = _orientation == Orientation.Vertical ? _scrollbar.measuredWidth : _scrollbar.measuredHeight; + int sbsize = _orientation == Orientation.Vertical ? _scrollbar.measuredWidth + : _scrollbar.measuredHeight; // measure children Point sz; _sbsz.destroy(); - for (int i = 0; i < itemCount; i++) { + for (int i = 0; i < itemCount; i++) + { Widget w = itemWidget(i); - if (w is null || w.visibility == Visibility.Gone) { + if (w is null || w.visibility == Visibility.Gone) + { _itemSizes[i].x = _itemSizes[i].y = 0; continue; } w.measure(pwidth, pheight); _itemSizes[i].x = w.measuredWidth; _itemSizes[i].y = w.measuredHeight; - if (_orientation == Orientation.Vertical) { + if (_orientation == Orientation.Vertical) + { // Vertical if (sz.x < w.measuredWidth) sz.x = w.measuredWidth; sz.y += w.measuredHeight; - } else { + } + else + { // Horizontal if (sz.y < w.measuredHeight) sz.y = w.measuredHeight; @@ -1038,41 +1224,53 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } } _needScrollbar = false; - if (_orientation == Orientation.Vertical) { - if (pheight != SIZE_UNSPECIFIED && sz.y > pheight) { + if (_orientation == Orientation.Vertical) + { + if (pheight != SIZE_UNSPECIFIED && sz.y > pheight) + { // need scrollbar - if (pwidth != SIZE_UNSPECIFIED) { + if (pwidth != SIZE_UNSPECIFIED) + { pwidth -= sbsize; _sbsz.x = sbsize; _needScrollbar = true; } } - } else { - if (pwidth != SIZE_UNSPECIFIED && sz.x > pwidth) { + } + else + { + if (pwidth != SIZE_UNSPECIFIED && sz.x > pwidth) + { // need scrollbar - if (pheight != SIZE_UNSPECIFIED) { + if (pheight != SIZE_UNSPECIFIED) + { pheight -= sbsize; _sbsz.y = sbsize; _needScrollbar = true; } } } - if (_needScrollbar) { + if (_needScrollbar) + { // recalculate with scrollbar sz.x = sz.y = 0; - for (int i = 0; i < itemCount; i++) { + for (int i = 0; i < itemCount; i++) + { Widget w = itemWidget(i); if (w is null || w.visibility == Visibility.Gone) continue; w.measure(pwidth, pheight); _itemSizes[i].x = w.measuredWidth; _itemSizes[i].y = w.measuredHeight; - if (_orientation == Orientation.Vertical) { + if (_orientation == Orientation.Vertical) + { // Vertical if (sz.x < w.measuredWidth) sz.x = w.measuredWidth; sz.y += w.measuredHeight; - } else { + } + else + { // Horizontal w.measure(pwidth, pheight); if (sz.y < w.measuredHeight) @@ -1083,20 +1281,23 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } measuredContent(parentWidth, parentHeight, sz.x + _sbsz.x, sz.y + _sbsz.y); - if (_scrollbar.visibility == oldScrollbarVisibility) { + if (_scrollbar.visibility == oldScrollbarVisibility) + { _needLayout = oldNeedLayout; _scrollbar.cancelLayout(); } } - - protected void updateItemPositions() { + protected void updateItemPositions() + { Rect r; int p = 0; - for (int i = 0; i < itemCount; i++) { + for (int i = 0; i < itemCount; i++) + { if (_itemSizes[i].x == 0 && _itemSizes[i].y == 0) continue; - if (_orientation == Orientation.Vertical) { + if (_orientation == Orientation.Vertical) + { // Vertical int w = _clientRc.width; int h = _itemSizes[i].y; @@ -1106,7 +1307,9 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { r.right = w; _itemRects[i] = r; p += h; - } else { + } + else + { // Horizontal int h = _clientRc.height; int w = _itemSizes[i].x; @@ -1119,23 +1322,30 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } } _totalSize = p; - if (_needScrollbar) { - if (_orientation == Orientation.Vertical) { + if (_needScrollbar) + { + if (_orientation == Orientation.Vertical) + { _scrollbar.setRange(0, p); _scrollbar.pageSize = _clientRc.height; _scrollbar.position = _scrollPosition; - } else { + } + else + { _scrollbar.setRange(0, p); _scrollbar.pageSize = _clientRc.width; _scrollbar.position = _scrollPosition; } } /// maximum scroll position - if (_orientation == Orientation.Vertical) { + if (_orientation == Orientation.Vertical) + { _maxScrollPosition = _totalSize - _clientRc.height; if (_maxScrollPosition < 0) _maxScrollPosition = 0; - } else { + } + else + { _maxScrollPosition = _totalSize - _clientRc.width; if (_maxScrollPosition < 0) _maxScrollPosition = 0; @@ -1144,19 +1354,25 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { _scrollPosition = _maxScrollPosition; if (_scrollPosition < 0) _scrollPosition = 0; - if (_needScrollbar) { - if (_orientation == Orientation.Vertical) { // FIXME: + if (_needScrollbar) + { + if (_orientation == Orientation.Vertical) + { // FIXME: _scrollbar.position = _scrollPosition; - } else { + } + else + { _scrollbar.position = _scrollPosition; } } } /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). - override void layout(Rect rc) { + override void layout(Rect rc) + { _needLayout = false; - if (visibility == Visibility.Gone) { + if (visibility == Visibility.Gone) + { return; } _pos = rc; @@ -1175,10 +1391,13 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { // hide scrollbar or update rc for scrollbar Rect sbrect = rc; // layout scrollbar - if (_needScrollbar) { + if (_needScrollbar) + { rc.right -= _sbsz.x; rc.bottom -= _sbsz.y; - } else { + } + else + { _scrollbar.visibility = Visibility.Gone; } @@ -1188,7 +1407,8 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { updateItemPositions(); // layout scrollbar - must be under updateItemPositions() - if (_needScrollbar) { + if (_needScrollbar) + { _scrollbar.visibility = Visibility.Visible; if (_orientation == Orientation.Vertical) sbrect.left = sbrect.right - _sbsz.x; @@ -1197,7 +1417,8 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { _scrollbar.layout(sbrect); } - if (_makeSelectionVisibleOnNextLayout) { + if (_makeSelectionVisibleOnNextLayout) + { makeSelectionVisible(); _makeSelectionVisibleOnNextLayout = false; } @@ -1206,7 +1427,8 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// Draw widget at its position to buffer - override void onDraw(DrawBuf buf) { + override void onDraw(DrawBuf buf) + { if (visibility != Visibility.Visible) return; super.onDraw(buf); @@ -1219,19 +1441,24 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { _scrollbar.onDraw(buf); Point scrollOffset; - if (_orientation == Orientation.Vertical) { + if (_orientation == Orientation.Vertical) + { scrollOffset.y = _scrollPosition; - } else { + } + else + { scrollOffset.x = _scrollPosition; } // draw items - for (int i = 0; i < itemCount; i++) { + for (int i = 0; i < itemCount; i++) + { Rect itemrc = _itemRects[i]; itemrc.left += rc.left - scrollOffset.x; itemrc.right += rc.left - scrollOffset.x; itemrc.top += rc.top - scrollOffset.y; itemrc.bottom += rc.top - scrollOffset.y; - if (itemrc.intersects(rc)) { + if (itemrc.intersects(rc)) + { Widget w = itemWidget(i); if (w is null || w.visibility != Visibility.Visible) continue; @@ -1242,45 +1469,62 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// list navigation using keys - override bool onKeyEvent(KeyEvent event) { + override bool onKeyEvent(KeyEvent event) + { if (itemCount == 0) return false; int navigationDelta = 0; - if (event.action == KeyAction.KeyDown) { - if (orientation == Orientation.Vertical) { + if (event.action == KeyAction.KeyDown) + { + if (orientation == Orientation.Vertical) + { if (event.keyCode == KeyCode.DOWN) navigationDelta = 1; else if (event.keyCode == KeyCode.UP) navigationDelta = -1; - } else { + } + else + { if (event.keyCode == KeyCode.RIGHT) navigationDelta = 1; else if (event.keyCode == KeyCode.LEFT) navigationDelta = -1; } } - if (navigationDelta != 0) { + if (navigationDelta != 0) + { moveSelection(navigationDelta); return true; } - if (event.action == KeyAction.KeyDown) { - if (event.keyCode == KeyCode.HOME) { + if (event.action == KeyAction.KeyDown) + { + if (event.keyCode == KeyCode.HOME) + { // select first enabled item on HOME key selectItem(0, 1); return true; - } else if (event.keyCode == KeyCode.END) { + } + else if (event.keyCode == KeyCode.END) + { // select last enabled item on END key selectItem(itemCount - 1, -1); return true; - } else if (event.keyCode == KeyCode.PAGEDOWN) { + } + else if (event.keyCode == KeyCode.PAGEDOWN) + { // TODO - } else if (event.keyCode == KeyCode.PAGEUP) { + } + else if (event.keyCode == KeyCode.PAGEUP) + { // TODO } } - if ((event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN)) { - if (event.action == KeyAction.KeyDown && enabled) { - if (itemEnabled(_selectedItemIndex)) { + if ((event.keyCode == KeyCode.SPACE || event.keyCode == KeyCode.RETURN)) + { + if (event.action == KeyAction.KeyDown && enabled) + { + if (itemEnabled(_selectedItemIndex)) + { itemClicked(_selectedItemIndex); } } @@ -1313,15 +1557,18 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } /// process mouse event; return true if event is processed by widget. - override bool onMouseEvent(MouseEvent event) { + override bool onMouseEvent(MouseEvent event) + { //Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")"); super.onMouseEvent(event); - if (event.action == MouseAction.Leave || event.action == MouseAction.Cancel) { + if (event.action == MouseAction.Leave || event.action == MouseAction.Cancel) + { setHoverItem(-1); return true; } // delegate processing of mouse wheel to scrollbar widget - if (event.action == MouseAction.Wheel && _needScrollbar) { + if (event.action == MouseAction.Wheel && _needScrollbar) + { return _scrollbar.onMouseEvent(event); } // support onClick @@ -1329,33 +1576,45 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { applyMargins(rc); applyPadding(rc); Point scrollOffset; - if (_orientation == Orientation.Vertical) { + if (_orientation == Orientation.Vertical) + { scrollOffset.y = _scrollPosition; - } else { + } + else + { scrollOffset.x = _scrollPosition; } - if (event.action == MouseAction.Wheel) { + if (event.action == MouseAction.Wheel) + { if (_scrollbar) - _scrollbar.sendScrollEvent(event.wheelDelta > 0 ? ScrollAction.LineUp : ScrollAction.LineDown); + _scrollbar.sendScrollEvent(event.wheelDelta > 0 ? ScrollAction.LineUp + : ScrollAction.LineDown); return true; } - if (event.action == MouseAction.ButtonDown && (event.flags & (MouseFlag.LButton || MouseFlag.RButton))) + if (event.action == MouseAction.ButtonDown && (event.flags & (MouseFlag.LButton || MouseFlag + .RButton))) setFocus(); if (itemCount > _itemRects.length) return true; // layout not yet called - for (int i = 0; i < itemCount; i++) { + for (int i = 0; i < itemCount; i++) + { Rect itemrc = _itemRects[i]; itemrc.left += rc.left - scrollOffset.x; itemrc.right += rc.left - scrollOffset.x; itemrc.top += rc.top - scrollOffset.y; itemrc.bottom += rc.top - scrollOffset.y; - if (itemrc.isPointInside(Point(event.x, event.y))) { - if (_adapter && _adapter.wantMouseEvents) { + if (itemrc.isPointInside(Point(event.x, event.y))) + { + if (_adapter && _adapter.wantMouseEvents) + { auto itemWidget = _adapter.itemWidget(i); - if (itemWidget) { + if (itemWidget) + { Widget oldParent = itemWidget.parent; itemWidget.parent = this; - if (event.action == MouseAction.Move && event.noModifiers && itemWidget.hasTooltip) { + if (event.action == MouseAction.Move && event.noModifiers && itemWidget + .hasTooltip) + { itemWidget.scheduleTooltip(200); } //itemWidget.onMouseEvent(event); @@ -1363,20 +1622,28 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } } //Log.d("mouse event action=", event.action, " button=", event.button, " flags=", event.flags); - if ((event.flags & (MouseFlag.LButton || MouseFlag.RButton)) || _selectOnHover) { - if (_selectedItemIndex != i && itemEnabled(i)) { + if ((event.flags & (MouseFlag.LButton || MouseFlag.RButton)) || _selectOnHover) + { + if (_selectedItemIndex != i && itemEnabled(i)) + { int prevSelection = _selectedItemIndex; selectItem(i); setHoverItem(-1); selectionChanged(_selectedItemIndex, prevSelection); } - } else { + } + else + { if (itemEnabled(i)) setHoverItem(i); } - if (event.button == MouseButton.Left || event.button == MouseButton.Right) { - if ((_clickOnButtonDown && event.action == MouseAction.ButtonDown) || (!_clickOnButtonDown && event.action == MouseAction.ButtonUp)) { - if (itemEnabled(i)) { + if (event.button == MouseButton.Left || event.button == MouseButton.Right) + { + if ((_clickOnButtonDown && event.action == MouseAction.ButtonDown) || (!_clickOnButtonDown && event + .action == MouseAction.ButtonUp)) + { + if (itemEnabled(i)) + { itemClicked(i); if (_clickOnButtonDown) event.doNotTrackButtonDown = true; @@ -1389,9 +1656,12 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { return true; } /// returns true if item is child of this widget (when deepSearch == true - returns true if item is this widget or one of children inside children tree). - override bool isChild(Widget item, bool deepSearch = true) { - if (_adapter && _adapter.wantMouseEvents) { - for (int i = 0; i < itemCount; i++) { + override bool isChild(Widget item, bool deepSearch = true) + { + if (_adapter && _adapter.wantMouseEvents) + { + for (int i = 0; i < itemCount; i++) + { auto itemWidget = _adapter.itemWidget(i); if (itemWidget is item) return true; @@ -1401,70 +1671,84 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { } } -class StringListWidget : ListWidget { +class StringListWidget : ListWidget +{ import std.conv : to; import std.datetime.stopwatch : StopWatch; import core.time : dur; + private dstring _searchString; private StopWatch _stopWatch; - this(string ID = null) { + this(string ID = null) + { super(ID); styleId = STYLE_EDIT_BOX; clickable = true; } - this(string ID, string[] items) { + this(string ID, string[] items) + { super(ID); styleId = STYLE_EDIT_BOX; ownAdapter = new StringListAdapter(items); clickable = true; } - this(string ID, dstring[] items) { + this(string ID, dstring[] items) + { super(ID); styleId = STYLE_EDIT_BOX; ownAdapter = new StringListAdapter(items); clickable = true; } - this(string ID, StringListValue[] items) { + this(string ID, StringListValue[] items) + { super(ID); styleId = STYLE_EDIT_BOX; ownAdapter = new StringListAdapter(items); clickable = true; } - @property void items(string[] itemResourceIds) { + @property void items(string[] itemResourceIds) + { _selectedItemIndex = -1; ownAdapter = new StringListAdapter(itemResourceIds); - if(itemResourceIds.length > 0) { + if (itemResourceIds.length > 0) + { selectedItemIndex = 0; } requestLayout(); } - @property void items(dstring[] items) { + @property void items(dstring[] items) + { _selectedItemIndex = -1; ownAdapter = new StringListAdapter(items); - if(items.length > 0) { + if (items.length > 0) + { selectedItemIndex = 0; } requestLayout(); } - @property void items(StringListValue[] items) { + @property void items(StringListValue[] items) + { _selectedItemIndex = -1; ownAdapter = new StringListAdapter(items); - if(items.length > 0) { + if (items.length > 0) + { selectedItemIndex = 0; } requestLayout(); } /// StringListValue list values - override bool setStringListValueListProperty(string propName, StringListValue[] values) { - if (propName == "items") { + override bool setStringListValueListProperty(string propName, StringListValue[] values) + { + if (propName == "items") + { items = values; return true; } @@ -1472,32 +1756,45 @@ class StringListWidget : ListWidget { } /// get selected item as text - @property dstring selectedItem() { + @property dstring selectedItem() + { if (_selectedItemIndex < 0 || _selectedItemIndex >= _adapter.itemCount) return ""; - return (cast(StringListAdapter)adapter).items.get(_selectedItemIndex); + return (cast(StringListAdapter) adapter).items.get(_selectedItemIndex); } - override bool onKeyEvent(KeyEvent event) { - if (itemCount == 0) return false; + override bool onKeyEvent(KeyEvent event) + { + if (itemCount == 0) + return false; // Accept user input and try to find a match in the list. - if (event.action == KeyAction.Text) { - if ( !_stopWatch.running) { _stopWatch.start; } + if (event.action == KeyAction.Text) + { + if (!_stopWatch.running) + { + _stopWatch.start; + } - version(DigitalMars) { + version (DigitalMars) + { auto timePassed = _stopWatch.peek; //.to!("seconds", float)(); // dtop is std.datetime.to - if (timePassed > dur!"msecs"(500)) _searchString = ""d; - } else { - auto timePassed = (cast(float)_stopWatch.peek.total!"msecs")/1000.0f; + if (timePassed > dur!"msecs"(500)) + _searchString = ""d; + } + else + { + auto timePassed = (cast(float) _stopWatch.peek.total!"msecs") / 1000.0f; - if (timePassed > 0.5) _searchString = ""d; // TODO_GRIM: make everything look-alike + if (timePassed > 0.5) + _searchString = ""d; // TODO_GRIM: make everything look-alike } _searchString ~= to!dchar(event.text.toUTF8); _stopWatch.reset; - if ( selectClosestMatch(_searchString) ) { + if (selectClosestMatch(_searchString)) + { invalidate(); return true; } @@ -1506,40 +1803,53 @@ class StringListWidget : ListWidget { return super.onKeyEvent(event); } - - private bool selectClosestMatch(dstring term) { + private bool selectClosestMatch(dstring term) + { import std.uni : toLower; - if (term.length == 0) return false; - auto myItems = (cast(StringListAdapter)adapter).items; + + if (term.length == 0) + return false; + auto myItems = (cast(StringListAdapter) adapter).items; // Perfect match or best match int[] indexes; - foreach(int itemIndex; 0 .. myItems.length) { + foreach (int itemIndex; 0 .. myItems.length) + { dstring item = myItems.get(itemIndex); - if (item == term) { + if (item == term) + { // Perfect match indexes ~= itemIndex; break; - } else { + } + else + { // Term approximate to something bool addItem = true; - foreach(int termIndex; 0 .. cast(int)term.length) { - if (termIndex < item.length) { - if ( toLower(term[termIndex]) != toLower(item[termIndex]) ) { + foreach (int termIndex; 0 .. cast(int) term.length) + { + if (termIndex < item.length) + { + if (toLower(term[termIndex]) != toLower(item[termIndex])) + { addItem = false; break; } } } - if (addItem) { indexes ~= itemIndex; } + if (addItem) + { + indexes ~= itemIndex; + } } } // Return best match - if (indexes.length > 0) { + if (indexes.length > 0) + { selectItem(indexes[0]); itemSelected(this, indexes[0]); return true; @@ -1549,8 +1859,6 @@ class StringListWidget : ListWidget { } - - } //import dlangui.widgets.metadata;