Пример #1
0
        protected override void ComposeTree(TreeComposer composer)
        {
            if (!CompilationStore.Compilation.Diagnostics.Any())
            {
                return;
            }

            composer.Element("errors-space", body: () =>
            {
                composer.Element(
                    name: "title-row",
                    events: new TreeComposer.Events
                {
                    OnClick = args => this.areErrorsExpanded = !this.areErrorsExpanded
                },
                    body: () =>
                {
                    composer.Element("icon");

                    composer.Element("errors-count", body: () =>
                    {
                        composer.Text(string.Format(CultureInfo.CurrentCulture, EditorResources.Errors_Count, CompilationStore.Compilation.Diagnostics.Count));
                    });

                    composer.Element(this.areErrorsExpanded ? "caret-opened" : "caret-closed");
                });

                if (!this.areErrorsExpanded)
                {
                    return;
                }

                composer.Element("header-line", body: () =>
                {
                    composer.Element("line-number", body: () => composer.Text(EditorResources.Errors_Line));
                    composer.Element("description", body: () => composer.Text(EditorResources.Errors_Description));
                });

                composer.Element("errors-list", body: () =>
                {
                    foreach (var error in CompilationStore.Compilation.Diagnostics.OrderBy(d => d.Range.Start.Line))
                    {
                        var range = error.Range.ToMonacoRange();

                        composer.Element(
                            name: "error-line",
                            events: new TreeComposer.Events
                        {
                            OnClickAsync = args => JSInterop.Monaco.SelectRange(range)
                        },
                            body: () =>
                        {
                            composer.Element("line-number", body: () => composer.Text(range.startLineNumber.ToString(CultureInfo.CurrentCulture)));
                            composer.Element("description", body: () => composer.Text(error.ToDisplayString()));
                        });
                    }
                });
            });
        }
Пример #2
0
        protected override void ComposeTree(TreeComposer composer)
        {
            composer.Element(
                name: "text-display",
                capture: element => this.textDisplayRef = element,
                styles: new Dictionary <string, string>
            {
                { "background-color", this.backgroundColor }
            },
                attributes: new Dictionary <string, string>
            {
                { "tabindex", "0" },     // required to receive focus
            },
                events: new TreeComposer.Events
            {
                OnKeyDownAsync = args => this.AcceptInput(args.Key)
            },
                body: () =>
            {
                if (!string.IsNullOrEmpty(this.Title))
                {
                    composer.Element(
                        name: "title",
                        body: () => composer.Text(this.Title));
                }
                foreach (var chunk in this.outputChunks)
                {
                    composer.Element(
                        name: "span",
                        body: () => composer.Text(chunk.Text),
                        styles: new Dictionary <string, string>
                    {
                        { "color", chunk.HexColor }
                    });

                    if (chunk.AppendNewLine)
                    {
                        composer.Element("br");
                    }
                }

                composer.Element("input-field", capture: element => this.inputFieldRef = element, body: () =>
                {
                    if (this.mode != AcceptedInputMode.None)
                    {
                        composer.Element("span", body: () => composer.Text(this.inputBuffer));
                        composer.Element(name: "span", body: () =>
                        {
                            composer.Element("cursor", body: () =>
                            {
                                composer.Markup("&#x2588;");
                            });
                        });
                    }
                });
            });
        }
Пример #3
0
        public static void DisabledAction(TreeComposer composer, string name, string title, string message)
        {
            composer.Element("disabled-action-container", body: () =>
            {
                composer.Element("action", body: () =>
                {
                    composer.Element("icon-" + name);
                    composer.Text(title);
                });

                composer.Element("disabled-message", body: () => composer.Text(message));
            });
        }
Пример #4
0
        private void ComposeCallStack(TreeComposer composer)
        {
            composer.Element("call-stack-member", body: () =>
            {
                composer.Element("member-title-area", body: () =>
                {
                    composer.Element("logo-area", body: () => composer.Element("logo"));
                    composer.Element("title-text", body: () => composer.Text(EditorResources.MemoryExplorer_CallStack));
                });

                composer.Element("member-table-header", body: () =>
                {
                    composer.Element("left-text", body: () => composer.Text(EditorResources.MemoryExplorer_Line));
                    composer.Element("right-text", body: () => composer.Text(EditorResources.MemoryExplorer_Module));
                });

                this.ComposeOnlyIfNotRunning(composer, showEvenIfTerminated: false, body: () =>
                {
                    composer.Element("call-stack", body: () =>
                    {
                        composer.Element("blue-box");
                        composer.Element("container-box", body: () =>
                        {
                            bool firstFrame = true;
                            foreach (var frame in this.Engine.GetSnapshot().ExecutionStack.Reverse())
                            {
                                string name;
                                if (firstFrame)
                                {
                                    firstFrame = false;
                                    name       = "stack-frame-highlighted";
                                }
                                else
                                {
                                    name = "stack-frame";
                                }

                                composer.Element(name, body: () =>
                                {
                                    var line = frame.CurrentSourceLine + 1; // Monaco editor is one-based
                                    composer.Element("line-cell", body: () => composer.Text(line.ToString(CultureInfo.CurrentCulture)));
                                    composer.Element("module-name-cell", body: () => composer.Text(frame.Module.Name));
                                });
                            }
                        });
                    });
                });
            });
        }
