Hatena::ブログ(Diary)

miauの避難所

2011-07-08

Windows7 エクスプローラのアイコンオーバーレイで使われるアイコンのサイズ

先週あたりにエクスプローラアイコンオーバーレイをやりたくなって、

を参考に作ってたんですが、せっかく 256x256 のアイコンを作っても 48x48 のアイコンが使われてしまったりして悲しかったので、どの表示方法でどのサイズのアイコンが使われるか調べてみました。


検証環境

Windows7 SP1 で、テキストサイズは「中 - 125%(規定)」に設定した状態で検証しています。

表示方法ごとに使われるオーバーレイアイコンリソース

アイコンリソースは複数のサイズを持つことができて、

を使うと 16x16、24x24、32x32、48x48、256x256 の 5 種類が標準のサイズとして指定できます。

この 5 種類のリソースを持つアイコン

  • 一方は .ico ファイル単体で
  • もう一方はアイコンオーバーレイ表示に利用する形で

エクスプローラ上で表示してみます。

クスプローラの「表示方法」を少しずつ変えていくと、以下のように使われるリソースが変化していきました。

表示方法 表示サイズ.icoプレビュー時に
使われるリソース
アイコンオーバーレイで
使われるリソース
特大アイコン 256 256x256 256x256
: 123〜250 256x256 256x256
アイコン 120 256x256 256x256
: 65〜119 256x256 256x256
: 61〜 63 256x256 48x48
アイコン 60 256x256 48x48
: 41〜 59 256x256 48x48
: 40 48x48 48x48
: 21〜 39 48x48 24x24
アイコン 20 24x24 24x24
一覧 20 24x24 24x24
詳細 20 24x24 24x24
並べて表示 60 256x256 48x48
コンテンツ 40 48x48 48x48

.ico ファイル(たぶん .exe の場合も同様)では中アイコンくらいから 256x256 のリソースが使われますが、アイコンオーバーレイで使うときは大アイコンくらいにしないと 256x256 のリソースは使われないようです。

Windows7 では 24x24、48x48、256x256 のアイコンしか使われないようですが、昔の Windows では 16x16 や 32x32 が使われていた気がしますし、この 5 種類があれば大丈夫そうですね。

オーバーレイアイコンの表示位置&サイズ

オーバーレイアイコンは元のアイコンの左下に表示されるルールのようで、エクスプローラの「表示方法」によってその表示サイズが大きく変わります。このあたりの関係も調べてみました。

表示方法 表示サイズオーバーレイアイコン
表示サイズ
元のサイズに対する割合アイコンオーバーレイで
使われるリソース
(前出)
特大アイコン 256 100 39% 256x256
: 123〜250 59〜100 48〜39% 256x256
アイコン 120 58 48% 256x256
: 65〜119 41〜 58 63〜49% 256x256
: 61〜 63 40 66〜63% 48x48
アイコン 60 40 67% 48x48
: 41〜 59 40 98〜68% 48x48
: 40 40 100% 48x48
: 21〜 39 20 95〜51% 24x24
アイコン 20 20 100% 24x24
一覧 20 20 100% 24x24
詳細 20 20 100% 24x24
並べて表示 60 40 67% 48x48
コンテンツ 40 40 100% 48x48

途中から徐々にサイズが大きくなっていきますが、ここは

オーバーレイアイコンのサイズ = 元アイコンのサイズ * 5 / 16 + 20

というような関係になっていそうです。(±1 程度の誤差はありますが、丸め誤差か何かでしょう。)

グラフにするとこんな感じでした。

  • f:id:miau:20110709033515p:image

場合によっては元アイコンの全体を占めるケースもあるのに、特大アイコンにした場合は

  • f:id:miau:20110709033516p:image

のように幅の 39% 程度しか占めなくなります。TortoiseXxx や Dropboxアイコンが左下に表示されるので、それにかぶらないよう右上にオーバーレイアイコンを出す形で考えていたのですが、そうすると特大アイコンで表示した場合に(この赤い部分の右上にしかオーバーレイされず)真ん中くらいにオーバーレイアイコンが表示されて格好悪いことになってしまいそうです。

(2011-07-19 追記 ここから)

リソースがオーバーレイ時にどのようなサイズで表示されるかもまとめました。

リソース元のサイズに対する割合
256x256 39〜63%
48x48 63〜100%
24x24 51〜100%

(2011-07-19 追記 ここまで)

もとのサイズに対して 100% 等の大きな割合で表示されるのは 24x24 と 48x48 の二種類なので、これらは右上に出す前提のデザインにして、256x256 だけ左下に表示されるようなデザインにするという手もあるかもしれません。

2 つの表を見比べてみると

オーバーレイアイコンが縮小されるから使われるリソースが .icoプレビューとずれていただけで、表示サイズとリソースの関係は同じルールになってました。

