ユーザ用ツール

サイト用ツール


ハイハイスクールアドベンチャー_windows版

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
ハイハイスクールアドベンチャー_windows版 [2025/09/22 00:27] – [テーマ] arakiハイハイスクールアドベンチャー_windows版 [2025/09/27 03:30] (現在) – [リソースファイルのコピー] araki
行 30: 行 30:
 そのうち気が向いたらインストーラを作るかもしれません。</del> そのうち気が向いたらインストーラを作るかもしれません。</del>
  
-[[https://www.wildtree.jp/~araki/HHSAdvWinSetup.zip|インストーラ]]をダウンロードして展開したら、Setup.exe を実行してください。+[[https://www.wildtree.jp/~araki/HHSAdvWin110.zip|インストーラ]]をダウンロードして展開したら、Setup.exe を実行してください。 
 + 
 +もし古いバージョンがインストールされていましたら、**お手数ですが、必ず、まず古いバージョンをアンインストールしてください**。 
 +勝手インストーラで無署名のため、どうもアップデートがうまくいかず、古いものが残ったままのように見えてしまいます。((実際には新しいもので上書きされているのに。)) 
 +インストール情報だけだと思っていますが、副作用があっても困るので、よろしくお願いします。 
 +ユーザーデータは削除されませんのでセーブデータなどは失われません
  
 初回実行時に、データフォルダを勝手に作って勝手にデータを放り込みます。 初回実行時に、データフォルダを勝手に作って勝手にデータを放り込みます。
行 48: 行 53:
 そう思ったので、Windowsのビットマップイメージに対して、ダブルバッファでの読み書きが可能かどうか AIに尋ねたら、できるよ、というので、実験コードを作って、思ったように動くことを確認し、一気に移植しました。 そう思ったので、Windowsのビットマップイメージに対して、ダブルバッファでの読み書きが可能かどうか AIに尋ねたら、できるよ、というので、実験コードを作って、思ったように動くことを確認し、一気に移植しました。
  
-そもそも、SDL1番も C#で開発しており、SDL2にべったり依存している部分以外はそのまま流用可能なので、移植にかかった時間は非常に短かったといえます。+そもそも、SDL2版も C#で開発しており、SDL2にべったり依存している部分以外はそのまま流用可能なので、移植にかかった時間は非常に短かったといえます。
  
 SDL2に依存していた描画、サウンド機能、そしてイベントループはすべてWPFのそれで置き換わっています。 SDL2に依存していた描画、サウンド機能、そしてイベントループはすべてWPFのそれで置き換わっています。
行 159: 行 164:
  
 === そもそも一撃でキレイにテーマ対応させられない === === そもそも一撃でキレイにテーマ対応させられない ===
 +
 +マイクロソフトは「テーマ」というものをどう考えているんでしょうか?
 +Androidはテーマは、そもそも雑にシステムの用意してるものを継承したとしても、そこそこの見栄えのものになるのに、基本的にWPFであるならば、自前で頑張らなあかん、ということらしいのです。
 +
 +雑に「テーマ」を適用するだけなら、App.xaml にテーマファイルを用意しておいて、読み込ませるだけです。
 +
 +<file XML App.xaml>
 +<Application x:Class="HHSAdvWin.App"
 +             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 +             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 +             xmlns:local="clr-namespace:HHSAdvWin"
 +             StartupUri="MainWindow.xaml">
 +    <Application.Resources>
 +        <ResourceDictionary>
 +            <ResourceDictionary.MergedDictionaries>
 +                <!-- デフォルトはライトテーマ -->
 +                <ResourceDictionary Source="themes/LightTheme.xaml"/>
 +            </ResourceDictionary.MergedDictionaries>
 +            <local:EnumToBooleanConverter x:Key="EnumToBooleanConverter"/>
 +        </ResourceDictionary>
 +    </Application.Resources>
 +
 +</Application>
 +</file>
 +
 +基本的に、テーマとしては「ライト」「ダーク」の大枠があります。
 +今後増えないことを祈りますが。
 +
 +Windowsのシステムがユーザごとにシステムテーマとして、ダークなのかライトなのかを保持しています。
 +これはWPFの場合はAPIみたいに気の利いたのじゃなくてレジストリをじかに覗くことで取得できます。
 +
 +つまり、アプリ動いてる最中にシステムの設定変えられたら、自分でもう一回見に行かない限り変わったことを知るすべはないってことです。
 +
 +完璧にやりたいならタイマーとかで定期的にチェックしろとAIはいいましたが、めんどくさすぎてそこまでやる気にはなれません。
 +動作中に切り替えられたら、それはもう放置です。
 +
 +この辺がめんどくさすぎたからなんでしょうか?
 +多くのアプリが、テーマをシステム追随するか、あるいはもう、システムは関係なく、ダークまたはライトを強制する設定を持っているのは。
 +
 +ハイハイスクールアドベンチャーもこの先人たちの知恵に倣って、同じような設定を入れることにしました。
 +
 +設定に従って、用意しておいた themes/LightTheme.xaml または themes/DarkTheme.xml を切り替えるだけです。
 +
 +<code c#>
 +string themePath = mode ? "themes/DarkTheme.xml" : "themes/LightTheme.xml";
 +var uri = new URI(themePath, UriKind.Relative);
 +ResourceDictionary themeDict = new ResourceDictionary { Source = uri };
 +
 +Application.Current.Resources.MergeDictionaries.Clear();
 +Application.Current.Resources.MergeDictionaries.Add(themeDict);
 +</code>
 +
 +テーマファイルの中身は、「色」の指定と、それを使って、ウィジェットごとに「色」を割り当てていく作業になります。
 +Androidだと、ライトテーマだけ全部書いておいて、ダークは色情報だけを上書きする、というような感じで作れますが、Windowsはよくわかりません。
 +とりあえず、ウィジェットまわりは同じ内容を書いておいて、頭の方に集めた色情報の変更でライトとダークを分ける感じでテーマファイルを作っています。
 +
 +<file XML LightTheme.xaml>
 +<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 +                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 +
 +    <!-- 色定義 -->
 +    <Color x:Key="BackgroundColor">#FFFFFFFF</Color>
 +    <Color x:Key="ForegroundColor">#FF000000</Color>
 +        <!-- コントロールスタイル例 -->
 +    <Style TargetType="Window">
 +        <Setter Property="Background" Value="{StaticResource BackgroundBrush}" />
 +        <Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
 +    </Style>
 +
 +    <Style TargetType="TextBlock">
 +        <Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
 +    </Style>
 +
 +    <!-- TextBox -->
 +    <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
 +        <Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
 +        <Setter Property="Background" Value="{StaticResource BackgroundBrush}" />
 +        <Setter Property="BorderBrush" Value="{StaticResource ForegroundBrush}" />
 +        <Setter Property="CaretBrush" Value="{StaticResource ForegroundBrush}" />
 +    </Style>   
 +</ResourceDictionary>
 +</file>
 +
 +<file XML DarkTheme.xaml>
 +<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 +                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 +
 +    <!-- 色定義 -->
 +    <Color x:Key="BackgroundColor">#FF1E1E1E</Color>
 +    <Color x:Key="ForegroundColor">#FFFFFFFF</Color>
 +        <!-- コントロールスタイル例 -->
 +    <Style TargetType="Window">
 +        <Setter Property="Background" Value="{StaticResource BackgroundBrush}" />
 +        <Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
 +    </Style>
 +
 +    <Style TargetType="TextBlock">
 +        <Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
 +    </Style>
 +
 +    <!-- TextBox -->
 +    <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
 +        <Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
 +        <Setter Property="Background" Value="{StaticResource BackgroundBrush}" />
 +        <Setter Property="BorderBrush" Value="{StaticResource ForegroundBrush}" />
 +        <Setter Property="CaretBrush" Value="{StaticResource ForegroundBrush}" />
 +    </Style>   
 +</ResourceDictionary>
 +</file>
 +
 +ダークとライトの違いは最初の色の定義だけなのがわかると思います。((もちろんもっと複雑にライトだけの処理、ダークだけの処理を入れていくこともできますが。))
 +
 +こんな感じで、メニューがアクティブの時の色とか、必要なだけ色を作って、必要なウィジェットに色を割り当てていきます。
 +
 +静的なウィジェットはまあ問題ないんですが、メニューのドロップダウンとか、スクロールビューにおけるスクロールバーなど、フローティングなウィジェットはテーマの割り当て方が何通りかあるようで、理解しきれません。
 +AIの言うとおりにしておきました。
 +うまくいかないときだけ頑張って調整しました。
 +
 +Androidはほとんど色をいじればあとは放置しておいてもウィジェットがいい感じに色を拾ってくれたのとは大違いです。
 +柔軟性が高いといえるのかもしれませんが、Androidだって、別に細かくやろうと思えばできるので、たぶんそういう話でもないです。
 +要は、あんまりテーマ使ってもらいたくないんじゃないかっていうのが正直な感想です。
 +
 +そういったことは、この後の「タイトルバー」などの扱いにも表れているように感じます。
 +
 +とにかく、テーマは WPFに関しては、とてもめんどくさい存在です。
  
 === タイトルバーは自前でつくれ === === タイトルバーは自前でつくれ ===
行 205: 行 335:
     }     }
 </code> </code>
 +
  
 あと、タイトルをドラッグしたときのイベントハンドラもつけとかないとビルドできません。 あと、タイトルをドラッグしたときのイベントハンドラもつけとかないとビルドできません。
 +
 +さらに、ここまでやったのに、ボタンが全然反応しないのです。
 +あくまでタイトルバーに配置されただけで、タイトルバーの一部と認識されるため、ボタンとして機能させるには、ボタン要素ごとにいちいち WindowChrome.IsHitTestVisibleInChrome="True" をつけてやる必要があります。
 +
 +やればやっただけ、次に必要なことが襲ってきます。
 +
 自前の道は長く果てしないのです。 自前の道は長く果てしないのです。
  
