Просмотр исходного кода

Workbench UI: theme switcher and interface font size

- Modula-2: Switch Color Theme (quick-pick) and Toggle Light/Dark Theme,
  wired into the Modula-2 menu
- modula2.ui.interfaceFontSize preference (10-24px, default 13) applied
  to menus and message notifications via a frontend contribution
- workbench tsconfig: enable decorator metadata like modula2-compiler
Eric Streit 1 неделя назад
Родитель
Сommit
c0f651c9ef

+ 44 - 0
extensions/modula2-workbench/src/browser/modula2-theme-commands.ts

@@ -0,0 +1,44 @@
+import { inject, injectable } from '@theia/core/shared/inversify';
+import { Command, CommandContribution, CommandRegistry } from '@theia/core/lib/common';
+import { ThemeService } from '@theia/core/lib/browser/theming';
+import { QuickInputService } from '@theia/core/lib/common/quick-pick-service';
+
+export const SwitchThemeCommand: Command = Command.toLocalizedCommand({
+  id: 'modula2.switchTheme', label: 'Switch Color Theme', category: 'Modula-2',
+});
+
+export const ToggleThemeCommand: Command = Command.toLocalizedCommand({
+  id: 'modula2.toggleTheme', label: 'Toggle Light/Dark Theme', category: 'Modula-2',
+});
+
+@injectable()
+export class Modula2ThemeCommands implements CommandContribution {
+  @inject(ThemeService) protected readonly themeService: ThemeService;
+  @inject(QuickInputService) protected readonly quickInput: QuickInputService;
+
+  registerCommands(commands: CommandRegistry): void {
+    commands.registerCommand(SwitchThemeCommand, { execute: () => this.switchTheme() });
+    commands.registerCommand(ToggleThemeCommand, { execute: () => this.toggleTheme() });
+  }
+
+  protected async switchTheme(): Promise<void> {
+    const current = this.themeService.getCurrentTheme();
+    const items = this.themeService.getThemes().map(theme => ({
+      label: theme.label,
+      description: theme.id === current.id ? 'current' : theme.type,
+      value: theme.id,
+    }));
+    const picked = await this.quickInput.showQuickPick(items, { placeholder: 'Select a color theme' });
+    if (picked) {
+      this.themeService.setCurrentTheme(picked.value);
+    }
+  }
+
+  protected toggleTheme(): void {
+    const current = this.themeService.getCurrentTheme();
+    const isLight = current.type === 'light' || current.type === 'hcLight';
+    const target = this.themeService.getThemes().find(theme => isLight ? theme.type === 'dark' : theme.type === 'light')
+      ?? this.themeService.defaultTheme;
+    this.themeService.setCurrentTheme(target.id);
+  }
+}

+ 44 - 0
extensions/modula2-workbench/src/browser/modula2-ui-font-contribution.ts

@@ -0,0 +1,44 @@
+import { inject, injectable } from '@theia/core/shared/inversify';
+import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application-contribution';
+import { PreferenceService } from '@theia/core/lib/common/preferences/preference-service';
+import { UI_FONT_SIZE } from './modula2-ui-preferences';
+
+const STYLE_ID = 'modula2-ui-font-size';
+const DEFAULT_SIZE = 13;
+
+@injectable()
+export class Modula2UIFontContribution implements FrontendApplicationContribution {
+  @inject(PreferenceService) protected readonly prefs: PreferenceService;
+
+  onStart(): void {
+    this.apply(this.currentSize());
+    this.prefs.onPreferenceChanged(event => {
+      if (event.preferenceName === UI_FONT_SIZE) {
+        this.apply(this.currentSize());
+      }
+    });
+  }
+
+  protected currentSize(): number {
+    const value = this.prefs.get<number>(UI_FONT_SIZE);
+    if (typeof value !== 'number' || !Number.isFinite(value)) {
+      return DEFAULT_SIZE;
+    }
+    return Math.min(24, Math.max(10, Math.round(value)));
+  }
+
+  protected apply(px: number): void {
+    let element = document.getElementById(STYLE_ID) as HTMLStyleElement | null;
+    if (!element) {
+      element = document.createElement('style');
+      element.id = STYLE_ID;
+      document.head.appendChild(element);
+    }
+    element.textContent = [
+      `.p-MenuBar, .p-Menu, .lm-MenuBar, .lm-Menu { font-size: ${px}px !important; }`,
+      '.theia-notifications-container, .theia-notification-center,',
+      '.theia-notification-list-item, .theia-notification-message,',
+      `.theia-message, .theia-toast { font-size: ${px}px !important; }`,
+    ].join('\n');
+  }
+}