表示方法 オーバーレイアイコン
表示サイズ
アイコンオーバーレイで
使われるリソース
特大アイコン 100 256x256
: 59〜100 256x256
アイコン 58 256x256
: 41〜 58 256x256
: 40 48x48
アイコン 40 48x48
: 40 48x48
: 40 48x48
: 20 24x24
アイコン 20 24x24
一覧 20 24x24
詳細 20 24x24
並べて表示 40 48x48
コンテンツ 40 48x48

今回使った補助スクリプト

いちいち表示サイズ計測するのは面倒なので、真っ赤なアイコンファイルを作って、「画面内で赤の pixcel が連続している最大長を出力する」Python スクリプトを走らせながら検証していました。

スクリプトは gist に置いています。

画面の右端から左端に連続した色があるような場合は対応できない手抜きスクリプトですが、手軽に作れたわりに役に立ちました。

今回参考になったページです。

----

書いてから気づいたんですが、こういう情報ってどこかにまとまってそうですね・・・。もし何かご存知な方は教えてください。

2010-09-04

コントロールの幅を広げるスクリプト書いた

一昔前のアプリケーションだと、狭いディスプレイを想定して小さなダイアログを出すようになっていたりします。

例えば「ファイル名を指定して実行」で長いパス名を入れたい場合、

  • f:id:miau:20100905043325p:image

こんな感じで全部表示しきれなかったりして不便です。

そんなわけで、コントロールの幅を広げるスクリプトを書いてみました。


完成品

また Gist に置いてますので、適当にダウンロードなり clone してください。

実行方法&実行例

広げたいコントロールの上にマウスポインタを置いた状態で、ランチャーショートカットキーで↑のスクリプトを起動してください。

  • f:id:miau:20100905043324p:image

こんな感じでコントロール(&親コントロール)の幅が広くなります。

現在は 800 pixel 増やすようにしていますが、「これだけあれば足りるだろう」という適当なものですので、適当に調整してください。

本当は・・・

Excel の「シートの移動またはコピー」ダイアログ

  • f:id:miau:20100905043323p:image

に対して使いたかったんですけど、コントロールの構成が

  • f:id:miau:20100905043322p:image

こんな感じで。スクロールバー以外の部分は独自描画っぽくて、こういった手段ではリサイズできないようでした。残念。

その他感想とか

Python の ctypes は結構便利ですけど、ctypes.wintypes で構造体なんかも定義されているので、Win32 API の呼び出しも結構お手軽なんですねぇ・・・。前使ったときは POINT とか RECT とか、自分で定義しちゃっていた気がするので、書き直さねば。

ついうっかりスクリプト書いてしまいましたけど、もっとよさげなツールがあったら教えてください。あとスクリプトへのツッコミもあればお願いします。

2010-01-23

wedata を .ini に変換するサービスを GAE で作り直した

去年、

こんなものを作っていたんですが、ここで使っている AppJet は 2009 年 6 月末でサービス終了してしまっています。せっかく Python Hack-a-thon #3 に来たので、Python のリハビリがてら GAE for Python で作り直してみました。


できたもの

http://wedata.net/databases/AppSnap/items

のデータが、

http://wedata2ini.appjet.net/AppSnap

のような URL で .ini ファイルとして取得されます。この URL を GetIt や AppSnap で指定してやれば、リポジトリとして使えるはずです。Wedata は誰でもデータを追加/編集できるので、データベースを信用してしまうと変なアプリケーションダウンロードさせられる可能性があります。その点は気をつけてください。

「AppSnap」の部分を Wedata のデータベース名に変えたらほかのデータベースも使えるはずです。

以降ソースです。エラー処理(404 とかのステータスコードの返し方)は手抜き実装がすぐに見つからなかったのでやってません。JS の時と同じで、.ini は改行コード CRLF で吐かないと AppSnap での読み取り時に最後の文字が削れてしまったので、強引に置換してます。

何かツッコミあればお願いします。

import sys
import os
import ConfigParser
import StringIO
from google.appengine.api import urlfetch
from django.utils import simplejson as json

print 'Content-Type: text/plain'
print ''

database_id = os.environ['PATH_INFO'][1:]

url = 'http://wedata.net/databases/%s/items.json' % database_id
result = urlfetch.fetch(url)
if result.status_code == 200:
    apps = json.loads(result.content)
    ini = ConfigParser.SafeConfigParser()
    for app in apps:
        name = app['name']
        ini.add_section(name)
        for key, val in app['data'].iteritems():
            ini.set(name, key, val)

    tmp = StringIO.StringIO()
    ini.write(tmp)
    print tmp.getvalue().replace("\n", "\r\n")

wxPython での IME 操作についていくつか

StaccatoEditor で IME まわりの処理を実装しているんだけど、それ絡みでいくつか。

IME の候補ウィンドウにフォントが反映されない件

ImmSetCompositionFontW を呼び出しているはずなのに、フォントが変わらない現象が起きていて。いろいろ試してたけど、実はしょうもないバグだった。

-        lf.lfPitchAndFamily = 1 & 48    # FIXED_PITCH & FF_MODERN
+        lf.lfPitchAndFamily = 1 | 48    # FIXED_PITCH | FF_MODERN

