chore: import upstream snapshot with attribution
@@ -0,0 +1,101 @@
|
||||
---
|
||||
name: add-locale
|
||||
description: Adds a new locale to RunCat365. Use when adding a new language, creating a Strings.{lc}.resx file, registering a CultureInfo, or extending SupportedLanguage.cs with a new entry.
|
||||
argument-hint: <language name or BCP 47 code>
|
||||
---
|
||||
|
||||
# Add a New Locale to RunCat365
|
||||
|
||||
Modify 3 files to add support for `$ARGUMENTS`. French (`fr`) is used as an example.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Create `RunCat365/Properties/Strings.{lc}.resx`
|
||||
|
||||
Read `RunCat365/Properties/Strings.resx` for all keys and their English values.
|
||||
Use `Strings.es.resx` as the structural template.
|
||||
|
||||
- File name: `Strings.{lc}.resx` (e.g. `Strings.fr.resx`)
|
||||
- Copy the XML header, schema, and `<resheader>` blocks verbatim from `Strings.es.resx`
|
||||
- Include every key from `Strings.resx` — no more, no less — with each `<value>` translated
|
||||
- Keep all attribute names, XML structure, and `<comment>` content in English; translate only `<value>` text
|
||||
- Verify every key from `Strings.resx` is present in the new file
|
||||
|
||||
### 2. Edit `RunCat365/SupportedLanguage.cs`
|
||||
|
||||
Keep the `SupportedLanguage` enum and every `switch` arm sorted **alphabetically by enum identifier** (e.g. `French` before `German` before `Japanese`). Insert the new language at its alphabetical position in each location below — do not append.
|
||||
|
||||
Add the language to the `SupportedLanguage` enum:
|
||||
|
||||
```csharp
|
||||
enum SupportedLanguage
|
||||
{
|
||||
English,
|
||||
French,
|
||||
Japanese,
|
||||
Spanish,
|
||||
}
|
||||
```
|
||||
|
||||
Add the ISO code to `GetCurrentLanguage()` (arms ordered by enum identifier, so `"fr"` appears before `"ja"` even though the ISO codes aren't themselves alphabetical):
|
||||
|
||||
```csharp
|
||||
return culture.TwoLetterISOLanguageName switch
|
||||
{
|
||||
"fr" => SupportedLanguage.French,
|
||||
"ja" => SupportedLanguage.Japanese,
|
||||
"es" => SupportedLanguage.Spanish,
|
||||
_ => SupportedLanguage.English,
|
||||
};
|
||||
```
|
||||
|
||||
Add the culture to `GetDefaultCultureInfo()`:
|
||||
|
||||
```csharp
|
||||
return language switch
|
||||
{
|
||||
SupportedLanguage.French => new CultureInfo("fr-FR"),
|
||||
SupportedLanguage.Japanese => new CultureInfo("ja-JP"),
|
||||
SupportedLanguage.Spanish => new CultureInfo("es-ES"),
|
||||
_ => new CultureInfo("en-US"),
|
||||
};
|
||||
```
|
||||
|
||||
Add the font to `GetFontName()` — use `"Consolas"` for Latin-script languages:
|
||||
|
||||
```csharp
|
||||
return language switch
|
||||
{
|
||||
SupportedLanguage.French => "Consolas",
|
||||
SupportedLanguage.Japanese => "Noto Sans JP",
|
||||
SupportedLanguage.Spanish => "Consolas",
|
||||
_ => "Consolas",
|
||||
};
|
||||
```
|
||||
|
||||
Add the full-width flag to `IsFullWidth()` — use `false` for Latin-script languages:
|
||||
|
||||
```csharp
|
||||
return language switch
|
||||
{
|
||||
SupportedLanguage.French => false,
|
||||
SupportedLanguage.Japanese => true,
|
||||
SupportedLanguage.Spanish => false,
|
||||
_ => false,
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Update `README.md`
|
||||
|
||||
Add the new language to the **Installation** → **Language:** list, preserving the existing alphabetical order by English display name (e.g. `French` between `English (default)` and `German`). Match the existing two-space indentation under the `- Language:` bullet.
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Created `Strings.{lc}.resx` with all keys translated
|
||||
- [ ] Added language to the `SupportedLanguage` enum
|
||||
- [ ] Added ISO code to `GetCurrentLanguage()`
|
||||
- [ ] Added culture to `GetDefaultCultureInfo()`
|
||||
- [ ] Added font to `GetFontName()`
|
||||
- [ ] Added full-width flag to `IsFullWidth()`
|
||||
- [ ] Added the language to the Installation language list in `README.md`
|
||||
- [ ] Built in Visual Studio and verified UI with OS language set to the target language
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
name: create-pr
|
||||
description: Creates a GitHub Pull Request for RunCat365 following the project's PR template. Use this skill whenever the user wants to open, submit, or create a PR, pull request, or wants to propose changes to the main branch.
|
||||
---
|
||||
|
||||
# Create a Pull Request for RunCat365
|
||||
|
||||
Follow these steps to create a PR that conforms to the `.github/pull_request_template.md`.
|
||||
|
||||
## Step 1: Gather branch information
|
||||
|
||||
Run these commands in parallel to understand the changes:
|
||||
|
||||
```bash
|
||||
git log main..HEAD --oneline
|
||||
git diff main..HEAD --stat
|
||||
git diff main..HEAD
|
||||
```
|
||||
|
||||
Also check the current branch name:
|
||||
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
## Step 2: Determine the PR type
|
||||
|
||||
Based on the diff, classify the change as exactly one of:
|
||||
|
||||
| Type | When to use |
|
||||
| --------------- | ---------------------------------------------------------------- |
|
||||
| **Bug Fix** | Corrects incorrect behavior without adding new functionality |
|
||||
| **Refactoring** | Improves code structure or readability without changing behavior |
|
||||
| **New Feature** | Adds new user-visible functionality |
|
||||
| **Others** | Documentation, CI changes, build config, etc. |
|
||||
|
||||
If unsure, ask the user before proceeding.
|
||||
|
||||
## Step 3: Draft the PR body
|
||||
|
||||
**IMPORTANT: The entire PR body must be written in English, regardless of the language the user is communicating in.**
|
||||
|
||||
Fill in the template below. Every section must be present — do not omit any.
|
||||
|
||||
```markdown
|
||||
## Context of Contribution
|
||||
|
||||
- [x] Bug Fix ← check only the one that applies
|
||||
- [ ] Refactoring
|
||||
- [ ] New Feature
|
||||
- [ ] Others
|
||||
|
||||
## Summary of the Proposal
|
||||
|
||||
<concise summary of what this PR proposes — 1–3 sentences>
|
||||
|
||||
## Reason for the new feature
|
||||
|
||||
<If Bug Fix / Refactoring / Others: write "N/A">
|
||||
<If New Feature: explain why the feature is necessary, how many users it benefits,
|
||||
and why benefits outweigh maintenance cost>
|
||||
|
||||
## Checklist
|
||||
|
||||
- [x] This PR does not contain commits of multiple contexts.
|
||||
- [x] Code follows proper indentation and naming conventions.
|
||||
- [x] Implemented using only APIs that can be submitted to the Microsoft Store.
|
||||
- [x] Works correctly in both dark theme and light theme.
|
||||
- [x] Works correctly on any device.
|
||||
```
|
||||
|
||||
**Checklist rules:**
|
||||
|
||||
- All checklist items default to `[x]` (checked).
|
||||
- If you have reason to believe an item may **not** hold (e.g., the change is UI-only so dark/light theme was not verifiable), leave it as `[ ]` and note the concern in the Summary.
|
||||
- The "multiple contexts" item is `[x]` only if all commits on this branch belong to a single topic. If they don't, warn the user before creating the PR.
|
||||
|
||||
## Step 4: Generate a concise PR title
|
||||
|
||||
- Under 70 characters
|
||||
- Imperative form, e.g. "Add French localization" or "Fix CPU usage spike on wake"
|
||||
- Do not prefix with a tag like `feat:` or `fix:` — this repo does not use Conventional Commits
|
||||
|
||||
## Step 5: Confirm with the user
|
||||
|
||||
Show the user:
|
||||
|
||||
- The proposed **title**
|
||||
- The full **body** (rendered as markdown if possible)
|
||||
|
||||
Ask: "Does this look right? Any changes before I create the PR?"
|
||||
|
||||
Make requested edits, then proceed only after the user confirms.
|
||||
|
||||
## Step 6: Create the PR
|
||||
|
||||
```bash
|
||||
gh pr create \
|
||||
--title "<title>" \
|
||||
--body "$(cat <<'EOF'
|
||||
<body>
|
||||
EOF
|
||||
)" \
|
||||
--base main
|
||||
```
|
||||
|
||||
Return the PR URL to the user.
|
||||
|
||||
## Notes
|
||||
|
||||
- Always target `main` as the base branch unless the user specifies otherwise.
|
||||
- Do not push the branch yourself — assume it is already pushed. If `gh pr create` fails because the branch has no upstream, run `git push -u origin HEAD` first and inform the user.
|
||||
- If the branch already has an open PR, use `gh pr edit` to update it instead of creating a duplicate.
|
||||
@@ -0,0 +1,8 @@
|
||||
root = true
|
||||
|
||||
[*.cs]
|
||||
# FlatTrackBar is instantiated only from code, never placed on the WinForms designer,
|
||||
# so designer-serialization metadata is unnecessary on its properties.
|
||||
|
||||
[FlatTrackBar.cs]
|
||||
dotnet_diagnostic.WFO1000.severity = none
|
||||
@@ -0,0 +1,67 @@
|
||||
name: Bug Report
|
||||
description: File a bug report.
|
||||
title: "[Bug]: "
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We do not accept issues in languages other than English.
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: "App version"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: bug-description
|
||||
attributes:
|
||||
label: "Describe the bug"
|
||||
description: "A clear and concise description of what the bug is."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
attributes:
|
||||
label: "How to reproduce"
|
||||
description: "Steps to reproduce the bug."
|
||||
value: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: "Expected behavior"
|
||||
description: "A description of what you expected to happen."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: "Screenshots"
|
||||
description: "If possible, attach screenshots."
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: "Check List"
|
||||
options:
|
||||
- label: "I have read the [CONTRIBUTING.md](https://github.com/runcat-dev/RunCat365/blob/main/CONTRIBUTING.md) and agree to follow it."
|
||||
required: true
|
||||
- label: "Uninstalled App."
|
||||
required: true
|
||||
- label: "Re-launched your computer."
|
||||
required: true
|
||||
- label: "Checked that no similar issues already exist."
|
||||
required: true
|
||||
@@ -0,0 +1,45 @@
|
||||
name: Feature Request
|
||||
description: File a feature request.
|
||||
title: "[Idea]: "
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We do not accept requests in languages other than English.
|
||||
|
||||
- type: textarea
|
||||
id: overview
|
||||
attributes:
|
||||
label: "Overview of the requested feature"
|
||||
description: "Please provide a brief summary of the feature you're requesting."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reason
|
||||
attributes:
|
||||
label: "Reason for the request"
|
||||
description: "Explain why this feature is needed and what motivated your request."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: related-issues
|
||||
attributes:
|
||||
label: "Related Issues"
|
||||
description: "Link to related issues, if applicable."
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: "Check List"
|
||||
options:
|
||||
- label: "I have read the [CONTRIBUTING.md](https://github.com/runcat-dev/RunCat365/blob/main/CONTRIBUTING.md) and agree to follow it."
|
||||
required: true
|
||||
- label: "The proposed feature is beneficial to a wide range of users and not just a personal preference."
|
||||
required: true
|
||||
- label: "Checked that no similar requests already exist."
|
||||
required: true
|
||||
@@ -0,0 +1,42 @@
|
||||
# How to Release a New Version to Microsoft Store
|
||||
|
||||
This document is for code owners.
|
||||
|
||||
## 1. Update Version Numbers
|
||||
|
||||
Version numbers must be updated in **two** locations:
|
||||
|
||||
1. **RunCat365/RunCat365.csproj**
|
||||
- Update `<Version>X.Y.Z</Version>` (3-digit format)
|
||||
2. **WapForStore/Package.appxmanifest**
|
||||
- Update `Version="X.Y.Z.0"` in the `<Identity>` element (4-digit format)
|
||||
|
||||
## 2. Build the App
|
||||
|
||||
1. Open the solution in Visual Studio
|
||||
2. Verify the build succeeds in Release configuration
|
||||
|
||||
## 3. Create the Package
|
||||
|
||||
1. In Visual Studio, right-click on the **WapForStore** project
|
||||
2. Select **Publish** > **Create App Packages**
|
||||
3. Choose **Microsoft Store as MSIX package** and sign in with your Microsoft account
|
||||
4. Select the existing app "RunCat 365"
|
||||
5. Configure package settings (x86, x64, arm64)
|
||||
6. Generate the `.msixupload` file
|
||||
|
||||
## 4. Submit to Partner Center
|
||||
|
||||
1. Sign in to [Partner Center](https://partner.microsoft.com/dashboard)
|
||||
2. Navigate to **Apps and games** > **RunCat 365**
|
||||
3. Click **Start a new submission**
|
||||
4. Update the following sections:
|
||||
- **Packages**: Upload the generated `.msixupload` file
|
||||
- **Store listings**: Update description/screenshots if needed
|
||||
- **Release notes**: Describe changes in this version
|
||||
5. Click **Submit to the Store**
|
||||
|
||||
## 5. Wait for Certification
|
||||
|
||||
- Certification typically takes 1-3 business days
|
||||
- If issues are found, fix them and resubmit
|
||||
@@ -0,0 +1,28 @@
|
||||
## Context of Contribution
|
||||
|
||||
<!-- Each pull request should fix only one issue or propose one feature. -->
|
||||
<!-- Do not mix unrelated changes in a single PR. -->
|
||||
|
||||
- [ ] Bug Fix
|
||||
- [ ] Refactoring
|
||||
- [ ] New Feature
|
||||
- [ ] Others
|
||||
|
||||
## Summary of the Proposal
|
||||
|
||||
<!-- Provide a concise summary of what this pull request proposes. -->
|
||||
|
||||
## Reason for the new feature
|
||||
|
||||
<!-- If it's a new feature, explain why this feature is necessary. -->
|
||||
<!-- Explain how important this feature is to many users. -->
|
||||
<!-- Explain if the benefits of the new feature outweigh the maintenance cost. -->
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] I have read the [CONTRIBUTING.md](../blob/main/CONTRIBUTING.md) and agree to follow it.
|
||||
- [ ] This PR does not contain commits of multiple contexts.
|
||||
- [ ] Code follows proper indentation and naming conventions.
|
||||
- [ ] Implemented using only APIs that can be submitted to the Microsoft Store.
|
||||
- [ ] Works correctly in both dark theme and light theme.
|
||||
- [ ] Works correctly on any device.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Visual Studio
|
||||
.vs/
|
||||
bin/
|
||||
obj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
.DS_Store
|
||||
TestResults
|
||||
|
||||
/WapForStore/AppPackages/**
|
||||
!/WapForStore/AppPackages/rm-wap-for-store.sh
|
||||
BundleArtifacts/
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# Wap
|
||||
WapForStore/**/*.assets.cache
|
||||
|
||||
# Claude Code
|
||||
.claude/*
|
||||
!.claude/skills/
|
||||
@@ -0,0 +1,52 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## You Must
|
||||
|
||||
- Respond in the same language the user is writing in.
|
||||
- Commit to Git only when instructed.
|
||||
- If multiple requirements are given in a single instruction, divide the commits into appropriate sizes/granularities.
|
||||
- When creating a pull request, use the `.claude/skills/create-pr` skill so the project's `.github/pull_request_template.md` is followed.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Windows Forms application (.NET 9.0 / C#) distributed via the Microsoft Store. Runs as a system tray icon whose animation reflects system load.
|
||||
|
||||
**Top-level layout:**
|
||||
|
||||
- `RunCat365.sln` — Main solution
|
||||
- `RunCat365/` — Main application project
|
||||
- `WapForStore/` — Windows Application Packaging project for the Microsoft Store
|
||||
|
||||
**Build:** Open `RunCat365.sln` in Visual Studio. Supported platforms: x64, x86, ARM64. Target framework: .NET 9.0 (Windows 10.0.26100.0).
|
||||
|
||||
**Releasing — version numbers must be updated in two places:**
|
||||
|
||||
1. `RunCat365/RunCat365.csproj` — `<Version>X.Y.Z</Version>` (3-digit)
|
||||
2. `WapForStore/Package.appxmanifest` — `Version="X.Y.Z.0"` in `<Identity>` (4-digit)
|
||||
|
||||
## Architecture (patterns, not file lists)
|
||||
|
||||
- **Entry point:** `Program.cs` hosts the tray application context that owns the timers, the tray icon, and the context menu.
|
||||
- **Repository pattern for system metrics:** Each metric has a `*Repository` class that produces a matching `*Info` struct (CPU / GPU / memory / storage / network / temperature). Add a new metric by adding a paired repository and info struct.
|
||||
- **Animation loop:** A 1-second fetch timer refreshes the `*Info` structs; a separate animate timer advances frames at a rate derived from the `SpeedSource` setting. Theme-aware icon recoloring lives in `BitmapExtension`.
|
||||
- **Custom runners:** User-defined animations are loaded from `profiles.json` and managed by the `CustomRunner*` classes; the active profile is stored in the `CustomRunnerName` setting.
|
||||
- **EndlessGame:** Mini-game living in `EndlessGameForm` and its collaborator classes.
|
||||
- **Settings & resources:** Persisted user preferences in `Properties/UserSettings.settings`; embedded images/icons in `Properties/Resources.resx`.
|
||||
|
||||
## Localization
|
||||
|
||||
- Localized strings live in `Properties/Strings.resx` (English default) and sibling `Properties/Strings.{locale}.resx` files. Any new string must be added to every variant.
|
||||
- Per-locale font and culture settings live in `SupportedLanguage.cs`.
|
||||
- When adding a brand-new locale (not just new strings), follow the `.claude/skills/add-locale` skill.
|
||||
|
||||
## Coding Rules
|
||||
|
||||
General contribution rules — indentation style, `var` usage, single-change PRs, English-only code, license, and the rest — are documented in [`CONTRIBUTING.md`](CONTRIBUTING.md). Follow those first.
|
||||
|
||||
Project-specific additions:
|
||||
|
||||
- Do not write comments within the source code. Use names that make intent obvious.
|
||||
- Write abbreviations such as URL or ID in either all lowercase or all uppercase (do not use Upper Camel Case for them).
|
||||
- Do not use abbreviations like `img` for `image` or `cnt` for `count`.
|
||||
@@ -0,0 +1,189 @@
|
||||
# Contributing to RunCat365
|
||||
|
||||
Thank you for your interest in contributing to **RunCat365** 🐈
|
||||
RunCat365 is a Windows system monitoring application represented as a running cat animation.
|
||||
|
||||
All kinds of contributions are welcome: bug reports, feature requests, and code contributions.
|
||||
|
||||
This document describes the rules, steps, and expectations for contributing to this project.
|
||||
|
||||
---
|
||||
|
||||
## Before Getting Started
|
||||
|
||||
- **Only contributions in English are accepted.** Any contribution in another language may be closed.
|
||||
- **This project is Windows-only.** Issues or requests related to Linux, macOS, or other platforms will not be accepted.
|
||||
- Always use the provided **Issue** and **Pull Request** templates. Submissions that do not follow the templates may be closed.
|
||||
- Be respectful, constructive, and professional in all interactions.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Before Getting Started](#before-getting-started)
|
||||
- [Issues](#issues)
|
||||
- [Bug Reports](#bug-reports)
|
||||
- [Feature Requests](#feature-requests)
|
||||
- [Other Issues](#other-issues)
|
||||
- [Pull Requests](#pull-requests)
|
||||
- [Before Opening a Pull Request](#before-opening-a-pull-request)
|
||||
- [Cloning and Working on the Repository](#cloning-and-working-on-the-repository)
|
||||
- [Submitting a Pull Request](#submitting-a-pull-request)
|
||||
- [Code Style Guidelines](#code-style-guidelines)
|
||||
- [Review Process](#review-process)
|
||||
- [Community Reviews](#community-reviews)
|
||||
- [Responding to Review Comments](#responding-to-review-comments)
|
||||
- [Thank You](#thank-you)
|
||||
|
||||
---
|
||||
|
||||
## Issues
|
||||
|
||||
### Bug Reports
|
||||
|
||||
To report a bug:
|
||||
|
||||
1. Make sure there is no existing issue reporting the same bug.
|
||||
If one exists, add any additional relevant information as a comment instead of creating a new issue.
|
||||
2. Click `New issue` and select the `Bug Report` template.
|
||||
3. Follow all checklist steps and confirm that the bug still occurs.
|
||||
4. Provide clear and complete information. More details help maintainers resolve the issue faster.
|
||||
5. Submit the issue and stay attentive, as maintainers may request additional information.
|
||||
|
||||
---
|
||||
|
||||
### Feature Requests
|
||||
|
||||
To suggest a new feature:
|
||||
|
||||
1. Check if a similar feature request already exists.
|
||||
If so, please contribute to the existing discussion instead of opening a new one.
|
||||
2. Ensure your suggestion benefits a broad range of users and is not only a personal preference.
|
||||
3. Click `New issue` and select the `Feature Request` template.
|
||||
4. Fill out the template as clearly and completely as possible.
|
||||
5. Submit the issue and remain available for follow-up questions.
|
||||
|
||||
---
|
||||
|
||||
### Other Issues
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This option is only for issues that do not fit into the categories above.
|
||||
> Issues that do not use the appropriate template will be closed without notice.
|
||||
|
||||
1. Click `New issue` and select `Blank issue`.
|
||||
2. Describe your request clearly and in detail.
|
||||
3. Submit the issue and stay attentive to maintainer feedback.
|
||||
|
||||
---
|
||||
|
||||
## Pull Requests
|
||||
|
||||
### Before Opening a Pull Request
|
||||
|
||||
- **.NET 9.0** is required.
|
||||
- All code must be written in **English**.
|
||||
Use the localization system for user-facing text in other languages.
|
||||
If you use Claude Code, the `.claude/skills/add-locale` skill walks through every file that needs updating when introducing a new locale.
|
||||
- Use the **[Allman indentation style](https://en.wikipedia.org/wiki/Indentation_style#Allman_style)**.
|
||||
- Use `var` when the type is obvious from the assignment.
|
||||
- Follow the existing formatting and conventions used in the codebase.
|
||||
- Keep each pull request focused on **a single change or context**.
|
||||
For multiple unrelated changes, create separate pull requests.
|
||||
- Keep code clean, readable, and easy to understand.
|
||||
- **Review the entire diff yourself before opening a pull request.**
|
||||
This applies whether the code was hand-written or generated by an AI assistant — you are responsible for every line you submit.
|
||||
- This repository is licensed under **Apache-2.0**.
|
||||
|
||||
---
|
||||
|
||||
### Cloning and Working on the Repository
|
||||
|
||||
1. Fork the `main` branch.
|
||||
2. Make sure Git is installed.
|
||||
3. Clone your fork locally:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-username/RunCat365.git
|
||||
cd RunCat365
|
||||
```
|
||||
4. Create a new branch:
|
||||
|
||||
```bash
|
||||
git switch -c branch-name
|
||||
```
|
||||
|
||||
Use a short, descriptive branch name.
|
||||
5. Make your changes using your preferred IDE
|
||||
(Visual Studio is recommended).
|
||||
6. Keep functions within their respective classes.
|
||||
7. Verify that the project builds and runs without errors.
|
||||
8. Ensure no unnecessary or accidental changes were made.
|
||||
9. Stage your changes:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
```
|
||||
10. Commit your changes:
|
||||
|
||||
```bash
|
||||
git commit -m "Clear and descriptive commit message"
|
||||
```
|
||||
11. Push the branch:
|
||||
|
||||
```bash
|
||||
git push origin branch-name
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Submitting a Pull Request
|
||||
|
||||
1. Click **New pull request**.
|
||||
2. Select the branch you worked on.
|
||||
3. Choose the type of contribution.
|
||||
4. Fill in all requested information clearly and completely.
|
||||
5. Ensure all checklist items are satisfied.
|
||||
6. Submit the pull request.
|
||||
|
||||
---
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
* Follow existing project conventions.
|
||||
* Use the [Allman indentation style](https://en.wikipedia.org/wiki/Indentation_style#Allman_style).
|
||||
* Use meaningful and descriptive names.
|
||||
* Avoid unnecessary complexity.
|
||||
* Prefer readable and self-explanatory code over clever solutions.
|
||||
|
||||
---
|
||||
|
||||
## Review Process
|
||||
|
||||
* Pull requests are reviewed as time permits.
|
||||
* Not all contributions are guaranteed to be accepted.
|
||||
* Maintainers may request changes before merging.
|
||||
* Inactive or non-responsive pull requests may be closed.
|
||||
|
||||
### Community Reviews
|
||||
|
||||
* Reviews and comments from non-maintainer community members are welcome and appreciated.
|
||||
* However, **only feedback from maintainers is considered official**, and only maintainers decide whether a pull request is merged.
|
||||
* Community reviewers may not be fully familiar with this project's contribution guidelines, so their suggestions may not always align with project policy.
|
||||
* Contributors are free to consider community feedback, but should use their own judgment and wait for maintainer review before treating any change as required.
|
||||
|
||||
### Responding to Review Comments
|
||||
|
||||
* **Do not click `Resolve conversation` unless you are the reviewer.**
|
||||
Even after pushing a fix in response to a review comment, only the reviewer can decide whether the issue is actually resolved.
|
||||
Pushing a follow-up commit and resolving the conversation yourself bypasses that judgment.
|
||||
* **Address each review comment individually rather than bundling them together**, unless there is a clear reason to combine them.
|
||||
The larger a single response or diff becomes, the harder it is for the reviewer to evaluate whether each point has been handled correctly.
|
||||
Reply to each comment with the corresponding change so that the discussion stays focused and easy to follow.
|
||||
|
||||
---
|
||||
|
||||
## Thank You
|
||||
|
||||
Thank you again for contributing to **RunCat365**.
|
||||
Your time and effort help make this project better for everyone 😸
|
||||
@@ -0,0 +1,176 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -0,0 +1,60 @@
|
||||
# RunCat 365
|
||||
|
||||
**A cute running cat animation on your Windows Taskbar.**
|
||||
|
||||
> [!CAUTION]
|
||||
>
|
||||
> - This project is for Windows, so we do not accept inquiries about macOS version.
|
||||
> - We do not accept issues or pull requests in languages other than English.
|
||||
> - Issues that do not follow the Issue Template will be closed without question.
|
||||
|
||||
[](https://github.com/runcat-dev/RunCat365/issues)
|
||||
[](https://github.com/runcat-dev/RunCat365/network/members)
|
||||
[](https://github.com/runcat-dev/RunCat365/stargazers)
|
||||
[](https://github.com/runcat-dev/RunCat365/)
|
||||
[](https://github.com/runcat-dev/RunCat365/releases)
|
||||
[](https://github.com/runcat-dev/RunCat365/)
|
||||
|
||||
`C#` `Win32` `.NET 9.0` `Visual Studio` `RunCat`
|
||||
|
||||
## Demo
|
||||
|
||||
<img src="./docs/images/demo.gif" width="600" height="200" alt="demo" />
|
||||
<br/>
|
||||
<img src="./docs/images/overview.png" width="600" height="600" alt="overview" />
|
||||
<br/>
|
||||
<img src="./docs/images/custom_runner.png" width="600" height="467" alt="overview" />
|
||||
<br/>
|
||||
<img src="./docs/images/endless_game.png" width="600" height="375" alt="endless game" />
|
||||
|
||||
## Installation
|
||||
|
||||
RunCat 365 is available for installation on the Microsoft Store.
|
||||
|
||||
- Requirement: Windows 10 version 19041.0 or higher
|
||||
- Microsoft Store: https://apps.microsoft.com/detail/9nw5lpnvwfwj
|
||||
- Language:
|
||||
- Chinese (simplified)
|
||||
- Chinese (traditional)
|
||||
- English (default)
|
||||
- French
|
||||
- German
|
||||
- Japanese
|
||||
- Korean
|
||||
- Spanish
|
||||
|
||||
## RunCat Developers' Community
|
||||
|
||||
This is a space for RunCat contributors to communicate closely regarding development and operations.
|
||||
We welcome anyone interested in contributing to RunCat.
|
||||
However, please note that this is a place for discussing features, not for submitting requests.
|
||||
For requests, please create an Issue according to the template.
|
||||
|
||||
Portal: https://runcat-dev.github.io
|
||||
Discord: https://discord.gg/wja3mmHt9z
|
||||
|
||||
## Contributors
|
||||
|
||||
<a href="https://github.com/runcat-dev/RunCat365/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=runcat-dev/RunCat365" />
|
||||
</a>
|
||||
@@ -0,0 +1,7 @@
|
||||
# WeHub 来源说明
|
||||
|
||||
- 原始项目:`runcat-dev/RunCat365`
|
||||
- 原始仓库:https://github.com/runcat-dev/RunCat365
|
||||
- 导入方式:上游默认分支的最新快照
|
||||
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
|
||||
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36301.6
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RunCat365", "RunCat365\RunCat365.csproj", "{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}"
|
||||
EndProject
|
||||
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "WapForStore", "WapForStore\WapForStore.wapproj", "{5B865D12-1A70-4311-8EBA-010E117FE616}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Debug|x64.Build.0 = Debug|x64
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Debug|x86.Build.0 = Debug|x86
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Release|x64.ActiveCfg = Release|x64
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Release|x64.Build.0 = Release|x64
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Release|x86.ActiveCfg = Release|x86
|
||||
{CE0ABB30-977D-4DBC-8B69-EC9D6BD72000}.Release|x86.Build.0 = Release|x86
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Debug|x64.Build.0 = Debug|x64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Debug|x86.Build.0 = Debug|x86
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Release|x64.ActiveCfg = Release|x64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Release|x64.Build.0 = Release|x64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Release|x64.Deploy.0 = Release|x64
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Release|x86.ActiveCfg = Release|x86
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Release|x86.Build.0 = Release|x86
|
||||
{5B865D12-1A70-4311-8EBA-010E117FE616}.Release|x86.Deploy.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {04BCEA3C-C8B1-4028-A4AD-6C50E8210E5B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="RunCat365.Properties.UserSettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<userSettings>
|
||||
<RunCat365.Properties.UserSettings>
|
||||
<setting name="Runner" serializeAs="String">
|
||||
<value>Cat</value>
|
||||
</setting>
|
||||
<setting name="Theme" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="FPSMaxLimit" serializeAs="String">
|
||||
<value>FPS40</value>
|
||||
</setting>
|
||||
<setting name="FirstLaunch" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="HighScore" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="SpeedSource" serializeAs="String">
|
||||
<value>CPU</value>
|
||||
</setting>
|
||||
</RunCat365.Properties.UserSettings>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal readonly struct BalloonTipInfo(string title, string text, ToolTipIcon icon)
|
||||
{
|
||||
internal string Title { get; } = title;
|
||||
internal string Text { get; } = text;
|
||||
internal ToolTipIcon Icon { get; } = icon;
|
||||
}
|
||||
|
||||
internal enum BalloonTipType
|
||||
{
|
||||
AppLaunched,
|
||||
CPUInfoUnavailable,
|
||||
}
|
||||
|
||||
internal static class BalloonTipTypeExtension
|
||||
{
|
||||
internal static BalloonTipInfo GetInfo(this BalloonTipType balloonTipType)
|
||||
{
|
||||
return balloonTipType switch
|
||||
{
|
||||
BalloonTipType.AppLaunched => new("RunCat 365", Strings.Message_AppLaunched, ToolTipIcon.Info),
|
||||
BalloonTipType.CPUInfoUnavailable => new(Strings.Message_Warning, Strings.Message_CPUUsageUnavailable, ToolTipIcon.Warning),
|
||||
_ => new("RunCat 365", string.Empty, ToolTipIcon.None),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal readonly ref struct BitmapLock
|
||||
{
|
||||
private readonly Bitmap bitmap;
|
||||
internal BitmapData Data { get; }
|
||||
|
||||
internal BitmapLock(Bitmap bitmap, ImageLockMode mode)
|
||||
{
|
||||
this.bitmap = bitmap;
|
||||
Data = bitmap.LockBits(
|
||||
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
mode,
|
||||
PixelFormat.Format32bppArgb
|
||||
);
|
||||
}
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
bitmap.UnlockBits(Data);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class BitmapExtension
|
||||
{
|
||||
internal static Bitmap Recolor(this Bitmap bitmap, Color color)
|
||||
{
|
||||
var newBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb);
|
||||
|
||||
using var srcLock = new BitmapLock(bitmap, ImageLockMode.ReadOnly);
|
||||
using var dstLock = new BitmapLock(newBitmap, ImageLockMode.WriteOnly);
|
||||
|
||||
unsafe
|
||||
{
|
||||
byte* srcPtr = (byte*)srcLock.Data.Scan0;
|
||||
byte* dstPtr = (byte*)dstLock.Data.Scan0;
|
||||
|
||||
for (int y = 0; y < bitmap.Height; y++)
|
||||
{
|
||||
byte* srcRow = srcPtr + (y * srcLock.Data.Stride);
|
||||
byte* dstRow = dstPtr + (y * dstLock.Data.Stride);
|
||||
|
||||
for (int x = 0; x < bitmap.Width; x++)
|
||||
{
|
||||
byte* srcPixel = srcRow + (x * 4);
|
||||
byte* dstPixel = dstRow + (x * 4);
|
||||
|
||||
dstPixel[0] = color.B;
|
||||
dstPixel[1] = color.G;
|
||||
dstPixel[2] = color.R;
|
||||
dstPixel[3] = srcPixel[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newBitmap;
|
||||
}
|
||||
|
||||
internal static Icon ToIcon(this Bitmap bitmap)
|
||||
{
|
||||
using var pngStream = new MemoryStream();
|
||||
bitmap.Save(pngStream, ImageFormat.Png);
|
||||
var pngData = pngStream.ToArray();
|
||||
|
||||
using var icoStream = new MemoryStream();
|
||||
using var bw = new BinaryWriter(icoStream);
|
||||
|
||||
bw.Write((short)0);
|
||||
bw.Write((short)1);
|
||||
bw.Write((short)1);
|
||||
|
||||
bw.Write((byte)(bitmap.Width >= 256 ? 0 : bitmap.Width));
|
||||
bw.Write((byte)(bitmap.Height >= 256 ? 0 : bitmap.Height));
|
||||
bw.Write((byte)0);
|
||||
bw.Write((byte)0);
|
||||
bw.Write((short)1);
|
||||
bw.Write((short)32);
|
||||
bw.Write(pngData.Length);
|
||||
bw.Write(22);
|
||||
|
||||
bw.Write(pngData);
|
||||
|
||||
icoStream.Position = 0;
|
||||
return new Icon(icoStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal static class ByteFormatter
|
||||
{
|
||||
internal static string ToByteFormatted(this long bytes)
|
||||
{
|
||||
string[] units = ["B", "KB", "MB", "GB", "TB"];
|
||||
int i = 0;
|
||||
double doubleBytes = bytes;
|
||||
while (1024 <= doubleBytes && i < units.Length - 1)
|
||||
{
|
||||
doubleBytes /= 1024;
|
||||
i++;
|
||||
}
|
||||
return string.Format("{0:0.##} {1}", doubleBytes, units[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
struct CPUInfo
|
||||
{
|
||||
internal float Total { get; set; }
|
||||
internal float User { get; set; }
|
||||
internal float Kernel { get; set; }
|
||||
internal float Idle { get; set; }
|
||||
}
|
||||
|
||||
internal static class CPUInfoExtension
|
||||
{
|
||||
internal static string GetDescription(this CPUInfo cpuInfo)
|
||||
{
|
||||
return $"{Strings.SystemInfo_CPU}: {cpuInfo.Total:f1}%";
|
||||
}
|
||||
|
||||
internal static List<string> GenerateIndicator(this CPUInfo cpuInfo)
|
||||
{
|
||||
var resultLines = new List<string>
|
||||
{
|
||||
TreeFormatter.CreateRoot($"{Strings.SystemInfo_CPU}: {cpuInfo.Total:f1}%"),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_User}: {cpuInfo.User:f1}%", false),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Kernel}: {cpuInfo.Kernel:f1}%", false),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Available}: {cpuInfo.Idle:f1}%", true)
|
||||
};
|
||||
return resultLines;
|
||||
}
|
||||
}
|
||||
|
||||
internal class CPUPerformanceCounters
|
||||
{
|
||||
private const string PROCESSOR_INFORMATION_CATEGORY = "Processor Information";
|
||||
private const string PROCESSOR_CATEGORY = "Processor";
|
||||
private const string TOTAL_INSTANCE = "_Total";
|
||||
private const string PROCESSOR_UTILITY_COUNTER = "% Processor Utility";
|
||||
private const string PROCESSOR_TIME_COUNTER = "% Processor Time";
|
||||
private const string USER_TIME_COUNTER = "% User Time";
|
||||
private const string PRIVILEGED_TIME_COUNTER = "% Privileged Time";
|
||||
private const int PROCESSOR_TIME_BASED_TASK_MANAGER_MINIMUM_BUILD = 26100;
|
||||
|
||||
internal PerformanceCounter Total { get; }
|
||||
internal PerformanceCounter User { get; }
|
||||
internal PerformanceCounter Kernel { get; }
|
||||
|
||||
private CPUPerformanceCounters(
|
||||
PerformanceCounter total,
|
||||
PerformanceCounter user,
|
||||
PerformanceCounter kernel)
|
||||
{
|
||||
Total = total;
|
||||
User = user;
|
||||
Kernel = kernel;
|
||||
}
|
||||
|
||||
internal static CPUPerformanceCounters? TryCreate()
|
||||
{
|
||||
return TryCreateFromCategory(PROCESSOR_INFORMATION_CATEGORY, TOTAL_INSTANCE)
|
||||
?? TryCreateFromCategory(PROCESSOR_CATEGORY, TOTAL_INSTANCE);
|
||||
}
|
||||
|
||||
private static bool TaskManagerUsesProcessorTime()
|
||||
{
|
||||
return PROCESSOR_TIME_BASED_TASK_MANAGER_MINIMUM_BUILD <= Environment.OSVersion.Version.Build;
|
||||
}
|
||||
|
||||
private static CPUPerformanceCounters? TryCreateFromCategory(string categoryName, string instanceName)
|
||||
{
|
||||
PerformanceCounter? total = null;
|
||||
PerformanceCounter? user = null;
|
||||
PerformanceCounter? kernel = null;
|
||||
if (!TaskManagerUsesProcessorTime())
|
||||
{
|
||||
try
|
||||
{
|
||||
total = new PerformanceCounter(categoryName, PROCESSOR_UTILITY_COUNTER, instanceName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
total?.Close();
|
||||
total = null;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
total ??= new PerformanceCounter(categoryName, PROCESSOR_TIME_COUNTER, instanceName);
|
||||
user = new PerformanceCounter(categoryName, USER_TIME_COUNTER, instanceName);
|
||||
kernel = new PerformanceCounter(categoryName, PRIVILEGED_TIME_COUNTER, instanceName);
|
||||
_ = total.NextValue();
|
||||
_ = user.NextValue();
|
||||
_ = kernel.NextValue();
|
||||
return new CPUPerformanceCounters(total, user, kernel);
|
||||
}
|
||||
catch
|
||||
{
|
||||
total?.Close();
|
||||
user?.Close();
|
||||
kernel?.Close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Close()
|
||||
{
|
||||
Total.Close();
|
||||
User.Close();
|
||||
Kernel.Close();
|
||||
}
|
||||
}
|
||||
|
||||
internal class CPURepository
|
||||
{
|
||||
private readonly CPUPerformanceCounters? counters;
|
||||
private readonly List<CPUInfo> cpuInfoList = [];
|
||||
private const int CPU_INFO_LIST_LIMIT_SIZE = 5;
|
||||
|
||||
internal bool IsAvailable => counters is not null;
|
||||
|
||||
internal CPURepository()
|
||||
{
|
||||
counters = CPUPerformanceCounters.TryCreate();
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
if (counters is null) return;
|
||||
|
||||
var total = Math.Min(100, counters.Total.NextValue());
|
||||
var user = Math.Min(100, counters.User.NextValue());
|
||||
var kernel = Math.Min(100, counters.Kernel.NextValue());
|
||||
var idle = Math.Max(0, 100 - user - kernel);
|
||||
|
||||
var cpuInfo = new CPUInfo
|
||||
{
|
||||
Total = total,
|
||||
User = user,
|
||||
Kernel = kernel,
|
||||
Idle = idle,
|
||||
};
|
||||
|
||||
cpuInfoList.Add(cpuInfo);
|
||||
if (CPU_INFO_LIST_LIMIT_SIZE < cpuInfoList.Count)
|
||||
{
|
||||
cpuInfoList.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
internal CPUInfo Get()
|
||||
{
|
||||
if (cpuInfoList.Count == 0) return new CPUInfo();
|
||||
|
||||
return new CPUInfo
|
||||
{
|
||||
Total = cpuInfoList.Average(x => x.Total),
|
||||
User = cpuInfoList.Average(x => x.User),
|
||||
Kernel = cpuInfoList.Average(x => x.Kernel),
|
||||
Idle = cpuInfoList.Average(x => x.Idle)
|
||||
};
|
||||
}
|
||||
|
||||
internal void Close()
|
||||
{
|
||||
counters?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal abstract class Cat
|
||||
{
|
||||
internal abstract List<int> ViolationIndices();
|
||||
internal abstract Cat Next();
|
||||
internal abstract string GetString();
|
||||
|
||||
internal class Running : Cat
|
||||
{
|
||||
internal Frame CurrentFrame { get; }
|
||||
|
||||
internal Running(Frame frame)
|
||||
{
|
||||
CurrentFrame = frame;
|
||||
}
|
||||
|
||||
internal override List<int> ViolationIndices()
|
||||
{
|
||||
return CurrentFrame switch
|
||||
{
|
||||
Frame.Frame0 => [5, 6, 7],
|
||||
Frame.Frame1 => [5, 6],
|
||||
Frame.Frame2 => [5, 6],
|
||||
Frame.Frame3 => [5],
|
||||
Frame.Frame4 => [5, 7],
|
||||
_ => [],
|
||||
};
|
||||
}
|
||||
|
||||
internal override Cat Next()
|
||||
{
|
||||
var nextFrame = (Frame)(((int)CurrentFrame + 1) % Enum.GetValues<Frame>().Length);
|
||||
return new Running(nextFrame);
|
||||
}
|
||||
|
||||
internal override string GetString()
|
||||
{
|
||||
return $"running_{(int)CurrentFrame}";
|
||||
}
|
||||
|
||||
internal enum Frame
|
||||
{
|
||||
Frame0,
|
||||
Frame1,
|
||||
Frame2,
|
||||
Frame3,
|
||||
Frame4
|
||||
}
|
||||
}
|
||||
|
||||
internal class Jumping : Cat
|
||||
{
|
||||
internal Frame CurrentFrame { get; }
|
||||
|
||||
internal Jumping(Frame frame)
|
||||
{
|
||||
CurrentFrame = frame;
|
||||
}
|
||||
|
||||
internal override List<int> ViolationIndices()
|
||||
{
|
||||
return CurrentFrame switch
|
||||
{
|
||||
Frame.Frame0 => [5, 6, 7],
|
||||
Frame.Frame1 => [5, 6],
|
||||
Frame.Frame2 => [5, 6],
|
||||
Frame.Frame3 => [5, 6],
|
||||
Frame.Frame4 => [5, 6],
|
||||
Frame.Frame5 => [5],
|
||||
Frame.Frame6 => [],
|
||||
Frame.Frame7 => [],
|
||||
Frame.Frame8 => [],
|
||||
Frame.Frame9 => [7],
|
||||
_ => [],
|
||||
};
|
||||
}
|
||||
|
||||
internal override Cat Next()
|
||||
{
|
||||
var nextFrame = (Frame)(((int)CurrentFrame + 1) % Enum.GetValues<Frame>().Length);
|
||||
return new Jumping(nextFrame);
|
||||
}
|
||||
|
||||
internal override string GetString()
|
||||
{
|
||||
return $"jumping_{(int)CurrentFrame}";
|
||||
}
|
||||
|
||||
internal enum Frame
|
||||
{
|
||||
Frame0,
|
||||
Frame1,
|
||||
Frame2,
|
||||
Frame3,
|
||||
Frame4,
|
||||
Frame5,
|
||||
Frame6,
|
||||
Frame7,
|
||||
Frame8,
|
||||
Frame9
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,508 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal class ContextMenuManager : IDisposable
|
||||
{
|
||||
private readonly CustomToolStripMenuItem systemInfoMenu = new();
|
||||
private readonly NotifyIcon notifyIcon = new();
|
||||
private readonly List<Icon> icons = [];
|
||||
private readonly Lock iconLock = new();
|
||||
private int current = 0;
|
||||
private EndlessGameForm? endlessGameForm;
|
||||
private CustomRunnerForm? customRunnerForm;
|
||||
private List<Bitmap>? customRunnerSourceFrames;
|
||||
|
||||
internal ContextMenuManager(
|
||||
Func<Runner> getRunner,
|
||||
Action<Runner> setRunner,
|
||||
CustomRunnerRepository customRunnerRepository,
|
||||
Func<string?> getCustomRunnerName,
|
||||
Action<string> applyCustomRunner,
|
||||
Action<string> onCustomRunnerDeleted,
|
||||
Func<Theme> getSystemTheme,
|
||||
Func<Theme> getManualTheme,
|
||||
Action<Theme> setManualTheme,
|
||||
Func<SpeedSource> getSpeedSource,
|
||||
Action<SpeedSource> setSpeedSource,
|
||||
Func<SpeedSource, bool> isSpeedSourceAvailable,
|
||||
Func<FPSMaxLimit> getFPSMaxLimit,
|
||||
Action<FPSMaxLimit> setFPSMaxLimit,
|
||||
Func<TemperatureUnit> getTemperatureUnit,
|
||||
Action<TemperatureUnit> setTemperatureUnit,
|
||||
Func<bool> getLaunchAtStartup,
|
||||
Func<bool, bool> toggleLaunchAtStartup,
|
||||
Action openProjectPage,
|
||||
Action onExit
|
||||
)
|
||||
{
|
||||
systemInfoMenu.Text = "-\n-\n-\n-\n-";
|
||||
systemInfoMenu.Enabled = false;
|
||||
|
||||
var runnersMenu = new CustomToolStripMenuItem(Strings.Menu_Runner);
|
||||
runnersMenu.SetupSubMenusFromEnum<Runner>(
|
||||
r => r.GetLocalizedString(),
|
||||
(parent, sender, e) =>
|
||||
{
|
||||
HandleMenuItemSelection<Runner>(
|
||||
parent,
|
||||
sender,
|
||||
(string? s, out Runner r) => Enum.TryParse(s, out r),
|
||||
r => setRunner(r)
|
||||
);
|
||||
SetIcons(getSystemTheme(), getManualTheme(), getRunner());
|
||||
},
|
||||
r => getCustomRunnerName() is null && getRunner() == r,
|
||||
r => GetRunnerThumbnailBitmap(getSystemTheme(), r)
|
||||
);
|
||||
runnersMenu.DropDownOpening += (sender, e) => RefreshCustomRunnerMenu(
|
||||
runnersMenu,
|
||||
customRunnerRepository,
|
||||
ResolveTheme(getSystemTheme(), getManualTheme()),
|
||||
getRunner,
|
||||
getCustomRunnerName,
|
||||
applyCustomRunner
|
||||
);
|
||||
|
||||
var themeMenu = new CustomToolStripMenuItem(Strings.Menu_Theme);
|
||||
themeMenu.SetupSubMenusFromEnum<Theme>(
|
||||
t => t.GetLocalizedString(),
|
||||
(parent, sender, e) =>
|
||||
{
|
||||
HandleMenuItemSelection<Theme>(
|
||||
parent,
|
||||
sender,
|
||||
(string? s, out Theme t) => Enum.TryParse(s, out t),
|
||||
t => setManualTheme(t)
|
||||
);
|
||||
SetIcons(getSystemTheme(), getManualTheme(), getRunner());
|
||||
},
|
||||
t => getManualTheme() == t,
|
||||
_ => null
|
||||
);
|
||||
|
||||
var speedSourceMenu = new CustomToolStripMenuItem(Strings.Menu_SpeedSource);
|
||||
speedSourceMenu.SetupSubMenusFromEnum<SpeedSource>(
|
||||
s => s.GetLocalizedString(),
|
||||
(parent, sender, e) =>
|
||||
{
|
||||
HandleMenuItemSelection<SpeedSource>(
|
||||
parent,
|
||||
sender,
|
||||
(string? s, out SpeedSource ss) => Enum.TryParse(s, out ss),
|
||||
s => setSpeedSource(s)
|
||||
);
|
||||
},
|
||||
s => getSpeedSource() == s,
|
||||
_ => null,
|
||||
isSpeedSourceAvailable
|
||||
);
|
||||
|
||||
var fpsMaxLimitMenu = new CustomToolStripMenuItem(Strings.Menu_FPSMaxLimit);
|
||||
fpsMaxLimitMenu.SetupSubMenusFromEnum<FPSMaxLimit>(
|
||||
f => f.GetString(),
|
||||
(parent, sender, e) =>
|
||||
{
|
||||
HandleMenuItemSelection<FPSMaxLimit>(
|
||||
parent,
|
||||
sender,
|
||||
(string? s, out FPSMaxLimit f) => FPSMaxLimitExtension.TryParse(s, out f),
|
||||
f => setFPSMaxLimit(f)
|
||||
);
|
||||
},
|
||||
f => getFPSMaxLimit() == f,
|
||||
_ => null
|
||||
);
|
||||
|
||||
var temperatureUnitMenu = new CustomToolStripMenuItem(Strings.Menu_TemperatureUnit);
|
||||
temperatureUnitMenu.SetupSubMenusFromEnum<TemperatureUnit>(
|
||||
u => u.GetLocalizedString(),
|
||||
(parent, sender, e) =>
|
||||
{
|
||||
HandleMenuItemSelection<TemperatureUnit>(
|
||||
parent,
|
||||
sender,
|
||||
(string? s, out TemperatureUnit u) => Enum.TryParse(s, out u),
|
||||
u => setTemperatureUnit(u)
|
||||
);
|
||||
},
|
||||
u => getTemperatureUnit() == u,
|
||||
_ => null
|
||||
);
|
||||
|
||||
var launchAtStartupMenu = new CustomToolStripMenuItem(Strings.Menu_LaunchAtStartup)
|
||||
{
|
||||
Checked = getLaunchAtStartup()
|
||||
};
|
||||
launchAtStartupMenu.Click += (sender, e) => HandleStartupMenuClick(sender, toggleLaunchAtStartup);
|
||||
|
||||
var settingsMenu = new CustomToolStripMenuItem(Strings.Menu_Settings);
|
||||
settingsMenu.DropDownItems.AddRange(
|
||||
themeMenu,
|
||||
speedSourceMenu,
|
||||
fpsMaxLimitMenu,
|
||||
temperatureUnitMenu,
|
||||
launchAtStartupMenu
|
||||
);
|
||||
|
||||
var customRunnersMenu = new CustomToolStripMenuItem(Strings.Menu_CustomRunners);
|
||||
customRunnersMenu.Click += (sender, e) => ShowOrActivateCustomRunnerWindow(
|
||||
customRunnerRepository, onCustomRunnerDeleted
|
||||
);
|
||||
|
||||
var endlessGameMenu = new CustomToolStripMenuItem(Strings.Menu_EndlessGame);
|
||||
endlessGameMenu.Click += (sender, e) => ShowOrActivateGameWindow(getSystemTheme);
|
||||
|
||||
var appVersionMenu = new CustomToolStripMenuItem(
|
||||
$"{Application.ProductName} v{Application.ProductVersion}"
|
||||
)
|
||||
{
|
||||
Enabled = false
|
||||
};
|
||||
|
||||
var projectPageMenu = new CustomToolStripMenuItem(Strings.Menu_OpenProjectPage);
|
||||
projectPageMenu.Click += (sender, e) => openProjectPage();
|
||||
|
||||
var informationMenu = new CustomToolStripMenuItem(Strings.Menu_Information);
|
||||
informationMenu.DropDownItems.AddRange(
|
||||
appVersionMenu,
|
||||
projectPageMenu
|
||||
);
|
||||
|
||||
var exitMenu = new CustomToolStripMenuItem(Strings.Menu_Exit);
|
||||
exitMenu.Click += (sender, e) => onExit();
|
||||
|
||||
var contextMenuStrip = new ContextMenuStrip(new Container());
|
||||
contextMenuStrip.Items.AddRange(
|
||||
systemInfoMenu,
|
||||
new ToolStripSeparator(),
|
||||
runnersMenu,
|
||||
customRunnersMenu,
|
||||
new ToolStripSeparator(),
|
||||
settingsMenu,
|
||||
informationMenu,
|
||||
endlessGameMenu,
|
||||
new ToolStripSeparator(),
|
||||
exitMenu
|
||||
);
|
||||
contextMenuStrip.Renderer = new ContextMenuRenderer();
|
||||
|
||||
SetIcons(getSystemTheme(), getManualTheme(), getRunner());
|
||||
|
||||
notifyIcon.Visible = true;
|
||||
notifyIcon.ContextMenuStrip = contextMenuStrip;
|
||||
}
|
||||
|
||||
private static void HandleMenuItemSelection<T>(
|
||||
ToolStripMenuItem parentMenu,
|
||||
object? sender,
|
||||
CustomTryParseDelegate<T> tryParseMethod,
|
||||
Action<T> assignValueAction
|
||||
)
|
||||
{
|
||||
if (sender is null) return;
|
||||
var item = (ToolStripMenuItem)sender;
|
||||
foreach (ToolStripItem childItem in parentMenu.DropDownItems)
|
||||
{
|
||||
if (childItem is ToolStripMenuItem menuItem)
|
||||
{
|
||||
menuItem.Checked = false;
|
||||
}
|
||||
}
|
||||
item.Checked = true;
|
||||
|
||||
if (item.Tag is T tagValue)
|
||||
{
|
||||
assignValueAction(tagValue);
|
||||
}
|
||||
else if (tryParseMethod(item.Text, out T parsedValue))
|
||||
{
|
||||
assignValueAction(parsedValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap? GetRunnerThumbnailBitmap(Theme systemTheme, Runner runner)
|
||||
{
|
||||
var color = systemTheme.GetContrastColor();
|
||||
var iconName = $"{runner.GetString()}_0".ToLower();
|
||||
var obj = Resources.ResourceManager.GetObject(iconName);
|
||||
if (obj is not Bitmap bitmap) return null;
|
||||
return systemTheme == Theme.Light ? bitmap : bitmap.Recolor(color);
|
||||
}
|
||||
|
||||
private static void RefreshCustomRunnerMenu(
|
||||
CustomToolStripMenuItem runnersMenu,
|
||||
CustomRunnerRepository customRunnerRepository,
|
||||
Theme theme,
|
||||
Func<Runner> getRunner,
|
||||
Func<string?> getCustomRunnerName,
|
||||
Action<string> applyCustomRunner
|
||||
)
|
||||
{
|
||||
foreach (ToolStripItem item in runnersMenu.DropDownItems)
|
||||
{
|
||||
if (item is ToolStripMenuItem menuItem && item.Tag is Runner runner)
|
||||
{
|
||||
menuItem.Checked = getCustomRunnerName() is null && getRunner() == runner;
|
||||
}
|
||||
}
|
||||
|
||||
var customItems = runnersMenu.DropDownItems
|
||||
.Cast<ToolStripItem>()
|
||||
.Where(item => item.Tag is CustomRunnerMenuTag)
|
||||
.ToList();
|
||||
foreach (var item in customItems)
|
||||
{
|
||||
runnersMenu.DropDownItems.Remove(item);
|
||||
if (item is ToolStripMenuItem menuItem)
|
||||
{
|
||||
menuItem.Image?.Dispose();
|
||||
}
|
||||
item.Dispose();
|
||||
}
|
||||
|
||||
var profiles = customRunnerRepository.GetAll().OrderBy(p => p.Name).ToList();
|
||||
if (profiles.Count == 0) return;
|
||||
|
||||
runnersMenu.DropDownItems.Add(new ToolStripSeparator { Tag = new CustomRunnerMenuTag("") });
|
||||
foreach (var profile in profiles)
|
||||
{
|
||||
var name = profile.Name;
|
||||
var item = new CustomToolStripMenuItem(name)
|
||||
{
|
||||
Tag = new CustomRunnerMenuTag(name),
|
||||
Checked = string.Equals(getCustomRunnerName(), name, StringComparison.OrdinalIgnoreCase),
|
||||
Image = CreateCustomRunnerThumbnail(customRunnerRepository, name, theme)
|
||||
};
|
||||
item.Click += (sender, e) => applyCustomRunner(name);
|
||||
runnersMenu.DropDownItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap? CreateCustomRunnerThumbnail(CustomRunnerRepository repository, string name, Theme theme)
|
||||
{
|
||||
var firstFrame = repository.LoadFirstFrame(name);
|
||||
if (firstFrame is null) return null;
|
||||
if (theme == Theme.Light) return firstFrame;
|
||||
using (firstFrame)
|
||||
{
|
||||
return firstFrame.Recolor(theme.GetContrastColor());
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetIcons(Theme systemTheme, Theme manualTheme, Runner runner)
|
||||
{
|
||||
ClearCustomRunnerSourceFrames();
|
||||
|
||||
var runnerName = runner.GetString();
|
||||
var rm = Resources.ResourceManager;
|
||||
var capacity = runner.GetFrameNumber();
|
||||
var bitmaps = new List<Bitmap>(capacity);
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
var iconName = $"{runnerName}_{i}".ToLower();
|
||||
if (rm.GetObject(iconName) is Bitmap bitmap)
|
||||
{
|
||||
bitmaps.Add(bitmap);
|
||||
}
|
||||
}
|
||||
ReplaceIconList(bitmaps, ResolveTheme(systemTheme, manualTheme));
|
||||
}
|
||||
|
||||
internal void SetCustomIcons(List<Bitmap> frames, Theme systemTheme, Theme manualTheme)
|
||||
{
|
||||
ClearCustomRunnerSourceFrames();
|
||||
customRunnerSourceFrames = frames.Select(f => new Bitmap(f)).ToList();
|
||||
ReplaceIconList(customRunnerSourceFrames, ResolveTheme(systemTheme, manualTheme));
|
||||
}
|
||||
|
||||
internal void RecolorActiveCustomIcons(Theme systemTheme, Theme manualTheme)
|
||||
{
|
||||
if (customRunnerSourceFrames is null) return;
|
||||
ReplaceIconList(customRunnerSourceFrames, ResolveTheme(systemTheme, manualTheme));
|
||||
}
|
||||
|
||||
internal bool HasActiveCustomIcons => customRunnerSourceFrames is not null;
|
||||
|
||||
private void ReplaceIconList(IList<Bitmap> frames, Theme theme)
|
||||
{
|
||||
var color = theme.GetContrastColor();
|
||||
var list = new List<Icon>(frames.Count);
|
||||
foreach (var frame in frames)
|
||||
{
|
||||
if (theme == Theme.Light)
|
||||
{
|
||||
list.Add(frame.ToIcon());
|
||||
}
|
||||
else
|
||||
{
|
||||
using var recolored = frame.Recolor(color);
|
||||
list.Add(recolored.ToIcon());
|
||||
}
|
||||
}
|
||||
|
||||
List<Icon> oldIcons;
|
||||
lock (iconLock)
|
||||
{
|
||||
oldIcons = new List<Icon>(icons);
|
||||
icons.Clear();
|
||||
icons.AddRange(list);
|
||||
current = 0;
|
||||
if (icons.Count > 0)
|
||||
{
|
||||
notifyIcon.Icon = icons[0];
|
||||
current = 1 % icons.Count;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var icon in oldIcons) icon.Dispose();
|
||||
}
|
||||
|
||||
private void ClearCustomRunnerSourceFrames()
|
||||
{
|
||||
if (customRunnerSourceFrames is null) return;
|
||||
foreach (var bitmap in customRunnerSourceFrames) bitmap.Dispose();
|
||||
customRunnerSourceFrames = null;
|
||||
}
|
||||
|
||||
private static Theme ResolveTheme(Theme systemTheme, Theme manualTheme)
|
||||
{
|
||||
return manualTheme == Theme.System ? systemTheme : manualTheme;
|
||||
}
|
||||
|
||||
private static void HandleStartupMenuClick(object? sender, Func<bool, bool> toggleLaunchAtStartup)
|
||||
{
|
||||
if (sender is null) return;
|
||||
var item = (ToolStripMenuItem)sender;
|
||||
try
|
||||
{
|
||||
if (toggleLaunchAtStartup(item.Checked))
|
||||
{
|
||||
item.Checked = !item.Checked;
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, Strings.Message_Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ShowOrActivateGameWindow(Func<Theme> getSystemTheme)
|
||||
{
|
||||
if (endlessGameForm is null)
|
||||
{
|
||||
endlessGameForm = new EndlessGameForm(getSystemTheme());
|
||||
endlessGameForm.FormClosed += (sender, e) =>
|
||||
{
|
||||
endlessGameForm = null;
|
||||
};
|
||||
endlessGameForm.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
endlessGameForm.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowOrActivateCustomRunnerWindow(
|
||||
CustomRunnerRepository repository,
|
||||
Action<string> onCustomRunnerDeleted
|
||||
)
|
||||
{
|
||||
if (customRunnerForm is null)
|
||||
{
|
||||
customRunnerForm = new CustomRunnerForm(repository, onCustomRunnerDeleted);
|
||||
customRunnerForm.FormClosed += (sender, e) =>
|
||||
{
|
||||
customRunnerForm = null;
|
||||
};
|
||||
customRunnerForm.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
customRunnerForm.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
internal void ShowBalloonTip(BalloonTipType balloonTipType)
|
||||
{
|
||||
var info = balloonTipType.GetInfo();
|
||||
notifyIcon.ShowBalloonTip(5000, info.Title, info.Text, info.Icon);
|
||||
}
|
||||
|
||||
internal void AdvanceFrame()
|
||||
{
|
||||
lock (iconLock)
|
||||
{
|
||||
if (icons.Count == 0) return;
|
||||
if (icons.Count <= current) current = 0;
|
||||
notifyIcon.Icon = icons[current];
|
||||
current = (current + 1) % icons.Count;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetSystemInfoMenuText(string text)
|
||||
{
|
||||
systemInfoMenu.Text = text;
|
||||
}
|
||||
|
||||
internal void SetNotifyIconText(string text)
|
||||
{
|
||||
notifyIcon.Text = text;
|
||||
}
|
||||
|
||||
internal void HideNotifyIcon()
|
||||
{
|
||||
notifyIcon.Visible = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
lock (iconLock)
|
||||
{
|
||||
foreach (var icon in icons) icon.Dispose();
|
||||
icons.Clear();
|
||||
}
|
||||
|
||||
ClearCustomRunnerSourceFrames();
|
||||
|
||||
if (notifyIcon is not null)
|
||||
{
|
||||
notifyIcon.ContextMenuStrip?.Dispose();
|
||||
notifyIcon.Dispose();
|
||||
}
|
||||
|
||||
endlessGameForm?.Dispose();
|
||||
customRunnerForm?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private delegate bool CustomTryParseDelegate<T>(string? value, out T result);
|
||||
|
||||
private sealed record CustomRunnerMenuTag(string Name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal class ContextMenuRenderer : ToolStripProfessionalRenderer
|
||||
{
|
||||
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Text) && e.Item is CustomToolStripMenuItem item)
|
||||
{
|
||||
var textRectangle = e.TextRectangle;
|
||||
textRectangle.Height = item.Bounds.Height;
|
||||
TextRenderer.DrawText(
|
||||
e.Graphics,
|
||||
e.Text,
|
||||
e.TextFont,
|
||||
textRectangle,
|
||||
item.ForeColor,
|
||||
item.Flags()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnRenderItemText(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,900 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal class CustomRunnerForm : Form
|
||||
{
|
||||
private const int PREVIEW_INITIAL_INTERVAL_MS = 100;
|
||||
private const int PREVIEW_MIN_INTERVAL_MS = 20;
|
||||
private const int PREVIEW_BASE_RATE = 500;
|
||||
private const int RUNNER_NAME_MAX_LENGTH = 30;
|
||||
|
||||
private readonly CustomRunnerRepository repository;
|
||||
private readonly Action<string> onCustomRunnerDeleted;
|
||||
private readonly string fontFamily;
|
||||
private readonly Font tileLabelFont;
|
||||
private readonly ToolTip toolTip = new();
|
||||
private ListBox runnerListBox = null!;
|
||||
private TextBox nameTextBox = null!;
|
||||
private FlowLayoutPanel framePanel = null!;
|
||||
private Button addFramesButton = null!;
|
||||
private Button removeFrameButton = null!;
|
||||
private Button saveButton = null!;
|
||||
private Button deleteButton = null!;
|
||||
private FrameAnimationView previewView = null!;
|
||||
private FlatTrackBar speedSlider = null!;
|
||||
|
||||
private readonly List<Bitmap> pendingFrames = [];
|
||||
private readonly List<Bitmap> recoloredFrames = [];
|
||||
private int selectedFrameIndex = -1;
|
||||
private Point? dragOriginPoint;
|
||||
private int dragSourceIndex = -1;
|
||||
|
||||
internal CustomRunnerForm(
|
||||
CustomRunnerRepository repository,
|
||||
Action<string> onCustomRunnerDeleted
|
||||
)
|
||||
{
|
||||
this.repository = repository;
|
||||
this.onCustomRunnerDeleted = onCustomRunnerDeleted;
|
||||
fontFamily = SupportedLanguageExtension.GetCurrentLanguage().GetFontName();
|
||||
tileLabelFont = new Font(fontFamily, 7.5F);
|
||||
|
||||
InitializeFormProperties();
|
||||
InitializeControls();
|
||||
InitializeEventHandlers();
|
||||
|
||||
FitWindowToContent();
|
||||
|
||||
RefreshRunnerList();
|
||||
ValidateFormState();
|
||||
}
|
||||
|
||||
private void FitWindowToContent()
|
||||
{
|
||||
if (Controls.Count == 0) return;
|
||||
var root = Controls[0];
|
||||
root.PerformLayout();
|
||||
var preferred = root.PreferredSize;
|
||||
ClientSize = new Size(
|
||||
preferred.Width + Padding.Horizontal,
|
||||
preferred.Height + Padding.Vertical
|
||||
);
|
||||
}
|
||||
|
||||
private void InitializeFormProperties()
|
||||
{
|
||||
Text = Strings.Window_CustomRunners;
|
||||
Icon = Resources.AppIcon;
|
||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
MaximizeBox = false;
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
BackColor = Palette.FormBackground;
|
||||
ForeColor = Palette.TextPrimary;
|
||||
Padding = new Padding(20);
|
||||
}
|
||||
|
||||
private void InitializeControls()
|
||||
{
|
||||
var listColumn = BuildListColumn();
|
||||
var separator = BuildVerticalSeparator();
|
||||
var editorColumn = BuildEditorColumn();
|
||||
|
||||
var root = new TableLayoutPanel
|
||||
{
|
||||
AutoSize = true,
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||
ColumnCount = 3,
|
||||
RowCount = 1,
|
||||
BackColor = Color.Transparent
|
||||
};
|
||||
root.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||||
root.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||||
root.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||
root.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
root.Controls.Add(listColumn, 0, 0);
|
||||
root.Controls.Add(separator, 1, 0);
|
||||
root.Controls.Add(editorColumn, 2, 0);
|
||||
|
||||
Controls.Add(root);
|
||||
root.Location = new Point(Padding.Left, Padding.Top);
|
||||
}
|
||||
|
||||
private TableLayoutPanel BuildListColumn()
|
||||
{
|
||||
var listLabel = CreateLabel(
|
||||
Strings.CustomRunner_AddedRunners,
|
||||
9F, FontStyle.Bold, Palette.TextSecondary
|
||||
);
|
||||
listLabel.Margin = new Padding(0, 0, 0, 4);
|
||||
|
||||
runnerListBox = new ListBox
|
||||
{
|
||||
MinimumSize = new Size(160, 200),
|
||||
BackColor = Palette.ControlBackground,
|
||||
ForeColor = Palette.TextPrimary,
|
||||
Font = new Font(fontFamily, 9F),
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
IntegralHeight = false,
|
||||
Dock = DockStyle.Fill,
|
||||
Margin = new Padding(0, 0, 0, 8)
|
||||
};
|
||||
|
||||
deleteButton = CreateIconColoredButton(
|
||||
"×",
|
||||
new Size(32, 28),
|
||||
Palette.DangerRed,
|
||||
Palette.DangerBorder,
|
||||
Strings.CustomRunner_Delete,
|
||||
initiallyEnabled: false
|
||||
);
|
||||
deleteButton.Anchor = AnchorStyles.Left;
|
||||
deleteButton.Margin = new Padding(0);
|
||||
|
||||
var column = new TableLayoutPanel
|
||||
{
|
||||
AutoSize = true,
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||
Dock = DockStyle.Fill,
|
||||
ColumnCount = 1,
|
||||
RowCount = 3,
|
||||
BackColor = Color.Transparent
|
||||
};
|
||||
column.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||||
column.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
column.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
|
||||
column.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
column.Controls.Add(listLabel, 0, 0);
|
||||
column.Controls.Add(runnerListBox, 0, 1);
|
||||
column.Controls.Add(deleteButton, 0, 2);
|
||||
return column;
|
||||
}
|
||||
|
||||
private static Panel BuildVerticalSeparator()
|
||||
{
|
||||
return new Panel
|
||||
{
|
||||
Width = 1,
|
||||
BackColor = Palette.BorderAccent,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
|
||||
Margin = new Padding(12, 0, 12, 0)
|
||||
};
|
||||
}
|
||||
|
||||
private Label CreateLabel(string text, float fontSize, FontStyle fontStyle, Color foreColor)
|
||||
{
|
||||
var font = new Font(fontFamily, fontSize, fontStyle);
|
||||
var measured = TextRenderer.MeasureText(text, font);
|
||||
return new Label
|
||||
{
|
||||
Text = text,
|
||||
AutoSize = true,
|
||||
MinimumSize = new Size(measured.Width + 2, 0),
|
||||
Font = font,
|
||||
ForeColor = foreColor
|
||||
};
|
||||
}
|
||||
|
||||
private TableLayoutPanel BuildEditorColumn()
|
||||
{
|
||||
var nameLabel = CreateLabel(
|
||||
Strings.CustomRunner_Name,
|
||||
9F, FontStyle.Regular, Palette.TextSecondary
|
||||
);
|
||||
nameLabel.Anchor = AnchorStyles.Top | AnchorStyles.Right;
|
||||
nameLabel.TextAlign = ContentAlignment.MiddleRight;
|
||||
nameLabel.Margin = new Padding(0, 6, 12, 8);
|
||||
|
||||
nameTextBox = new TextBox
|
||||
{
|
||||
MinimumSize = new Size(280, 24),
|
||||
BackColor = Palette.ControlBackground,
|
||||
ForeColor = Palette.TextPrimary,
|
||||
Font = new Font(fontFamily, 9F),
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
MaxLength = RUNNER_NAME_MAX_LENGTH,
|
||||
Anchor = AnchorStyles.Left | AnchorStyles.Right,
|
||||
Margin = new Padding(0, 0, 0, 8)
|
||||
};
|
||||
|
||||
var requirementsCaption = CreateLabel(
|
||||
Strings.CustomRunner_RequirementsLabel,
|
||||
9F, FontStyle.Regular, Palette.TextSecondary
|
||||
);
|
||||
requirementsCaption.Anchor = AnchorStyles.Top | AnchorStyles.Right;
|
||||
requirementsCaption.TextAlign = ContentAlignment.MiddleRight;
|
||||
requirementsCaption.Margin = new Padding(0, 0, 12, 8);
|
||||
|
||||
var requirementsContent = CreateLabel(
|
||||
Strings.CustomRunner_Requirements,
|
||||
9F, FontStyle.Regular, Palette.TextMuted
|
||||
);
|
||||
requirementsContent.Margin = new Padding(0, 0, 0, 8);
|
||||
|
||||
var framesCaption = CreateLabel(
|
||||
Strings.CustomRunner_FramesLabel,
|
||||
9F, FontStyle.Regular, Palette.TextSecondary
|
||||
);
|
||||
framesCaption.Anchor = AnchorStyles.Top | AnchorStyles.Right;
|
||||
framesCaption.TextAlign = ContentAlignment.MiddleRight;
|
||||
framesCaption.Margin = new Padding(0, 0, 12, 8);
|
||||
|
||||
var framesArea = BuildFramesArea();
|
||||
framesArea.Margin = new Padding(0, 0, 0, 8);
|
||||
framesArea.Anchor = AnchorStyles.Left | AnchorStyles.Right;
|
||||
|
||||
var previewCaption = CreateLabel(
|
||||
Strings.CustomRunner_Preview,
|
||||
9F, FontStyle.Regular, Palette.TextSecondary
|
||||
);
|
||||
previewCaption.Anchor = AnchorStyles.Top | AnchorStyles.Right;
|
||||
previewCaption.TextAlign = ContentAlignment.MiddleRight;
|
||||
previewCaption.Margin = new Padding(0, 0, 12, 8);
|
||||
|
||||
var previewArea = BuildPreviewArea();
|
||||
previewArea.Margin = new Padding(0, 0, 0, 8);
|
||||
previewArea.Anchor = AnchorStyles.Left | AnchorStyles.Right;
|
||||
|
||||
saveButton = CreateColoredButton(
|
||||
Strings.CustomRunner_Save,
|
||||
new Size(85, 30),
|
||||
Palette.AccentBlue,
|
||||
Palette.AccentBlueBorder,
|
||||
bold: true,
|
||||
initiallyEnabled: false
|
||||
);
|
||||
saveButton.Anchor = AnchorStyles.Right;
|
||||
saveButton.Margin = new Padding(0);
|
||||
|
||||
var column = new TableLayoutPanel
|
||||
{
|
||||
AutoSize = true,
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||
ColumnCount = 2,
|
||||
RowCount = 5,
|
||||
BackColor = Color.Transparent
|
||||
};
|
||||
column.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||||
column.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
column.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
}
|
||||
|
||||
column.Controls.Add(nameLabel, 0, 0);
|
||||
column.Controls.Add(nameTextBox, 1, 0);
|
||||
column.Controls.Add(requirementsCaption, 0, 1);
|
||||
column.Controls.Add(requirementsContent, 1, 1);
|
||||
column.Controls.Add(framesCaption, 0, 2);
|
||||
column.Controls.Add(framesArea, 1, 2);
|
||||
column.Controls.Add(previewCaption, 0, 3);
|
||||
column.Controls.Add(previewArea, 1, 3);
|
||||
column.Controls.Add(saveButton, 1, 4);
|
||||
return column;
|
||||
}
|
||||
|
||||
private TableLayoutPanel BuildFramesArea()
|
||||
{
|
||||
framePanel = new FlowLayoutPanel
|
||||
{
|
||||
MinimumSize = new Size(350, 280),
|
||||
AutoScroll = true,
|
||||
BackColor = Palette.FramePanelBackground,
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
WrapContents = true,
|
||||
AllowDrop = true,
|
||||
Anchor = AnchorStyles.Left | AnchorStyles.Right,
|
||||
Margin = new Padding(0, 0, 0, 4)
|
||||
};
|
||||
framePanel.DragEnter += FrameDragOver;
|
||||
framePanel.DragOver += FrameDragOver;
|
||||
framePanel.DragDrop += FramePanelDragDrop;
|
||||
|
||||
addFramesButton = CreateIconButton(
|
||||
"+",
|
||||
new Size(28, 24),
|
||||
Strings.CustomRunner_AddFrames
|
||||
);
|
||||
addFramesButton.Margin = new Padding(0, 0, 4, 0);
|
||||
|
||||
removeFrameButton = CreateIconButton(
|
||||
"−",
|
||||
new Size(28, 24),
|
||||
Strings.CustomRunner_RemoveFrame,
|
||||
initiallyEnabled: false
|
||||
);
|
||||
removeFrameButton.Margin = new Padding(0);
|
||||
|
||||
var buttonRow = new FlowLayoutPanel
|
||||
{
|
||||
AutoSize = true,
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||
FlowDirection = FlowDirection.LeftToRight,
|
||||
WrapContents = false,
|
||||
BackColor = Color.Transparent,
|
||||
Anchor = AnchorStyles.Left,
|
||||
Margin = new Padding(0)
|
||||
};
|
||||
buttonRow.Controls.Add(addFramesButton);
|
||||
buttonRow.Controls.Add(removeFrameButton);
|
||||
|
||||
var area = new TableLayoutPanel
|
||||
{
|
||||
AutoSize = true,
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||
ColumnCount = 1,
|
||||
RowCount = 2,
|
||||
BackColor = Color.Transparent
|
||||
};
|
||||
area.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||
area.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
area.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
area.Controls.Add(framePanel, 0, 0);
|
||||
area.Controls.Add(buttonRow, 0, 1);
|
||||
return area;
|
||||
}
|
||||
|
||||
private TableLayoutPanel BuildPreviewArea()
|
||||
{
|
||||
previewView = new FrameAnimationView
|
||||
{
|
||||
Size = new Size(64, 64),
|
||||
BackColor = Palette.FramePanelBackground,
|
||||
FrameIntervalMs = PREVIEW_INITIAL_INTERVAL_MS,
|
||||
Anchor = AnchorStyles.None,
|
||||
Margin = new Padding(0, 0, 12, 0)
|
||||
};
|
||||
|
||||
var turtleIcon = new PictureBox
|
||||
{
|
||||
Size = new Size(24, 24),
|
||||
SizeMode = PictureBoxSizeMode.Zoom,
|
||||
Image = Resources.slider_turtle,
|
||||
BackColor = Color.Transparent,
|
||||
Anchor = AnchorStyles.None,
|
||||
Margin = new Padding(0, 0, 8, 0)
|
||||
};
|
||||
|
||||
speedSlider = new FlatTrackBar
|
||||
{
|
||||
Height = 24,
|
||||
Minimum = 1,
|
||||
Maximum = 10,
|
||||
Value = 5,
|
||||
Anchor = AnchorStyles.Left | AnchorStyles.Right,
|
||||
Margin = new Padding(0)
|
||||
};
|
||||
toolTip.SetToolTip(speedSlider, Strings.CustomRunner_PreviewSpeed);
|
||||
|
||||
var rabbitIcon = new PictureBox
|
||||
{
|
||||
Size = new Size(24, 24),
|
||||
SizeMode = PictureBoxSizeMode.Zoom,
|
||||
Image = Resources.slider_rabbit,
|
||||
BackColor = Color.Transparent,
|
||||
Anchor = AnchorStyles.None,
|
||||
Margin = new Padding(8, 0, 0, 0)
|
||||
};
|
||||
|
||||
var area = new TableLayoutPanel
|
||||
{
|
||||
AutoSize = true,
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||
ColumnCount = 4,
|
||||
RowCount = 1,
|
||||
BackColor = Color.Transparent
|
||||
};
|
||||
area.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||||
area.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||||
area.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||
area.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||||
area.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
area.Controls.Add(previewView, 0, 0);
|
||||
area.Controls.Add(turtleIcon, 1, 0);
|
||||
area.Controls.Add(speedSlider, 2, 0);
|
||||
area.Controls.Add(rabbitIcon, 3, 0);
|
||||
return area;
|
||||
}
|
||||
|
||||
private void InitializeEventHandlers()
|
||||
{
|
||||
runnerListBox.SelectedIndexChanged += RunnerListBoxSelectedIndexChanged;
|
||||
nameTextBox.TextChanged += (sender, e) => ValidateFormState();
|
||||
|
||||
addFramesButton.Click += AddFramesButtonClick;
|
||||
removeFrameButton.Click += RemoveFrameButtonClick;
|
||||
|
||||
speedSlider.ValueChanged += (sender, e) =>
|
||||
{
|
||||
if (speedSlider.Value > 0)
|
||||
{
|
||||
previewView.FrameIntervalMs = Math.Max(PREVIEW_MIN_INTERVAL_MS, PREVIEW_BASE_RATE / speedSlider.Value);
|
||||
}
|
||||
};
|
||||
|
||||
deleteButton.Click += DeleteButtonClick;
|
||||
saveButton.Click += SaveButtonClick;
|
||||
}
|
||||
|
||||
private ThemedButton CreateIconButton(string glyph, Size size, string tooltipText, bool initiallyEnabled = true)
|
||||
{
|
||||
var button = new ThemedButton
|
||||
{
|
||||
Text = glyph,
|
||||
AutoSize = false,
|
||||
Size = size,
|
||||
MinimumSize = size,
|
||||
Padding = new Padding(0),
|
||||
FlatStyle = FlatStyle.Flat,
|
||||
BackColor = Palette.ButtonBackground,
|
||||
ForeColor = Palette.TextPrimary,
|
||||
Font = new Font("Segoe UI", 11F, FontStyle.Regular),
|
||||
Cursor = Cursors.Hand,
|
||||
Enabled = initiallyEnabled
|
||||
};
|
||||
button.FlatAppearance.BorderColor = Palette.BorderAccent;
|
||||
toolTip.SetToolTip(button, tooltipText);
|
||||
return button;
|
||||
}
|
||||
|
||||
private ThemedButton CreateIconColoredButton(
|
||||
string glyph,
|
||||
Size size,
|
||||
Color backColor,
|
||||
Color borderColor,
|
||||
string tooltipText,
|
||||
bool initiallyEnabled
|
||||
)
|
||||
{
|
||||
var button = new ThemedButton
|
||||
{
|
||||
Text = glyph,
|
||||
AutoSize = false,
|
||||
Size = size,
|
||||
MinimumSize = size,
|
||||
Padding = new Padding(0),
|
||||
FlatStyle = FlatStyle.Flat,
|
||||
BackColor = backColor,
|
||||
ForeColor = Palette.TextPrimary,
|
||||
Font = new Font("Segoe UI", 11F, FontStyle.Regular),
|
||||
Cursor = Cursors.Hand,
|
||||
Enabled = initiallyEnabled
|
||||
};
|
||||
button.FlatAppearance.BorderColor = borderColor;
|
||||
toolTip.SetToolTip(button, tooltipText);
|
||||
return button;
|
||||
}
|
||||
|
||||
private ThemedButton CreateColoredButton(
|
||||
string text,
|
||||
Size minimumSize,
|
||||
Color backColor,
|
||||
Color borderColor,
|
||||
bool bold,
|
||||
bool initiallyEnabled
|
||||
)
|
||||
{
|
||||
var button = new ThemedButton
|
||||
{
|
||||
Text = text,
|
||||
AutoSize = true,
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||
MinimumSize = minimumSize,
|
||||
Padding = new Padding(14, 4, 14, 4),
|
||||
FlatStyle = FlatStyle.Flat,
|
||||
BackColor = backColor,
|
||||
ForeColor = Palette.TextPrimary,
|
||||
Font = new Font(fontFamily, bold ? 9F : 8.5F, bold ? FontStyle.Bold : FontStyle.Regular),
|
||||
Cursor = Cursors.Hand,
|
||||
Enabled = initiallyEnabled
|
||||
};
|
||||
button.FlatAppearance.BorderColor = borderColor;
|
||||
return button;
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
{
|
||||
base.OnFormClosing(e);
|
||||
ClearPendingFrames();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (var frame in pendingFrames) frame.Dispose();
|
||||
pendingFrames.Clear();
|
||||
foreach (var frame in recoloredFrames) frame.Dispose();
|
||||
recoloredFrames.Clear();
|
||||
tileLabelFont.Dispose();
|
||||
toolTip.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void RefreshRunnerList()
|
||||
{
|
||||
runnerListBox.Items.Clear();
|
||||
foreach (var profile in repository.GetAll())
|
||||
{
|
||||
runnerListBox.Items.Add(profile.Name);
|
||||
}
|
||||
UpdateRunnerActionButtons();
|
||||
}
|
||||
|
||||
private void RunnerListBoxSelectedIndexChanged(object? sender, EventArgs e)
|
||||
{
|
||||
var hasSelection = runnerListBox.SelectedIndex >= 0;
|
||||
UpdateRunnerActionButtons();
|
||||
|
||||
if (hasSelection && runnerListBox.SelectedItem is string selectedName)
|
||||
{
|
||||
nameTextBox.Text = selectedName;
|
||||
ClearPendingFrames();
|
||||
var frames = repository.LoadFrames(selectedName);
|
||||
pendingFrames.AddRange(frames);
|
||||
selectedFrameIndex = pendingFrames.Count > 0 ? 0 : -1;
|
||||
OnFramesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddFramesButtonClick(object? sender, EventArgs e)
|
||||
{
|
||||
using var dialog = new OpenFileDialog
|
||||
{
|
||||
Filter = "PNG Images|*.png",
|
||||
Multiselect = true,
|
||||
Title = Strings.CustomRunner_AddFrames
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog() != DialogResult.OK) return;
|
||||
|
||||
var sortedFiles = dialog.FileNames.OrderBy(f => f).ToArray();
|
||||
foreach (var file in sortedFiles)
|
||||
{
|
||||
if (pendingFrames.Count >= CustomRunnerRepository.MAX_FRAME_COUNT) break;
|
||||
try
|
||||
{
|
||||
pendingFrames.Add(new Bitmap(file));
|
||||
}
|
||||
catch (Exception ex) when (ex is OutOfMemoryException or ArgumentException or FileNotFoundException)
|
||||
{
|
||||
Debug.WriteLine($"Failed to load frame '{file}': {ex.Message}");
|
||||
}
|
||||
}
|
||||
OnFramesChanged();
|
||||
}
|
||||
|
||||
private void RemoveFrameButtonClick(object? sender, EventArgs e)
|
||||
{
|
||||
if (selectedFrameIndex < 0 || pendingFrames.Count <= selectedFrameIndex) return;
|
||||
|
||||
pendingFrames[selectedFrameIndex].Dispose();
|
||||
pendingFrames.RemoveAt(selectedFrameIndex);
|
||||
selectedFrameIndex = pendingFrames.Count == 0
|
||||
? -1
|
||||
: Math.Min(selectedFrameIndex, pendingFrames.Count - 1);
|
||||
OnFramesChanged();
|
||||
}
|
||||
|
||||
private void OnFramesChanged()
|
||||
{
|
||||
RebuildRecoloredFrames();
|
||||
RebuildFrameGrid();
|
||||
RestartPreview();
|
||||
ValidateFormState();
|
||||
}
|
||||
|
||||
private void RebuildRecoloredFrames()
|
||||
{
|
||||
foreach (var frame in recoloredFrames) frame.Dispose();
|
||||
recoloredFrames.Clear();
|
||||
foreach (var frame in pendingFrames)
|
||||
{
|
||||
recoloredFrames.Add(frame.Recolor(Color.White));
|
||||
}
|
||||
if (pendingFrames.Count <= selectedFrameIndex)
|
||||
{
|
||||
selectedFrameIndex = pendingFrames.Count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildFrameGrid()
|
||||
{
|
||||
framePanel.SuspendLayout();
|
||||
foreach (Control oldTile in framePanel.Controls)
|
||||
{
|
||||
oldTile.Dispose();
|
||||
}
|
||||
framePanel.Controls.Clear();
|
||||
|
||||
for (int i = 0; i < recoloredFrames.Count; i++)
|
||||
{
|
||||
framePanel.Controls.Add(CreateFrameTile(i));
|
||||
}
|
||||
|
||||
framePanel.ResumeLayout();
|
||||
}
|
||||
|
||||
private Panel CreateFrameTile(int frameIndex)
|
||||
{
|
||||
var container = new Panel
|
||||
{
|
||||
Size = new Size(70, 76),
|
||||
Margin = new Padding(4),
|
||||
BackColor = frameIndex == selectedFrameIndex ? Palette.SelectionHighlight : Color.Transparent,
|
||||
Cursor = Cursors.SizeAll
|
||||
};
|
||||
|
||||
var pictureBox = new PictureBox
|
||||
{
|
||||
Size = new Size(48, 48),
|
||||
Location = new Point(11, 0),
|
||||
SizeMode = PictureBoxSizeMode.Zoom,
|
||||
Image = recoloredFrames[frameIndex],
|
||||
BackColor = Palette.FrameThumbnailBackground,
|
||||
Cursor = Cursors.SizeAll
|
||||
};
|
||||
|
||||
var indexLabel = new Label
|
||||
{
|
||||
Text = $"{frameIndex}",
|
||||
Size = new Size(70, 18),
|
||||
Location = new Point(0, 52),
|
||||
TextAlign = ContentAlignment.TopCenter,
|
||||
ForeColor = Palette.TextThumbnailIndex,
|
||||
Font = tileLabelFont,
|
||||
Cursor = Cursors.SizeAll
|
||||
};
|
||||
|
||||
foreach (var control in new Control[] { container, pictureBox, indexLabel })
|
||||
{
|
||||
control.Click += (sender, e) => SelectFrame(frameIndex);
|
||||
WireFrameDragSource(control, frameIndex);
|
||||
WireFrameDragReceiver(control, frameIndex);
|
||||
}
|
||||
|
||||
container.Controls.Add(pictureBox);
|
||||
container.Controls.Add(indexLabel);
|
||||
return container;
|
||||
}
|
||||
|
||||
private void WireFrameDragSource(Control control, int frameIndex)
|
||||
{
|
||||
control.MouseDown += (sender, e) =>
|
||||
{
|
||||
if (e.Button != MouseButtons.Left) return;
|
||||
dragOriginPoint = e.Location;
|
||||
dragSourceIndex = frameIndex;
|
||||
};
|
||||
control.MouseMove += (sender, e) =>
|
||||
{
|
||||
if (dragOriginPoint is null || dragSourceIndex < 0) return;
|
||||
if (e.Button != MouseButtons.Left) return;
|
||||
var dx = Math.Abs(e.X - dragOriginPoint.Value.X);
|
||||
var dy = Math.Abs(e.Y - dragOriginPoint.Value.Y);
|
||||
if (dx < SystemInformation.DragSize.Width && dy < SystemInformation.DragSize.Height) return;
|
||||
var startedIndex = dragSourceIndex;
|
||||
dragOriginPoint = null;
|
||||
dragSourceIndex = -1;
|
||||
control.DoDragDrop(startedIndex, DragDropEffects.Move);
|
||||
};
|
||||
control.MouseUp += (sender, e) =>
|
||||
{
|
||||
dragOriginPoint = null;
|
||||
dragSourceIndex = -1;
|
||||
};
|
||||
}
|
||||
|
||||
private void WireFrameDragReceiver(Control control, int frameIndex)
|
||||
{
|
||||
control.AllowDrop = true;
|
||||
control.DragEnter += FrameDragOver;
|
||||
control.DragOver += FrameDragOver;
|
||||
control.DragDrop += (sender, e) => HandleFrameDrop(e, frameIndex);
|
||||
}
|
||||
|
||||
private static void FrameDragOver(object? sender, DragEventArgs e)
|
||||
{
|
||||
e.Effect = e.Data?.GetDataPresent(typeof(int)) == true
|
||||
? DragDropEffects.Move
|
||||
: DragDropEffects.None;
|
||||
}
|
||||
|
||||
private void HandleFrameDrop(DragEventArgs e, int targetIndex)
|
||||
{
|
||||
if (e.Data?.GetData(typeof(int)) is not int sourceIndex) return;
|
||||
ReorderFrame(sourceIndex, targetIndex);
|
||||
}
|
||||
|
||||
private void FramePanelDragDrop(object? sender, DragEventArgs e)
|
||||
{
|
||||
if (e.Data?.GetData(typeof(int)) is not int sourceIndex) return;
|
||||
ReorderFrame(sourceIndex, pendingFrames.Count);
|
||||
}
|
||||
|
||||
private void ReorderFrame(int sourceIndex, int targetIndex)
|
||||
{
|
||||
if (sourceIndex < 0 || sourceIndex >= pendingFrames.Count) return;
|
||||
if (sourceIndex == targetIndex) return;
|
||||
|
||||
var item = pendingFrames[sourceIndex];
|
||||
pendingFrames.RemoveAt(sourceIndex);
|
||||
|
||||
var insertAt = sourceIndex < targetIndex ? targetIndex - 1 : targetIndex;
|
||||
insertAt = Math.Clamp(insertAt, 0, pendingFrames.Count);
|
||||
pendingFrames.Insert(insertAt, item);
|
||||
|
||||
selectedFrameIndex = insertAt;
|
||||
OnFramesChanged();
|
||||
}
|
||||
|
||||
private void RestartPreview()
|
||||
{
|
||||
previewView.FrameIntervalMs = Math.Max(PREVIEW_MIN_INTERVAL_MS, PREVIEW_BASE_RATE / speedSlider.Value);
|
||||
previewView.SetFrames(recoloredFrames);
|
||||
}
|
||||
|
||||
private void SelectFrame(int frameIndex)
|
||||
{
|
||||
if (frameIndex < 0 || pendingFrames.Count <= frameIndex) return;
|
||||
selectedFrameIndex = frameIndex;
|
||||
RebuildFrameGrid();
|
||||
UpdateFrameActionButtons();
|
||||
}
|
||||
|
||||
private void ValidateFormState()
|
||||
{
|
||||
var name = nameTextBox.Text.Trim();
|
||||
bool hasValidName = !string.IsNullOrWhiteSpace(name);
|
||||
bool hasValidFrames = pendingFrames.Count >= CustomRunnerRepository.MIN_FRAME_COUNT;
|
||||
|
||||
saveButton.Enabled = hasValidName && hasValidFrames;
|
||||
|
||||
UpdateFrameActionButtons();
|
||||
}
|
||||
|
||||
private void UpdateFrameActionButtons()
|
||||
{
|
||||
var hasSelectedFrame = 0 <= selectedFrameIndex && selectedFrameIndex < pendingFrames.Count;
|
||||
removeFrameButton.Enabled = hasSelectedFrame;
|
||||
}
|
||||
|
||||
private void UpdateRunnerActionButtons()
|
||||
{
|
||||
deleteButton.Enabled = runnerListBox.SelectedIndex >= 0;
|
||||
}
|
||||
|
||||
private void SaveButtonClick(object? sender, EventArgs e)
|
||||
{
|
||||
var name = nameTextBox.Text.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name)) return;
|
||||
if (pendingFrames.Count < CustomRunnerRepository.MIN_FRAME_COUNT) return;
|
||||
|
||||
if (repository.Exists(name))
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
Strings.CustomRunner_ConfirmOverwrite,
|
||||
Strings.Message_Warning,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question
|
||||
);
|
||||
if (result != DialogResult.Yes) return;
|
||||
}
|
||||
|
||||
if (repository.Save(name, pendingFrames))
|
||||
{
|
||||
RefreshRunnerList();
|
||||
for (int i = 0; i < runnerListBox.Items.Count; i++)
|
||||
{
|
||||
if (runnerListBox.Items[i] is string itemName &&
|
||||
itemName.Equals(name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
runnerListBox.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ValidateFormState();
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteButtonClick(object? sender, EventArgs e)
|
||||
{
|
||||
if (runnerListBox.SelectedItem is not string selectedName) return;
|
||||
|
||||
var result = MessageBox.Show(
|
||||
string.Format(Strings.CustomRunner_ConfirmDelete, selectedName),
|
||||
Strings.Message_Warning,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Warning
|
||||
);
|
||||
if (result != DialogResult.Yes) return;
|
||||
|
||||
repository.Delete(selectedName);
|
||||
onCustomRunnerDeleted(selectedName);
|
||||
ClearPendingFrames();
|
||||
OnFramesChanged();
|
||||
nameTextBox.Clear();
|
||||
RefreshRunnerList();
|
||||
UpdateRunnerActionButtons();
|
||||
}
|
||||
|
||||
private void ClearPendingFrames()
|
||||
{
|
||||
previewView.Clear();
|
||||
foreach (var frame in pendingFrames) frame.Dispose();
|
||||
pendingFrames.Clear();
|
||||
foreach (var frame in recoloredFrames) frame.Dispose();
|
||||
recoloredFrames.Clear();
|
||||
selectedFrameIndex = -1;
|
||||
UpdateFrameActionButtons();
|
||||
}
|
||||
|
||||
private static class Palette
|
||||
{
|
||||
internal static readonly Color FormBackground = Color.FromArgb(45, 45, 45);
|
||||
internal static readonly Color ControlBackground = Color.FromArgb(60, 60, 60);
|
||||
internal static readonly Color ButtonBackground = Color.FromArgb(70, 70, 70);
|
||||
internal static readonly Color BorderAccent = Color.FromArgb(100, 100, 100);
|
||||
internal static readonly Color FramePanelBackground = Color.FromArgb(55, 55, 55);
|
||||
internal static readonly Color FrameThumbnailBackground = Color.FromArgb(40, 40, 40);
|
||||
internal static readonly Color SelectionHighlight = Color.FromArgb(75, 95, 125);
|
||||
internal static readonly Color TextPrimary = Color.White;
|
||||
internal static readonly Color TextSecondary = Color.FromArgb(200, 200, 200);
|
||||
internal static readonly Color TextMuted = Color.FromArgb(150, 150, 150);
|
||||
internal static readonly Color TextThumbnailIndex = Color.FromArgb(170, 170, 170);
|
||||
internal static readonly Color DangerRed = Color.FromArgb(120, 40, 40);
|
||||
internal static readonly Color DangerBorder = Color.FromArgb(150, 60, 60);
|
||||
internal static readonly Color AccentBlue = Color.FromArgb(50, 90, 160);
|
||||
internal static readonly Color AccentBlueBorder = Color.FromArgb(70, 120, 200);
|
||||
}
|
||||
|
||||
private sealed class ThemedButton : Button
|
||||
{
|
||||
private static readonly Color DisabledBackColor = Color.FromArgb(58, 58, 58);
|
||||
private static readonly Color DisabledForeColor = Color.FromArgb(145, 145, 145);
|
||||
private static readonly Color DisabledBorderColor = Color.FromArgb(82, 82, 82);
|
||||
|
||||
protected override void OnEnabledChanged(EventArgs e)
|
||||
{
|
||||
base.OnEnabledChanged(e);
|
||||
Cursor = Enabled ? Cursors.Hand : Cursors.Default;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
var backColor = Enabled ? BackColor : DisabledBackColor;
|
||||
var foreColor = Enabled ? ForeColor : DisabledForeColor;
|
||||
var borderColor = Enabled ? FlatAppearance.BorderColor : DisabledBorderColor;
|
||||
|
||||
using var backBrush = new SolidBrush(backColor);
|
||||
using var borderPen = new Pen(borderColor);
|
||||
e.Graphics.FillRectangle(backBrush, ClientRectangle);
|
||||
e.Graphics.DrawRectangle(borderPen, 0, 0, Width - 1, Height - 1);
|
||||
|
||||
var textSize = TextRenderer.MeasureText(e.Graphics, Text, Font, ClientSize, TextFormatFlags.NoPadding);
|
||||
var location = new Point(
|
||||
(Width - textSize.Width) / 2,
|
||||
(Height - textSize.Height) / 2
|
||||
);
|
||||
TextRenderer.DrawText(e.Graphics, Text, Font, location, foreColor, TextFormatFlags.NoPadding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal class CustomRunnerProfile
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("frameFileNames")]
|
||||
public List<string> FrameFileNames { get; set; } = [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal class CustomRunnerRepository
|
||||
{
|
||||
internal const int MIN_FRAME_COUNT = 2;
|
||||
internal const int MAX_FRAME_COUNT = 30;
|
||||
private const int MAX_FRAME_HEIGHT = 32;
|
||||
private const int MIN_FRAME_WIDTH = 10;
|
||||
private const int MAX_FRAME_WIDTH = 32;
|
||||
private const string PROFILES_FILE_NAME = "profiles.json";
|
||||
|
||||
private readonly string basePath;
|
||||
private List<CustomRunnerProfile> profiles = [];
|
||||
|
||||
internal CustomRunnerRepository()
|
||||
{
|
||||
basePath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"RunCat365",
|
||||
"CustomRunners"
|
||||
);
|
||||
Directory.CreateDirectory(basePath);
|
||||
Load();
|
||||
}
|
||||
|
||||
internal List<CustomRunnerProfile> GetAll()
|
||||
{
|
||||
return [.. profiles];
|
||||
}
|
||||
|
||||
internal CustomRunnerProfile? GetByName(string name)
|
||||
{
|
||||
return profiles.Find(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
internal List<Bitmap> LoadFrames(string name)
|
||||
{
|
||||
var profile = GetByName(name);
|
||||
if (profile is null) return [];
|
||||
|
||||
var runnerDirectory = Path.Combine(basePath, SanitizeDirectoryName(name));
|
||||
var frames = new List<Bitmap>();
|
||||
foreach (var fileName in profile.FrameFileNames)
|
||||
{
|
||||
var filePath = Path.Combine(runnerDirectory, fileName);
|
||||
if (!File.Exists(filePath)) continue;
|
||||
var frame = TryLoadBitmap(filePath);
|
||||
if (frame is not null) frames.Add(frame);
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
internal Bitmap? LoadFirstFrame(string name)
|
||||
{
|
||||
var profile = GetByName(name);
|
||||
if (profile is null || profile.FrameFileNames.Count == 0) return null;
|
||||
var runnerDirectory = Path.Combine(basePath, SanitizeDirectoryName(name));
|
||||
var filePath = Path.Combine(runnerDirectory, profile.FrameFileNames[0]);
|
||||
return File.Exists(filePath) ? TryLoadBitmap(filePath) : null;
|
||||
}
|
||||
|
||||
private static Bitmap? TryLoadBitmap(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new Bitmap(filePath);
|
||||
}
|
||||
catch (Exception ex) when (ex is ArgumentException or OutOfMemoryException or FileNotFoundException)
|
||||
{
|
||||
Debug.WriteLine($"Failed to load custom runner frame '{filePath}': {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool Save(string name, List<Bitmap> frames)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) return false;
|
||||
if (frames.Count < MIN_FRAME_COUNT || frames.Count > MAX_FRAME_COUNT) return false;
|
||||
|
||||
var runnerDirectory = Path.Combine(basePath, SanitizeDirectoryName(name));
|
||||
Directory.CreateDirectory(runnerDirectory);
|
||||
|
||||
var existingProfile = GetByName(name);
|
||||
if (existingProfile is not null)
|
||||
{
|
||||
DeleteFrameFiles(existingProfile);
|
||||
profiles.Remove(existingProfile);
|
||||
}
|
||||
|
||||
var profile = new CustomRunnerProfile { Name = name };
|
||||
for (int i = 0; i < frames.Count; i++)
|
||||
{
|
||||
using var resized = ResizeFrame(frames[i]);
|
||||
var fileName = $"frame_{i}.png";
|
||||
var filePath = Path.Combine(runnerDirectory, fileName);
|
||||
resized.Save(filePath, ImageFormat.Png);
|
||||
profile.FrameFileNames.Add(fileName);
|
||||
}
|
||||
|
||||
profiles.Add(profile);
|
||||
return TrySaveProfiles();
|
||||
}
|
||||
|
||||
internal bool Delete(string name)
|
||||
{
|
||||
var profile = GetByName(name);
|
||||
if (profile is null) return false;
|
||||
|
||||
DeleteFrameFiles(profile);
|
||||
var runnerDirectory = Path.Combine(basePath, SanitizeDirectoryName(name));
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(runnerDirectory))
|
||||
{
|
||||
Directory.Delete(runnerDirectory, true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
Debug.WriteLine($"Failed to delete runner directory '{runnerDirectory}': {ex.Message}");
|
||||
}
|
||||
|
||||
profiles.Remove(profile);
|
||||
TrySaveProfiles();
|
||||
return true;
|
||||
}
|
||||
|
||||
internal bool Exists(string name)
|
||||
{
|
||||
return GetByName(name) is not null;
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
var profilesPath = Path.Combine(basePath, PROFILES_FILE_NAME);
|
||||
if (!File.Exists(profilesPath))
|
||||
{
|
||||
profiles = [];
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(profilesPath);
|
||||
profiles = JsonSerializer.Deserialize<List<CustomRunnerProfile>>(json) ?? [];
|
||||
}
|
||||
catch (Exception ex) when (ex is JsonException or IOException or UnauthorizedAccessException)
|
||||
{
|
||||
Debug.WriteLine($"Failed to load custom runner profiles: {ex.Message}");
|
||||
profiles = [];
|
||||
}
|
||||
}
|
||||
|
||||
private bool TrySaveProfiles()
|
||||
{
|
||||
var profilesPath = Path.Combine(basePath, PROFILES_FILE_NAME);
|
||||
try
|
||||
{
|
||||
var options = new JsonSerializerOptions { WriteIndented = true };
|
||||
var json = JsonSerializer.Serialize(profiles, options);
|
||||
File.WriteAllText(profilesPath, json);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
Debug.WriteLine($"Failed to write custom runner profiles: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteFrameFiles(CustomRunnerProfile profile)
|
||||
{
|
||||
var runnerDirectory = Path.Combine(basePath, SanitizeDirectoryName(profile.Name));
|
||||
foreach (var fileName in profile.FrameFileNames)
|
||||
{
|
||||
var filePath = Path.Combine(runnerDirectory, fileName);
|
||||
try
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
Debug.WriteLine($"Failed to delete frame file '{filePath}': {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap ResizeFrame(Bitmap original)
|
||||
{
|
||||
if (original.Height <= MAX_FRAME_HEIGHT &&
|
||||
original.Width >= MIN_FRAME_WIDTH &&
|
||||
original.Width <= MAX_FRAME_WIDTH)
|
||||
{
|
||||
return new Bitmap(original);
|
||||
}
|
||||
|
||||
var scale = (float)MAX_FRAME_HEIGHT / original.Height;
|
||||
var newWidth = Math.Clamp((int)(original.Width * scale), MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
|
||||
var newHeight = MAX_FRAME_HEIGHT;
|
||||
|
||||
var resized = new Bitmap(newWidth, newHeight);
|
||||
using var graphics = Graphics.FromImage(resized);
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
graphics.DrawImage(original, 0, 0, newWidth, newHeight);
|
||||
return resized;
|
||||
}
|
||||
|
||||
private static string SanitizeDirectoryName(string name)
|
||||
{
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
var sanitized = new string(name.Select(c => invalidChars.Contains(c) ? '_' : c).ToArray());
|
||||
return sanitized.ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal class CustomToolStripMenuItem : ToolStripMenuItem
|
||||
{
|
||||
private static readonly Font MenuFont = new(
|
||||
SupportedLanguageExtension.GetCurrentLanguage().GetFontName(),
|
||||
9F,
|
||||
FontStyle.Regular
|
||||
);
|
||||
|
||||
internal CustomToolStripMenuItem() : base()
|
||||
{
|
||||
Font = MenuFont;
|
||||
}
|
||||
|
||||
internal CustomToolStripMenuItem(string? text) : base(text)
|
||||
{
|
||||
Font = MenuFont;
|
||||
}
|
||||
|
||||
private CustomToolStripMenuItem(string? text, Image? image, object? tag, bool isChecked, EventHandler? onClick) : base(text, image, onClick)
|
||||
{
|
||||
Tag = tag;
|
||||
Checked = isChecked;
|
||||
Font = MenuFont;
|
||||
}
|
||||
|
||||
private readonly TextFormatFlags multiLineTextFlags =
|
||||
TextFormatFlags.LeftAndRightPadding |
|
||||
TextFormatFlags.VerticalCenter |
|
||||
TextFormatFlags.WordBreak |
|
||||
TextFormatFlags.TextBoxControl;
|
||||
|
||||
private readonly TextFormatFlags singleLineTextFlags =
|
||||
TextFormatFlags.LeftAndRightPadding |
|
||||
TextFormatFlags.VerticalCenter |
|
||||
TextFormatFlags.EndEllipsis;
|
||||
|
||||
public override Size GetPreferredSize(Size constrainingSize)
|
||||
{
|
||||
Size baseSize = base.GetPreferredSize(constrainingSize);
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
{
|
||||
return new Size(baseSize.Width, 22);
|
||||
}
|
||||
var textRenderWidth = Math.Max(constrainingSize.Width - 20, 1);
|
||||
|
||||
SizeF measuredSize = TextRenderer.MeasureText(
|
||||
Text,
|
||||
Font,
|
||||
new Size(textRenderWidth, int.MaxValue),
|
||||
Flags()
|
||||
);
|
||||
var calculatedHeight = (int)Math.Ceiling(measuredSize.Height) + 4;
|
||||
var height = IsSingleLine() ? calculatedHeight : Math.Max(baseSize.Height, calculatedHeight);
|
||||
return new Size(baseSize.Width, height);
|
||||
}
|
||||
|
||||
internal bool IsSingleLine()
|
||||
{
|
||||
return string.IsNullOrEmpty(Text) || !Text.Contains('\n');
|
||||
}
|
||||
|
||||
internal TextFormatFlags Flags()
|
||||
{
|
||||
return IsSingleLine() ? singleLineTextFlags : multiLineTextFlags;
|
||||
}
|
||||
|
||||
internal void SetupSubMenusFromEnum<T>(
|
||||
Func<T, string> getTitle,
|
||||
Action<CustomToolStripMenuItem, object?, EventArgs> onClick,
|
||||
Func<T, bool> isChecked,
|
||||
Func<Runner, Bitmap?> getRunnerThumbnailBitmap,
|
||||
Func<T, bool>? isVisible = null
|
||||
) where T : Enum
|
||||
{
|
||||
isVisible ??= _ => true;
|
||||
var items = new List<CustomToolStripMenuItem>();
|
||||
foreach (T value in Enum.GetValues(typeof(T)))
|
||||
{
|
||||
if (!isVisible(value)) continue;
|
||||
var entityName = getTitle(value);
|
||||
var iconImage = value is Runner runner ? getRunnerThumbnailBitmap(runner) : null;
|
||||
var item = new CustomToolStripMenuItem(
|
||||
entityName,
|
||||
iconImage,
|
||||
value,
|
||||
isChecked(value),
|
||||
(sender, e) => onClick(this, sender, e)
|
||||
);
|
||||
items.Add(item);
|
||||
}
|
||||
DropDownItems.AddRange([.. items]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using FormsTimer = System.Windows.Forms.Timer;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal class EndlessGameForm : Form
|
||||
{
|
||||
private const int JUMP_THRESHOLD = 17;
|
||||
private readonly FormsTimer timer;
|
||||
private readonly Theme systemTheme;
|
||||
private GameStatus status = GameStatus.NewGame;
|
||||
private Cat cat = new Cat.Running(Cat.Running.Frame.Frame0);
|
||||
private readonly List<Road> roads = [];
|
||||
private readonly Dictionary<string, Bitmap> catIcons = [];
|
||||
private readonly Dictionary<string, Bitmap> roadIcons = [];
|
||||
private int counter = 0;
|
||||
private int limit = 5;
|
||||
private int score = 0;
|
||||
private int highScore = UserSettings.Default.HighScore;
|
||||
private bool isJumpRequested = false;
|
||||
private readonly bool isAutoPlay = false;
|
||||
|
||||
internal EndlessGameForm(Theme systemTheme)
|
||||
{
|
||||
this.systemTheme = systemTheme;
|
||||
|
||||
DoubleBuffered = true;
|
||||
ClientSize = new Size(600, 250);
|
||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
MaximizeBox = false;
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = Strings.Window_EndlessGame;
|
||||
Icon = Resources.AppIcon;
|
||||
BackColor = systemTheme == Theme.Light ? Color.Gainsboro : Color.Gray;
|
||||
|
||||
var rm = Resources.ResourceManager;
|
||||
var rs = rm.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
|
||||
if (rs is not null)
|
||||
{
|
||||
var catRegex = new Regex(@"^cat_.*_.*$");
|
||||
var color = systemTheme.GetContrastColor();
|
||||
foreach (DictionaryEntry entry in rs)
|
||||
{
|
||||
var key = entry.Key.ToString();
|
||||
if (string.IsNullOrEmpty(key)) continue;
|
||||
|
||||
if (catRegex.IsMatch(key))
|
||||
{
|
||||
if (entry.Value is Bitmap icon)
|
||||
{
|
||||
catIcons.Add(key, systemTheme == Theme.Light ? new Bitmap(icon) : icon.Recolor(color));
|
||||
}
|
||||
}
|
||||
else if (key.StartsWith("road"))
|
||||
{
|
||||
if (entry.Value is Bitmap icon)
|
||||
{
|
||||
roadIcons.Add(key, systemTheme == Theme.Light ? new Bitmap(icon) : icon.Recolor(color));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Paint += RenderScene;
|
||||
|
||||
KeyDown += HandleKeyDown;
|
||||
|
||||
timer = new FormsTimer
|
||||
{
|
||||
Interval = 100
|
||||
};
|
||||
timer.Tick += GameTick;
|
||||
|
||||
Initialize();
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
{
|
||||
base.OnFormClosing(e);
|
||||
timer.Stop();
|
||||
timer.Dispose();
|
||||
|
||||
foreach (var bitmap in catIcons.Values) bitmap.Dispose();
|
||||
foreach (var bitmap in roadIcons.Values) bitmap.Dispose();
|
||||
catIcons.Clear();
|
||||
roadIcons.Clear();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
counter = JUMP_THRESHOLD;
|
||||
isJumpRequested = false;
|
||||
score = 0;
|
||||
cat = new Cat.Running(Cat.Running.Frame.Frame0);
|
||||
roads.RemoveAll(r => r == Road.Sprout);
|
||||
Enumerable.Range(0, 20 - roads.Count).ToList().ForEach(
|
||||
_ => roads.Add((Road)(new Random().Next(0, 3)))
|
||||
);
|
||||
}
|
||||
|
||||
private bool Judge()
|
||||
{
|
||||
if (status != GameStatus.Playing) return false;
|
||||
var sproutIndices = roads
|
||||
.Select((road, index) => { return road == Road.Sprout ? index : (int?)null; })
|
||||
.OfType<int>()
|
||||
.ToList();
|
||||
if (cat.ViolationIndices().HasCommonElements(sproutIndices))
|
||||
{
|
||||
status = GameStatus.GameOver;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRoads()
|
||||
{
|
||||
var firstRoad = roads.First();
|
||||
roads.RemoveAt(0);
|
||||
if (firstRoad == Road.Sprout)
|
||||
{
|
||||
score = Math.Min(score + 1, 999);
|
||||
highScore = Math.Max(score, highScore);
|
||||
}
|
||||
counter = counter > 0 ? counter - 1 : limit - 1;
|
||||
if (counter == 0)
|
||||
{
|
||||
var randomValue = new Random().Next(0, 27);
|
||||
var subRoads = new List<Road>();
|
||||
if (randomValue % 3 == 0)
|
||||
{
|
||||
subRoads.Add(Road.Sprout);
|
||||
}
|
||||
if (randomValue % 9 == 0)
|
||||
{
|
||||
subRoads.Add(Road.Sprout);
|
||||
}
|
||||
if (randomValue % 27 == 0)
|
||||
{
|
||||
subRoads.Add(Road.Sprout);
|
||||
}
|
||||
roads.AddRange(subRoads);
|
||||
limit = subRoads.Count == 0 ? 5 : 10;
|
||||
}
|
||||
if (roads.Count < 20)
|
||||
{
|
||||
roads.Add((Road)(new Random().Next(0, 3)));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCat()
|
||||
{
|
||||
if (cat is Cat.Running runningCat)
|
||||
{
|
||||
if (runningCat.CurrentFrame == Cat.Running.Frame.Frame4 && isJumpRequested)
|
||||
{
|
||||
cat = new Cat.Jumping(Cat.Jumping.Frame.Frame0);
|
||||
isJumpRequested = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (cat is Cat.Jumping jumpingCat)
|
||||
{
|
||||
if (jumpingCat.CurrentFrame == Cat.Jumping.Frame.Frame9)
|
||||
{
|
||||
if (isJumpRequested)
|
||||
{
|
||||
cat = cat.Next();
|
||||
isJumpRequested = false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
cat = new Cat.Running(Cat.Running.Frame.Frame0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
cat = cat.Next();
|
||||
}
|
||||
|
||||
private void AutoJump()
|
||||
{
|
||||
if (isAutoPlay && roads[JUMP_THRESHOLD - 1] == Road.Sprout)
|
||||
{
|
||||
isJumpRequested = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void GameTick(object? sender, EventArgs e)
|
||||
{
|
||||
if (Judge())
|
||||
{
|
||||
UpdateRoads();
|
||||
UpdateCat();
|
||||
AutoJump();
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
private void HandleKeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Space)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case GameStatus.NewGame:
|
||||
case GameStatus.GameOver:
|
||||
Initialize();
|
||||
status = GameStatus.Playing;
|
||||
break;
|
||||
case GameStatus.Playing when !isAutoPlay:
|
||||
isJumpRequested = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderScene(object? sender, PaintEventArgs e)
|
||||
{
|
||||
var rm = Resources.ResourceManager;
|
||||
var textColor = systemTheme.GetContrastColor();
|
||||
var g = e.Graphics;
|
||||
|
||||
using (Font font15 = new("Consolas", 15))
|
||||
using (Brush brush = new SolidBrush(textColor))
|
||||
{
|
||||
var stringFormat = new StringFormat
|
||||
{
|
||||
Alignment = StringAlignment.Far,
|
||||
LineAlignment = StringAlignment.Center
|
||||
};
|
||||
var scoreText = status == GameStatus.GameOver
|
||||
? $"HI {highScore:D3} {score:D3}"
|
||||
: $"{score:D3}";
|
||||
g.DrawString(scoreText, font15, brush, new Rectangle(20, 0, 560, 50), stringFormat);
|
||||
}
|
||||
|
||||
roads.Take(20).Select((road, index) => new { road, index }).ToList().ForEach(
|
||||
item =>
|
||||
{
|
||||
var fileName = $"road_{item.road.GetString()}".ToLower();
|
||||
if (!roadIcons.TryGetValue(fileName, out Bitmap? image)) return;
|
||||
g.DrawImage(image, new Rectangle(item.index * 30, 200, 30, 50));
|
||||
}
|
||||
);
|
||||
|
||||
var fileName = $"cat_{cat.GetString()}".ToLower();
|
||||
if (!catIcons.TryGetValue(fileName, out Bitmap? image)) return;
|
||||
g.DrawImage(image, new Rectangle(120, 130, 120, 100));
|
||||
|
||||
if (status != GameStatus.Playing)
|
||||
{
|
||||
using Brush fillBrush = new SolidBrush(Color.FromArgb(77, 0, 0, 0));
|
||||
g.FillRectangle(fillBrush, new Rectangle(0, 0, 600, 250));
|
||||
|
||||
using Font font18 = new("Segoe UI", 16, FontStyle.Bold);
|
||||
using Brush brush = new SolidBrush(textColor);
|
||||
var message = Strings.Game_PressSpaceToPlay;
|
||||
if (status == GameStatus.GameOver)
|
||||
{
|
||||
if (score >= highScore)
|
||||
{
|
||||
SaveRecord(score);
|
||||
message = $"{Strings.Game_NewRecord}!!\n{message}";
|
||||
}
|
||||
else
|
||||
{
|
||||
message = $"{Strings.Game_GameOver}\n{message}";
|
||||
}
|
||||
}
|
||||
var stringFormat = new StringFormat
|
||||
{
|
||||
Alignment = StringAlignment.Center,
|
||||
LineAlignment = StringAlignment.Center
|
||||
};
|
||||
g.DrawString(message, font18, brush, new Rectangle(0, 0, 600, 250), stringFormat);
|
||||
}
|
||||
}
|
||||
private void SaveRecord(int score)
|
||||
{
|
||||
UserSettings.Default.HighScore = score;
|
||||
UserSettings.Default.Save();
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ListExtension
|
||||
{
|
||||
internal static bool HasCommonElements(this List<int> list1, List<int> list2)
|
||||
{
|
||||
return list1.Intersect(list2).Any();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
enum FPSMaxLimit
|
||||
{
|
||||
FPS40,
|
||||
FPS30,
|
||||
FPS20,
|
||||
FPS10,
|
||||
}
|
||||
|
||||
internal static class FPSMaxLimitExtension
|
||||
{
|
||||
internal static string GetString(this FPSMaxLimit fpsMaxLimit)
|
||||
{
|
||||
return fpsMaxLimit switch
|
||||
{
|
||||
FPSMaxLimit.FPS40 => "40fps",
|
||||
FPSMaxLimit.FPS30 => "30fps",
|
||||
FPSMaxLimit.FPS20 => "20fps",
|
||||
FPSMaxLimit.FPS10 => "10fps",
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
internal static float GetRate(this FPSMaxLimit fpsMaxLimit)
|
||||
{
|
||||
return fpsMaxLimit switch
|
||||
{
|
||||
FPSMaxLimit.FPS40 => 1f,
|
||||
FPSMaxLimit.FPS30 => 0.75f,
|
||||
FPSMaxLimit.FPS20 => 0.5f,
|
||||
FPSMaxLimit.FPS10 => 0.25f,
|
||||
_ => 1f,
|
||||
};
|
||||
}
|
||||
|
||||
internal static bool TryParse([NotNullWhen(true)] string? value, out FPSMaxLimit result)
|
||||
{
|
||||
FPSMaxLimit? nullableResult = value switch
|
||||
{
|
||||
"40fps" => FPSMaxLimit.FPS40,
|
||||
"30fps" => FPSMaxLimit.FPS30,
|
||||
"20fps" => FPSMaxLimit.FPS20,
|
||||
"10fps" => FPSMaxLimit.FPS10,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
if (nullableResult is FPSMaxLimit nonNullableResult)
|
||||
{
|
||||
result = nonNullableResult;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = FPSMaxLimit.FPS40;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal sealed class FlatTrackBar : Control
|
||||
{
|
||||
private int minimum = 1;
|
||||
private int maximum = 10;
|
||||
private int currentValue = 5;
|
||||
private bool dragging;
|
||||
|
||||
internal event EventHandler? ValueChanged;
|
||||
|
||||
[DefaultValue(1)]
|
||||
internal int Minimum
|
||||
{
|
||||
get => minimum;
|
||||
set
|
||||
{
|
||||
minimum = value;
|
||||
if (currentValue < minimum) Value = minimum;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[DefaultValue(10)]
|
||||
internal int Maximum
|
||||
{
|
||||
get => maximum;
|
||||
set
|
||||
{
|
||||
maximum = value;
|
||||
if (currentValue > maximum) Value = maximum;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
[DefaultValue(5)]
|
||||
internal int Value
|
||||
{
|
||||
get => currentValue;
|
||||
set
|
||||
{
|
||||
var clamped = Math.Clamp(value, minimum, maximum);
|
||||
if (currentValue == clamped) return;
|
||||
currentValue = clamped;
|
||||
Invalidate();
|
||||
ValueChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
internal Color TrackColor { get; set; } = Color.FromArgb(110, 110, 110);
|
||||
internal Color TrackFilledColor { get; set; } = Color.FromArgb(180, 180, 180);
|
||||
internal Color ThumbColor { get; set; } = Color.FromArgb(70, 120, 200);
|
||||
internal Color ThumbBorderColor { get; set; } = Color.FromArgb(140, 170, 220);
|
||||
|
||||
internal int TrackThickness { get; set; } = 3;
|
||||
internal int ThumbWidth { get; set; } = 12;
|
||||
internal int ThumbHeight { get; set; } = 18;
|
||||
|
||||
public FlatTrackBar()
|
||||
{
|
||||
SetStyle(
|
||||
ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer |
|
||||
ControlStyles.UserPaint |
|
||||
ControlStyles.SupportsTransparentBackColor |
|
||||
ControlStyles.ResizeRedraw,
|
||||
true);
|
||||
BackColor = Color.Transparent;
|
||||
Height = 24;
|
||||
Cursor = Cursors.Hand;
|
||||
}
|
||||
|
||||
private Rectangle GetTrackRectangle()
|
||||
{
|
||||
var halfThumb = ThumbWidth / 2;
|
||||
var trackY = (Height - TrackThickness) / 2;
|
||||
return new Rectangle(halfThumb, trackY, Math.Max(0, Width - ThumbWidth), TrackThickness);
|
||||
}
|
||||
|
||||
private int GetThumbCenterX()
|
||||
{
|
||||
var range = Math.Max(1, maximum - minimum);
|
||||
var ratio = (float)(currentValue - minimum) / range;
|
||||
var trackWidth = Math.Max(0, Width - ThumbWidth);
|
||||
return ThumbWidth / 2 + (int)(trackWidth * ratio);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
var track = GetTrackRectangle();
|
||||
var thumbCenterX = GetThumbCenterX();
|
||||
|
||||
using var trackBrush = new SolidBrush(TrackColor);
|
||||
e.Graphics.FillRectangle(trackBrush, track);
|
||||
|
||||
var filledRect = new Rectangle(track.X, track.Y, thumbCenterX - track.X, track.Height);
|
||||
if (filledRect.Width > 0)
|
||||
{
|
||||
using var filledBrush = new SolidBrush(TrackFilledColor);
|
||||
e.Graphics.FillRectangle(filledBrush, filledRect);
|
||||
}
|
||||
|
||||
var thumbRect = new Rectangle(
|
||||
thumbCenterX - ThumbWidth / 2,
|
||||
(Height - ThumbHeight) / 2,
|
||||
ThumbWidth,
|
||||
ThumbHeight);
|
||||
using var thumbBrush = new SolidBrush(ThumbColor);
|
||||
using var thumbPen = new Pen(ThumbBorderColor);
|
||||
e.Graphics.FillRectangle(thumbBrush, thumbRect);
|
||||
e.Graphics.DrawRectangle(thumbPen, thumbRect.X, thumbRect.Y, thumbRect.Width - 1, thumbRect.Height - 1);
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
if (e.Button != MouseButtons.Left) return;
|
||||
dragging = true;
|
||||
UpdateValueFromMouseX(e.X);
|
||||
Focus();
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
if (!dragging) return;
|
||||
UpdateValueFromMouseX(e.X);
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseUp(e);
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnKeyDown(e);
|
||||
if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Down)
|
||||
{
|
||||
Value = currentValue - 1;
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.KeyCode == Keys.Right || e.KeyCode == Keys.Up)
|
||||
{
|
||||
Value = currentValue + 1;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateValueFromMouseX(int x)
|
||||
{
|
||||
var trackWidth = Math.Max(1, Width - ThumbWidth);
|
||||
var relativeX = Math.Clamp(x - ThumbWidth / 2, 0, trackWidth);
|
||||
var ratio = (float)relativeX / trackWidth;
|
||||
var newValue = minimum + (int)Math.Round(ratio * (maximum - minimum));
|
||||
Value = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal sealed class FrameAnimationView : Control
|
||||
{
|
||||
private readonly System.Threading.Timer timer;
|
||||
private IReadOnlyList<Bitmap> frames = [];
|
||||
private int currentFrame = 0;
|
||||
private int intervalMs = 100;
|
||||
private volatile bool running = false;
|
||||
|
||||
internal FrameAnimationView()
|
||||
{
|
||||
SetStyle(
|
||||
ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.OptimizedDoubleBuffer |
|
||||
ControlStyles.UserPaint |
|
||||
ControlStyles.ResizeRedraw,
|
||||
true);
|
||||
timer = new System.Threading.Timer(OnTimerTick, null, Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
internal int FrameIntervalMs
|
||||
{
|
||||
get => intervalMs;
|
||||
set => intervalMs = Math.Max(1, value);
|
||||
}
|
||||
|
||||
internal void SetFrames(IReadOnlyList<Bitmap> newFrames)
|
||||
{
|
||||
frames = newFrames;
|
||||
currentFrame = 0;
|
||||
Invalidate();
|
||||
if (frames.Count > 1)
|
||||
{
|
||||
running = true;
|
||||
timer.Change(intervalMs, Timeout.Infinite);
|
||||
}
|
||||
else
|
||||
{
|
||||
running = false;
|
||||
timer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
running = false;
|
||||
timer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
frames = [];
|
||||
currentFrame = 0;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
private void OnTimerTick(object? state)
|
||||
{
|
||||
if (!running) return;
|
||||
if (IsDisposed || !IsHandleCreated) return;
|
||||
try
|
||||
{
|
||||
BeginInvoke(AdvanceFrame);
|
||||
}
|
||||
catch (Exception ex) when (ex is InvalidOperationException or ObjectDisposedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (running) timer.Change(intervalMs, Timeout.Infinite);
|
||||
}
|
||||
|
||||
private void AdvanceFrame()
|
||||
{
|
||||
if (!running || frames.Count < 2) return;
|
||||
currentFrame = (currentFrame + 1) % frames.Count;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
e.Graphics.Clear(BackColor);
|
||||
if (frames.Count == 0 || currentFrame >= frames.Count) return;
|
||||
|
||||
var frame = frames[currentFrame];
|
||||
e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
|
||||
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
|
||||
|
||||
var scale = Math.Min(
|
||||
(float)ClientSize.Width / frame.Width,
|
||||
(float)ClientSize.Height / frame.Height);
|
||||
var width = (int)(frame.Width * scale);
|
||||
var height = (int)(frame.Height * scale);
|
||||
var x = (ClientSize.Width - width) / 2;
|
||||
var y = (ClientSize.Height - height) / 2;
|
||||
e.Graphics.DrawImage(frame, x, y, width, height);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
running = false;
|
||||
timer.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
struct GPUInfo
|
||||
{
|
||||
internal float Average { get; set; }
|
||||
internal float Maximum { get; set; }
|
||||
}
|
||||
|
||||
internal static class GPUInfoExtension
|
||||
{
|
||||
internal static string GetDescription(this GPUInfo gpuInfo)
|
||||
{
|
||||
return $"{Strings.SystemInfo_GPU}: {gpuInfo.Maximum:f1}%";
|
||||
}
|
||||
|
||||
internal static List<string> GenerateIndicator(this GPUInfo gpuInfo)
|
||||
{
|
||||
var resultLines = new List<string>
|
||||
{
|
||||
TreeFormatter.CreateRoot($"{Strings.SystemInfo_GPU}:"),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Average}: {gpuInfo.Average:f1}%", false),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Maximum}: {gpuInfo.Maximum:f1}%", true)
|
||||
};
|
||||
return resultLines;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class GPUPerformanceCounters : InstancedPerformanceCounters
|
||||
{
|
||||
private const string ENGINE_TYPE_FILTER = "engtype_3D";
|
||||
|
||||
protected override string CategoryName => "GPU Engine";
|
||||
protected override string CounterName => "Utilization Percentage";
|
||||
|
||||
protected override bool ShouldIncludeInstance(string instanceName)
|
||||
{
|
||||
return instanceName.Contains(ENGINE_TYPE_FILTER, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
internal static GPUPerformanceCounters? TryCreate()
|
||||
{
|
||||
var instance = new GPUPerformanceCounters();
|
||||
return instance.TryInitialize() ? instance : null;
|
||||
}
|
||||
}
|
||||
|
||||
internal class GPURepository
|
||||
{
|
||||
private const int GPU_INFO_LIST_LIMIT_SIZE = 5;
|
||||
private const int REFRESH_INTERVAL_TICKS = 30;
|
||||
|
||||
private readonly GPUPerformanceCounters? counters;
|
||||
private readonly List<GPUInfo> gpuInfoList = [];
|
||||
private int ticksSinceLastRefresh;
|
||||
|
||||
internal bool IsAvailable => counters is not null;
|
||||
|
||||
internal GPURepository()
|
||||
{
|
||||
counters = GPUPerformanceCounters.TryCreate();
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
if (counters is null) return;
|
||||
|
||||
ticksSinceLastRefresh += 1;
|
||||
if (REFRESH_INTERVAL_TICKS <= ticksSinceLastRefresh)
|
||||
{
|
||||
ticksSinceLastRefresh = 0;
|
||||
counters.RefreshInstances();
|
||||
}
|
||||
|
||||
var values = counters.ReadValues();
|
||||
if (values.Count == 0) return;
|
||||
|
||||
var gpuInfo = new GPUInfo
|
||||
{
|
||||
Average = Math.Min(100, values.Average()),
|
||||
Maximum = Math.Min(100, values.Max())
|
||||
};
|
||||
|
||||
gpuInfoList.Add(gpuInfo);
|
||||
if (GPU_INFO_LIST_LIMIT_SIZE < gpuInfoList.Count)
|
||||
{
|
||||
gpuInfoList.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
internal GPUInfo? Get()
|
||||
{
|
||||
if (counters is null || gpuInfoList.Count == 0) return null;
|
||||
|
||||
return new GPUInfo
|
||||
{
|
||||
Average = gpuInfoList.Average(x => x.Average),
|
||||
Maximum = gpuInfoList.Max(x => x.Maximum)
|
||||
};
|
||||
}
|
||||
|
||||
internal void Close()
|
||||
{
|
||||
counters?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal enum GameStatus
|
||||
{
|
||||
NewGame,
|
||||
Playing,
|
||||
GameOver
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal abstract class InstancedPerformanceCounters
|
||||
{
|
||||
private readonly Dictionary<string, PerformanceCounter> countersByInstance = [];
|
||||
|
||||
protected abstract string CategoryName { get; }
|
||||
protected abstract string CounterName { get; }
|
||||
|
||||
protected virtual bool ShouldIncludeInstance(string instanceName) => true;
|
||||
|
||||
internal int Count => countersByInstance.Count;
|
||||
|
||||
protected bool TryInitialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = new PerformanceCounterCategory(CategoryName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RefreshInstances();
|
||||
return Count != 0;
|
||||
}
|
||||
|
||||
internal void RefreshInstances()
|
||||
{
|
||||
string[] currentInstanceNames;
|
||||
try
|
||||
{
|
||||
var category = new PerformanceCounterCategory(CategoryName);
|
||||
currentInstanceNames = category.GetInstanceNames()
|
||||
.Where(ShouldIncludeInstance)
|
||||
.ToArray();
|
||||
}
|
||||
catch (Exception exception) when (IsExpectedCounterException(exception))
|
||||
{
|
||||
Debug.WriteLine($"{GetType().Name}.RefreshInstances failed: {exception.Message}");
|
||||
return;
|
||||
}
|
||||
|
||||
var currentSet = new HashSet<string>(currentInstanceNames, StringComparer.Ordinal);
|
||||
var staleInstances = countersByInstance.Keys
|
||||
.Where(name => !currentSet.Contains(name))
|
||||
.ToList();
|
||||
foreach (var instanceName in staleInstances)
|
||||
{
|
||||
countersByInstance[instanceName].Close();
|
||||
countersByInstance.Remove(instanceName);
|
||||
}
|
||||
|
||||
foreach (var instanceName in currentInstanceNames)
|
||||
{
|
||||
if (countersByInstance.ContainsKey(instanceName)) continue;
|
||||
PerformanceCounter? counter = null;
|
||||
try
|
||||
{
|
||||
counter = new PerformanceCounter(CategoryName, CounterName, instanceName);
|
||||
_ = counter.NextValue();
|
||||
countersByInstance[instanceName] = counter;
|
||||
counter = null;
|
||||
}
|
||||
catch (Exception exception) when (IsExpectedCounterException(exception))
|
||||
{
|
||||
Debug.WriteLine($"{GetType().Name}: failed to create counter for {instanceName}: {exception.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
counter?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal List<float> ReadValues()
|
||||
{
|
||||
var values = new List<float>(countersByInstance.Count);
|
||||
var deadInstances = new List<string>();
|
||||
foreach (var pair in countersByInstance)
|
||||
{
|
||||
try
|
||||
{
|
||||
values.Add(pair.Value.NextValue());
|
||||
}
|
||||
catch (Exception exception) when (IsExpectedCounterException(exception))
|
||||
{
|
||||
Debug.WriteLine($"{GetType().Name}: counter {pair.Key} failed: {exception.Message}");
|
||||
deadInstances.Add(pair.Key);
|
||||
}
|
||||
}
|
||||
foreach (var instanceName in deadInstances)
|
||||
{
|
||||
countersByInstance[instanceName].Close();
|
||||
countersByInstance.Remove(instanceName);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
internal void Close()
|
||||
{
|
||||
foreach (var counter in countersByInstance.Values) counter.Close();
|
||||
countersByInstance.Clear();
|
||||
}
|
||||
|
||||
private static bool IsExpectedCounterException(Exception exception)
|
||||
{
|
||||
return exception is InvalidOperationException
|
||||
or System.ComponentModel.Win32Exception
|
||||
or UnauthorizedAccessException;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using Microsoft.Win32;
|
||||
using Windows.ApplicationModel;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal interface ILaunchAtStartupManager
|
||||
{
|
||||
bool GetEnabled();
|
||||
bool Toggle(bool currentlyEnabled);
|
||||
}
|
||||
|
||||
internal sealed class PackagedLaunchAtStartupManager : ILaunchAtStartupManager
|
||||
{
|
||||
private static StartupTask? startupTask;
|
||||
|
||||
public bool GetEnabled()
|
||||
{
|
||||
startupTask ??= Task.Run(async () => await StartupTask.GetAsync("RunCatStartup")).Result;
|
||||
if (startupTask is null) return false;
|
||||
if (startupTask.State == StartupTaskState.Enabled) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Toggle(bool currentlyEnabled)
|
||||
{
|
||||
startupTask ??= Task.Run(async () => await StartupTask.GetAsync("RunCatStartup")).Result;
|
||||
if (currentlyEnabled)
|
||||
{
|
||||
if (startupTask.State == StartupTaskState.Enabled) startupTask.Disable();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (startupTask.State)
|
||||
{
|
||||
case StartupTaskState.Enabled:
|
||||
return true;
|
||||
case StartupTaskState.Disabled:
|
||||
var newStartupState = Task.Run(async () => await startupTask.RequestEnableAsync()).Result;
|
||||
if (newStartupState == StartupTaskState.Enabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Launch at Startup could not be activated.");
|
||||
}
|
||||
case StartupTaskState.DisabledByUser:
|
||||
throw new InvalidOperationException("Launch at startup was disabled by the user, enable it in Task Manager > Startup, search RunCat 365 and enable it.");
|
||||
case StartupTaskState.DisabledByPolicy:
|
||||
throw new InvalidOperationException("Launch at startup was disabled by policy.");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class UnpackagedLaunchAtStartupManager : ILaunchAtStartupManager
|
||||
{
|
||||
public bool GetEnabled()
|
||||
{
|
||||
var keyName = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||
using var rKey = Registry.CurrentUser.OpenSubKey(keyName);
|
||||
if (rKey is null) return false;
|
||||
var value = (rKey.GetValue(Application.ProductName) is not null);
|
||||
rKey.Close();
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool Toggle(bool currentlyEnabled)
|
||||
{
|
||||
var productName = Application.ProductName;
|
||||
if (productName is null) return false;
|
||||
var keyName = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||
using var rKey = Registry.CurrentUser.OpenSubKey(keyName, true);
|
||||
if (rKey is null) return false;
|
||||
if (currentlyEnabled)
|
||||
{
|
||||
rKey.DeleteValue(productName, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var fileName = Environment.ProcessPath;
|
||||
if (fileName is not null)
|
||||
{
|
||||
rKey.SetValue(productName, fileName);
|
||||
}
|
||||
}
|
||||
rKey.Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal class LaunchAtStartupManager
|
||||
{
|
||||
private readonly ILaunchAtStartupManager launchAtStartupManager;
|
||||
|
||||
public LaunchAtStartupManager()
|
||||
{
|
||||
launchAtStartupManager = IsRunningAsPackaged()
|
||||
? new PackagedLaunchAtStartupManager()
|
||||
: new UnpackagedLaunchAtStartupManager();
|
||||
}
|
||||
|
||||
public bool GetStartup() => launchAtStartupManager.GetEnabled();
|
||||
|
||||
public bool ToggleStartup(bool currentlyEnabled) => launchAtStartupManager.Toggle(currentlyEnabled);
|
||||
|
||||
private static bool IsRunningAsPackaged()
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = Package.Current;
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
struct MemoryInfo
|
||||
{
|
||||
internal uint MemoryLoad { get; set; }
|
||||
internal long TotalMemory { get; set; }
|
||||
internal long AvailableMemory { get; set; }
|
||||
internal long UsedMemory { get; set; }
|
||||
}
|
||||
|
||||
internal static class MemoryInfoExtension
|
||||
{
|
||||
internal static string GetDescription(this MemoryInfo memoryInfo)
|
||||
{
|
||||
return $"{Strings.SystemInfo_Memory}: {memoryInfo.MemoryLoad}%";
|
||||
}
|
||||
|
||||
internal static List<string> GenerateIndicator(this MemoryInfo memoryInfo)
|
||||
{
|
||||
var resultLines = new List<string>
|
||||
{
|
||||
TreeFormatter.CreateRoot($"{Strings.SystemInfo_Memory}: {memoryInfo.MemoryLoad}%"),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Total}: {memoryInfo.TotalMemory.ToByteFormatted()}", false),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Used}: {memoryInfo.UsedMemory.ToByteFormatted()}", false),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Available}: {memoryInfo.AvailableMemory.ToByteFormatted()}", true)
|
||||
};
|
||||
return resultLines;
|
||||
}
|
||||
}
|
||||
|
||||
internal partial class MemoryRepository
|
||||
{
|
||||
private MemoryInfo memoryInfo;
|
||||
|
||||
internal MemoryRepository()
|
||||
{
|
||||
memoryInfo = new MemoryInfo();
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
var memStatus = new MemoryStatusEx();
|
||||
memStatus.dwLength = (uint)Marshal.SizeOf(memStatus);
|
||||
|
||||
if (GlobalMemoryStatusEx(ref memStatus))
|
||||
{
|
||||
memoryInfo.MemoryLoad = memStatus.dwMemoryLoad;
|
||||
memoryInfo.TotalMemory = (long)memStatus.ullTotalPhys;
|
||||
memoryInfo.AvailableMemory = (long)memStatus.ullAvailPhys;
|
||||
memoryInfo.UsedMemory = (long)(memStatus.ullTotalPhys - memStatus.ullAvailPhys);
|
||||
}
|
||||
}
|
||||
|
||||
internal MemoryInfo Get()
|
||||
{
|
||||
return memoryInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct MemoryStatusEx
|
||||
{
|
||||
public uint dwLength;
|
||||
public uint dwMemoryLoad;
|
||||
public ulong ullTotalPhys;
|
||||
public ulong ullAvailPhys;
|
||||
public ulong ullTotalPageFile;
|
||||
public ulong ullAvailPageFile;
|
||||
public ulong ullTotalVirtual;
|
||||
public ulong ullAvailVirtual;
|
||||
public ulong ullAvailExtendedVirtual;
|
||||
}
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static partial bool GlobalMemoryStatusEx(ref MemoryStatusEx lpBuffer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
struct NetworkInfo
|
||||
{
|
||||
internal float SentSpeed { get; set; }
|
||||
internal float ReceivedSpeed { get; set; }
|
||||
}
|
||||
|
||||
internal static class NetworkInfoExtension
|
||||
{
|
||||
internal static List<string> GenerateIndicator(this NetworkInfo networkInfo)
|
||||
{
|
||||
return [
|
||||
TreeFormatter.CreateRoot($"{Strings.SystemInfo_Network}:"),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Sent}: {FormatSpeed(networkInfo.SentSpeed)}", false),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Received}: {FormatSpeed(networkInfo.ReceivedSpeed)}", true)
|
||||
];
|
||||
}
|
||||
|
||||
private static string FormatSpeed(float speedBytes)
|
||||
{
|
||||
return ((long)speedBytes).ToByteFormatted() + "/s";
|
||||
}
|
||||
}
|
||||
|
||||
internal class NetworkRepository
|
||||
{
|
||||
private readonly NetworkInterface? networkInterface;
|
||||
private long lastSent;
|
||||
private long lastReceived;
|
||||
private DateTime lastUpdate;
|
||||
private NetworkInfo? networkInfo;
|
||||
|
||||
internal bool IsAvailable => networkInterface is not null;
|
||||
|
||||
internal NetworkRepository()
|
||||
{
|
||||
networkInterface = GetActiveNetworkInterface();
|
||||
if (networkInterface is null) return;
|
||||
var stats = networkInterface.GetIPStatistics();
|
||||
lastSent = stats.BytesSent;
|
||||
lastReceived = stats.BytesReceived;
|
||||
lastUpdate = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
private static NetworkInterface? GetActiveNetworkInterface()
|
||||
{
|
||||
try
|
||||
{
|
||||
var interfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
return interfaces.FirstOrDefault(IsValidNetworkInterface);
|
||||
}
|
||||
catch (NetworkInformationException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsValidNetworkInterface(NetworkInterface networkInterface)
|
||||
{
|
||||
if (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Loopback) return false;
|
||||
if (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Tunnel) return false;
|
||||
if (networkInterface.OperationalStatus != OperationalStatus.Up) return false;
|
||||
|
||||
var description = networkInterface.Description.ToLower();
|
||||
if (description.Contains("vpn")) return false;
|
||||
if (description.Contains("tap")) return false;
|
||||
if (description.Contains("virtual")) return false;
|
||||
if (description.Contains("tun")) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
if (networkInterface is null) return;
|
||||
try
|
||||
{
|
||||
var stats = networkInterface.GetIPStatistics();
|
||||
var now = DateTime.UtcNow;
|
||||
var elapsedSec = (now - lastUpdate).TotalSeconds;
|
||||
if (elapsedSec > 0)
|
||||
{
|
||||
networkInfo = new NetworkInfo
|
||||
{
|
||||
SentSpeed = (float)((stats.BytesSent - lastSent) / elapsedSec),
|
||||
ReceivedSpeed = (float)((stats.BytesReceived - lastReceived) / elapsedSec)
|
||||
};
|
||||
}
|
||||
lastSent = stats.BytesSent;
|
||||
lastReceived = stats.BytesReceived;
|
||||
lastUpdate = now;
|
||||
}
|
||||
catch (NetworkInformationException)
|
||||
{
|
||||
networkInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal NetworkInfo? Get()
|
||||
{
|
||||
return networkInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
// Copyright 2020 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using Microsoft.Win32;
|
||||
using RunCat365.Properties;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using FormsTimer = System.Windows.Forms.Timer;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
#if DEBUG
|
||||
var defaultCultureInfo = SupportedLanguage.English.GetDefaultCultureInfo();
|
||||
#else
|
||||
var defaultCultureInfo = SupportedLanguageExtension.GetCurrentLanguage().GetDefaultCultureInfo();
|
||||
#endif
|
||||
CultureInfo.CurrentUICulture = defaultCultureInfo;
|
||||
CultureInfo.CurrentCulture = defaultCultureInfo;
|
||||
|
||||
using var procMutex = new Mutex(true, "_RUNCAT_MUTEX", out var result);
|
||||
if (!result) return;
|
||||
|
||||
try
|
||||
{
|
||||
ApplicationConfiguration.Initialize();
|
||||
Application.SetColorMode(SystemColorMode.System);
|
||||
Application.Run(new RunCat365ApplicationContext());
|
||||
}
|
||||
finally
|
||||
{
|
||||
procMutex?.ReleaseMutex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class RunCat365ApplicationContext : ApplicationContext
|
||||
{
|
||||
private const int FETCH_TIMER_DEFAULT_INTERVAL = 1000;
|
||||
private const int FETCH_COUNTER_SIZE = 5;
|
||||
private const int ANIMATE_TIMER_DEFAULT_INTERVAL = 200;
|
||||
private readonly CPURepository cpuRepository;
|
||||
private readonly GPURepository gpuRepository;
|
||||
private readonly MemoryRepository memoryRepository;
|
||||
private readonly TemperatureRepository temperatureRepository;
|
||||
private readonly StorageRepository storageRepository;
|
||||
private readonly NetworkRepository networkRepository;
|
||||
private readonly CustomRunnerRepository customRunnerRepository;
|
||||
private readonly LaunchAtStartupManager launchAtStartupManager;
|
||||
private readonly ContextMenuManager contextMenuManager;
|
||||
private readonly FormsTimer fetchTimer;
|
||||
private readonly FormsTimer animateTimer;
|
||||
private Runner runner = Runner.Cat;
|
||||
private Theme manualTheme = Theme.System;
|
||||
private TemperatureUnit temperatureUnit = TemperatureUnit.System;
|
||||
private FPSMaxLimit fpsMaxLimit = FPSMaxLimit.FPS40;
|
||||
private SpeedSource speedSource = SpeedSource.CPU;
|
||||
private string? customRunnerName;
|
||||
private int fetchCounter = 5;
|
||||
private bool isFetching;
|
||||
|
||||
public RunCat365ApplicationContext()
|
||||
{
|
||||
UserSettings.Default.Reload();
|
||||
_ = Enum.TryParse(UserSettings.Default.Runner, out runner);
|
||||
_ = Enum.TryParse(UserSettings.Default.Theme, out manualTheme);
|
||||
_ = Enum.TryParse(UserSettings.Default.TemperatureUnit, out temperatureUnit);
|
||||
_ = Enum.TryParse(UserSettings.Default.FPSMaxLimit, out fpsMaxLimit);
|
||||
_ = Enum.TryParse(UserSettings.Default.SpeedSource, out speedSource);
|
||||
customRunnerName = string.IsNullOrEmpty(UserSettings.Default.CustomRunnerName)
|
||||
? null
|
||||
: UserSettings.Default.CustomRunnerName;
|
||||
|
||||
SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(UserPreferenceChanged);
|
||||
|
||||
cpuRepository = new CPURepository();
|
||||
gpuRepository = new GPURepository();
|
||||
memoryRepository = new MemoryRepository();
|
||||
temperatureRepository = new TemperatureRepository();
|
||||
storageRepository = new StorageRepository();
|
||||
networkRepository = new NetworkRepository();
|
||||
customRunnerRepository = new CustomRunnerRepository();
|
||||
launchAtStartupManager = new LaunchAtStartupManager();
|
||||
|
||||
ResolveSpeedSource();
|
||||
|
||||
contextMenuManager = new ContextMenuManager(
|
||||
() => runner,
|
||||
r => ChangeRunner(r),
|
||||
customRunnerRepository,
|
||||
() => customRunnerName,
|
||||
name => ApplyCustomRunner(name),
|
||||
deletedName => HandleCustomRunnerDeleted(deletedName),
|
||||
() => GetSystemTheme(),
|
||||
() => manualTheme,
|
||||
t => ChangeManualTheme(t),
|
||||
() => speedSource,
|
||||
s => ChangeSpeedSource(s),
|
||||
s => IsSpeedSourceAvailable(s),
|
||||
() => fpsMaxLimit,
|
||||
f => ChangeFPSMaxLimit(f),
|
||||
() => temperatureUnit,
|
||||
u => ChangeTemperatureUnit(u),
|
||||
() => launchAtStartupManager.GetStartup(),
|
||||
s => launchAtStartupManager.ToggleStartup(s),
|
||||
() => OpenProjectPage(),
|
||||
() => Application.Exit()
|
||||
);
|
||||
|
||||
if (customRunnerName is not null)
|
||||
{
|
||||
ApplyCustomRunner(customRunnerName);
|
||||
}
|
||||
|
||||
animateTimer = new FormsTimer
|
||||
{
|
||||
Interval = ANIMATE_TIMER_DEFAULT_INTERVAL
|
||||
};
|
||||
animateTimer.Tick += new EventHandler(AnimationTick);
|
||||
animateTimer.Start();
|
||||
|
||||
fetchTimer = new FormsTimer
|
||||
{
|
||||
Interval = FETCH_TIMER_DEFAULT_INTERVAL
|
||||
};
|
||||
fetchTimer.Tick += new EventHandler(FetchTick);
|
||||
fetchTimer.Start();
|
||||
|
||||
ShowBalloonTipIfNeeded();
|
||||
}
|
||||
|
||||
private static Theme GetSystemTheme()
|
||||
{
|
||||
var keyName = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
|
||||
using var rKey = Registry.CurrentUser.OpenSubKey(keyName);
|
||||
if (rKey is null) return Theme.Light;
|
||||
var value = rKey.GetValue("SystemUsesLightTheme");
|
||||
if (value is null) return Theme.Light;
|
||||
return (int)value == 0 ? Theme.Dark : Theme.Light;
|
||||
}
|
||||
|
||||
private bool IsSpeedSourceAvailable(SpeedSource speedSource)
|
||||
{
|
||||
return speedSource switch
|
||||
{
|
||||
SpeedSource.CPU => true,
|
||||
SpeedSource.GPU => gpuRepository.IsAvailable,
|
||||
SpeedSource.Memory => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
private void ResolveSpeedSource()
|
||||
{
|
||||
if (!IsSpeedSourceAvailable(speedSource))
|
||||
{
|
||||
ChangeSpeedSource(SpeedSource.CPU);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowBalloonTipIfNeeded()
|
||||
{
|
||||
if (!cpuRepository.IsAvailable)
|
||||
{
|
||||
contextMenuManager.ShowBalloonTip(BalloonTipType.CPUInfoUnavailable);
|
||||
}
|
||||
else if (UserSettings.Default.FirstLaunch)
|
||||
{
|
||||
contextMenuManager.ShowBalloonTip(BalloonTipType.AppLaunched);
|
||||
UserSettings.Default.FirstLaunch = false;
|
||||
UserSettings.Default.Save();
|
||||
}
|
||||
}
|
||||
|
||||
private void UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
|
||||
{
|
||||
if (e.Category != UserPreferenceCategory.General) return;
|
||||
var systemTheme = GetSystemTheme();
|
||||
if (contextMenuManager.HasActiveCustomIcons)
|
||||
{
|
||||
contextMenuManager.RecolorActiveCustomIcons(systemTheme, manualTheme);
|
||||
}
|
||||
else
|
||||
{
|
||||
contextMenuManager.SetIcons(systemTheme, manualTheme, runner);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OpenProjectPage()
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
FileName = "https://github.com/runcat-dev/RunCat365",
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Error: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeRunner(Runner r)
|
||||
{
|
||||
runner = r;
|
||||
customRunnerName = null;
|
||||
UserSettings.Default.Runner = runner.ToString();
|
||||
UserSettings.Default.CustomRunnerName = string.Empty;
|
||||
UserSettings.Default.Save();
|
||||
}
|
||||
|
||||
private void ApplyCustomRunner(string name)
|
||||
{
|
||||
var frames = customRunnerRepository.LoadFrames(name);
|
||||
if (frames.Count == 0) return;
|
||||
customRunnerName = name;
|
||||
UserSettings.Default.CustomRunnerName = name;
|
||||
UserSettings.Default.Save();
|
||||
contextMenuManager.SetCustomIcons(frames, GetSystemTheme(), manualTheme);
|
||||
foreach (var frame in frames) frame.Dispose();
|
||||
}
|
||||
|
||||
private void RevertToBuiltInRunner()
|
||||
{
|
||||
customRunnerName = null;
|
||||
UserSettings.Default.CustomRunnerName = string.Empty;
|
||||
UserSettings.Default.Save();
|
||||
contextMenuManager.SetIcons(GetSystemTheme(), manualTheme, runner);
|
||||
}
|
||||
|
||||
private void HandleCustomRunnerDeleted(string deletedName)
|
||||
{
|
||||
if (!string.Equals(customRunnerName, deletedName, StringComparison.OrdinalIgnoreCase)) return;
|
||||
RevertToBuiltInRunner();
|
||||
}
|
||||
|
||||
private void ChangeManualTheme(Theme t)
|
||||
{
|
||||
manualTheme = t;
|
||||
UserSettings.Default.Theme = manualTheme.ToString();
|
||||
UserSettings.Default.Save();
|
||||
}
|
||||
|
||||
private void ChangeTemperatureUnit(TemperatureUnit u)
|
||||
{
|
||||
temperatureUnit = u;
|
||||
UserSettings.Default.TemperatureUnit = temperatureUnit.ToString();
|
||||
UserSettings.Default.Save();
|
||||
}
|
||||
|
||||
private void ChangeSpeedSource(SpeedSource s)
|
||||
{
|
||||
speedSource = s;
|
||||
UserSettings.Default.SpeedSource = speedSource.ToString();
|
||||
UserSettings.Default.Save();
|
||||
}
|
||||
|
||||
private void ChangeFPSMaxLimit(FPSMaxLimit f)
|
||||
{
|
||||
fpsMaxLimit = f;
|
||||
UserSettings.Default.FPSMaxLimit = fpsMaxLimit.ToString();
|
||||
UserSettings.Default.Save();
|
||||
}
|
||||
|
||||
private void AnimationTick(object? sender, EventArgs e)
|
||||
{
|
||||
contextMenuManager.AdvanceFrame();
|
||||
}
|
||||
|
||||
private string GetInfoDescription(CPUInfo cpuInfo, GPUInfo? gpuInfo, MemoryInfo memoryInfo, TemperatureInfo? temperatureInfo)
|
||||
{
|
||||
var baseDescription = speedSource switch
|
||||
{
|
||||
SpeedSource.CPU => cpuInfo.GetDescription(),
|
||||
SpeedSource.GPU => gpuInfo?.GetDescription() ?? "",
|
||||
SpeedSource.Memory => memoryInfo.GetDescription(),
|
||||
_ => "",
|
||||
};
|
||||
|
||||
var temperatureDescription = temperatureInfo?.GetDescription(temperatureUnit) ?? "";
|
||||
return string.IsNullOrEmpty(temperatureDescription) ? baseDescription : $"{baseDescription}\n{temperatureDescription}";
|
||||
}
|
||||
|
||||
private int CalculateInterval(CPUInfo cpuInfo, GPUInfo? gpuInfo, MemoryInfo memoryInfo)
|
||||
{
|
||||
var load = speedSource switch
|
||||
{
|
||||
SpeedSource.CPU => cpuInfo.Total,
|
||||
SpeedSource.GPU => gpuInfo?.Maximum ?? 0f,
|
||||
SpeedSource.Memory => memoryInfo.MemoryLoad,
|
||||
_ => 0f,
|
||||
};
|
||||
var speed = (float)Math.Max(1.0f, (load / 5.0f) * fpsMaxLimit.GetRate());
|
||||
return (int)(500.0f / speed);
|
||||
}
|
||||
|
||||
private int FetchSystemInfo()
|
||||
{
|
||||
var cpuInfo = cpuRepository.Get();
|
||||
var gpuInfo = gpuRepository.Get();
|
||||
var memoryInfo = memoryRepository.Get();
|
||||
var temperatureInfo = temperatureRepository.Get();
|
||||
var storageInfo = storageRepository.Get();
|
||||
var networkInfo = networkRepository.Get();
|
||||
|
||||
contextMenuManager.SetNotifyIconText(GetInfoDescription(cpuInfo, gpuInfo, memoryInfo, temperatureInfo));
|
||||
|
||||
var systemInfoValues = new List<string>();
|
||||
systemInfoValues.AddRange(cpuInfo.GenerateIndicator());
|
||||
if (gpuInfo.HasValue)
|
||||
{
|
||||
systemInfoValues.AddRange(gpuInfo.Value.GenerateIndicator());
|
||||
}
|
||||
systemInfoValues.AddRange(memoryInfo.GenerateIndicator());
|
||||
if (temperatureInfo.HasValue)
|
||||
{
|
||||
systemInfoValues.AddRange(temperatureInfo.Value.GenerateIndicator(temperatureUnit));
|
||||
}
|
||||
systemInfoValues.AddRange(storageInfo.GenerateIndicator());
|
||||
if (networkInfo.HasValue)
|
||||
{
|
||||
systemInfoValues.AddRange(networkInfo.Value.GenerateIndicator());
|
||||
}
|
||||
contextMenuManager.SetSystemInfoMenuText(string.Join("\n", [.. systemInfoValues]));
|
||||
|
||||
return CalculateInterval(cpuInfo, gpuInfo, memoryInfo);
|
||||
}
|
||||
|
||||
private async void FetchTick(object? sender, EventArgs e)
|
||||
{
|
||||
if (isFetching) return;
|
||||
isFetching = true;
|
||||
try
|
||||
{
|
||||
var doHeavySlice = await Task.Run(() =>
|
||||
{
|
||||
cpuRepository.Update();
|
||||
gpuRepository.Update();
|
||||
fetchCounter += 1;
|
||||
if (fetchCounter < FETCH_COUNTER_SIZE) return false;
|
||||
fetchCounter = 0;
|
||||
temperatureRepository.Update();
|
||||
memoryRepository.Update();
|
||||
storageRepository.Update();
|
||||
networkRepository.Update();
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!doHeavySlice) return;
|
||||
|
||||
var interval = FetchSystemInfo();
|
||||
animateTimer.Stop();
|
||||
animateTimer.Interval = interval;
|
||||
animateTimer.Start();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Console.WriteLine($"FetchTick failed: {exception.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
isFetching = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
SystemEvents.UserPreferenceChanged -= UserPreferenceChanged;
|
||||
|
||||
animateTimer?.Stop();
|
||||
animateTimer?.Dispose();
|
||||
fetchTimer?.Stop();
|
||||
fetchTimer?.Dispose();
|
||||
|
||||
cpuRepository?.Close();
|
||||
gpuRepository?.Close();
|
||||
temperatureRepository?.Close();
|
||||
|
||||
contextMenuManager?.HideNotifyIcon();
|
||||
contextMenuManager?.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,483 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RunCat365.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RunCat365.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||
/// </summary>
|
||||
internal static System.Drawing.Icon AppIcon {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("AppIcon", resourceCulture);
|
||||
return ((System.Drawing.Icon)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_0 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_0", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_1 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_1", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_2 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_2", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_3 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_3", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_4 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_4", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_0 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_0", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_1 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_1", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_2 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_2", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_3 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_3", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_4 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_4", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_5 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_5", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_6 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_6", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_7 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_7", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_8 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_8", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_jumping_9 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_jumping_9", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_running_0 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_running_0", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_running_1 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_running_1", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_running_2 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_running_2", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_running_3 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_running_3", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap cat_running_4 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("cat_running_4", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap horse_0 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("horse_0", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap horse_1 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("horse_1", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap horse_2 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("horse_2", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap horse_3 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("horse_3", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap horse_4 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("horse_4", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_0 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_0", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_1 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_1", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_2 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_2", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_3 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_3", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_4 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_4", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_5 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_5", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_6 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_6", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_7 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_7", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_8 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_8", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap parrot_9 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("parrot_9", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap road_crater {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("road_crater", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap road_flat {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("road_flat", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap road_hill {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("road_hill", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap road_sprout {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("road_sprout", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap slider_rabbit {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("slider_rabbit", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap slider_turtle {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("slider_turtle", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="AppIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\app_icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_0" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_0.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_4" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_5" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_5.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_6" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_6.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_7" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_7.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_8" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_8.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_jumping_9" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_jumping_9.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_running_0" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_running_0.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_running_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_running_1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_running_2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_running_2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_running_3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_running_3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_running_4" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\cat_running_4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="road_crater" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\road_crater.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="road_flat" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\road_flat.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="road_hill" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\road_hill.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="road_sprout" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\game\road_sprout.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_0" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\cat\cat_0.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\cat\cat_1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\cat\cat_2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\cat\cat_3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="cat_4" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\cat\cat_4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="horse_0" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\horse\horse_0.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="horse_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\horse\horse_1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="horse_2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\horse\horse_2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="horse_3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\horse\horse_3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="horse_4" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\horse\horse_4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_0" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_0.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_4" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_4.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_5" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_5.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_6" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_6.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_7" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_7.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_8" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_8.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="parrot_9" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\runners\parrot\parrot_9.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="slider_rabbit" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\rabbit.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="slider_turtle" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\turtle.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,531 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RunCat365.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Strings {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Strings() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RunCat365.Properties.Strings", typeof(Strings).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to GAME OVER.
|
||||
/// </summary>
|
||||
internal static string Game_GameOver {
|
||||
get {
|
||||
return ResourceManager.GetString("Game_GameOver", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Press space to play..
|
||||
/// </summary>
|
||||
internal static string Game_PressSpaceToPlay {
|
||||
get {
|
||||
return ResourceManager.GetString("Game_PressSpaceToPlay", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to New Record.
|
||||
/// </summary>
|
||||
internal static string Game_NewRecord
|
||||
{
|
||||
get
|
||||
{
|
||||
return ResourceManager.GetString("Game_NewRecord", resourceCulture);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Endless Game.
|
||||
/// </summary>
|
||||
internal static string Menu_EndlessGame {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_EndlessGame", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Exit.
|
||||
/// </summary>
|
||||
internal static string Menu_Exit {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_Exit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to FPS Max Limit.
|
||||
/// </summary>
|
||||
internal static string Menu_FPSMaxLimit {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_FPSMaxLimit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Information.
|
||||
/// </summary>
|
||||
internal static string Menu_Information {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_Information", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Launch at startup.
|
||||
/// </summary>
|
||||
internal static string Menu_LaunchAtStartup {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_LaunchAtStartup", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Open Project Page.
|
||||
/// </summary>
|
||||
internal static string Menu_OpenProjectPage {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_OpenProjectPage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Runner.
|
||||
/// </summary>
|
||||
internal static string Menu_Runner {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_Runner", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Settings.
|
||||
/// </summary>
|
||||
internal static string Menu_Settings {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_Settings", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Menu_SpeedSource {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_SpeedSource", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Theme.
|
||||
/// </summary>
|
||||
internal static string Menu_Theme {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_Theme", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to App has launched. If the icon is not on the taskbar, it has been omitted, so please move it manually and pin it..
|
||||
/// </summary>
|
||||
internal static string Message_AppLaunched {
|
||||
get {
|
||||
return ResourceManager.GetString("Message_AppLaunched", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Failed to get CPU usage. Unable to update running speed..
|
||||
/// </summary>
|
||||
internal static string Message_CPUUsageUnavailable {
|
||||
get {
|
||||
return ResourceManager.GetString("Message_CPUUsageUnavailable", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Warning.
|
||||
/// </summary>
|
||||
internal static string Message_Warning {
|
||||
get {
|
||||
return ResourceManager.GetString("Message_Warning", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cat.
|
||||
/// </summary>
|
||||
internal static string Runner_Cat {
|
||||
get {
|
||||
return ResourceManager.GetString("Runner_Cat", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Horse.
|
||||
/// </summary>
|
||||
internal static string Runner_Horse {
|
||||
get {
|
||||
return ResourceManager.GetString("Runner_Horse", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Parrot.
|
||||
/// </summary>
|
||||
internal static string Runner_Parrot {
|
||||
get {
|
||||
return ResourceManager.GetString("Runner_Parrot", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Dark.
|
||||
/// </summary>
|
||||
internal static string Theme_Dark {
|
||||
get {
|
||||
return ResourceManager.GetString("Theme_Dark", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Light.
|
||||
/// </summary>
|
||||
internal static string Theme_Light {
|
||||
get {
|
||||
return ResourceManager.GetString("Theme_Light", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to System.
|
||||
/// </summary>
|
||||
internal static string Theme_System {
|
||||
get {
|
||||
return ResourceManager.GetString("Theme_System", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Endless Game.
|
||||
/// </summary>
|
||||
internal static string Window_EndlessGame {
|
||||
get {
|
||||
return ResourceManager.GetString("Window_EndlessGame", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to CPU.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_CPU {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_CPU", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to User.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_User {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_User", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Kernel.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_Kernel {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Kernel", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Available.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_Available {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Available", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Memory.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_Memory {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Memory", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Total.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_Total {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Total", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Used.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_Used {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Used", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Storage.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_Storage {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Storage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to C Drive.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_DriveC {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_DriveC", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to D Drive.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_DriveD {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_DriveD", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Network.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_Network {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Network", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Sent.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_Sent {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Sent", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Received.
|
||||
/// </summary>
|
||||
internal static string SystemInfo_Received {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Received", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string SystemInfo_GPU {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_GPU", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string SystemInfo_Average {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Average", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string SystemInfo_Maximum {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Maximum", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string SystemInfo_Temperature {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_Temperature", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string SystemInfo_TemperatureCelsiusFormat {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_TemperatureCelsiusFormat", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string SystemInfo_TemperatureFahrenheitFormat {
|
||||
get {
|
||||
return ResourceManager.GetString("SystemInfo_TemperatureFahrenheitFormat", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Menu_CustomRunners {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_CustomRunners", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Window_CustomRunners {
|
||||
get {
|
||||
return ResourceManager.GetString("Window_CustomRunners", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_AddedRunners {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_AddedRunners", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_Name {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_Name", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_AddFrames {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_AddFrames", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_RemoveFrame {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_RemoveFrame", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_Save {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_Save", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_Delete {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_Delete", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_Requirements {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_Requirements", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_ConfirmOverwrite {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_ConfirmOverwrite", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_ConfirmDelete {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_ConfirmDelete", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_RequirementsLabel {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_RequirementsLabel", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_FramesLabel {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_FramesLabel", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_Preview {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_Preview", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string CustomRunner_PreviewSpeed {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomRunner_PreviewSpeed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string Menu_TemperatureUnit {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu_TemperatureUnit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string TemperatureUnit_System {
|
||||
get {
|
||||
return ResourceManager.GetString("TemperatureUnit_System", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string TemperatureUnit_Celsius {
|
||||
get {
|
||||
return ResourceManager.GetString("TemperatureUnit_Celsius", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string TemperatureUnit_Fahrenheit {
|
||||
get {
|
||||
return ResourceManager.GetString("TemperatureUnit_Fahrenheit", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Menu_Runner" xml:space="preserve">
|
||||
<value>Läufer</value>
|
||||
</data>
|
||||
<data name="Menu_Theme" xml:space="preserve">
|
||||
<value>Design</value>
|
||||
</data>
|
||||
<data name="Menu_FPSMaxLimit" xml:space="preserve">
|
||||
<value>FPS-Maximallimit</value>
|
||||
</data>
|
||||
<data name="Menu_LaunchAtStartup" xml:space="preserve">
|
||||
<value>Beim Start ausführen</value>
|
||||
</data>
|
||||
<data name="Menu_Settings" xml:space="preserve">
|
||||
<value>Einstellungen</value>
|
||||
</data>
|
||||
<data name="Menu_EndlessGame" xml:space="preserve">
|
||||
<value>Endlosspiel</value>
|
||||
</data>
|
||||
<data name="Menu_Information" xml:space="preserve">
|
||||
<value>Information</value>
|
||||
</data>
|
||||
<data name="Menu_OpenProjectPage" xml:space="preserve">
|
||||
<value>Projektseite öffnen</value>
|
||||
</data>
|
||||
<data name="Menu_Exit" xml:space="preserve">
|
||||
<value>Beenden</value>
|
||||
</data>
|
||||
<data name="Theme_System" xml:space="preserve">
|
||||
<value>System</value>
|
||||
</data>
|
||||
<data name="Theme_Light" xml:space="preserve">
|
||||
<value>Hell</value>
|
||||
</data>
|
||||
<data name="Theme_Dark" xml:space="preserve">
|
||||
<value>Dunkel</value>
|
||||
</data>
|
||||
<data name="Menu_TemperatureUnit" xml:space="preserve">
|
||||
<value>Temperatureinheit</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_System" xml:space="preserve">
|
||||
<value>System</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Celsius" xml:space="preserve">
|
||||
<value>Celsius</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Fahrenheit" xml:space="preserve">
|
||||
<value>Fahrenheit</value>
|
||||
</data>
|
||||
<data name="Runner_Cat" xml:space="preserve">
|
||||
<value>Katze</value>
|
||||
</data>
|
||||
<data name="Runner_Parrot" xml:space="preserve">
|
||||
<value>Papagei</value>
|
||||
</data>
|
||||
<data name="Runner_Horse" xml:space="preserve">
|
||||
<value>Pferd</value>
|
||||
</data>
|
||||
<data name="Message_AppLaunched" xml:space="preserve">
|
||||
<value>Die App wurde gestartet. Wenn das Symbol nicht in der Taskleiste angezeigt wird, wurde es ausgeblendet. Bitte verschieben Sie es manuell und heften Sie es an.</value>
|
||||
</data>
|
||||
<data name="Message_Warning" xml:space="preserve">
|
||||
<value>Warnung</value>
|
||||
</data>
|
||||
<data name="Window_EndlessGame" xml:space="preserve">
|
||||
<value>Endlosspiel</value>
|
||||
</data>
|
||||
<data name="Game_PressSpaceToPlay" xml:space="preserve">
|
||||
<value>Leertaste drücken zum Spielen.</value>
|
||||
</data>
|
||||
<data name="Game_GameOver" xml:space="preserve">
|
||||
<value>SPIEL VORBEI</value>
|
||||
</data>
|
||||
<data name="SystemInfo_CPU" xml:space="preserve">
|
||||
<value>CPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_User" xml:space="preserve">
|
||||
<value>Benutzer</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Kernel" xml:space="preserve">
|
||||
<value>Kernel</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Available" xml:space="preserve">
|
||||
<value>Verfügbar</value>
|
||||
</data>
|
||||
<data name="SystemInfo_GPU" xml:space="preserve">
|
||||
<value>GPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Average" xml:space="preserve">
|
||||
<value>Durchschnitt</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Maximum" xml:space="preserve">
|
||||
<value>Maximum</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Memory" xml:space="preserve">
|
||||
<value>Arbeitsspeicher</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Total" xml:space="preserve">
|
||||
<value>Gesamt</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Used" xml:space="preserve">
|
||||
<value>Verwendet</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Storage" xml:space="preserve">
|
||||
<value>Speicher</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveC" xml:space="preserve">
|
||||
<value>Laufwerk C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveD" xml:space="preserve">
|
||||
<value>Laufwerk D</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Network" xml:space="preserve">
|
||||
<value>Netzwerk</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Sent" xml:space="preserve">
|
||||
<value>Gesendet</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Received" xml:space="preserve">
|
||||
<value>Empfangen</value>
|
||||
</data>
|
||||
<data name="Message_CPUUsageUnavailable" xml:space="preserve">
|
||||
<value>CPU-Auslastung konnte nicht abgerufen werden. Die Laufgeschwindigkeit kann nicht aktualisiert werden.</value>
|
||||
</data>
|
||||
<data name="Menu_SpeedSource" xml:space="preserve">
|
||||
<value>Geschwindigkeit basierend auf</value>
|
||||
</data>
|
||||
<data name="Game_NewRecord" xml:space="preserve">
|
||||
<value>Neuer Rekord</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Temperature" xml:space="preserve">
|
||||
<value>Temperatur</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureCelsiusFormat" xml:space="preserve">
|
||||
<value>{0:f1}°C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureFahrenheitFormat" xml:space="preserve">
|
||||
<value>{0:f1}°F</value>
|
||||
</data>
|
||||
<data name="Menu_CustomRunners" xml:space="preserve">
|
||||
<value>Benutzerdefinierte Runner...</value>
|
||||
</data>
|
||||
<data name="Window_CustomRunners" xml:space="preserve">
|
||||
<value>Benutzerdefinierte Runner</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddedRunners" xml:space="preserve">
|
||||
<value>Benutzerdefinierte Runner:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Name" xml:space="preserve">
|
||||
<value>Runner-Name:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddFrames" xml:space="preserve">
|
||||
<value>Frames hinzufügen...</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RemoveFrame" xml:space="preserve">
|
||||
<value>Frame entfernen</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Save" xml:space="preserve">
|
||||
<value>Speichern</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Delete" xml:space="preserve">
|
||||
<value>Entfernen</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Requirements" xml:space="preserve">
|
||||
<value>Format: PNG | Max Abmessungen: 32x32px</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmOverwrite" xml:space="preserve">
|
||||
<value>Ein Runner mit diesem Namen existiert bereits. Überschreiben?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmDelete" xml:space="preserve">
|
||||
<value>Runner "{0}" löschen?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RequirementsLabel" xml:space="preserve">
|
||||
<value>Anforderungen:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_FramesLabel" xml:space="preserve">
|
||||
<value>Frames:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Preview" xml:space="preserve">
|
||||
<value>Vorschau:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_PreviewSpeed" xml:space="preserve">
|
||||
<value>Vorschaugeschwindigkeit:</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Menu_Runner" xml:space="preserve">
|
||||
<value>Corredor</value>
|
||||
</data>
|
||||
<data name="Menu_Theme" xml:space="preserve">
|
||||
<value>Tema</value>
|
||||
</data>
|
||||
<data name="Menu_FPSMaxLimit" xml:space="preserve">
|
||||
<value>Límite Máximo de FPS</value>
|
||||
</data>
|
||||
<data name="Menu_LaunchAtStartup" xml:space="preserve">
|
||||
<value>Ejecutar al inicio</value>
|
||||
</data>
|
||||
<data name="Menu_Settings" xml:space="preserve">
|
||||
<value>Ajustes</value>
|
||||
</data>
|
||||
<data name="Menu_EndlessGame" xml:space="preserve">
|
||||
<value>Juego Sin Fin</value>
|
||||
</data>
|
||||
<data name="Menu_Information" xml:space="preserve">
|
||||
<value>Información</value>
|
||||
</data>
|
||||
<data name="Menu_OpenProjectPage" xml:space="preserve">
|
||||
<value>Abrir página del proyecto</value>
|
||||
</data>
|
||||
<data name="Menu_Exit" xml:space="preserve">
|
||||
<value>Salir</value>
|
||||
</data>
|
||||
<data name="Theme_System" xml:space="preserve">
|
||||
<value>Sistema</value>
|
||||
</data>
|
||||
<data name="Theme_Light" xml:space="preserve">
|
||||
<value>Claro</value>
|
||||
</data>
|
||||
<data name="Theme_Dark" xml:space="preserve">
|
||||
<value>Oscuro</value>
|
||||
</data>
|
||||
<data name="Menu_TemperatureUnit" xml:space="preserve">
|
||||
<value>Unidad de temperatura</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_System" xml:space="preserve">
|
||||
<value>Sistema</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Celsius" xml:space="preserve">
|
||||
<value>Celsius</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Fahrenheit" xml:space="preserve">
|
||||
<value>Fahrenheit</value>
|
||||
</data>
|
||||
<data name="Runner_Cat" xml:space="preserve">
|
||||
<value>Gato</value>
|
||||
</data>
|
||||
<data name="Runner_Parrot" xml:space="preserve">
|
||||
<value>Loro</value>
|
||||
</data>
|
||||
<data name="Runner_Horse" xml:space="preserve">
|
||||
<value>Caballo</value>
|
||||
</data>
|
||||
<data name="Message_AppLaunched" xml:space="preserve">
|
||||
<value>La aplicación se ha iniciado. Si el ícono no aparece en la barra de tareas, puede estar oculto; por favor muévelo manualmente y fíjalo.</value>
|
||||
</data>
|
||||
<data name="Message_Warning" xml:space="preserve">
|
||||
<value>Advertencia</value>
|
||||
</data>
|
||||
<data name="Window_EndlessGame" xml:space="preserve">
|
||||
<value>Juego Sin Fin</value>
|
||||
</data>
|
||||
<data name="Game_PressSpaceToPlay" xml:space="preserve">
|
||||
<value>Presiona espacio para jugar.</value>
|
||||
</data>
|
||||
<data name="Game_GameOver" xml:space="preserve">
|
||||
<value>FIN DEL JUEGO</value>
|
||||
</data>
|
||||
<data name="SystemInfo_CPU" xml:space="preserve">
|
||||
<value>CPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_User" xml:space="preserve">
|
||||
<value>Usuario</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Kernel" xml:space="preserve">
|
||||
<value>Núcleo</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Available" xml:space="preserve">
|
||||
<value>Disponible</value>
|
||||
</data>
|
||||
<data name="SystemInfo_GPU" xml:space="preserve">
|
||||
<value>GPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Average" xml:space="preserve">
|
||||
<value>Promedio</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Maximum" xml:space="preserve">
|
||||
<value>Máximo</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Memory" xml:space="preserve">
|
||||
<value>Memoria</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Total" xml:space="preserve">
|
||||
<value>Total</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Used" xml:space="preserve">
|
||||
<value>Usado</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Storage" xml:space="preserve">
|
||||
<value>Almacenamiento</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveC" xml:space="preserve">
|
||||
<value>Disco C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveD" xml:space="preserve">
|
||||
<value>Disco D</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Network" xml:space="preserve">
|
||||
<value>Red</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Sent" xml:space="preserve">
|
||||
<value>Enviado</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Received" xml:space="preserve">
|
||||
<value>Recibido</value>
|
||||
</data>
|
||||
<data name="Message_CPUUsageUnavailable" xml:space="preserve">
|
||||
<value>No se pudo obtener el uso de la CPU. No es posible actualizar la velocidad del corredor.</value>
|
||||
</data>
|
||||
<data name="Menu_SpeedSource" xml:space="preserve">
|
||||
<value>Velocidad basada en</value>
|
||||
</data>
|
||||
<data name="Game_NewRecord" xml:space="preserve">
|
||||
<value>Nuevo Récord</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Temperature" xml:space="preserve">
|
||||
<value>Temperatura</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureCelsiusFormat" xml:space="preserve">
|
||||
<value>{0:f1}°C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureFahrenheitFormat" xml:space="preserve">
|
||||
<value>{0:f1}°F</value>
|
||||
</data>
|
||||
<data name="Menu_CustomRunners" xml:space="preserve">
|
||||
<value>Runners personalizados...</value>
|
||||
</data>
|
||||
<data name="Window_CustomRunners" xml:space="preserve">
|
||||
<value>Runners personalizados</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddedRunners" xml:space="preserve">
|
||||
<value>Runners personalizados:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Name" xml:space="preserve">
|
||||
<value>Nombre del runner:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddFrames" xml:space="preserve">
|
||||
<value>Añadir fotogramas...</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RemoveFrame" xml:space="preserve">
|
||||
<value>Eliminar fotograma</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Save" xml:space="preserve">
|
||||
<value>Guardar</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Delete" xml:space="preserve">
|
||||
<value>Eliminar</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Requirements" xml:space="preserve">
|
||||
<value>Formato: PNG | Dimensiones máx: 32x32px</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmOverwrite" xml:space="preserve">
|
||||
<value>Ya existe un runner con este nombre. ¿Sobrescribir?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmDelete" xml:space="preserve">
|
||||
<value>¿Eliminar runner "{0}"?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RequirementsLabel" xml:space="preserve">
|
||||
<value>Requisitos:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_FramesLabel" xml:space="preserve">
|
||||
<value>Fotogramas:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Preview" xml:space="preserve">
|
||||
<value>Vista previa:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_PreviewSpeed" xml:space="preserve">
|
||||
<value>Velocidad de vista previa:</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Menu_Runner" xml:space="preserve">
|
||||
<value>Coureur</value>
|
||||
</data>
|
||||
<data name="Menu_Theme" xml:space="preserve">
|
||||
<value>Thème</value>
|
||||
</data>
|
||||
<data name="Menu_FPSMaxLimit" xml:space="preserve">
|
||||
<value>Limite FPS maximale</value>
|
||||
</data>
|
||||
<data name="Menu_LaunchAtStartup" xml:space="preserve">
|
||||
<value>Lancer au démarrage</value>
|
||||
</data>
|
||||
<data name="Menu_Settings" xml:space="preserve">
|
||||
<value>Paramètres</value>
|
||||
</data>
|
||||
<data name="Menu_EndlessGame" xml:space="preserve">
|
||||
<value>Jeu sans fin</value>
|
||||
</data>
|
||||
<data name="Menu_Information" xml:space="preserve">
|
||||
<value>Informations</value>
|
||||
</data>
|
||||
<data name="Menu_OpenProjectPage" xml:space="preserve">
|
||||
<value>Ouvrir la page du projet</value>
|
||||
</data>
|
||||
<data name="Menu_Exit" xml:space="preserve">
|
||||
<value>Quitter</value>
|
||||
</data>
|
||||
<data name="Theme_System" xml:space="preserve">
|
||||
<value>Système</value>
|
||||
</data>
|
||||
<data name="Theme_Light" xml:space="preserve">
|
||||
<value>Clair</value>
|
||||
</data>
|
||||
<data name="Theme_Dark" xml:space="preserve">
|
||||
<value>Sombre</value>
|
||||
</data>
|
||||
<data name="Menu_TemperatureUnit" xml:space="preserve">
|
||||
<value>Unité de température</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_System" xml:space="preserve">
|
||||
<value>Système</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Celsius" xml:space="preserve">
|
||||
<value>Celsius</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Fahrenheit" xml:space="preserve">
|
||||
<value>Fahrenheit</value>
|
||||
</data>
|
||||
<data name="Runner_Cat" xml:space="preserve">
|
||||
<value>Chat</value>
|
||||
</data>
|
||||
<data name="Runner_Parrot" xml:space="preserve">
|
||||
<value>Perroquet</value>
|
||||
</data>
|
||||
<data name="Runner_Horse" xml:space="preserve">
|
||||
<value>Cheval</value>
|
||||
</data>
|
||||
<data name="Message_AppLaunched" xml:space="preserve">
|
||||
<value>L'application a démarré. Si l'icône n'apparaît pas dans la barre des tâches, elle a peut-être été masquée ; veuillez la déplacer manuellement et l'épingler.</value>
|
||||
</data>
|
||||
<data name="Message_Warning" xml:space="preserve">
|
||||
<value>Avertissement</value>
|
||||
</data>
|
||||
<data name="Window_EndlessGame" xml:space="preserve">
|
||||
<value>Jeu sans fin</value>
|
||||
</data>
|
||||
<data name="Game_PressSpaceToPlay" xml:space="preserve">
|
||||
<value>Appuyez sur espace pour jouer.</value>
|
||||
</data>
|
||||
<data name="Game_GameOver" xml:space="preserve">
|
||||
<value>GAME OVER</value>
|
||||
</data>
|
||||
<data name="SystemInfo_CPU" xml:space="preserve">
|
||||
<value>CPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_User" xml:space="preserve">
|
||||
<value>Utilisateur</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Kernel" xml:space="preserve">
|
||||
<value>Noyau</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Available" xml:space="preserve">
|
||||
<value>Disponible</value>
|
||||
</data>
|
||||
<data name="SystemInfo_GPU" xml:space="preserve">
|
||||
<value>GPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Average" xml:space="preserve">
|
||||
<value>Moyenne</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Maximum" xml:space="preserve">
|
||||
<value>Maximum</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Memory" xml:space="preserve">
|
||||
<value>Mémoire</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Total" xml:space="preserve">
|
||||
<value>Total</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Used" xml:space="preserve">
|
||||
<value>Utilisé</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Storage" xml:space="preserve">
|
||||
<value>Stockage</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveC" xml:space="preserve">
|
||||
<value>Disque C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveD" xml:space="preserve">
|
||||
<value>Disque D</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Network" xml:space="preserve">
|
||||
<value>Réseau</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Sent" xml:space="preserve">
|
||||
<value>Envoyé</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Received" xml:space="preserve">
|
||||
<value>Reçu</value>
|
||||
</data>
|
||||
<data name="Message_CPUUsageUnavailable" xml:space="preserve">
|
||||
<value>Impossible d'obtenir l'utilisation du CPU. Impossible de mettre à jour la vitesse du coureur.</value>
|
||||
</data>
|
||||
<data name="Menu_SpeedSource" xml:space="preserve">
|
||||
<value>Vitesse basée sur</value>
|
||||
</data>
|
||||
<data name="Game_NewRecord" xml:space="preserve">
|
||||
<value>Nouveau record</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Temperature" xml:space="preserve">
|
||||
<value>Température</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureCelsiusFormat" xml:space="preserve">
|
||||
<value>{0:f1}°C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureFahrenheitFormat" xml:space="preserve">
|
||||
<value>{0:f1}°F</value>
|
||||
</data>
|
||||
<data name="Menu_CustomRunners" xml:space="preserve">
|
||||
<value>Runners personnalisés...</value>
|
||||
</data>
|
||||
<data name="Window_CustomRunners" xml:space="preserve">
|
||||
<value>Runners personnalisés</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddedRunners" xml:space="preserve">
|
||||
<value>Runners personnalisés :</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Name" xml:space="preserve">
|
||||
<value>Nom du runner :</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddFrames" xml:space="preserve">
|
||||
<value>Ajouter des images...</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RemoveFrame" xml:space="preserve">
|
||||
<value>Supprimer l'image</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Save" xml:space="preserve">
|
||||
<value>Enregistrer</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Delete" xml:space="preserve">
|
||||
<value>Supprimer</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Requirements" xml:space="preserve">
|
||||
<value>Format : PNG | Dimensions max : 32x32px</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmOverwrite" xml:space="preserve">
|
||||
<value>Un runner avec ce nom existe déjà. Écraser ?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmDelete" xml:space="preserve">
|
||||
<value>Supprimer le runner « {0} » ?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RequirementsLabel" xml:space="preserve">
|
||||
<value>Exigences :</value>
|
||||
</data>
|
||||
<data name="CustomRunner_FramesLabel" xml:space="preserve">
|
||||
<value>Images :</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Preview" xml:space="preserve">
|
||||
<value>Aperçu :</value>
|
||||
</data>
|
||||
<data name="CustomRunner_PreviewSpeed" xml:space="preserve">
|
||||
<value>Vitesse d'aperçu :</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Menu_Runner" xml:space="preserve">
|
||||
<value>ランナー</value>
|
||||
</data>
|
||||
<data name="Menu_Theme" xml:space="preserve">
|
||||
<value>テーマ</value>
|
||||
</data>
|
||||
<data name="Menu_FPSMaxLimit" xml:space="preserve">
|
||||
<value>FPSの上限</value>
|
||||
</data>
|
||||
<data name="Menu_LaunchAtStartup" xml:space="preserve">
|
||||
<value>スタートアップ時に起動</value>
|
||||
</data>
|
||||
<data name="Menu_Settings" xml:space="preserve">
|
||||
<value>設定</value>
|
||||
</data>
|
||||
<data name="Menu_EndlessGame" xml:space="preserve">
|
||||
<value>エンドレスゲーム</value>
|
||||
</data>
|
||||
<data name="Menu_Information" xml:space="preserve">
|
||||
<value>情報</value>
|
||||
</data>
|
||||
<data name="Menu_OpenProjectPage" xml:space="preserve">
|
||||
<value>プロジェクトページを開く</value>
|
||||
</data>
|
||||
<data name="Menu_Exit" xml:space="preserve">
|
||||
<value>終了</value>
|
||||
</data>
|
||||
<data name="Theme_System" xml:space="preserve">
|
||||
<value>システム</value>
|
||||
</data>
|
||||
<data name="Theme_Light" xml:space="preserve">
|
||||
<value>ライト</value>
|
||||
</data>
|
||||
<data name="Theme_Dark" xml:space="preserve">
|
||||
<value>ダーク</value>
|
||||
</data>
|
||||
<data name="Menu_TemperatureUnit" xml:space="preserve">
|
||||
<value>温度単位</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_System" xml:space="preserve">
|
||||
<value>システム</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Celsius" xml:space="preserve">
|
||||
<value>摂氏</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Fahrenheit" xml:space="preserve">
|
||||
<value>華氏</value>
|
||||
</data>
|
||||
<data name="Runner_Cat" xml:space="preserve">
|
||||
<value>ネコ</value>
|
||||
</data>
|
||||
<data name="Runner_Parrot" xml:space="preserve">
|
||||
<value>オウム</value>
|
||||
</data>
|
||||
<data name="Runner_Horse" xml:space="preserve">
|
||||
<value>早馬</value>
|
||||
</data>
|
||||
<data name="Message_AppLaunched" xml:space="preserve">
|
||||
<value>アプリが起動しました。タスクバーにアイコンが表示されていない場合は、省略されているので手動で移動してピン留めしてください。</value>
|
||||
</data>
|
||||
<data name="Message_Warning" xml:space="preserve">
|
||||
<value>警告</value>
|
||||
</data>
|
||||
<data name="Window_EndlessGame" xml:space="preserve">
|
||||
<value>エンドレスゲーム</value>
|
||||
</data>
|
||||
<data name="Game_PressSpaceToPlay" xml:space="preserve">
|
||||
<value>スペースキーでスタート</value>
|
||||
</data>
|
||||
<data name="Game_GameOver" xml:space="preserve">
|
||||
<value>ゲームオーバー</value>
|
||||
</data>
|
||||
<data name="SystemInfo_CPU" xml:space="preserve">
|
||||
<value>CPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_User" xml:space="preserve">
|
||||
<value>ユーザー</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Kernel" xml:space="preserve">
|
||||
<value>カーネル</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Available" xml:space="preserve">
|
||||
<value>使用可能</value>
|
||||
</data>
|
||||
<data name="SystemInfo_GPU" xml:space="preserve">
|
||||
<value>GPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Average" xml:space="preserve">
|
||||
<value>平均</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Maximum" xml:space="preserve">
|
||||
<value>最大</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Memory" xml:space="preserve">
|
||||
<value>メモリ</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Total" xml:space="preserve">
|
||||
<value>合計</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Used" xml:space="preserve">
|
||||
<value>使用中</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Storage" xml:space="preserve">
|
||||
<value>ストレージ</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveC" xml:space="preserve">
|
||||
<value>Cドライブ</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveD" xml:space="preserve">
|
||||
<value>Dドライブ</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Network" xml:space="preserve">
|
||||
<value>ネットワーク</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Sent" xml:space="preserve">
|
||||
<value>送信</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Received" xml:space="preserve">
|
||||
<value>受信</value>
|
||||
</data>
|
||||
<data name="Message_CPUUsageUnavailable" xml:space="preserve">
|
||||
<value>CPU使用率の取得ができません。走る速度を更新できません。</value>
|
||||
</data>
|
||||
<data name="Menu_SpeedSource" xml:space="preserve">
|
||||
<value>速度の基準</value>
|
||||
</data>
|
||||
<data name="Game_NewRecord" xml:space="preserve">
|
||||
<value>新記録</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Temperature" xml:space="preserve">
|
||||
<value>温度</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureCelsiusFormat" xml:space="preserve">
|
||||
<value>{0:f1}°C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureFahrenheitFormat" xml:space="preserve">
|
||||
<value>{0:f1}°F</value>
|
||||
</data>
|
||||
<data name="Menu_CustomRunners" xml:space="preserve">
|
||||
<value>カスタムランナー...</value>
|
||||
</data>
|
||||
<data name="Window_CustomRunners" xml:space="preserve">
|
||||
<value>カスタムランナー</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddedRunners" xml:space="preserve">
|
||||
<value>カスタムランナー:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Name" xml:space="preserve">
|
||||
<value>ランナー名:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddFrames" xml:space="preserve">
|
||||
<value>フレーム追加...</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RemoveFrame" xml:space="preserve">
|
||||
<value>フレームを削除</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Save" xml:space="preserve">
|
||||
<value>保存</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Delete" xml:space="preserve">
|
||||
<value>削除</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Requirements" xml:space="preserve">
|
||||
<value>形式: PNG | 最大サイズ: 32x32px</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmOverwrite" xml:space="preserve">
|
||||
<value>同名のランナーが既に存在します。上書きしますか?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmDelete" xml:space="preserve">
|
||||
<value>ランナー「{0}」を削除しますか?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RequirementsLabel" xml:space="preserve">
|
||||
<value>要件:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_FramesLabel" xml:space="preserve">
|
||||
<value>フレーム:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Preview" xml:space="preserve">
|
||||
<value>プレビュー:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_PreviewSpeed" xml:space="preserve">
|
||||
<value>プレビュー速度:</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Menu_Runner" xml:space="preserve">
|
||||
<value>러너</value>
|
||||
</data>
|
||||
<data name="Menu_Theme" xml:space="preserve">
|
||||
<value>테마</value>
|
||||
</data>
|
||||
<data name="Menu_FPSMaxLimit" xml:space="preserve">
|
||||
<value>최대 FPS 제한</value>
|
||||
</data>
|
||||
<data name="Menu_LaunchAtStartup" xml:space="preserve">
|
||||
<value>윈도우 시작 시 자동 실행</value>
|
||||
</data>
|
||||
<data name="Menu_Settings" xml:space="preserve">
|
||||
<value>설정</value>
|
||||
</data>
|
||||
<data name="Menu_EndlessGame" xml:space="preserve">
|
||||
<value>무한 게임</value>
|
||||
</data>
|
||||
<data name="Menu_Information" xml:space="preserve">
|
||||
<value>정보</value>
|
||||
</data>
|
||||
<data name="Menu_OpenProjectPage" xml:space="preserve">
|
||||
<value>프로젝트 페이지 열기</value>
|
||||
</data>
|
||||
<data name="Menu_Exit" xml:space="preserve">
|
||||
<value>종료</value>
|
||||
</data>
|
||||
<data name="Theme_System" xml:space="preserve">
|
||||
<value>시스템 설정 사용</value>
|
||||
</data>
|
||||
<data name="Theme_Light" xml:space="preserve">
|
||||
<value>라이트 모드</value>
|
||||
</data>
|
||||
<data name="Theme_Dark" xml:space="preserve">
|
||||
<value>다크 모드</value>
|
||||
</data>
|
||||
<data name="Menu_TemperatureUnit" xml:space="preserve">
|
||||
<value>온도 단위</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_System" xml:space="preserve">
|
||||
<value>시스템</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Celsius" xml:space="preserve">
|
||||
<value>섭씨</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Fahrenheit" xml:space="preserve">
|
||||
<value>화씨</value>
|
||||
</data>
|
||||
<data name="Runner_Cat" xml:space="preserve">
|
||||
<value>고양이</value>
|
||||
</data>
|
||||
<data name="Runner_Parrot" xml:space="preserve">
|
||||
<value>앵무새</value>
|
||||
</data>
|
||||
<data name="Runner_Horse" xml:space="preserve">
|
||||
<value>말</value>
|
||||
</data>
|
||||
<data name="Message_AppLaunched" xml:space="preserve">
|
||||
<value>앱이 실행되었습니다. 작업 표시줄에 아이콘이 보이지 않는다면 숨겨진 아이콘 영역에 있을 수 있으니, 직접 드래그하여 작업 표시줄에 고정해 주세요.</value>
|
||||
</data>
|
||||
<data name="Message_Warning" xml:space="preserve">
|
||||
<value>경고</value>
|
||||
</data>
|
||||
<data name="Window_EndlessGame" xml:space="preserve">
|
||||
<value>무한 게임</value>
|
||||
</data>
|
||||
<data name="Game_PressSpaceToPlay" xml:space="preserve">
|
||||
<value>스페이스바를 눌러 시작하세요.</value>
|
||||
</data>
|
||||
<data name="Game_GameOver" xml:space="preserve">
|
||||
<value>게임 오버</value>
|
||||
</data>
|
||||
<data name="SystemInfo_CPU" xml:space="preserve">
|
||||
<value>CPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_User" xml:space="preserve">
|
||||
<value>사용자</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Kernel" xml:space="preserve">
|
||||
<value>커널</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Available" xml:space="preserve">
|
||||
<value>사용 가능</value>
|
||||
</data>
|
||||
<data name="SystemInfo_GPU" xml:space="preserve">
|
||||
<value>GPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Average" xml:space="preserve">
|
||||
<value>평균</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Maximum" xml:space="preserve">
|
||||
<value>최대</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Memory" xml:space="preserve">
|
||||
<value>메모리</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Total" xml:space="preserve">
|
||||
<value>전체</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Used" xml:space="preserve">
|
||||
<value>사용 중</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Storage" xml:space="preserve">
|
||||
<value>저장 장치</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveC" xml:space="preserve">
|
||||
<value>C 드라이브</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveD" xml:space="preserve">
|
||||
<value>D 드라이브</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Network" xml:space="preserve">
|
||||
<value>네트워크</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Sent" xml:space="preserve">
|
||||
<value>업로드</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Received" xml:space="preserve">
|
||||
<value>다운로드</value>
|
||||
</data>
|
||||
<data name="Message_CPUUsageUnavailable" xml:space="preserve">
|
||||
<value>CPU 사용량을 가져오지 못했습니다. 러너의 달리기 속도를 갱신할 수 없습니다.</value>
|
||||
</data>
|
||||
<data name="Menu_SpeedSource" xml:space="preserve">
|
||||
<value>달리기 속도 기준</value>
|
||||
</data>
|
||||
<data name="Game_NewRecord" xml:space="preserve">
|
||||
<value>최고 기록 달성!</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Temperature" xml:space="preserve">
|
||||
<value>온도</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureCelsiusFormat" xml:space="preserve">
|
||||
<value>{0:f1}°C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureFahrenheitFormat" xml:space="preserve">
|
||||
<value>{0:f1}°F</value>
|
||||
</data>
|
||||
<data name="Menu_CustomRunners" xml:space="preserve">
|
||||
<value>커스텀 러너 설정...</value>
|
||||
</data>
|
||||
<data name="Window_CustomRunners" xml:space="preserve">
|
||||
<value>커스텀 러너</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddedRunners" xml:space="preserve">
|
||||
<value>추가된 러너 목록:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Name" xml:space="preserve">
|
||||
<value>러너 이름:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddFrames" xml:space="preserve">
|
||||
<value>프레임 추가...</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RemoveFrame" xml:space="preserve">
|
||||
<value>프레임 삭제</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Save" xml:space="preserve">
|
||||
<value>저장</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Delete" xml:space="preserve">
|
||||
<value>삭제</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Requirements" xml:space="preserve">
|
||||
<value>포맷: PNG | 최대 크기: 32x32px</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmOverwrite" xml:space="preserve">
|
||||
<value>같은 이름의 러너가 이미 존재합니다. 덮어쓰시겠습니까?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmDelete" xml:space="preserve">
|
||||
<value>"{0}" 러너를 삭제하시겠습니까?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RequirementsLabel" xml:space="preserve">
|
||||
<value>요구 사양:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_FramesLabel" xml:space="preserve">
|
||||
<value>프레임:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Preview" xml:space="preserve">
|
||||
<value>미리보기:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_PreviewSpeed" xml:space="preserve">
|
||||
<value>미리보기 속도:</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Menu_Runner" xml:space="preserve">
|
||||
<value>Runner</value>
|
||||
</data>
|
||||
<data name="Menu_Theme" xml:space="preserve">
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
<data name="Menu_FPSMaxLimit" xml:space="preserve">
|
||||
<value>FPS Max Limit</value>
|
||||
</data>
|
||||
<data name="Menu_LaunchAtStartup" xml:space="preserve">
|
||||
<value>Launch at startup</value>
|
||||
</data>
|
||||
<data name="Menu_Settings" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Menu_EndlessGame" xml:space="preserve">
|
||||
<value>Endless Game</value>
|
||||
</data>
|
||||
<data name="Menu_Information" xml:space="preserve">
|
||||
<value>Information</value>
|
||||
</data>
|
||||
<data name="Menu_OpenProjectPage" xml:space="preserve">
|
||||
<value>Open Project Page</value>
|
||||
</data>
|
||||
<data name="Menu_Exit" xml:space="preserve">
|
||||
<value>Exit</value>
|
||||
</data>
|
||||
<data name="Theme_System" xml:space="preserve">
|
||||
<value>System</value>
|
||||
</data>
|
||||
<data name="Theme_Light" xml:space="preserve">
|
||||
<value>Light</value>
|
||||
</data>
|
||||
<data name="Theme_Dark" xml:space="preserve">
|
||||
<value>Dark</value>
|
||||
</data>
|
||||
<data name="Menu_TemperatureUnit" xml:space="preserve">
|
||||
<value>Temperature Unit</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_System" xml:space="preserve">
|
||||
<value>System</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Celsius" xml:space="preserve">
|
||||
<value>Celsius</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Fahrenheit" xml:space="preserve">
|
||||
<value>Fahrenheit</value>
|
||||
</data>
|
||||
<data name="Runner_Cat" xml:space="preserve">
|
||||
<value>Cat</value>
|
||||
</data>
|
||||
<data name="Runner_Parrot" xml:space="preserve">
|
||||
<value>Parrot</value>
|
||||
</data>
|
||||
<data name="Runner_Horse" xml:space="preserve">
|
||||
<value>Horse</value>
|
||||
</data>
|
||||
<data name="Message_AppLaunched" xml:space="preserve">
|
||||
<value>App has launched. If the icon is not on the taskbar, it has been omitted, so please move it manually and pin it.</value>
|
||||
</data>
|
||||
<data name="Message_Warning" xml:space="preserve">
|
||||
<value>Warning</value>
|
||||
</data>
|
||||
<data name="Window_EndlessGame" xml:space="preserve">
|
||||
<value>Endless Game</value>
|
||||
</data>
|
||||
<data name="Game_PressSpaceToPlay" xml:space="preserve">
|
||||
<value>Press space to play.</value>
|
||||
</data>
|
||||
<data name="Game_GameOver" xml:space="preserve">
|
||||
<value>GAME OVER</value>
|
||||
</data>
|
||||
<data name="SystemInfo_CPU" xml:space="preserve">
|
||||
<value>CPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_User" xml:space="preserve">
|
||||
<value>User</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Kernel" xml:space="preserve">
|
||||
<value>Kernel</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Available" xml:space="preserve">
|
||||
<value>Available</value>
|
||||
</data>
|
||||
<data name="SystemInfo_GPU" xml:space="preserve">
|
||||
<value>GPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Average" xml:space="preserve">
|
||||
<value>Average</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Maximum" xml:space="preserve">
|
||||
<value>Maximum</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Memory" xml:space="preserve">
|
||||
<value>Memory</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Total" xml:space="preserve">
|
||||
<value>Total</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Used" xml:space="preserve">
|
||||
<value>Used</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Storage" xml:space="preserve">
|
||||
<value>Storage</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveC" xml:space="preserve">
|
||||
<value>C Drive</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveD" xml:space="preserve">
|
||||
<value>D Drive</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Network" xml:space="preserve">
|
||||
<value>Network</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Sent" xml:space="preserve">
|
||||
<value>Sent</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Received" xml:space="preserve">
|
||||
<value>Received</value>
|
||||
</data>
|
||||
<data name="Message_CPUUsageUnavailable" xml:space="preserve">
|
||||
<value>Failed to get CPU usage. Unable to update running speed.</value>
|
||||
</data>
|
||||
<data name="Menu_SpeedSource" xml:space="preserve">
|
||||
<value>Speed based on</value>
|
||||
</data>
|
||||
<data name="Game_NewRecord" xml:space="preserve">
|
||||
<value>New Record</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Temperature" xml:space="preserve">
|
||||
<value>Temperature</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureCelsiusFormat" xml:space="preserve">
|
||||
<value>{0:f1}°C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureFahrenheitFormat" xml:space="preserve">
|
||||
<value>{0:f1}°F</value>
|
||||
</data>
|
||||
<data name="Menu_CustomRunners" xml:space="preserve">
|
||||
<value>Custom Runners...</value>
|
||||
</data>
|
||||
<data name="Window_CustomRunners" xml:space="preserve">
|
||||
<value>Custom Runners</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddedRunners" xml:space="preserve">
|
||||
<value>Custom Runners:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Name" xml:space="preserve">
|
||||
<value>Runner Name:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddFrames" xml:space="preserve">
|
||||
<value>Add Frames...</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RemoveFrame" xml:space="preserve">
|
||||
<value>Remove Frame</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Save" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Delete" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Requirements" xml:space="preserve">
|
||||
<value>Format: PNG | Max Dimensions: 32x32px</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmOverwrite" xml:space="preserve">
|
||||
<value>A runner with this name already exists. Overwrite?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmDelete" xml:space="preserve">
|
||||
<value>Delete runner "{0}"?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RequirementsLabel" xml:space="preserve">
|
||||
<value>Requirements:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_FramesLabel" xml:space="preserve">
|
||||
<value>Frames:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Preview" xml:space="preserve">
|
||||
<value>Preview:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_PreviewSpeed" xml:space="preserve">
|
||||
<value>Preview Speed:</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Menu_Runner" xml:space="preserve">
|
||||
<value>跑步者</value>
|
||||
</data>
|
||||
<data name="Menu_Theme" xml:space="preserve">
|
||||
<value>主题</value>
|
||||
</data>
|
||||
<data name="Menu_FPSMaxLimit" xml:space="preserve">
|
||||
<value>FPS 最大限制</value>
|
||||
</data>
|
||||
<data name="Menu_LaunchAtStartup" xml:space="preserve">
|
||||
<value>跟随 Windows 启动</value>
|
||||
</data>
|
||||
<data name="Menu_Settings" xml:space="preserve">
|
||||
<value>设置</value>
|
||||
</data>
|
||||
<data name="Menu_EndlessGame" xml:space="preserve">
|
||||
<value>无尽游戏</value>
|
||||
</data>
|
||||
<data name="Menu_Information" xml:space="preserve">
|
||||
<value>信息</value>
|
||||
</data>
|
||||
<data name="Menu_OpenProjectPage" xml:space="preserve">
|
||||
<value>打开项目页面</value>
|
||||
</data>
|
||||
<data name="Menu_Exit" xml:space="preserve">
|
||||
<value>退出</value>
|
||||
</data>
|
||||
<data name="Theme_System" xml:space="preserve">
|
||||
<value>系统</value>
|
||||
</data>
|
||||
<data name="Theme_Light" xml:space="preserve">
|
||||
<value>浅色</value>
|
||||
</data>
|
||||
<data name="Theme_Dark" xml:space="preserve">
|
||||
<value>深色</value>
|
||||
</data>
|
||||
<data name="Menu_TemperatureUnit" xml:space="preserve">
|
||||
<value>温度单位</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_System" xml:space="preserve">
|
||||
<value>系统</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Celsius" xml:space="preserve">
|
||||
<value>摄氏</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Fahrenheit" xml:space="preserve">
|
||||
<value>华氏</value>
|
||||
</data>
|
||||
<data name="Runner_Cat" xml:space="preserve">
|
||||
<value>猫咪</value>
|
||||
</data>
|
||||
<data name="Runner_Parrot" xml:space="preserve">
|
||||
<value>鹦鹉</value>
|
||||
</data>
|
||||
<data name="Runner_Horse" xml:space="preserve">
|
||||
<value>马</value>
|
||||
</data>
|
||||
<data name="Message_AppLaunched" xml:space="preserve">
|
||||
<value>应用已启动。如果图标不在任务栏上,则表示该应用已被省略,请手动移动并将其固定。</value>
|
||||
</data>
|
||||
<data name="Message_Warning" xml:space="preserve">
|
||||
<value>警告</value>
|
||||
</data>
|
||||
<data name="Window_EndlessGame" xml:space="preserve">
|
||||
<value>无尽游戏</value>
|
||||
</data>
|
||||
<data name="Game_PressSpaceToPlay" xml:space="preserve">
|
||||
<value>按空格键开始。</value>
|
||||
</data>
|
||||
<data name="Game_GameOver" xml:space="preserve">
|
||||
<value>游戏结束</value>
|
||||
</data>
|
||||
<data name="SystemInfo_CPU" xml:space="preserve">
|
||||
<value>CPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_User" xml:space="preserve">
|
||||
<value>用户</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Kernel" xml:space="preserve">
|
||||
<value>内核</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Available" xml:space="preserve">
|
||||
<value>可用</value>
|
||||
</data>
|
||||
<data name="SystemInfo_GPU" xml:space="preserve">
|
||||
<value>GPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Average" xml:space="preserve">
|
||||
<value>平均</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Maximum" xml:space="preserve">
|
||||
<value>最大</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Memory" xml:space="preserve">
|
||||
<value>内存</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Total" xml:space="preserve">
|
||||
<value>总计</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Used" xml:space="preserve">
|
||||
<value>已使用</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Storage" xml:space="preserve">
|
||||
<value>存储</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveC" xml:space="preserve">
|
||||
<value>C 盘</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveD" xml:space="preserve">
|
||||
<value>D 盘</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Network" xml:space="preserve">
|
||||
<value>网络</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Sent" xml:space="preserve">
|
||||
<value>发送</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Received" xml:space="preserve">
|
||||
<value>已接收</value>
|
||||
</data>
|
||||
<data name="Message_CPUUsageUnavailable" xml:space="preserve">
|
||||
<value>获取 CPU 使用率失败。无法更新运行速度。</value>
|
||||
</data>
|
||||
<data name="Menu_SpeedSource" xml:space="preserve">
|
||||
<value>速度来源</value>
|
||||
</data>
|
||||
<data name="Game_NewRecord" xml:space="preserve">
|
||||
<value>新纪录</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Temperature" xml:space="preserve">
|
||||
<value>温度</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureCelsiusFormat" xml:space="preserve">
|
||||
<value>{0:f1}°C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureFahrenheitFormat" xml:space="preserve">
|
||||
<value>{0:f1}°F</value>
|
||||
</data>
|
||||
<data name="Menu_CustomRunners" xml:space="preserve">
|
||||
<value>自定义跑步者...</value>
|
||||
</data>
|
||||
<data name="Window_CustomRunners" xml:space="preserve">
|
||||
<value>自定义跑步者</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddedRunners" xml:space="preserve">
|
||||
<value>自定义跑步者:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Name" xml:space="preserve">
|
||||
<value>跑步者名称:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddFrames" xml:space="preserve">
|
||||
<value>添加帧...</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RemoveFrame" xml:space="preserve">
|
||||
<value>删除帧</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Save" xml:space="preserve">
|
||||
<value>保存</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Delete" xml:space="preserve">
|
||||
<value>删除</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Requirements" xml:space="preserve">
|
||||
<value>格式: PNG | 最大尺寸: 32x32px</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmOverwrite" xml:space="preserve">
|
||||
<value>同名跑步者已存在。是否覆盖?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmDelete" xml:space="preserve">
|
||||
<value>删除跑步者"{0}"?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RequirementsLabel" xml:space="preserve">
|
||||
<value>要求:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_FramesLabel" xml:space="preserve">
|
||||
<value>帧:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Preview" xml:space="preserve">
|
||||
<value>预览:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_PreviewSpeed" xml:space="preserve">
|
||||
<value>预览速度:</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Menu_Runner" xml:space="preserve">
|
||||
<value>跑步者</value>
|
||||
</data>
|
||||
<data name="Menu_Theme" xml:space="preserve">
|
||||
<value>主題</value>
|
||||
</data>
|
||||
<data name="Menu_FPSMaxLimit" xml:space="preserve">
|
||||
<value>FPS 最大限制</value>
|
||||
</data>
|
||||
<data name="Menu_LaunchAtStartup" xml:space="preserve">
|
||||
<value>跟隨 Windows 啟動</value>
|
||||
</data>
|
||||
<data name="Menu_Settings" xml:space="preserve">
|
||||
<value>設定</value>
|
||||
</data>
|
||||
<data name="Menu_EndlessGame" xml:space="preserve">
|
||||
<value>無盡遊戲</value>
|
||||
</data>
|
||||
<data name="Menu_Information" xml:space="preserve">
|
||||
<value>資訊</value>
|
||||
</data>
|
||||
<data name="Menu_OpenProjectPage" xml:space="preserve">
|
||||
<value>開啟專案頁面</value>
|
||||
</data>
|
||||
<data name="Menu_Exit" xml:space="preserve">
|
||||
<value>結束</value>
|
||||
</data>
|
||||
<data name="Theme_System" xml:space="preserve">
|
||||
<value>系統</value>
|
||||
</data>
|
||||
<data name="Theme_Light" xml:space="preserve">
|
||||
<value>淺色</value>
|
||||
</data>
|
||||
<data name="Theme_Dark" xml:space="preserve">
|
||||
<value>深色</value>
|
||||
</data>
|
||||
<data name="Menu_TemperatureUnit" xml:space="preserve">
|
||||
<value>溫度單位</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_System" xml:space="preserve">
|
||||
<value>系統</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Celsius" xml:space="preserve">
|
||||
<value>攝氏</value>
|
||||
</data>
|
||||
<data name="TemperatureUnit_Fahrenheit" xml:space="preserve">
|
||||
<value>華氏</value>
|
||||
</data>
|
||||
<data name="Runner_Cat" xml:space="preserve">
|
||||
<value>貓咪</value>
|
||||
</data>
|
||||
<data name="Runner_Parrot" xml:space="preserve">
|
||||
<value>鸚鵡</value>
|
||||
</data>
|
||||
<data name="Runner_Horse" xml:space="preserve">
|
||||
<value>馬</value>
|
||||
</data>
|
||||
<data name="Message_AppLaunched" xml:space="preserve">
|
||||
<value>應用程式已啟動。如果圖示不在工作列上,表示已被省略,請手動移動並固定它。</value>
|
||||
</data>
|
||||
<data name="Message_Warning" xml:space="preserve">
|
||||
<value>警告</value>
|
||||
</data>
|
||||
<data name="Window_EndlessGame" xml:space="preserve">
|
||||
<value>無盡遊戲</value>
|
||||
</data>
|
||||
<data name="Game_PressSpaceToPlay" xml:space="preserve">
|
||||
<value>按空白鍵開始。</value>
|
||||
</data>
|
||||
<data name="Game_GameOver" xml:space="preserve">
|
||||
<value>遊戲結束</value>
|
||||
</data>
|
||||
<data name="SystemInfo_CPU" xml:space="preserve">
|
||||
<value>CPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_User" xml:space="preserve">
|
||||
<value>使用者</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Kernel" xml:space="preserve">
|
||||
<value>核心</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Available" xml:space="preserve">
|
||||
<value>可用</value>
|
||||
</data>
|
||||
<data name="SystemInfo_GPU" xml:space="preserve">
|
||||
<value>GPU</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Average" xml:space="preserve">
|
||||
<value>平均</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Maximum" xml:space="preserve">
|
||||
<value>最大</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Memory" xml:space="preserve">
|
||||
<value>記憶體</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Total" xml:space="preserve">
|
||||
<value>總計</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Used" xml:space="preserve">
|
||||
<value>已使用</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Storage" xml:space="preserve">
|
||||
<value>儲存</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveC" xml:space="preserve">
|
||||
<value>C 槽</value>
|
||||
</data>
|
||||
<data name="SystemInfo_DriveD" xml:space="preserve">
|
||||
<value>D 槽</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Network" xml:space="preserve">
|
||||
<value>網路</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Sent" xml:space="preserve">
|
||||
<value>傳送</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Received" xml:space="preserve">
|
||||
<value>已接收</value>
|
||||
</data>
|
||||
<data name="Message_CPUUsageUnavailable" xml:space="preserve">
|
||||
<value>取得 CPU 使用率失敗。無法更新執行速度。</value>
|
||||
</data>
|
||||
<data name="Menu_SpeedSource" xml:space="preserve">
|
||||
<value>速度來源</value>
|
||||
</data>
|
||||
<data name="Game_NewRecord" xml:space="preserve">
|
||||
<value>新紀錄</value>
|
||||
</data>
|
||||
<data name="SystemInfo_Temperature" xml:space="preserve">
|
||||
<value>溫度</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureCelsiusFormat" xml:space="preserve">
|
||||
<value>{0:f1}°C</value>
|
||||
</data>
|
||||
<data name="SystemInfo_TemperatureFahrenheitFormat" xml:space="preserve">
|
||||
<value>{0:f1}°F</value>
|
||||
</data>
|
||||
<data name="Menu_CustomRunners" xml:space="preserve">
|
||||
<value>自訂跑步者...</value>
|
||||
</data>
|
||||
<data name="Window_CustomRunners" xml:space="preserve">
|
||||
<value>自訂跑步者</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddedRunners" xml:space="preserve">
|
||||
<value>自訂跑步者:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Name" xml:space="preserve">
|
||||
<value>跑步者名稱:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_AddFrames" xml:space="preserve">
|
||||
<value>新增影格...</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RemoveFrame" xml:space="preserve">
|
||||
<value>刪除影格</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Save" xml:space="preserve">
|
||||
<value>儲存</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Delete" xml:space="preserve">
|
||||
<value>刪除</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Requirements" xml:space="preserve">
|
||||
<value>格式: PNG | 最大尺寸: 32x32px</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmOverwrite" xml:space="preserve">
|
||||
<value>同名跑步者已存在。是否覆蓋?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_ConfirmDelete" xml:space="preserve">
|
||||
<value>刪除跑步者「{0}」?</value>
|
||||
</data>
|
||||
<data name="CustomRunner_RequirementsLabel" xml:space="preserve">
|
||||
<value>需求:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_FramesLabel" xml:space="preserve">
|
||||
<value>影格:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_Preview" xml:space="preserve">
|
||||
<value>預覽:</value>
|
||||
</data>
|
||||
<data name="CustomRunner_PreviewSpeed" xml:space="preserve">
|
||||
<value>預覽速度:</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,122 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RunCat365.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
|
||||
internal sealed partial class UserSettings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static UserSettings defaultInstance = ((UserSettings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new UserSettings())));
|
||||
|
||||
public static UserSettings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("Cat")]
|
||||
public string Runner {
|
||||
get {
|
||||
return ((string)(this["Runner"]));
|
||||
}
|
||||
set {
|
||||
this["Runner"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string Theme {
|
||||
get {
|
||||
return ((string)(this["Theme"]));
|
||||
}
|
||||
set {
|
||||
this["Theme"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string TemperatureUnit {
|
||||
get {
|
||||
return ((string)(this["TemperatureUnit"]));
|
||||
}
|
||||
set {
|
||||
this["TemperatureUnit"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("FPS40")]
|
||||
public string FPSMaxLimit {
|
||||
get {
|
||||
return ((string)(this["FPSMaxLimit"]));
|
||||
}
|
||||
set {
|
||||
this["FPSMaxLimit"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
public bool FirstLaunch {
|
||||
get {
|
||||
return ((bool)(this["FirstLaunch"]));
|
||||
}
|
||||
set {
|
||||
this["FirstLaunch"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("0")]
|
||||
public int HighScore {
|
||||
get {
|
||||
return ((int)(this["HighScore"]));
|
||||
}
|
||||
set {
|
||||
this["HighScore"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("CPU")]
|
||||
public string SpeedSource {
|
||||
get {
|
||||
return ((string)(this["SpeedSource"]));
|
||||
}
|
||||
set {
|
||||
this["SpeedSource"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string CustomRunnerName {
|
||||
get {
|
||||
return ((string)(this["CustomRunnerName"]));
|
||||
}
|
||||
set {
|
||||
this["CustomRunnerName"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="RunCat365.Properties" GeneratedClassName="UserSettings">
|
||||
<Profiles />
|
||||
<Settings>
|
||||
<Setting Name="Runner" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Cat</Value>
|
||||
</Setting>
|
||||
<Setting Name="Theme" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="TemperatureUnit" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="FPSMaxLimit" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">FPS40</Value>
|
||||
</Setting>
|
||||
<Setting Name="FirstLaunch" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="HighScore" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="SpeedSource" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">CPU</Value>
|
||||
</Setting>
|
||||
<Setting Name="CustomRunnerName" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal enum Road
|
||||
{
|
||||
Flat,
|
||||
Hill,
|
||||
Crater,
|
||||
Sprout
|
||||
}
|
||||
|
||||
internal static class RoadExtension
|
||||
{
|
||||
internal static string GetString(this Road road)
|
||||
{
|
||||
return road switch
|
||||
{
|
||||
Road.Flat => "Flat",
|
||||
Road.Hill => "Hill",
|
||||
Road.Crater => "Crater",
|
||||
Road.Sprout => "Sprout",
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
|
||||
<AssemblyName>RunCat 365</AssemblyName>
|
||||
<ApplicationIcon>resources\app_icon.ico</ApplicationIcon>
|
||||
<Authors>Takuto Nakamura</Authors>
|
||||
<Company>Studio Kyome</Company>
|
||||
<Description>A cute running cat animation on your taskbar.</Description>
|
||||
<Copyright>© 2022 Takuto Nakamura</Copyright>
|
||||
<PackageProjectUrl>https://runcat-dev.github.io/RunCat365/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/runcat-dev/RunCat365</RepositoryUrl>
|
||||
<PackageTags>cpu;cat;taskbar</PackageTags>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageIcon>app_icon.png</PackageIcon>
|
||||
<Version>3.6.0</Version>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<StartupObject>RunCat365.Program</StartupObject>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<Platforms>x64;x86;ARM64</Platforms>
|
||||
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||
<NoWarn>$(NoWarn);WFO5001</NoWarn>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="resources\app_icon.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\docs\images\app_icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<None Include="..\README.md">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Properties\UserSettings.Designer.cs">
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>UserSettings.settings</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Properties\UserSettings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>UserSettings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
enum Runner
|
||||
{
|
||||
Cat,
|
||||
Parrot,
|
||||
Horse,
|
||||
}
|
||||
|
||||
internal static class RunnerExtension
|
||||
{
|
||||
internal static string GetString(this Runner runner)
|
||||
{
|
||||
return runner switch
|
||||
{
|
||||
Runner.Cat => "Cat",
|
||||
Runner.Parrot => "Parrot",
|
||||
Runner.Horse => "Horse",
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
internal static string GetLocalizedString(this Runner runner)
|
||||
{
|
||||
return runner switch
|
||||
{
|
||||
Runner.Cat => Strings.Runner_Cat,
|
||||
Runner.Parrot => Strings.Runner_Parrot,
|
||||
Runner.Horse => Strings.Runner_Horse,
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
internal static int GetFrameNumber(this Runner runner)
|
||||
{
|
||||
return runner switch
|
||||
{
|
||||
Runner.Cat => 5,
|
||||
Runner.Parrot => 10,
|
||||
Runner.Horse => 14,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
enum SpeedSource
|
||||
{
|
||||
CPU,
|
||||
GPU,
|
||||
Memory,
|
||||
}
|
||||
|
||||
internal static class SpeedSourceExtension
|
||||
{
|
||||
internal static string GetLocalizedString(this SpeedSource speedSource)
|
||||
{
|
||||
return speedSource switch
|
||||
{
|
||||
SpeedSource.CPU => Strings.SystemInfo_CPU,
|
||||
SpeedSource.GPU => Strings.SystemInfo_GPU,
|
||||
SpeedSource.Memory => Strings.SystemInfo_Memory,
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
internal static bool TryParse([NotNullWhen(true)] string? value, out SpeedSource result)
|
||||
{
|
||||
SpeedSource? nullableResult = value switch
|
||||
{
|
||||
"CPU" => SpeedSource.CPU,
|
||||
"GPU" => SpeedSource.GPU,
|
||||
"Memory" => SpeedSource.Memory,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
if (nullableResult is SpeedSource nonNullableResult)
|
||||
{
|
||||
result = nonNullableResult;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = SpeedSource.CPU;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
enum Drive
|
||||
{
|
||||
C,
|
||||
D
|
||||
}
|
||||
|
||||
internal static class DriveExtension
|
||||
{
|
||||
internal static string GetString(this Drive drive)
|
||||
{
|
||||
return drive switch
|
||||
{
|
||||
Drive.C => "C Drive",
|
||||
Drive.D => "D Drive",
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
internal static string GetLocalizedString(this Drive drive)
|
||||
{
|
||||
return drive switch
|
||||
{
|
||||
Drive.C => Strings.SystemInfo_DriveC,
|
||||
Drive.D => Strings.SystemInfo_DriveD,
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
internal static Drive? CreateFromString(string? value)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
"C:\\" => Drive.C,
|
||||
"D:\\" => Drive.D,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
struct StorageInfo
|
||||
{
|
||||
internal Drive Drive { get; set; }
|
||||
internal long TotalSize { get; set; }
|
||||
internal long AvailableSpaceSize { get; set; }
|
||||
internal long UsedSpaceSize { get; set; }
|
||||
}
|
||||
|
||||
internal static class StorageInfoExtension
|
||||
{
|
||||
internal static List<string> GenerateIndicator(this List<StorageInfo> storageInfoList)
|
||||
{
|
||||
var resultLines = new List<string>
|
||||
{
|
||||
TreeFormatter.CreateRoot($"{Strings.SystemInfo_Storage}:")
|
||||
};
|
||||
|
||||
if (storageInfoList.Count == 0) return resultLines;
|
||||
|
||||
for (int i = 0; i < storageInfoList.Count; i++)
|
||||
{
|
||||
var info = storageInfoList[i];
|
||||
var isLastItem = (i == storageInfoList.Count - 1);
|
||||
var percentage = ((double)info.UsedSpaceSize / info.TotalSize) * 100.0;
|
||||
resultLines.Add(TreeFormatter.CreateNode($"{info.Drive.GetLocalizedString()}: {percentage:f1}%", isLastItem));
|
||||
resultLines.Add(TreeFormatter.CreateNestedNode($"{Strings.SystemInfo_Used}: {info.UsedSpaceSize.ToByteFormatted()}", isLastItem, false));
|
||||
resultLines.Add(TreeFormatter.CreateNestedNode($"{Strings.SystemInfo_Available}: {info.AvailableSpaceSize.ToByteFormatted()}", isLastItem, true));
|
||||
}
|
||||
|
||||
return resultLines;
|
||||
}
|
||||
}
|
||||
|
||||
internal class StorageRepository
|
||||
{
|
||||
private readonly List<StorageInfo> storageInfoList = [];
|
||||
|
||||
internal StorageRepository() { }
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
storageInfoList.Clear();
|
||||
var allDrives = DriveInfo.GetDrives();
|
||||
foreach (var driveInfo in allDrives)
|
||||
{
|
||||
if (driveInfo.IsReady && DriveExtension.CreateFromString(driveInfo.Name) is Drive drive)
|
||||
{
|
||||
try
|
||||
{
|
||||
var storageInfo = new StorageInfo
|
||||
{
|
||||
Drive = drive,
|
||||
TotalSize = driveInfo.TotalSize,
|
||||
AvailableSpaceSize = driveInfo.AvailableFreeSpace,
|
||||
UsedSpaceSize = driveInfo.TotalSize - driveInfo.AvailableFreeSpace
|
||||
};
|
||||
storageInfoList.Add(storageInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal List<StorageInfo> Get()
|
||||
{
|
||||
return storageInfoList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
enum SupportedLanguage
|
||||
{
|
||||
ChineseSimplified,
|
||||
ChineseTraditional,
|
||||
English,
|
||||
French,
|
||||
German,
|
||||
Japanese,
|
||||
Korean,
|
||||
Spanish,
|
||||
}
|
||||
|
||||
internal static class SupportedLanguageExtension
|
||||
{
|
||||
private static SupportedLanguage DetectChineseVariant(CultureInfo culture)
|
||||
{
|
||||
return culture.Name.Contains("Hant") || culture.Name is "zh-TW" or "zh-HK" or "zh-MO"
|
||||
? SupportedLanguage.ChineseTraditional
|
||||
: SupportedLanguage.ChineseSimplified;
|
||||
}
|
||||
|
||||
internal static SupportedLanguage GetCurrentLanguage()
|
||||
{
|
||||
var culture = CultureInfo.CurrentUICulture;
|
||||
return culture.TwoLetterISOLanguageName switch
|
||||
{
|
||||
"zh" => DetectChineseVariant(culture),
|
||||
"fr" => SupportedLanguage.French,
|
||||
"de" => SupportedLanguage.German,
|
||||
"ja" => SupportedLanguage.Japanese,
|
||||
"ko" => SupportedLanguage.Korean,
|
||||
"es" => SupportedLanguage.Spanish,
|
||||
_ => SupportedLanguage.English,
|
||||
};
|
||||
}
|
||||
|
||||
internal static CultureInfo GetDefaultCultureInfo(this SupportedLanguage language)
|
||||
{
|
||||
return language switch
|
||||
{
|
||||
SupportedLanguage.ChineseSimplified => new CultureInfo("zh-CN"),
|
||||
SupportedLanguage.ChineseTraditional => new CultureInfo("zh-TW"),
|
||||
SupportedLanguage.French => new CultureInfo("fr-FR"),
|
||||
SupportedLanguage.German => new CultureInfo("de-DE"),
|
||||
SupportedLanguage.Japanese => new CultureInfo("ja-JP"),
|
||||
SupportedLanguage.Korean => new CultureInfo("ko-KR"),
|
||||
SupportedLanguage.Spanish => new CultureInfo("es-ES"),
|
||||
_ => new CultureInfo("en-US"),
|
||||
};
|
||||
}
|
||||
|
||||
internal static string GetFontName(this SupportedLanguage language)
|
||||
{
|
||||
return language switch
|
||||
{
|
||||
SupportedLanguage.ChineseSimplified => "Microsoft YaHei",
|
||||
SupportedLanguage.ChineseTraditional => "Microsoft JhengHei",
|
||||
SupportedLanguage.French => "Consolas",
|
||||
SupportedLanguage.German => "Consolas",
|
||||
SupportedLanguage.Japanese => "Noto Sans JP",
|
||||
SupportedLanguage.Korean => "Malgun Gothic",
|
||||
SupportedLanguage.Spanish => "Consolas",
|
||||
_ => "Consolas",
|
||||
};
|
||||
}
|
||||
|
||||
internal static bool IsFullWidth(this SupportedLanguage language)
|
||||
{
|
||||
return language switch
|
||||
{
|
||||
SupportedLanguage.ChineseSimplified => true,
|
||||
SupportedLanguage.ChineseTraditional => true,
|
||||
SupportedLanguage.French => false,
|
||||
SupportedLanguage.German => false,
|
||||
SupportedLanguage.Japanese => true,
|
||||
SupportedLanguage.Korean => true,
|
||||
SupportedLanguage.Spanish => false,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
using System.Globalization;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
struct TemperatureInfo
|
||||
{
|
||||
internal float AverageCelsius { get; set; }
|
||||
internal float MaximumCelsius { get; set; }
|
||||
}
|
||||
|
||||
internal static class TemperatureInfoExtension
|
||||
{
|
||||
private const float CELSIUS_TO_FAHRENHEIT_SCALE = 9.0f / 5.0f;
|
||||
private const float CELSIUS_TO_FAHRENHEIT_OFFSET = 32.0f;
|
||||
|
||||
internal static string GetDescription(this TemperatureInfo temperatureInfo, TemperatureUnit unit)
|
||||
{
|
||||
var resolvedUnit = unit.Resolve();
|
||||
return $"{Strings.SystemInfo_Temperature}: {temperatureInfo.MaximumCelsius.ToLocalizedTemperatureText(resolvedUnit)}";
|
||||
}
|
||||
|
||||
internal static List<string> GenerateIndicator(this TemperatureInfo temperatureInfo, TemperatureUnit unit)
|
||||
{
|
||||
var resolvedUnit = unit.Resolve();
|
||||
return [
|
||||
TreeFormatter.CreateRoot($"{Strings.SystemInfo_Temperature}:"),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Average}: {temperatureInfo.AverageCelsius.ToLocalizedTemperatureText(resolvedUnit)}", false),
|
||||
TreeFormatter.CreateNode($"{Strings.SystemInfo_Maximum}: {temperatureInfo.MaximumCelsius.ToLocalizedTemperatureText(resolvedUnit)}", true)
|
||||
];
|
||||
}
|
||||
|
||||
private static string ToLocalizedTemperatureText(this float temperatureCelsius, TemperatureUnit resolvedUnit)
|
||||
{
|
||||
var useFahrenheit = resolvedUnit == TemperatureUnit.Fahrenheit;
|
||||
var value = useFahrenheit
|
||||
? temperatureCelsius * CELSIUS_TO_FAHRENHEIT_SCALE + CELSIUS_TO_FAHRENHEIT_OFFSET
|
||||
: temperatureCelsius;
|
||||
var format = useFahrenheit
|
||||
? Strings.SystemInfo_TemperatureFahrenheitFormat
|
||||
: Strings.SystemInfo_TemperatureCelsiusFormat;
|
||||
return string.Format(CultureInfo.CurrentCulture, format, value);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TemperaturePerformanceCounters : InstancedPerformanceCounters
|
||||
{
|
||||
protected override string CategoryName => "Thermal Zone Information";
|
||||
protected override string CounterName => "Temperature";
|
||||
|
||||
internal static TemperaturePerformanceCounters? TryCreate()
|
||||
{
|
||||
var instance = new TemperaturePerformanceCounters();
|
||||
return instance.TryInitialize() ? instance : null;
|
||||
}
|
||||
}
|
||||
|
||||
internal class TemperatureRepository
|
||||
{
|
||||
private const float KELVIN_TO_CELSIUS_OFFSET = 273.15f;
|
||||
private const float MIN_VALID_TEMPERATURE_CELSIUS = -50.0f;
|
||||
private const float MAX_VALID_TEMPERATURE_CELSIUS = 150.0f;
|
||||
private const int REFRESH_INTERVAL_TICKS = 30;
|
||||
|
||||
private readonly TemperaturePerformanceCounters? counters;
|
||||
private TemperatureInfo? temperatureInfo;
|
||||
private int ticksSinceLastRefresh;
|
||||
|
||||
internal bool IsAvailable => counters is not null;
|
||||
|
||||
internal TemperatureRepository()
|
||||
{
|
||||
counters = TemperaturePerformanceCounters.TryCreate();
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
if (counters is null) return;
|
||||
|
||||
ticksSinceLastRefresh += 1;
|
||||
if (REFRESH_INTERVAL_TICKS <= ticksSinceLastRefresh)
|
||||
{
|
||||
ticksSinceLastRefresh = 0;
|
||||
counters.RefreshInstances();
|
||||
}
|
||||
|
||||
var rawValues = counters.ReadValues();
|
||||
var temperaturesCelsius = new List<float>(rawValues.Count);
|
||||
foreach (var temperatureKelvin in rawValues)
|
||||
{
|
||||
if (temperatureKelvin <= 0) continue;
|
||||
var temperatureCelsius = temperatureKelvin - KELVIN_TO_CELSIUS_OFFSET;
|
||||
if (temperatureCelsius is < MIN_VALID_TEMPERATURE_CELSIUS or > MAX_VALID_TEMPERATURE_CELSIUS) continue;
|
||||
temperaturesCelsius.Add(temperatureCelsius);
|
||||
}
|
||||
|
||||
temperatureInfo = temperaturesCelsius.Count == 0
|
||||
? null
|
||||
: new TemperatureInfo
|
||||
{
|
||||
AverageCelsius = temperaturesCelsius.Average(),
|
||||
MaximumCelsius = temperaturesCelsius.Max()
|
||||
};
|
||||
}
|
||||
|
||||
internal TemperatureInfo? Get()
|
||||
{
|
||||
return temperatureInfo;
|
||||
}
|
||||
|
||||
internal void Close()
|
||||
{
|
||||
counters?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
using System.Globalization;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
enum TemperatureUnit
|
||||
{
|
||||
System,
|
||||
Celsius,
|
||||
Fahrenheit,
|
||||
}
|
||||
|
||||
internal static class TemperatureUnitExtension
|
||||
{
|
||||
private static readonly TemperatureUnit systemDefault = DetectSystemDefault();
|
||||
|
||||
internal static string GetLocalizedString(this TemperatureUnit unit)
|
||||
{
|
||||
return unit switch
|
||||
{
|
||||
TemperatureUnit.System => Strings.TemperatureUnit_System,
|
||||
TemperatureUnit.Celsius => $"{Strings.TemperatureUnit_Celsius} (°C)",
|
||||
TemperatureUnit.Fahrenheit => $"{Strings.TemperatureUnit_Fahrenheit} (°F)",
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
internal static TemperatureUnit Resolve(this TemperatureUnit unit)
|
||||
{
|
||||
return unit == TemperatureUnit.System ? systemDefault : unit;
|
||||
}
|
||||
|
||||
private static TemperatureUnit DetectSystemDefault()
|
||||
{
|
||||
try
|
||||
{
|
||||
return new RegionInfo(CultureInfo.CurrentCulture.Name).IsMetric
|
||||
? TemperatureUnit.Celsius
|
||||
: TemperatureUnit.Fahrenheit;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return TemperatureUnit.Celsius;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using RunCat365.Properties;
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
enum Theme
|
||||
{
|
||||
System,
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
internal static class ThemeExtension
|
||||
{
|
||||
internal static string GetLocalizedString(this Theme theme)
|
||||
{
|
||||
return theme switch
|
||||
{
|
||||
Theme.System => Strings.Theme_System,
|
||||
Theme.Light => Strings.Theme_Light,
|
||||
Theme.Dark => Strings.Theme_Dark,
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
internal static Color GetContrastColor(this Theme theme)
|
||||
{
|
||||
return theme switch
|
||||
{
|
||||
Theme.Dark => Color.White,
|
||||
Theme.Light => Color.Black,
|
||||
_ => Color.Gray,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2025 Takuto Nakamura
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
namespace RunCat365
|
||||
{
|
||||
internal static class TreeFormatter
|
||||
{
|
||||
private static readonly bool isFullWidth = SupportedLanguageExtension.GetCurrentLanguage().IsFullWidth();
|
||||
|
||||
private static string BranchMiddle => isFullWidth ? "├─" : "├─ ";
|
||||
private static string BranchLast => isFullWidth ? "└─" : "└─ ";
|
||||
private static string IndentContinue => isFullWidth ? "│ " : "│ ";
|
||||
private static string IndentLast => isFullWidth ? " " : " ";
|
||||
|
||||
internal static string CreateRoot(string content)
|
||||
{
|
||||
return content;
|
||||
}
|
||||
|
||||
internal static string CreateNode(string content, bool isLast)
|
||||
{
|
||||
var prefix = isLast ? BranchLast : BranchMiddle;
|
||||
return $"{prefix}{content}";
|
||||
}
|
||||
|
||||
internal static string CreateNestedNode(string content, bool parentIsLast, bool isLast)
|
||||
{
|
||||
var indent = parentIsLast ? IndentLast : IndentContinue;
|
||||
var prefix = isLast ? BranchLast : BranchMiddle;
|
||||
return $"{indent}{prefix}{content}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 279 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 525 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |