imgui テキストを中心に表示 – FlyWithLua

2023年2月24日

テキストを中心に配置するという良く使うスクリプト。

FlyWithLua|imgui テキストをウインドウの中心に表示

float_wnd_set_imgui_builderを使った場合

ポイントは12行目から19行目まで。
17行の「text_width」は字数ではなく字のサイズ(長さ)になる。
18行の「win_width / 2 – text_width / 2」は、ウインドウサイズは「400」、テキストサイズは「91」になるので、400÷2 – 91÷2 は (400÷2) – (91÷2)ということで「154.5」になる。
つまり、ウインドウの左から「154.5」の位置からテキストが始まるということになる。この位置はウインドウの幅が変化するとリアルタイムにに計算し直して、常に中央に配置することになる。
割り算と掛け算に足し算や引き算がある場合は、割り算と掛け算を最初に計算するのがルール。

GetCursorPosX と GetCursorPosY は、次のウィジェットが配置される位置を返します。

-- imguiはフローティングウィンドウ内でのみ機能するため、最初に作成する必要があります。
demo_wnd = float_wnd_create(400, 150, 1, true)
float_wnd_set_title(demo_wnd, "imgui Demo")
float_wnd_set_imgui_builder(demo_wnd, "build_demo")
float_wnd_set_onclose(demo_wnd, "closed_demo")

text = ""

function build_demo(wnd, x, y) -- imguiはウィンドウ内に独自の座標系を持っています

    -- 以下でウィンドウの現在の幅と高さをリアルタイムに取得することができる。
    local win_width = imgui.GetWindowWidth() -- これらの関数は、ウィンドウの幅をボクセル単位で返します。
    local win_height = imgui.GetWindowHeight() -- これらの関数は、ウィンドウの高さをボクセル単位で返します。

    -- 最初にテキストサイズを測定し、次に行の中央に配置して、テキストを水平方向の中央に配置します。
    local text = "Centered Text"
    local text_width, text_height = imgui.CalcTextSize(text) -- CalcTextSize は "text" のサイズを取得
    imgui.SetCursorPos(win_width / 2 - text_width / 2, imgui.GetCursorPosY())
    imgui.TextUnformatted(text) -- テキストを表示
    -- CalcTextSize は、ボックス内のテキストの幅と高さを返します。
    -- GetCursorPosX と GetCursorPosY は、テキシストが配置される位置を返します。
    -- SetCursorPos を使用して、この位置を操作できます。
    -- imgui の座標は左上に原点があり、右と下に+します。
end

function closed_demo(wnd)
end

天地もウインドウの中心にテキストを配置する場合

18行目を以下のように変更

imgui.SetCursorPos(win_width / 2 – text_width / 2, win_height / 2 – text_height / 2)

float_wnd_set_ondrawを使った場合(日本語が使える)

float_wnd_set_ondrawを使うと日本語が使えるので、これを主体に使いたい。
しかし、上と同じようにテキストの長さを取得する方法だと、表示されるフォントが違うために長さが正確ではないという問題が起こっている。そこでテキストの数を数値で取得する方法を考えて見た。

10行目の「text_leng = string.len(text2)」がテキストの数を取得する。

日本語を使う場合

日本語と英語ではテキストの数が違う。英語の場合はそのままのテキスト数で所得できるが、日本語だと3倍のテキスト数になる。

11行目で日本語用のテキストを中心に表示する位置を設定している。これでうまく行った。
もしずれる場合は、(text_leng / 1.2) – text_leng を調整する必要がある。

text2 = ""

function XP_Library_menu_draw(XP_Library_menu_wnd, x, y)
 --x=0
 --y=0
  --win_Width, win_Heightはウインドウのサイズになる。リアルタイムにに変化する。
  win_Width2, win_Height2 = float_wnd_get_dimensions(XP_Library_menu_wnd)--dimensionsとは寸法

  local text2 = "日本語が使える"
  text_leng = string.len(text2)
  draw_string( x + ((win_Width2 / 2) - (text_leng / 1.2) - text_leng), y + 30, text2, "yellow")
end


XP_Library_menu_wnd = float_wnd_create(400, 100, 1, true)
float_wnd_set_title(XP_Library_menu_wnd, "XP Library Menu2")
float_wnd_set_ondraw(XP_Library_menu_wnd, "XP_Library_menu_draw")
float_wnd_set_position(XP_Library_menu_wnd, 30, 70)

英語を使う場合

11行目を以下のようにするとうまく行った。こちらはtext_lengに2を掛けている。

draw_string( x + ((win_Width2 / 2) – (text_leng * 2) – text_leng), y + 0, text2, “yellow”)

ボタンを作成してテキストを中心に入れる

テキストの長さに応じてボタン枠を広げることができる。しかしこれは近い感じにはできるが、文字の長さを正確に測る方法が分からないので実現が難しい。バイト数での取得はできるが英語はその文字数でちゃんと数えることができるが、日本語は1文字が3バイトに数えられるので設定が面倒になってしまう。
手作業で調整をするしか方法がないことになる。
英語の1バイトもテキストの形によって長さが変化するので正確な長さを測定できない。