& と | を間違えるとか恥ずかしいなぁ・・・。

この辺の処理は

で参考にされてたりするけど、他にも lfCharSet を設定しないとダメだったりとかあったので、参考にされる方は↓もご確認ください。前半は別のバグ対策を入れてしまったので、該当の変更は下のほうです。(日付見るとわかるけど、実は半年位前の話だったり・・・。)

wxPython で WndProc いじれる件

wxPython(wxWidget)はクロスプラットフォームなライブラリだから、Windows 特有の IME の処理なんかは考慮してくれません。なので IME が有効な状態でのキー入力を拾いたくても、それは拾えない・・・と思ってたんですけど、実は WM_xxxx 相当のメッセージを処理できるようで、

この辺に説明が載ってました。これでいろいろ制御できそうなので、↑のコミットではこの辺の調査用コードも入れちゃってます。

他にも MSWWindowProc を定義する方法とかあるみたいですね。

Editra(同じく wxPython を使っているエディタ)も IME まわりの処理がおかしいけど、頑張れば Windows だけでもそれっぽい動作にできるんじゃないかなとか。もし実装されたら参考にさせてもらおう。

2009-09-13

Python の new-style class property 用 .ctags 設定

Trac のとあるプラグインの処理を読んでいると、なんだかタグジャンプできない箇所があって。定義箇所を見てみると、

ticket_type_config = property(lambda self: self._get_ticket_config())

こんな感じでプロパティが設定されてるっぽい。property っていうのは

に書かれてるとおり、new-style class で使えるプロパティ設定方法と。うん。勉強した覚えはあるけどすっかり忘れてた。

最新の ctags でも対応されていないようなので、.ctags(Windows だと ctags.cnf)に以下を設定して対応。

--regex-python=/([A-Za-z0-9_.]+)[ \t]*=[ \t]*property\(/\1/p,property/

ちゃんとタグジャンプできるようになりましたよと。

2009-08-17

自プロジェクトで編集してそうな Wiki ページだけ一覧で出す Trac マクロ

Trac にはもともと TitleIndex というマクロが用意されていて、ページ一覧(TitleIndex ページ)でもこのマクロが使われているわけですが。TitleIndex マクロは Trac が最初に勝手に作るページ(Wiki* とか Trac* とか)も一覧にして出力してしまいます。この動作は、自分のプロジェクトで作成されたファイルの一覧を見たいだけの場合に結構不便だったりします。

ということで、自分のプロジェクトで編集されてそうなページの一覧だけ出力するマクロを作ってみました。なんとなく勢いで作っちゃいましたけど、似たようなものをご存知な方は教えてください。

(2011-01-04 追記)

同じ名前でほぼ同じマクロを作ってる方がいました・・・。

私の実装は TitleIndexMacro を継承しているので TitleIndex の機能がすべて使える反面、内部実装に依存しているのでいきなり動かなくなる可能性がある、といった感じです。


マクロの作り方

WikiMacros の最後らへんに載ってます。

元にするマクロ

trac/wiki/macros.py に TitleIndexMacro というクラスが用意されているので、これを改造すればよさげ。

作ってみる

ちょっと実装方法で迷ったけど、TitleIndexMacro でページ一覧を取得している処理が

    def expand_macro(self, formatter, name, content):
        #(略)
        wiki = formatter.wiki
        pages = sorted([page for page in wiki.get_pages(prefix) \
                        if 'WIKI_VIEW' in formatter.perm('wiki', page)])

こんなだから、formatter.wiki.get_pages の処理を差し替えて expand_macro を呼び出すサブクラスを作ってやれば楽そう。

ということで、

import re
from trac.wiki.macros import TitleIndexMacro

class MyTitleIndexMacro(TitleIndexMacro):
    STANDARD_RE = re.compile(r"""
        ^
        (?:
            (?:Trac|Wiki|Inter)[A-Z][a-z].*
            |CamelCase
            |PageTemplates
            |RecentChanges
            |TitleIndex
        )
        $
    """, re.VERBOSE)

    def expand_macro(self, formatter, name, content):
        _get_pages = formatter.wiki.get_pages
        def my_get_pages(prefix):
            return [page for page in _get_pages(prefix) \
                    if not self.STANDARD_RE.match(page)]
        formatter.wiki.get_pages = my_get_pages
        html = TitleIndexMacro.expand_macro(self, formatter, name, content)
        formatter.wiki.get_pages = _get_pages
        return html

こんな感じのファイルを plugins/MyTitleIndex.py として配置して、Apache を再起動。

Wiki 中に

[[MyTitleIndex(format=group,min=2)]]

みたいに書いておくと、期待どおりの動作になりました。

注意点というほどでもないですが

「Trac が勝手に作るページ」は正規表現で結構いいかげんに引っ掛けています。また、SandBox はプロジェクト内で編集している可能性があるので、除外対象には入れてません。