+ 16 - 0
extensions/modula2-workbench/src/browser/modula2-ui-preferences.ts

@@ -0,0 +1,16 @@
+import { PreferenceSchema } from '@theia/core/lib/common/preferences/preference-schema';
+
+export const UI_FONT_SIZE = 'modula2.ui.interfaceFontSize';
+
+export const modula2UIPreferenceSchema: PreferenceSchema = {
+  title: 'Modula-2',
+  properties: {
+    [UI_FONT_SIZE]: {
+      type: 'number',
+      default: 13,
+      minimum: 10,
+      maximum: 24,
+      description: 'Font size in pixels for IDE menus, context menus and message notifications.',
+    },
+  },
+};

+ 11 - 1
extensions/modula2-workbench/src/browser/modula2-workbench-frontend-module.ts

@@ -1,5 +1,10 @@
 import { ContainerModule } from '@theia/core/shared/inversify';
 import { Command, CommandContribution, CommandRegistry, MenuContribution, MenuModelRegistry } from '@theia/core/lib/common';
+import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application-contribution';
+import { PreferenceContribution } from '@theia/core/lib/common/preferences/preference-schema';
+import { modula2UIPreferenceSchema } from './modula2-ui-preferences';
+import { Modula2ThemeCommands, SwitchThemeCommand, ToggleThemeCommand } from './modula2-theme-commands';
+import { Modula2UIFontContribution } from './modula2-ui-font-contribution';
 
 const category = 'Modula-2';
 
@@ -10,7 +15,7 @@ const Commands = {
 class CommandsContribution implements CommandContribution {
   registerCommands(commands: CommandRegistry): void {
     commands.registerCommand(Commands.about, {
-      execute: () => window.alert('Modula-2 IDE\\n\\nGNU Modula-2 workbench for Eclipse Theia.')
+      execute: () => window.alert('Modula-2 IDE\n\nGNU Modula-2 workbench for Eclipse Theia.')
     });
   }
 }
@@ -20,10 +25,15 @@ class MenusContribution implements MenuContribution {
     const submenu = ['menubar', 'modula2'];
     menus.registerSubmenu(submenu, 'Modula-2');
     menus.registerMenuAction(submenu, { commandId: Commands.about.id });
+    menus.registerMenuAction(submenu, { commandId: SwitchThemeCommand.id });
+    menus.registerMenuAction(submenu, { commandId: ToggleThemeCommand.id });
   }
 }
 
 export default new ContainerModule(bind => {
+  bind(PreferenceContribution).toConstantValue({ schema: modula2UIPreferenceSchema });
   bind(CommandContribution).to(CommandsContribution).inSingletonScope();
+  bind(CommandContribution).to(Modula2ThemeCommands).inSingletonScope();
+  bind(FrontendApplicationContribution).to(Modula2UIFontContribution).inSingletonScope();
   bind(MenuContribution).to(MenusContribution).inSingletonScope();
 });

+ 2 - 0
extensions/modula2-workbench/tsconfig.json

@@ -2,6 +2,8 @@
   "compilerOptions": {
     "target": "ES2022", "module": "commonjs", "lib": ["ES2022"],
     "outDir": "lib", "rootDir": "src", "strict": true,
+    "experimentalDecorators": true, "emitDecoratorMetadata": true,
+    "strictPropertyInitialization": false,
     "sourceMap": true, "esModuleInterop": true, "skipLibCheck": true
   },
   "include": ["src/**/*.ts"]