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