1 /*$
2  Copyright (C) 2016-2020 Azel.
3 
4  This file is part of AzPainterB.
5 
6  AzPainterB is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  AzPainterB is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 $*/
19 
20 /*****************************************
21  * mAccelerator [アクセラレータ]
22  *****************************************/
23 
24 #include "mDef.h"
25 
26 #include "mAccelerator.h"
27 
28 #include "mGui.h"
29 #include "mList.h"
30 #include "mEvent.h"
31 #include "mWidget.h"
32 #include "mStr.h"
33 
34 
35 //-------------------------
36 
37 #define _ITEM(p)  ((mAccelItem *)(p))
38 
39 struct _mAccelerator
40 {
41 	mList list;
42 	mWidget *defaultWidget;
43 };
44 
45 typedef struct
46 {
47 	mListItem i;
48 
49 	int cmdid;
50 	uint32_t key;
51 	mWidget *widget;
52 }mAccelItem;
53 
54 //-------------------------
55 
56 
57 /***********************//**
58 
59 @defgroup accelerator mAccelerator
60 @brief アクセラレータ
61 @ingroup group_data
62 
63 @details
64 - アクセラレータはトップレベルウィンドウに関連付けることでキーが処理される。\n
65 ウィンドウに関連付けるには、mWindowData::accelerator にアクセラレータのポインタをセットする。
66 - 同じアクセラレータを複数のウィンドウにセット可能。
67 - アクセラレータは自動で削除されないので、明示的に解放する必要がある。
68 - 定義されたキーが押されたら、\b MEVENT_COMMAND イベントが追加される。
69 - メニュー項目と同じ ID を使う場合、メニュー項目が無効状態でもイベントが送られるので注意。
70 
71 @{
72 @file mAccelerator.h
73 
74 ****************************/
75 
76 
77 /** アクセラレータ作成 */
78 
mAcceleratorNew(void)79 mAccelerator *mAcceleratorNew(void)
80 {
81 	return (mAccelerator *)mMalloc(sizeof(mAccelerator), TRUE);
82 }
83 
84 /** 削除 */
85 
mAcceleratorDestroy(mAccelerator * accel)86 void mAcceleratorDestroy(mAccelerator *accel)
87 {
88 	if(accel)
89 	{
90 		mListDeleteAll(&accel->list);
91 
92 		mFree(accel);
93 	}
94 }
95 
96 /** デフォルトウィジェットセット */
97 
mAcceleratorSetDefaultWidget(mAccelerator * accel,mWidget * wg)98 void mAcceleratorSetDefaultWidget(mAccelerator *accel,mWidget *wg)
99 {
100 	accel->defaultWidget = wg;
101 }
102 
103 /** 追加
104  *
105  * @param key MKEY_* の仮想キーコード。装飾キーは MACCKEY_* で OR 指定。
106  * @param wg  イベントを送るウィジェット。NULL でアクセラレータ指定のデフォルトウィジェット。 */
107 
mAcceleratorAdd(mAccelerator * accel,int cmdid,uint32_t key,mWidget * wg)108 void mAcceleratorAdd(mAccelerator *accel,int cmdid,uint32_t key,mWidget *wg)
109 {
110 	mAccelItem *pi;
111 
112 	if(key == 0) return;
113 
114 	pi = (mAccelItem *)mListAppendNew(&accel->list, sizeof(mAccelItem), NULL);
115 	if(!pi) return;
116 
117 	pi->cmdid = cmdid;
118 	pi->key = key;
119 	pi->widget = wg;
120 }
121 
122 /** すべてのキー設定を削除 */
123 
mAcceleratorDeleteAll(mAccelerator * accel)124 void mAcceleratorDeleteAll(mAccelerator *accel)
125 {
126 	mListDeleteAll(&accel->list);
127 }
128 
129 /** コマンドIDから設定されているキーを取得
130  *
131  * @return 見つからなかった場合、0 */
132 
mAcceleratorGetKeyByID(mAccelerator * p,int cmdid)133 uint32_t mAcceleratorGetKeyByID(mAccelerator *p,int cmdid)
134 {
135 	mAccelItem *pi;
136 
137 	for(pi = _ITEM(p->list.top); pi; pi = _ITEM(pi->i.next))
138 	{
139 		if(pi->cmdid == cmdid)
140 			return pi->key;
141 	}
142 
143 	return 0;
144 }
145 
146 /** キーコードから文字列取得
147  *
148  * @return 確保された文字列のポインタ */
149 
mAcceleratorGetKeyText(uint32_t key)150 char *mAcceleratorGetKeyText(uint32_t key)
151 {
152 	mStr str = MSTR_INIT;
153 	char name[32],*buf;
154 
155 	if(key & MACCKEY_SHIFT)
156 		mStrAppendText(&str, "Shift+");
157 
158 	if(key & MACCKEY_CTRL)
159 		mStrAppendText(&str, "Ctrl+");
160 
161 	if(key & MACCKEY_ALT)
162 		mStrAppendText(&str, "Alt+");
163 
164 	mKeyCodeToName(key & MACCKEY_KEYMASK, name, 32);
165 	mStrAppendText(&str, name);
166 
167 	buf = mStrdup(str.buf);
168 
169 	mStrFree(&str);
170 
171 	return buf;
172 }
173 
174 /** キーイベントからアクセラレータのキーを取得 */
175 
mAcceleratorGetKeyFromEvent(mEvent * ev)176 uint32_t mAcceleratorGetKeyFromEvent(mEvent *ev)
177 {
178 	uint32_t key;
179 
180 	key = ev->key.code;
181 
182 	if(ev->key.state & M_MODS_SHIFT) key |= MACCKEY_SHIFT;
183 	if(ev->key.state & M_MODS_CTRL)  key |= MACCKEY_CTRL;
184 	if(ev->key.state & M_MODS_ALT)   key |= MACCKEY_ALT;
185 
186 	return key;
187 }
188 
189 /** @} */
190 
191 
192 //==================
193 
194 
195 /** トップウィンドウのキー処理 */
196 
__mAccelerator_keyevent(mAccelerator * accel,uint32_t key,uint32_t state,int press)197 mBool __mAccelerator_keyevent(mAccelerator *accel,uint32_t key,uint32_t state,int press)
198 {
199 	mAccelItem *pi;
200 
201 	if(state & M_MODS_SHIFT) key |= MACCKEY_SHIFT;
202 	if(state & M_MODS_CTRL)  key |= MACCKEY_CTRL;
203 	if(state & M_MODS_ALT)   key |= MACCKEY_ALT;
204 
205 	//キーから検索
206 
207 	for(pi = _ITEM(accel->list.top); pi; pi = _ITEM(pi->i.next))
208 	{
209 		if(pi->key == key) break;
210 	}
211 
212 	if(!pi) return FALSE;
213 
214 	//MEVENT_COMMAND
215 
216 	if(press)
217 	{
218 		mWidgetAppendEvent_command(
219 			(pi->widget)? pi->widget: accel->defaultWidget,
220 			pi->cmdid, 0, MEVENT_COMMAND_BY_ACCEL);
221 	}
222 
223 	return TRUE;
224 }
225