行 485: 行 622:
 </code> </code>
  
 +==== スライドスイッチ風にしたい ====
 +
 +チェックボックスはいまどきつまらないよね。
 +見栄えを考えたらスライドスイッチ。
 +
 +AIに聞いたらスタイルでできるというのでやってみました。
 +
 +{{::hhsadvwin:prefs.png?400|}}
 +
 +まず、XAMLファイルで、スタイルを定義します。
 +
 +<code xml>
 +    <!-- スライドスイッチ風 ToggleButton スタイル -->
 +    <Style x:Key="SlideSwitchStyle" TargetType="ToggleButton">
 +        <Setter Property="Width" Value="40"/>
 +        <Setter Property="Height" Value="20"/>
 +        <Setter Property="Template">
 +            <Setter.Value>
 +                <ControlTemplate TargetType="ToggleButton">
 +                    <Grid>
 +                        <!-- 背景 -->
 +                        <Border x:Name="SwitchTrack"
 +                                CornerRadius="10"
 +                                Background="{DynamicResource ButtonBorderBrush}"
 +                                Height="20" Width="40"/>
 +                        <!-- ノブ -->
 +                        <Ellipse x:Name="SwitchThumb"
 +                                 Fill="{DynamicResource ButtonBackgroundBrush}"
 +                                 Width="18" Height="18"
 +                                 Margin="1"
 +                                 HorizontalAlignment="Left"/>
 +                    </Grid>
 +                    <ControlTemplate.Triggers>
 +                        <Trigger Property="IsChecked" Value="True">
 +                            <Setter TargetName="SwitchTrack" Property="Background" Value="{DynamicResource ButtonPressedBackgroundBrush}"/>
 +                            <Setter TargetName="SwitchThumb" Property="HorizontalAlignment" Value="Right"/>
 +                        </Trigger>
 +                        <Trigger Property="IsEnabled" Value="False">
 +                            <Setter TargetName="SwitchTrack" Property="Opacity" Value="0.5"/>
 +                            <Setter TargetName="SwitchThumb" Property="Opacity" Value="0.5"/>
 +                        </Trigger>
 +                    </ControlTemplate.Triggers>
 +                </ControlTemplate>
 +            </Setter.Value>
 +        </Setter>
 +    </Style>
 +</code>
 +
 +そして、レイアウト用のXAMLファイルでこのスタイルを持つ ToggleButtonを作ります。
 +
 +<code xml>
 +<Grid Margin="16,8,16,8">
 +     <Grid.ColumnDefinitions>
 +         <ColumnDefinition Width="*"/>
 +             <ColumnDefinition Width="Auto"/>
 +         </Grid.ColumnDefinitions>
 +         <TextBlock Grid.Column="0" Text="音を鳴らします" VerticalAlignment="Center" Margin="0,0,8,0"/>
 +         <ToggleButton Grid.Column="1" x:Name="playSound" Style="{StaticResource SlideSwitchStyle}" IsChecked="{Binding PlaySound}" VerticalAlignment="Center"/>
 +     </Grid>
 +</Grid>
 +</code>
 +
 +スタイルだけでできるので簡単といえば簡単ですが、この程度のウィジェットは今どきデフォルトで用意してほしいですよね?
 +
 +==== リソースファイルのコピー ====
 +
 +リソースファイルのコピーをするには、ソリューションエクスプローラから、リソースファイルを一個一個選んで、ビルド時にコピーする設定をいれるといいのですが、実はこの方法だと、リソースディレクトリに階層がある場合にはうまくいきません。
 +勝手に一階層に改変されてしまうのです。
 +
 +ハイハイスクールアドベンチャーの場合は、data/themes と data の下に themesのフォルダーがある二階層になっているのですが、これを勝手に、data と themesという二つの別々のフォルダーとしてビルドディレクトリにコピーしてしまいます。
 +
 +これを避けようと思ったら、プロジェクトファイル((.csproj))を直接いじって、下のような設定を入れることでディレクトリ構造丸ごとコピーしてくれるようになります。
 +
 +<code xml>
 +<ItemGroup>
 + <!-- data 以下のすべてのファイルを対象にする -->
 + <Content Include="data\**\*.*">
 + <!-- 出力先にコピーするルール -->
 + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 + <!-- フォルダ構造を保持する -->
 + <Link>data\%(RecursiveDir)%(Filename)%(Extension)</Link>
 + </Content>
 +</ItemGroup>
 +</code>
ハイハイスクールアドベンチャー_windows版.1758500830.txt.gz · 最終更新: by araki