Пример #5
0
        private void ComposeHeader(TreeComposer composer)
        {
            composer.Element("header-area", body: () =>
            {
                composer.Element(
                    name: "logo-area",
                    events: new TreeComposer.Events
                {
                    OnClick = args => this.isExpanded = !this.isExpanded
                },
                    body: () =>
                {
                    composer.Element("logo");
                });

                composer.Element("empty-scroll-area");

                if (this.isExpanded)
                {
                    composer.Element("title-area", body: () => composer.Text(EditorResources.MemoryExplorer_Title));
                    composer.Element(
                        name: "minimize-button",
                        events: new TreeComposer.Events
                    {
                        OnClick = args => this.isExpanded = false
                    },
                        body: () =>
                    {
                        composer.Element("angle-left");
                    });
                }
            });
        }
Пример #6
0
        public override void ComposeTree(TreeComposer composer)
        {
            var attributes = new Dictionary <string, string>
            {
                { "x", this.X.ToString(CultureInfo.CurrentCulture) },
                { "y", this.Y.ToString(CultureInfo.CurrentCulture) },
                { "dy", this.Styles.FontSize.ToString(CultureInfo.CurrentCulture) }
            };

            if (this.Width.HasValue)
            {
                attributes.Add("textLength", this.Width.Value.ToString(CultureInfo.CurrentCulture));
            }

            composer.Element(
                name: "text",
                styles: new Dictionary <string, string>
            {
                { "fill", this.Styles.BrushColor },
                { "font-weight", this.Styles.FontBold ? "bold" : "normal" },
                { "font-style", this.Styles.FontItalic ? "italic" : "normal" },
                { "font-family", $@"""{this.Styles.FontName}""" },
                { "font-size", $"{this.Styles.FontSize}px" },
                { "pointer-events", "none" }
            },
                attributes: attributes,
                body: () => composer.Text(this.Text));
        }
Пример #7
0
        private void ComposeOnlyIfNotRunning(TreeComposer composer, bool showEvenIfTerminated, Action body)
        {
            switch (this.Engine.State)
            {
            case ExecutionState.BlockedOnNumberInput:
            case ExecutionState.BlockedOnStringInput:
            case ExecutionState.Paused:
            {
                body();
                break;
            }

            case ExecutionState.Running:
            {
                composer.Element("running-block", body: () =>
                    {
                        composer.Element("icon-container", body: () => composer.Element("program-running-icon"));
                        composer.Element("text-container", body: () => composer.Text(EditorResources.MemoryExplorer_ProgramRunning));
                    });

                break;
            }

            case ExecutionState.Terminated:
            {
                if (showEvenIfTerminated)
                {
                    body();
                }
                else
                {
                    composer.Element("running-block", body: () =>
                        {
                            composer.Element("icon-container", body: () => composer.Element("program-ended-icon"));
                            composer.Element("text-container", body: () => composer.Text(EditorResources.MemoryExplorer_ProgramEnded));
                        });
                }

                break;
            }

            default:
            {
                throw ExceptionUtilities.UnexpectedValue(this.Engine.State);
            }
            }
        }
Пример #8
0
        protected override void ComposeTree(TreeComposer composer)
        {
            if (!this.IsVisible)
            {
                return;
            }

            composer.Element(
                name: "graphics-display",
                attributes: new Dictionary <string, string>
            {
                { "tabindex", "0" },     // required to receive focus
            },
                styles: new Dictionary <string, string>
            {
                { "cursor", this.IsMouseVisible ? "initial" : "none" }
            },
                body: () =>
            {
                if (!string.IsNullOrEmpty(this.Title))
                {
                    composer.Element(
                        name: "title",
                        body: () => composer.Text(this.Title));
                }
                composer.Element(
                    name: "svg",
                    capture: element => this.RenderArea = element,
                    attributes: new Dictionary <string, string>
                {
                    { "height", "100%" },
                    { "width", "100%" },
                },
                    events: new TreeComposer.Events
                {
                    OnMouseDown = args => GraphicsDisplayStore.NotifyMouseDown(args.ClientX, args.ClientY, GetMouseButton(args.Button)),
                    OnMouseUp   = args => GraphicsDisplayStore.NotifyMouseUp(args.ClientX, args.ClientY, GetMouseButton(args.Button)),
                    OnMouseMove = args => GraphicsDisplayStore.NotifyMouseMove(args.ClientX, args.ClientY),
                },
                    body: () =>
                {
                    if (!this.Libraries.IsDefault())
                    {
                        this.Libraries.ImageList.EmbedImages(composer);
                        this.Libraries.GraphicsWindow.ComposeTree(composer);
                        this.Libraries.Shapes.ComposeTree(composer);
                        this.Libraries.Turtle.ComposeTree(composer);
                    }
                });

                if (!this.Libraries.IsDefault())
                {
                    this.Libraries.Controls.ComposeTree(composer);
                }
            });
        }