(日本語用)

28行目で日本語の長さを取得している(半角英数字とは長さが違うので一工夫が必要)、(text_leng*4)で長さを4倍にしている。これでうまく日本語の長さに対応できるようになる。

measure_string(“ABCDEFG”, “Helvetica_12”)

--初期設定
local polo_wnd = nil									-- window handle
local winLeft, winTop, winRight, winBottom = 0,0,0,0	-- float_wnd_get_geometry
local dWidth, dHeight = 0,0

-- functions ------------------------------------------------------------------
-- ここで作成した関数を下で使うことになる。
-- ボタンボックスを描画します-テキストの左の開始、テキストの右の終了、テキストの高さ、テキスト、ボタンの色
local function button_draw(pos_left,pos_top,text_left,pos_right,text_value,text_color)
	dWidth, dHeight = float_wnd_get_dimensions(polo_wnd)--ウインドウの幅と高さを取得
	winLeft, winTop, winRight, winBottom = float_wnd_get_geometry(polo_wnd)--ウインドウの左位置、上位置、右位置、下位置を取得

	local x1 = winLeft	--ウインドウの左からの位置
	local x2 = winLeft	--ウインドウの左からの位置
	local y1 = winTop	--ウインドウの上からの位置
	local y2 = winTop	--ウインドウの上からの位置

	local r,g,b = 1,1,1		--	何も指定にしない場合のボタンテキストカラー
    --色をテキストで指定できるようにするため
	if (text_color == "white") then
		r,g,b = 1,1,1	-- white
	elseif (text_color == "yellow") then
		r,g,b = 1,1,0	-- gray
    elseif (text_color == "green") then
		r,g,b = 0,1,0	-- green
	end

	local text_leng = string.len(text_value)	--テキストの長さを取得
	--ボタン枠の作成(日本語の長さに応じて変化する)
	graphics.draw_rectangle(x1 + pos_left + 0, y1 - pos_top - 0, x2 + pos_right + (text_leng*4) + 12, y2 - pos_top - 20)   --長方形
	--テキストを作成
	draw_string(x1 + pos_left + text_left, y1 - pos_top - 13, text_value, r,g,b)

end -- function button_draw

-- 実際のウインドウをここで作成
function polo_ondraw(polo_wnd, x, y)--xとyはウィンドウの原点、つまり左下、xは右に向かって増加し、yは上に向かって増加
	-- draw box around window
	XPLMSetGraphicsState(0,0,0,1,1,0,0)

    graphics.set_color( 0, 1, 1, 0.2 )  --ボタンの色
    --ウインドウからボタンの左から、上からの位置、テキスト前の空き、後の空き。
	button_draw(10, 10, 10, 10, "日本語が使える", "white")  --最後は色、何も指定しないなら白になる

end	-- function polo_ondraw

-- window close
function polo_onclose(polo_wnd)
	float_wnd_destroy(polo_wnd) --消し去る
end

--if(not polo_wnd) then
polo_wnd = float_wnd_create(171, 62, 1, false)
float_wnd_set_title(polo_wnd, "button draw test")
float_wnd_set_position(polo_wnd, 180, 150)
float_wnd_set_ondraw(polo_wnd, "polo_ondraw")
float_wnd_set_onclose(polo_wnd, "polo_onclose")

英(半角英数字)用

残念ながら完璧では無い、字数が変化するとうまく長さを調整できない。これはstring.len(text_value)では1文字1バイトと計算しているだけで、同じバイト数でも英語の文字は幅がバラバラなので全体の長さが変化する。従って全体の長さはバラバラで正確な寸法にならないからである。
後は手作業で調整するしか方法が無い。

graphics.draw_rectangle(x1 + pos_left, y1 – pos_top – 0, x2 + pos_right + (text_leng*9), y2 – pos_top – 20) –長方形

imguiボタンの下にテキストを中心に入れる

ポイントはボタンの中心を探すこと、その位置からテキストの長さを半分にして引くと半分だけ前に移動することになるのでテキストが中心にくる。

------------------------------------------------------------------------
-- ウインドウの作成
wnd = float_wnd_create(200, 150, 1, true)
float_wnd_set_title(wnd, "XP Image View Buttons") --wnd変数をセット
float_wnd_set_imgui_builder(wnd, "im_on_build")   --関数を読み込みセットする
------------------------------------------------------------------------
--ボタンの長さは120ピクセル、その中心に「Pilot」のテキストを配置する。
function im_on_build(wnd, x, y)
  if imgui.Button("Button", 120, 65) then

  end

  local text = "Pilot"
  local text_size = imgui.CalcTextSize(text)  --テキストのサイズを取得
  --68はボタンの中心位置、テキストサイズを半分にして引くとボタンに対してテキストが中心になる。
  imgui.SetCursorPos(68 - (text_size / 2), imgui.GetCursorPosY())--パラメーターは、Xの位置と、Yの位置
  imgui.TextUnformatted(text)
end