diff --git a/windows/src/developer/TIKE/dialogs/UfrmOptions.dfm b/windows/src/developer/TIKE/dialogs/UfrmOptions.dfm index c42615d925..8f8ecf9a57 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmOptions.dfm +++ b/windows/src/developer/TIKE/dialogs/UfrmOptions.dfm @@ -2,7 +2,6 @@ inherited frmOptions: TfrmOptions Left = 336 Top = 191 HelpContext = 1241 - ActiveControl = lbColours BorderIcons = [biSystemMenu, biHelp] BorderStyle = bsDialog Caption = 'Options' @@ -20,15 +19,11 @@ inherited frmOptions: TfrmOptions Top = 8 Width = 425 Height = 392 - ActivePage = tabColours + ActivePage = tabEditor TabOrder = 0 object tabGeneral: TTabSheet Caption = 'General' ImageIndex = 2 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object gbStartup: TGroupBox Left = 8 Top = 8 @@ -114,10 +109,6 @@ inherited frmOptions: TfrmOptions end object tabEditor: TTabSheet Caption = 'Editor' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object lblIndentSize: TLabel Left = 8 Top = 60 @@ -126,6 +117,21 @@ inherited frmOptions: TfrmOptions Caption = '&Indent size' FocusControl = editIndentSize end + object lblEditorTheme: TLabel + Left = 3 + Top = 162 + Width = 62 + Height = 13 + Caption = 'Editor &theme:' + end + object lblEditorCustomTheme: TLabel + Left = 120 + Top = 186 + Width = 187 + Height = 13 + AutoSize = False + Caption = '(custom theme filename)' + end object chkUseTab: TCheckBox Left = 8 Top = 12 @@ -153,7 +159,7 @@ inherited frmOptions: TfrmOptions object panFontSample: TPanel Left = 120 Top = 96 - Width = 125 + Width = 187 Height = 25 BevelOuter = bvLowered Caption = '' @@ -171,7 +177,7 @@ inherited frmOptions: TfrmOptions object panQuotedFontSample: TPanel Left = 120 Top = 128 - Width = 125 + Width = 187 Height = 25 BevelOuter = bvLowered Caption = '' @@ -185,391 +191,19 @@ inherited frmOptions: TfrmOptions Caption = '&Link quoted font size to primary font size' TabOrder = 6 end - end - object tabColours: TTabSheet - Caption = 'Colours' - ImageIndex = 1 - object panCol1: TPaintPanel - Left = 176 - Top = 8 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clBlack - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False - TabOrder = 0 - end - object lbColours: TListBox - Left = 4 - Top = 24 - Width = 121 - Height = 145 - ItemHeight = 13 - TabOrder = 1 - end - object panCol2: TPaintPanel - Tag = 1 - Left = 204 - Top = 8 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clMaroon - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False - TabOrder = 2 - end - object panCol3: TPaintPanel - Tag = 2 - Left = 232 - Top = 8 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clGreen - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False - TabOrder = 3 - end - object panCol4: TPaintPanel - Tag = 3 - Left = 260 - Top = 8 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clOlive - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False - TabOrder = 4 - end - object panCol5: TPaintPanel - Tag = 4 - Left = 176 - Top = 36 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clNavy - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False - TabOrder = 5 - end - object panCol6: TPaintPanel - Tag = 5 - Left = 204 - Top = 36 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clPurple - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False - TabOrder = 6 - end - object panCol7: TPaintPanel - Tag = 6 - Left = 232 - Top = 36 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clTeal - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False + object cbEditorTheme: TComboBox + Left = 120 + Top = 159 + Width = 187 + Height = 21 + Style = csDropDownList TabOrder = 7 - end - object panCol8: TPaintPanel - Tag = 7 - Left = 260 - Top = 36 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clGray - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False - TabOrder = 8 - end - object panCol9: TPaintPanel - Tag = 8 - Left = 176 - Top = 64 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clSilver - Ctl3D = False - ParentCtl3D = False - TabOrder = 9 - end - object panCol10: TPaintPanel - Tag = 9 - Left = 204 - Top = 64 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clRed - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False - TabOrder = 10 - end - object panCol11: TPaintPanel - Tag = 10 - Left = 232 - Top = 64 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clLime - Ctl3D = False - ParentCtl3D = False - TabOrder = 11 - end - object panCol12: TPaintPanel - Tag = 11 - Left = 260 - Top = 64 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clYellow - Ctl3D = False - ParentCtl3D = False - TabOrder = 12 - end - object panCol13: TPaintPanel - Tag = 12 - Left = 176 - Top = 92 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clBlue - Ctl3D = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWhite - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentCtl3D = False - ParentFont = False - TabOrder = 13 - end - object panCol14: TPaintPanel - Tag = 13 - Left = 204 - Top = 92 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clFuchsia - Ctl3D = False - ParentCtl3D = False - TabOrder = 14 - end - object panCol15: TPaintPanel - Tag = 14 - Left = 232 - Top = 92 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clAqua - Ctl3D = False - ParentCtl3D = False - TabOrder = 15 - end - object panCol16: TPaintPanel - Tag = 15 - Left = 260 - Top = 92 - Width = 25 - Height = 25 - BevelOuter = bvLowered - Caption = 'FG' - Color = clWhite - Ctl3D = False - ParentCtl3D = False - TabOrder = 16 - end - object cmdResetSelected: TButton - Left = 4 - Top = 176 - Width = 85 - Height = 25 - Caption = '&Reset selected' - TabOrder = 17 - end - object cmdResetAll: TButton - Left = 4 - Top = 208 - Width = 85 - Height = 25 - Caption = 'Reset &all' - TabOrder = 18 - end - object gbColourStyle: TGroupBox - Left = 296 - Top = 4 - Width = 113 - Height = 77 - Caption = 'Text attributes' - TabOrder = 19 - object chkColoursBold: TCheckBox - Left = 8 - Top = 16 - Width = 41 - Height = 17 - Caption = '&Bold' - TabOrder = 0 - end - object chkColoursItalic: TCheckBox - Left = 8 - Top = 34 - Width = 45 - Height = 17 - Caption = '&Italic' - TabOrder = 1 - end - object chkColoursUnderline: TCheckBox - Left = 8 - Top = 52 - Width = 69 - Height = 17 - Caption = '&Underline' - TabOrder = 2 - end - end - object pmSyntaxExample: TMemo - Left = 132 - Top = 124 - Width = 277 - Height = 113 - Cursor = crIBeam - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Courier New' - Font.Style = [] - Lines.Strings = ( - 'c Syntax Highlighting' - 'NAME "Syntax Highlight"' - '' - 'begin Unicode > use(main)' - '' - 'U+00FC + '#39'A'#39' > U+1124' - 'd225 + '#39'B'#39' > beep') - ParentFont = False - ReadOnly = True - ScrollBars = ssVertical - TabOrder = 20 - end - object chkUseSyntaxHighlighting: TCheckBox - Left = 4 - Top = 4 - Width = 137 - Height = 17 - Caption = 'Use &Syntax Highlighting' - Checked = True - State = cbChecked - TabOrder = 21 - end - object chkPlainBG: TCheckBox - Left = 296 - Top = 84 - Width = 117 - Height = 17 - Caption = '&Plain background' - TabOrder = 22 - end - object chkPlainFG: TCheckBox - Left = 296 - Top = 103 - Width = 113 - Height = 17 - Caption = 'Plain &foreground' - TabOrder = 23 + OnClick = cbEditorThemeClick end end object tabDebugger: TTabSheet Caption = 'Debugger' ImageIndex = 3 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object gbDebuggerSettings: TGroupBox Left = 8 Top = 8 @@ -646,10 +280,6 @@ inherited frmOptions: TfrmOptions object tabCharMap: TTabSheet Caption = 'Character Map' ImageIndex = 4 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object gbCharMapCharacterLookups: TGroupBox Left = 8 Top = 8 @@ -755,4 +385,12 @@ inherited frmOptions: TfrmOptions Left = 132 Top = 404 end + object dlgBrowseEditorTheme: TOpenDialog + DefaultExt = 'json' + Filter = 'Custom theme JSON (*.json)|*.json|All files (*.*)|*.*' + Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing] + Title = 'Browse for Editor Theme' + Left = 212 + Top = 403 + end end diff --git a/windows/src/developer/TIKE/dialogs/UfrmOptions.pas b/windows/src/developer/TIKE/dialogs/UfrmOptions.pas index ecbb03ab7d..d171f857c6 100644 --- a/windows/src/developer/TIKE/dialogs/UfrmOptions.pas +++ b/windows/src/developer/TIKE/dialogs/UfrmOptions.pas @@ -47,46 +47,18 @@ type TfrmOptions = class(TTikeForm) pages: TPageControl; tabEditor: TTabSheet; - tabColours: TTabSheet; cmdCancel: TButton; cmdOK: TButton; chkUseTab: TCheckBox; editIndentSize: TEdit; lblIndentSize: TLabel; - panCol1: TPaintPanel; - lbColours: TListBox; - panCol2: TPaintPanel; - panCol3: TPaintPanel; - panCol4: TPaintPanel; - panCol5: TPaintPanel; - panCol6: TPaintPanel; - panCol7: TPaintPanel; - panCol8: TPaintPanel; - panCol9: TPaintPanel; - panCol10: TPaintPanel; - panCol11: TPaintPanel; - panCol12: TPaintPanel; - panCol13: TPaintPanel; - panCol14: TPaintPanel; - panCol15: TPaintPanel; - panCol16: TPaintPanel; - cmdResetSelected: TButton; - cmdResetAll: TButton; - gbColourStyle: TGroupBox; - chkColoursBold: TCheckBox; - chkColoursItalic: TCheckBox; - chkColoursUnderline: TCheckBox; - chkUseSyntaxHighlighting: TCheckBox; cmdDefaultFont: TButton; dlgFonts: TFontDialog; panFontSample: TPanel; - chkPlainBG: TCheckBox; - chkPlainFG: TCheckBox; cmdQuotedFont: TButton; panQuotedFontSample: TPanel; chkLinkFontSizes: TCheckBox; tabGeneral: TTabSheet; - pmSyntaxExample: TMemo; gbStartup: TGroupBox; chkShowStartupDialog: TCheckBox; tabDebugger: TTabSheet; @@ -117,6 +89,10 @@ type cmdSMTPSettings: TButton; chkOpenKeyboardFilesInSourceView: TCheckBox; cmdResetToolWindows: TButton; + cbEditorTheme: TComboBox; + lblEditorTheme: TLabel; + lblEditorCustomTheme: TLabel; + dlgBrowseEditorTheme: TOpenDialog; procedure FormCreate(Sender: TObject); procedure cmdOKClick(Sender: TObject); procedure cmdDefaultFontClick(Sender: TObject); @@ -127,9 +103,9 @@ type procedure editWebHostDefaultPortKeyPress(Sender: TObject; var Key: Char); procedure cmdSMTPSettingsClick(Sender: TObject); procedure cmdResetToolWindowsClick(Sender: TObject); + procedure cbEditorThemeClick(Sender: TObject); private FDefaultFont, FQuotedFont: TFont; - panCol: array[1..16] of TPaintPanel; { Private declarations } protected function GetHelpTopic: string; override; @@ -142,8 +118,11 @@ implementation {$R *.DFM} uses + System.JSON, + Keyman.Developer.System.HelpTopics, + JsonUtil, JvDockControlForm, OnlineConstants, RedistFiles, @@ -160,37 +139,16 @@ uses { General functions } + procedure TfrmOptions.FormCreate(Sender: TObject); var deffont, altfont: string; + i: Integer; begin inherited; pages.ActivePage := tabGeneral; - { Initialise Colours tab } - panCol[1] := panCol1; - panCol[2] := panCol2; - panCol[3] := panCol3; - panCol[4] := panCol4; - panCol[5] := panCol5; - panCol[6] := panCol6; - panCol[7] := panCol7; - panCol[8] := panCol8; - panCol[9] := panCol9; - panCol[10] := panCol10; - panCol[11] := panCol11; - panCol[12] := panCol12; - panCol[13] := panCol13; - panCol[14] := panCol14; - panCol[15] := panCol15; - panCol[16] := panCol16; - - lbColours.ItemIndex := 0; - - chkUseSyntaxHighlighting.Checked := False; - chkUseSyntaxHighlighting.Enabled := False; - { Initialise Editor tab } FDefaultFont := TFont.Create; @@ -198,9 +156,13 @@ begin SetFontFromString(FDefaultFont, ''); SetFontFromString(FQuotedFont, ''); + for i := 0 to High(SDefaultEditorThemes) do + cbEditorTheme.Items.Add(SDefaultEditorThemes[i].Desc); + cbEditorTheme.Items.Add('Custom...'); + with FKeymanDeveloperOptions do begin - chkUseOldDebugger.Checked := UseOldDebugger; // or not chkUseOldDebugger.Enabled; + chkUseOldDebugger.Checked := UseOldDebugger; chkUseTab.Checked := UseTabChar; chkLinkFontSizes.Checked := LinkFontSizes; @@ -209,9 +171,7 @@ begin chkDebuggerShowStoreOffset.Checked := DebuggerShowStoreOffset; chkDebuggerAutoRecompile.Checked := DebuggerAutoRecompileWithDebugInfo; - chkShowStartupDialog.Checked := ShowStartupDialog;// or not chkShowStartupDialog.Enabled; - - //chkShowStartupHelperDialog.Checked := ShowStartupHelperDialog; + chkShowStartupDialog.Checked := ShowStartupDialog; chkCharMapAutoLookup.Checked := CharMapAutoLookup; chkCharMapDisableDatabaseLookups.Checked := CharMapDisableDatabaseLookups; @@ -226,24 +186,20 @@ begin editWebHostDefaultPort.Text := IntToStr(WebHostDefaultPort); // I4021 -// cbTheme.ItemIndex := cbTheme.Items.IndexOf(DisplayTheme); // I4796 + lblEditorCustomTheme.Caption := ''; + if EditorTheme = '' then + cbEditorTheme.ItemIndex := 0 + else if IsDefaultEditorTheme(EditorTheme) then + cbEditorTheme.ItemIndex := DefaultEditorThemeItemIndex(EditorTheme) + else + begin + cbEditorTheme.ItemIndex := cbEditorTheme.Items.Count - 1; // custom + lblEditorCustomTheme.Caption := EditorTheme; + end; end; editDatabasePath.Text := FUnicodeData.DBPath; -{ with TRegistryErrorControlled.Create do - try - RootKey := HKEY_CURRENT_USER; - if OpenKeyReadOnly(SRegKey_KeymanDeveloper) then - chkFileAssociations.Checked := - not ValueExists(SRegValue_NoCheckAssociations) or - (ReadString(SRegValue_NoCheckAssociations) = '0') - else - chkFileAssociations.Checked := True; - finally - Free; - end;} - with TRegistryErrorControlled.Create do // I2890 try RootKey := HKEY_CURRENT_USER; @@ -265,8 +221,6 @@ begin chkCharMapDisableDatabaseLookups.Checked := True; chkCharMapDisableDatabaseLookups.Enabled := False; - //cmdCharMapRebuildDatabase.Enabled := False; - //gbCharMapCharacterDatabase.Enabled := False; end; procedure TfrmOptions.FormDestroy(Sender: TObject); @@ -290,6 +244,9 @@ begin UseTabChar := chkUseTab.Checked; IndentSize := StrToIntDef(editIndentSize.Text, 4); LinkFontSizes := chkLinkFontSizes.Checked; + if cbEditorTheme.ItemIndex = cbEditorTheme.Items.Count - 1 + then EditorTheme := lblEditorCustomTheme.Caption + else EditorTheme := SDefaultEditorThemes[cbEditorTheme.ItemIndex].Name; DebuggerBreakWhenExitingLine := chkDebuggerBreakWhenExitingLine.Checked; DebuggerSingleStepAfterBreak := chkDebuggerSingleStepAfterBreak.Checked; @@ -322,8 +279,8 @@ begin Free; end; - for i := 0 to frmKeymanDeveloper.MDIChildCount - 1 do - PostMessage(frmKeymanDeveloper.MDIChildren[i].Handle, WM_USER_SYNTAXCOLOURCHANGE, 0, 0); + for i := 0 to Screen.FormCount - 1 do + PostMessage(Screen.Forms[i].Handle, WM_USER_SYNTAXCOLOURCHANGE, 0, 0); ModalResult := mrOk; end; @@ -389,6 +346,45 @@ begin end; end; +procedure TfrmOptions.cbEditorThemeClick(Sender: TObject); +var + j: TJSONObject; + offset: Integer; +begin + inherited; + if cbEditorTheme.ItemIndex = cbEditorTheme.Items.Count - 1 then + begin + dlgBrowseEditorTheme.FileName := lblEditorCustomTheme.Caption; + if not dlgBrowseEditorTheme.Execute then + begin + cbEditorTheme.ItemIndex := 0; + lblEditorCustomTheme.Caption := ''; + Exit; + end; + + // Validate the theme file, somewhat anyway + + try + j := LoadJSONFromFile(dlgBrowseEditorTheme.FileName, offset); + if j = nil then + raise Exception.CreateFmt('An error was encountered at offset %d', [offset]); + j.Free; + except + on E:Exception do + begin + ShowMessage('The file '+dlgBrowseEditorTheme.FileName+' is not a valid JSON file: '+E.Message); + cbEditorTheme.ItemIndex := 0; + lblEditorCustomTheme.Caption := ''; + Exit; + end; + end; + + lblEditorCustomTheme.Caption := dlgBrowseEditorTheme.FileName; + end + else + lblEditorCustomTheme.Caption := ''; +end; + procedure TfrmOptions.cmdCharMapRebuildDatabaseClick(Sender: TObject); var FUnicodeSourcePath: WideString; diff --git a/windows/src/developer/TIKE/http/Keyman.Developer.System.HttpServer.App.pas b/windows/src/developer/TIKE/http/Keyman.Developer.System.HttpServer.App.pas index 57ff80339c..46263a2b1d 100644 --- a/windows/src/developer/TIKE/http/Keyman.Developer.System.HttpServer.App.pas +++ b/windows/src/developer/TIKE/http/Keyman.Developer.System.HttpServer.App.pas @@ -231,6 +231,8 @@ procedure TAppHttpResponder.RespondSettings(doc: string; AContext: TIdContext; procedure RespondEditorSettings; var root: TJSONObject; + offset: Integer; + theme: TJSONObject; begin // Respond as JSON @@ -238,11 +240,32 @@ procedure TAppHttpResponder.RespondSettings(doc: string; AContext: TIdContext; try // Basic settings - tabs - // TODO: This is technically not thread safe. + // TODO: FKeymanDeveloperOptins is technically not thread safe. root.AddPair('useTabChar', TJSONBool.Create(FKeymanDeveloperOptions.UseTabChar)); root.AddPair('indentSize', TJSONNumber.Create(FKeymanDeveloperOptions.IndentSize)); - // Theme data + // Specify a theme by name or as a JSON object, loaded from a custom theme file + + if FKeymanDeveloperOptions.EditorTheme <> '' then + begin + if TKeymanDeveloperOptions.IsDefaultEditorTheme(FKeymanDeveloperOptions.EditorTheme) then + begin + root.AddPair('theme', FKeymanDeveloperOptions.EditorTheme); + end + else + begin + if FileExists(FKeymanDeveloperOptions.EditorTheme) then + begin + try + theme := LoadJSONFromFile(FKeymanDeveloperOptions.EditorTheme, offset); + if theme <> nil then + root.AddPair('theme', theme); + except + on E:Exception do ; // We will ignore file and json errors and use default theme + end; + end; + end; + end; AResponseInfo.ContentType := 'application/json'; AResponseInfo.CharSet := 'UTF-8'; diff --git a/windows/src/developer/TIKE/main/KeymanDeveloperOptions.pas b/windows/src/developer/TIKE/main/KeymanDeveloperOptions.pas index ad0d2d0ac7..f5c9fcfc78 100644 --- a/windows/src/developer/TIKE/main/KeymanDeveloperOptions.pas +++ b/windows/src/developer/TIKE/main/KeymanDeveloperOptions.pas @@ -58,6 +58,7 @@ type FTestEmailAddresses: string; // I4506 FOpenKeyboardFilesInSourceView: Boolean; // I4751 FDisplayTheme: string; + FEditorTheme: string; procedure CloseRegistry; procedure OpenRegistry; function regReadString(const nm, def: string): string; @@ -69,10 +70,15 @@ type public procedure Read; procedure Write; + + class function DefaultEditorThemeItemIndex(s: string): Integer; + class function IsDefaultEditorTheme(s: string): Boolean; + property UseTabChar: Boolean read FUseTabChar write FUseTabChar; property IndentSize: Integer read FIndentSize write FIndentSize; property LinkFontSizes: Boolean read FLinkFontSizes write FLinkFontSizes; property UseOldDebugger: Boolean read FUseOldDebugger write FUseOldDebugger; + property EditorTheme: string read FEditorTheme write FEditorTheme; property CharMapAutoLookup: Boolean read FCharMapAutoLookup write FCharMapAutoLookup; property CharMapDisableDatabaseLookups: Boolean read FCharMapDisableDatabaseLookups write FCharMapDisableDatabaseLookups; @@ -101,6 +107,18 @@ function FKeymanDeveloperOptions: TKeymanDeveloperOptions; //procedure CreateKeymanDeveloperOptions; //procedure DestroyKeymanDeveloperOptions; +type + TDefaultEditorTheme = record + Name: string; + Desc: string; + end; +const + SDefaultEditorThemes: array[0..2] of TDefaultEditorTheme = ( + (Name: 'vs'; Desc: 'Light (vs)'), + (Name: 'vs-dark'; Desc: 'Dark (vs-dark)'), + (Name: 'hc-black'; Desc: 'High Constrast (hc-black)') + ); + implementation uses @@ -152,6 +170,7 @@ begin FLinkFontSizes := regReadBool(SRegValue_IDEOptLinkFontSizes, True); FIndentSize := regReadInt (SRegValue_IDEOptIndentSize, 4); FUseOldDebugger := regReadBool(SRegValue_IDEOptUseOldDebugger, False); + FEditorTheme := regReadString(SRegValue_IDEOptEditorTheme, ''); FDebuggerBreakWhenExitingLine := regReadBool(SRegValue_IDEOptDebuggerBreakWhenExitingLine, True); FDebuggerSingleStepAfterBreak := regReadBool(SRegValue_IDEOptDebuggerSingleStepAfterBreak, False); @@ -190,6 +209,7 @@ begin regWriteBool(SRegValue_IDEOptLinkFontSizes, FLinkFontSizes); regWriteInt (SRegValue_IDEOptIndentSize, FIndentSize); regWriteBool(SRegValue_IDEOptUseOldDebugger, FUseOldDebugger); + regWriteString(SRegValue_IDEOptEditorTheme, FEditorTheme); regWriteBool(SRegValue_IDEOptDebuggerBreakWhenExitingLine, FDebuggerBreakWhenExitingLine); regWriteBool(SRegValue_IDEOptDebuggerSingleStepAfterBreak, FDebuggerSingleStepAfterBreak); @@ -263,6 +283,22 @@ begin end; end; +class function TKeymanDeveloperOptions.DefaultEditorThemeItemIndex(s: string): Integer; +var + i: Integer; +begin + for i := Low(SDefaultEditorThemes) to High(SDefaultEditorThemes) do + if SDefaultEditorThemes[i].Name = s then + Exit(i); + + Result := -1; +end; + +class function TKeymanDeveloperOptions.IsDefaultEditorTheme(s: string): Boolean; +begin + Result := DefaultEditorThemeItemIndex(s) >= 0; +end; + initialization finalization DestroyKeymanDeveloperOptions; diff --git a/windows/src/developer/TIKE/main/UframeTextEditor.pas b/windows/src/developer/TIKE/main/UframeTextEditor.pas index 4ee6f241ce..7a3a63ef76 100644 --- a/windows/src/developer/TIKE/main/UframeTextEditor.pas +++ b/windows/src/developer/TIKE/main/UframeTextEditor.pas @@ -88,6 +88,7 @@ type procedure WMUser_TextEditor_Command(var Message: TMessage); message WM_USER_TextEditor_Command; procedure WMUser_FireCommand(var Message: TMessage); message WM_USER_FireCommand; + procedure WMUser_SyntaxColourChange(var Message: TMessage); message WM_USER_SYNTAXCOLOURCHANGE; procedure FireCommand(const commands: TStringList); procedure LoadFileInBrowser(const AData: string); procedure UpdateInsertState(const AMode: string); @@ -746,6 +747,11 @@ begin params.Free; end; +procedure TframeTextEditor.WMUser_SyntaxColourChange(var Message: TMessage); +begin + ExecuteCommand('reloadSettings'); +end; + procedure TframeTextEditor.WMUser_TextEditor_Command(var Message: TMessage); begin case Message.wParam of diff --git a/windows/src/developer/TIKE/xml/app/editor/editor.js b/windows/src/developer/TIKE/xml/app/editor/editor.js index 7b8a705763..ef29716201 100644 --- a/windows/src/developer/TIKE/xml/app/editor/editor.js +++ b/windows/src/developer/TIKE/xml/app/editor/editor.js @@ -28,8 +28,6 @@ async function loadSettings() { mode = 'keyman'; } - const settings = loadSettings(); - /** Initialize the editor */ @@ -38,99 +36,83 @@ async function loadSettings() { 'vs': '../lib/monaco/min/vs' } }); - settings.then(function(_settings){ - require(['vs/editor/editor.main','language.keyman'], function (_editor, _language) { + require(['vs/editor/editor.main','language.keyman'], function (_editor, _language) { - _settings = $.extend({ - useTabChar: false, - indentSize: 4 - }, _settings); + // + // Register Keyman .kmn tokens provider and language formatter + // https://github.com/Microsoft/monaco-editor/blob/master/test/playground.generated/extending-language-services-custom-languages.html + // + + monaco.languages.register({ id: 'keyman' }); + monaco.languages.setMonarchTokensProvider('keyman', _language.language); + + // + // Create editor and load source file + // - // - // Define a custom theme - // + editor = monaco.editor.create(document.getElementById('editor'), { + language: mode, + minimap: { + enabled: false + }, + glyphMargin: true, + lineNumbersMinChars: 2, + disableMonospaceOptimizations: true + }); - if(_settings.theme) { - //monaco.editor.setTheme(); + $.get("/app/source/file", + { + Filename: filename + }, + function (response) { + context.loading = true; + editor.setValue(response); + context.loading = false; + }, + "text" + ); + + // + // Set initial fonts + // + + context.setFonts({ + codeFont: { name: params.get('codeFontName'), size: params.get('codeFontSize') }, + charFont: { name: params.get('charFontName'), size: params.get('charFontSize') } + }); + + // + // Setup callbacks + // + + const model = editor.getModel(); + + context.reloadSettings(); + + model.onDidChangeContent(() => { + // Even when loading, we post back the data to the backend so we have an original version + $.post("/app/source/file", { + Filename: filename, + Data: model.getValue() + // delta.start, delta.end, delta.lines, delta.action + }); + if (!context.loading) { + context.highlightError(); // clear the selected error + command('modified'); + updateState(); } + }); - // - // Register Keyman .kmn tokens provider and language formatter - // https://github.com/Microsoft/monaco-editor/blob/master/test/playground.generated/extending-language-services-custom-languages.html - // - - monaco.languages.register({ id: 'keyman' }); - monaco.languages.setMonarchTokensProvider('keyman', _language.language); - - // - // Create editor and load source file - // - - editor = monaco.editor.create(document.getElementById('editor'), { - language: mode, - minimap: { - enabled: false - }, - glyphMargin: true, - useTabStops: _settings.useTabChar, - lineNumbersMinChars: 2, - disableMonospaceOptimizations: true - }); - - $.get("/app/source/file", - { - Filename: filename - }, - function (response) { - context.loading = true; - editor.setValue(response); - context.loading = false; - }, - "text" - ); - - // - // Set initial fonts - // - - context.setFonts({ - codeFont: { name: params.get('codeFontName'), size: params.get('codeFontSize') }, - charFont: { name: params.get('charFontName'), size: params.get('charFontSize') } - }); - - // - // Setup callbacks - // - - const model = editor.getModel(); - model.updateOptions({ - tabSize: _settings.indentSize - }); - - model.onDidChangeContent(() => { - // Even when loading, we post back the data to the backend so we have an original version - $.post("/app/source/file", { - Filename: filename, - Data: model.getValue() - // delta.start, delta.end, delta.lines, delta.action - }); - if (!context.loading) { - context.highlightError(); // clear the selected error - command('modified'); - updateState(); - } - }); - - editor.onDidChangeCursorPosition(updateState); - editor.onDidChangeCursorSelection(updateState); - editor.onMouseDown(e => { - if (e.target.type !== monaco.editor.MouseTargetType.GUTTER_GLYPH_MARGIN) { - return; - } - command('breakpoint-clicked,'+(e.target.position.lineNumber-1)); - }); + editor.onDidChangeCursorPosition(updateState); + editor.onDidChangeCursorSelection(updateState); + editor.onMouseDown(e => { + if (e.target.type !== monaco.editor.MouseTargetType.GUTTER_GLYPH_MARGIN) { + return; + } + command('breakpoint-clicked,'+(e.target.position.lineNumber-1)); }); }); + // // Search and replace interfaces // @@ -308,6 +290,45 @@ async function loadSettings() { }); }; + // + // Themes and settings + // + + context.reloadSettings = function () { + loadSettings().then(function(_settings) { + _settings = $.extend({ + useTabChar: false, + indentSize: 4 + }, _settings); + + // + // Define a custom theme if specified in the settings + // + + var themeName = 'vs'; + + if(_settings.theme) { + if(typeof _settings.theme == 'string') { + themeName = _settings.theme; + } else { + themeName = 'keyman-custom'; + monaco.editor.defineTheme(themeName, _settings.theme); + } + } + + monaco.editor.setTheme(themeName); + + editor.updateOptions({ + useTabStops: _settings.useTabChar + }); + + editor.model.updateOptions({ + tabSize: _settings.indentSize + }); + }); + } + + // // Printing // diff --git a/windows/src/global/delphi/general/JsonUtil.pas b/windows/src/global/delphi/general/JsonUtil.pas index 8ea91c05a2..252b1a2fa1 100644 --- a/windows/src/global/delphi/general/JsonUtil.pas +++ b/windows/src/global/delphi/general/JsonUtil.pas @@ -1,18 +1,18 @@ (* Name: JsonUtil Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 10 Oct 2014 Modified Date: 30 May 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 10 Oct 2014 - mcdurdin - I4440 - V9.0 - If more than one language listed for a keyboard, the JSON file becomes invalid 30 May 2015 - mcdurdin - I4727 - Changing font while touch layout editor in Code mode results in broken \ rules *) @@ -31,6 +31,7 @@ procedure PrettyPrintJSON(JSONValue: TJSONValue; OutputStrings: TStrings; indent function ParseJSONValue(const Data: string; var Offset: Integer): TJSONObject; // I4035 // I4260 function JSONDateToDateTime(const Value: string; var DateTime: TDateTime): Boolean; function DateTimeToJSONDate(ADateTime: TDateTime): string; +function LoadJSONFromFile(const Filename: string; var Offset: Integer): TJSONObject; implementation @@ -159,5 +160,19 @@ begin end; end; +function LoadJSONFromFile(const Filename: string; var Offset: Integer): TJSONObject; +var + ss: TStringStream; +begin + ss := TStringStream.Create('', TEncoding.UTF8); + try + ss.LoadFromFile(Filename); + offset := 0; + Result := ParseJSONValue(ss.DataString, offset); + finally + ss.Free; + end; +end; + end. diff --git a/windows/src/global/delphi/general/RegistryKeys.pas b/windows/src/global/delphi/general/RegistryKeys.pas index 92779cc0e8..b03c48065e 100644 --- a/windows/src/global/delphi/general/RegistryKeys.pas +++ b/windows/src/global/delphi/general/RegistryKeys.pas @@ -375,6 +375,7 @@ const SRegValue_IDEOptUseSyntaxHighlighting = 'use syntax highlighting'; // CU SRegValue_IDEOptToolbarVisible = 'toolbar visible'; // CU SRegValue_IDEOptUseOldDebugger = 'use old debugger'; // CU + SRegValue_IDEOptEditorTheme = 'editor theme'; // CU SRegValue_IDEOptShowStartupDialog = 'show startup dialog'; // CU //SRegValue_IDEOptShowStartupHelperDialog = 'show startup helper dialog'; // CU