Пример #9
0
 public override void ComposeTree(ControlsLibrary library, TreeComposer composer)
 {
     composer.Element(
         name: "button",
         body: () => composer.Text(this.Caption),
         events: new TreeComposer.Events
     {
         OnClick = args => library.NotifyButtonClicked(this.Name)
     },
         styles: this.Styles);
 }
Пример #10
0
 public static void Action(TreeComposer composer, string name, string title, Func <Task> onClick)
 {
     composer.Element(
         name: "action",
         events: new TreeComposer.Events
     {
         OnClickAsync = args => onClick()
     },
         body: () =>
     {
         composer.Element("icon-" + name);
         composer.Text(title);
     });
 }
Пример #11
0
        protected sealed override void ComposeTree(TreeComposer composer)
        {
            composer.Element("main-layout", body: () =>
            {
                composer.Element("header-row", body: () =>
                {
                    composer.Element("logo-area", body: () =>
                    {
                        composer.Element(
                            name: "logo",
                            events: new TreeComposer.Events
                        {
                            OnClickAsync = args => OpenExtrernalLink("http://www.smallbasic.com")
                        });
                    });

                    composer.Element("header-links", body: () =>
                    {
                        foreach (var pair in HeaderLinks)
                        {
                            composer.Element(
                                name: "header-link",
                                events: new TreeComposer.Events
                            {
                                OnClickAsync = args => OpenExtrernalLink(pair.Value)
                            },
                                body: () =>
                            {
                                composer.Text(pair.Key);
                            });
                        }
                    });
                });

                Actions.Row(composer, left: () => this.ComposeLeftActions(composer), right: () => this.ComposeRightActions(composer));

                composer.Element("page-contents", body: () =>
                {
                    this.ComposeBody(composer);
                });
            });
        }
Пример #12
0
        private void ComposeVariables(TreeComposer composer)
        {
            composer.Element("variables-member", body: () =>
            {
                composer.Element("member-title-area", body: () =>
                {
                    composer.Element("logo-area", body: () => composer.Element("logo"));
                    composer.Element("title-text", body: () => composer.Text(EditorResources.MemoryExplorer_Variables));
                });

                composer.Element("member-table-header", body: () =>
                {
                    composer.Element("left-text", body: () => composer.Text(EditorResources.MemoryExplorer_Name));
                    composer.Element("right-text", body: () => composer.Text(EditorResources.MemoryExplorer_Value));
                });

                this.ComposeOnlyIfNotRunning(composer, showEvenIfTerminated: true, body: () =>
                {
                    var memory = this.Engine.GetSnapshot().Memory;

                    if (memory.Any())
                    {
                        composer.Element("variables-block", body: () =>
                        {
                            foreach (var variable in memory)
                            {
                                composer.Element("variable", body: () =>
                                {
                                    composer.Element("name-cell", body: () =>
                                    {
                                        composer.Element("icon-container", body: () =>
                                        {
                                            switch (variable.Value)
                                            {
                                            case StringValue stringValue:
                                            case BooleanValue booleanValue:
                                                composer.Element("string-type-icon");
                                                break;

                                            case NumberValue numberValue:
                                                composer.Element("number-type-icon");
                                                break;

                                            case ArrayValue arrayValue:
                                                composer.Element("array-type-icon");
                                                break;

                                            default:
                                                throw ExceptionUtilities.UnexpectedValue(variable.Value);
                                            }
                                        });

                                        composer.Element("name-container", body: () => composer.Text(variable.Key));
                                    });

                                    composer.Element("value-cell", body: () => composer.Text(variable.Value.ToDisplayString()));
                                });
                            }
                        });
                    }
                });
            });
        }
Пример #13
0
        protected override void ComposeTree(TreeComposer composer)
        {
            composer.Element("library-body", body: () =>
            {
                composer.Element("library-title", body: () =>
                {
                    composer.Element("icon", body: () => Micro.FontAwesome(composer, this.Library.ExplorerIcon));
                    composer.Element("name", body: () => composer.Text(this.Library.Name));
                });

                composer.Element("library-description", body: () => composer.Text(this.Library.Description));

                if (this.Library.Methods.Any())
                {
                    composer.Element("group-title", body: () =>
                    {
                        composer.Element("icon", body: () => Micro.FontAwesome(composer, "cube"));
                        composer.Element("name", body: () => composer.Text(EditorResources.LibraryExplorer_Methods));
                    });

                    foreach (var method in this.Library.Methods.Values)
                    {
                        LibraryMethod.Inject(
                            composer,
                            isSelected: method == this.selectedMethod,
                            library: this.Library,
                            method: method,
                            onHeaderClick: () => this.OnMethodHeaderClick(method));
                    }
                }

                if (this.Library.Properties.Any())
                {
                    composer.Element("group-title", body: () =>
                    {
                        composer.Element("icon", body: () => Micro.FontAwesome(composer, "wrench"));
                        composer.Element("name", body: () => composer.Text(EditorResources.LibraryExplorer_Properties));
                    });

                    foreach (var property in this.Library.Properties.Values)
                    {
                        composer.Element("member", body: () =>
                        {
                            composer.Element(name: "member-header-selected", body: () =>
                            {
                                composer.Element("member-title", body: () =>
                                {
                                    composer.Element("caret");
                                    composer.Element("name", body: () => composer.Text($"{this.Library.Name}.{property.Name}"));
                                });

                                composer.Element("member-description", body: () => composer.Text(property.Description));
                            });
                        });
                    }
                }

                if (this.Library.Events.Any())
                {
                    composer.Element("group-title", body: () =>
                    {
                        composer.Element("icon", body: () => Micro.FontAwesome(composer, "neuter"));
                        composer.Element("name", body: () => composer.Text(EditorResources.LibraryExplorer_Events));
                    });

                    foreach (var @event in this.Library.Events.Values)
                    {
                        composer.Element("member", body: () =>
                        {
                            composer.Element(name: "member-header-selected", body: () =>
                            {
                                composer.Element("member-title", body: () =>
                                {
                                    composer.Element("caret");
                                    composer.Element("name", body: () => composer.Text($"{this.Library.Name}.{@event.Name}"));
                                });

                                composer.Element("member-description", body: () => composer.Text(@event.Description));
                            });
                        });
                    }
                }
            });
        }
Пример #14
0
            protected override void ComposeTree(TreeComposer composer)
            {
                composer.Element("member", body: () =>
                {
                    composer.Element(
                        name: this.IsSelected ? "member-header-selected" : "member-header",
                        events: new TreeComposer.Events
                    {
                        OnClick = arg => this.OnHeaderClick()
                    },
                        body: () =>
                    {
                        composer.Element("member-title", body: () =>
                        {
                            composer.Element("caret", body: () =>
                            {
                                Micro.FontAwesome(composer, this.IsSelected ? "caret-down" : "caret-right");
                            });

                            composer.Element("name", body: () => composer.Text($"{this.Library.Name}.{this.Method.Name}()"));
                        });

                        composer.Element("member-description", body: () => composer.Text(this.Method.Description));
                    });

                    if (this.IsSelected)
                    {
                        composer.Element("member-body", body: () =>
                        {
                            composer.Element("example", body: () =>
                            {
                                composer.Text(string.Format(
                                                  CultureInfo.CurrentCulture,
                                                  "{0}{1}.{2}({3})",
                                                  this.Method.ReturnsValue ? "result = " : string.Empty,
                                                  this.Library.Name,
                                                  this.Method.Name,
                                                  this.Method.Parameters.Keys.Join(", ")));
                            });

                            if (this.Method.Parameters.Any())
                            {
                                composer.Element("block", body: () =>
                                {
                                    composer.Element("arguments-area", body: () =>
                                    {
                                        foreach (var parameter in this.Method.Parameters.Values)
                                        {
                                            composer.Element("name", body: () => composer.Text(parameter.Name));
                                            composer.Element("description", body: () => composer.Text(parameter.Description));
                                        }
                                    });
                                });
                            }

                            composer.Element("block", body: () =>
                            {
                                composer.Element("result-area", body: () =>
                                {
                                    if (this.Method.ReturnsValue)
                                    {
                                        composer.Element("name", body: () => composer.Text("result"));
                                        composer.Element("description", body: () => composer.Text(this.Method.ReturnValueDescription));
                                    }
                                    else
                                    {
                                        composer.Element("description", body: () => composer.Text(EditorResources.LibraryExplorer_ReturnsNothing));
                                    }
                                });
                            });
                        });
                    }
                });
            }