1 /*
2 LICENSE
3 -------
4 Copyright 2005-2013 Nullsoft, Inc.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without modification,
8 are permitted provided that the following conditions are met:
9
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12
13 * Redistributions in binary form must reproduce the above copyright notice,
14 this list of conditions and the following disclaimer in the documentation
15 and/or other materials provided with the distribution.
16
17 * Neither the name of Nullsoft nor the names of its contributors may be used to
18 endorse or promote products derived from this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
21 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "api.h"
31 #include "state.h" // for CBlendableFloat - fix this
32 #include "menu.h"
33 #include "plugin.h"
34 #include <stdio.h>
35 #include <math.h>
36 #include <assert.h>
37 #include "resource.h"
38
39 extern CPlugin g_plugin; // declared in main.cpp
40
41 //----------------------------------------
42
CMilkMenuItem()43 CMilkMenuItem::CMilkMenuItem()
44 {
45 WASABI_API_LNGSTRINGW_BUF(IDS_UNTITLED_MENU_ITEM,m_szName,64);
46 m_szToolTip[0] = 0;
47 m_type = MENUITEMTYPE_BUNK;
48 m_fMin = 0.0f;
49 m_fMax = 0.0f;
50 m_var_offset = NULL;
51 m_pCallbackFn = NULL;
52 m_pNext = NULL;
53 m_original_value = NULL;
54 m_nLastCursorPos = 0;
55 m_bEnabled = true;
56 }
57
~CMilkMenuItem()58 CMilkMenuItem::~CMilkMenuItem()
59 {
60 if (m_pNext)
61 {
62 delete m_pNext;
63 m_pNext = NULL;
64 }
65 }
66
67 //----------------------------------------
68
CMilkMenu()69 CMilkMenu::CMilkMenu()
70 {
71 //Reset();
72 }
73
~CMilkMenu()74 CMilkMenu::~CMilkMenu()
75 {
76 /*
77 if (m_pFirstChildItem)
78 {
79 delete m_pFirstChildItem;
80 m_pFirstChildItem = NULL;
81 }
82 */
83 }
84
85 //----------------------------------------
86
ItemIsEnabled(int j)87 bool CMilkMenu::ItemIsEnabled(int j)
88 {
89 if (j < m_nChildMenus)
90 return m_ppChildMenu[j]->IsEnabled();
91
92 int i = m_nChildMenus;
93 CMilkMenuItem *pChild = m_pFirstChildItem;
94 while (pChild && i<j)
95 {
96 pChild = pChild->m_pNext;
97 i++;
98 }
99 if (pChild)
100 return pChild->m_bEnabled;
101
102 return false;
103 }
104
105 //----------------------------------------
106
EnableItem(wchar_t * szName,bool bEnable)107 void CMilkMenu::EnableItem(wchar_t* szName, bool bEnable)
108 {
109 //search submenus
110 for (int i=0; i<m_nChildMenus; i++) {
111 if (!wcscmp(m_ppChildMenu[i]->GetName(), szName))
112 {
113 m_ppChildMenu[i]->Enable(bEnable);
114 if (!bEnable)
115 {
116 while (m_nCurSel > 0 && !ItemIsEnabled(m_nCurSel))
117 m_nCurSel--;
118 if (m_nCurSel==0 && !ItemIsEnabled(m_nCurSel))
119 while (m_nCurSel < m_nChildMenus+m_nChildItems-1 && !ItemIsEnabled(m_nCurSel))
120 m_nCurSel++;
121 }
122 return;
123 }
124 }
125
126 //search child items
127 CMilkMenuItem *pChild = m_pFirstChildItem;
128 while (pChild)
129 {
130 if (!wcscmp(pChild->m_szName, szName))
131 {
132 pChild->m_bEnabled = bEnable;
133 if (!bEnable)
134 {
135 while (m_nCurSel > 0 && !ItemIsEnabled(m_nCurSel))
136 m_nCurSel--;
137 if (m_nCurSel==0 && !ItemIsEnabled(m_nCurSel))
138 while (m_nCurSel < m_nChildMenus+m_nChildItems-1 && !ItemIsEnabled(m_nCurSel))
139 m_nCurSel++;
140 }
141 return;
142 }
143 pChild = pChild->m_pNext;
144 i++;
145 }
146 }
147
148 //----------------------------------------
149
Reset()150 void CMilkMenu::Reset()
151 {
152 m_pParentMenu = NULL;
153 for (int i=0; i<MAX_CHILD_MENUS; i++)
154 m_ppChildMenu[i] = NULL;
155 m_pFirstChildItem = NULL;
156 WASABI_API_LNGSTRINGW_BUF(IDS_UNTITLED_MENU,m_szMenuName,64);
157 m_nChildMenus = 0;
158 m_nChildItems = 0;
159 m_nCurSel = 0;
160 m_bEditingCurSel = false;
161 m_bEnabled = true;
162 }
163
164 //----------------------------------------
165
Init(wchar_t * szName)166 void CMilkMenu::Init(wchar_t *szName)
167 {
168 Reset();
169 if (szName && szName[0])
170 wcsncpy(m_szMenuName, szName, 64);
171 }
172
Finish()173 void CMilkMenu::Finish()
174 {
175 if (m_pFirstChildItem)
176 {
177 delete m_pFirstChildItem;
178 m_pFirstChildItem = NULL;
179 }
180 }
181
182 //----------------------------------------
183
AddChildMenu(CMilkMenu * pMenu)184 void CMilkMenu::AddChildMenu(CMilkMenu *pMenu)
185 {
186 if (m_nChildMenus < MAX_CHILD_MENUS)
187 {
188 m_ppChildMenu[m_nChildMenus++] = pMenu;
189 pMenu->SetParentPointer(this);
190 }
191 }
192
193 //----------------------------------------
194
AddItem(wchar_t * szName,void * var,MENUITEMTYPE type,wchar_t * szToolTip,float min,float max,MilkMenuCallbackFnPtr pCallback,unsigned int wParam,unsigned int lParam)195 void CMilkMenu::AddItem(wchar_t *szName, void *var, MENUITEMTYPE type, wchar_t *szToolTip,
196 float min, float max, MilkMenuCallbackFnPtr pCallback,
197 unsigned int wParam, unsigned int lParam)
198 {
199 CMilkMenuItem *pLastItem = NULL;
200
201 // find last item in linked list
202 if (!m_pFirstChildItem)
203 {
204 // first item
205 m_pFirstChildItem = new CMilkMenuItem;
206 pLastItem = m_pFirstChildItem;
207 }
208 else
209 {
210 pLastItem = m_pFirstChildItem;
211 while (pLastItem->m_pNext)
212 pLastItem = pLastItem->m_pNext;
213
214 // allocate a new CMilkMenuItem
215 pLastItem->m_pNext = new CMilkMenuItem;
216 pLastItem = pLastItem->m_pNext;
217 }
218
219 // set its attributes
220 wcsncpy(pLastItem->m_szName, szName, 64);
221 wcsncpy(pLastItem->m_szToolTip, szToolTip, 1024);
222 pLastItem->m_var_offset = (size_t)var - (size_t)(g_plugin.m_pState);
223 pLastItem->m_type = type;
224 pLastItem->m_fMin = min;
225 pLastItem->m_fMax = max;
226 pLastItem->m_wParam = wParam;
227 pLastItem->m_lParam = lParam;
228 if ((type==MENUITEMTYPE_LOGBLENDABLE || type==MENUITEMTYPE_LOGFLOAT) && min==max)
229 {
230 // special defaults
231 pLastItem->m_fMin = 0.01f;
232 pLastItem->m_fMax = 100.0f;
233 }
234 pLastItem->m_pCallbackFn = pCallback;
235
236 m_nChildItems++;
237 }
238
239 //----------------------------------------
240
MyMenuTextOut(eFontIndex font_index,wchar_t * str,DWORD color,RECT * pRect,int bCalcRect,RECT * pCalcRect)241 void MyMenuTextOut(eFontIndex font_index, wchar_t* str, DWORD color, RECT* pRect, int bCalcRect, RECT* pCalcRect)
242 {
243 if (bCalcRect)
244 {
245 RECT t = *pRect;
246 pRect->top += g_plugin.m_text.DrawTextW(g_plugin.GetFont(font_index), str, -1, &t, DT_SINGLELINE | DT_END_ELLIPSIS | DT_CALCRECT, 0xFFFFFFFF, false);
247 pCalcRect->bottom += t.bottom - t.top;
248 //if (pCalcRect->bottom > pRect->bottom)
249 // pCalcRect->bottom = pRect->bottom;
250 pCalcRect->right = max(pCalcRect->right, pCalcRect->left + t.right - t.left);
251 }
252 else
253 {
254 pRect->top += g_plugin.m_text.DrawTextW(g_plugin.GetFont(font_index), str, -1, pRect, DT_SINGLELINE | DT_END_ELLIPSIS, color, false);
255 }
256 }
257
DrawMenu(RECT rect,int xR,int yB,int bCalcRect,RECT * pCalcRect)258 void CMilkMenu::DrawMenu(RECT rect, int xR, int yB, int bCalcRect, RECT* pCalcRect)
259 {
260 // 'rect' is the bounding rectangle in which we're allowed to draw the menu;
261 // it's .top member is incremented as we draw downward.
262 // if bCalcRect==1, then we return pCalcRect as the area that the menu actually
263 // occupies, excluding any tooltips.
264
265 if (bCalcRect!=0 && pCalcRect==NULL)
266 return;
267
268 if (bCalcRect)
269 {
270 pCalcRect->left = rect.left;
271 pCalcRect->right = rect.left;
272 pCalcRect->top = rect.top;
273 pCalcRect->bottom = rect.top;
274 }
275
276 if (!m_bEditingCurSel)
277 {
278 int nLines = (rect.bottom - rect.top - PLAYLIST_INNER_MARGIN*2) / g_plugin.GetFontHeight(SIMPLE_FONT) - 1; // save 1 line for the tooltip
279 if (nLines<1) return;
280 int nStart = (m_nCurSel/nLines)*nLines;
281
282 int nLinesDrawn = 0;
283
284 for (int i=0; i < m_nChildMenus; i++)
285 {
286 if (i >= nStart && i < nStart+nLines)
287 {
288 //rect.top += g_plugin.GetFont(SIMPLE_FONT)->DrawText(m_ppChildMenu[i]->m_szMenuName, -1, pRect, DT_SINGLELINE | DT_END_ELLIPSIS, (i == m_nCurSel) ? MENU_HILITE_COLOR : MENU_COLOR);
289 if (m_ppChildMenu[i]->IsEnabled()) {
290 MyMenuTextOut(SIMPLE_FONT, m_ppChildMenu[i]->m_szMenuName, (i == m_nCurSel) ? MENU_HILITE_COLOR : MENU_COLOR, &rect, bCalcRect, pCalcRect);
291 nLinesDrawn++;
292 }
293
294 if (g_plugin.m_bShowMenuToolTips && i == m_nCurSel && !bCalcRect)
295 {
296 // tooltip:
297 g_plugin.DrawTooltip(WASABI_API_LNGSTRINGW(IDS_SZ_MENU_NAV_TOOLTIP), xR, yB);
298 }
299 }
300 }
301
302 CMilkMenuItem *pItem = m_pFirstChildItem;
303
304 while (pItem && nLinesDrawn < nStart+nLines)
305 {
306 if (!pItem->m_bEnabled)
307 {
308 pItem = pItem->m_pNext;
309 i++;
310 continue;
311 }
312
313 size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState;
314 if (i >= nStart)
315 {
316 wchar_t szItemText[256];
317 switch(pItem->m_type)
318 {
319 case MENUITEMTYPE_STRING:
320 lstrcpyW(szItemText, pItem->m_szName);
321 break;
322 case MENUITEMTYPE_BOOL:
323 swprintf(szItemText, L"%s [%s]", pItem->m_szName,
324 WASABI_API_LNGSTRINGW(*((bool *)(addr)) ? IDS_ON : IDS_OFF));
325 break;
326 default:
327 lstrcpyW(szItemText, pItem->m_szName);
328 break;
329 }
330
331 if (i == m_nCurSel)
332 {
333 MyMenuTextOut(SIMPLE_FONT, szItemText, MENU_HILITE_COLOR, &rect, bCalcRect, pCalcRect);
334
335 if (g_plugin.m_bShowMenuToolTips && !bCalcRect)
336 {
337 // tooltip:
338 g_plugin.DrawTooltip(pItem->m_szToolTip, xR, yB);
339 }
340 }
341 else
342 {
343 MyMenuTextOut(SIMPLE_FONT, szItemText, MENU_COLOR, &rect, bCalcRect, pCalcRect);
344 }
345 nLinesDrawn++;
346 }
347
348 pItem = pItem->m_pNext;
349 i++;
350 }
351 }
352 else
353 {
354 // editing current selection
355
356 // find the item
357 CMilkMenuItem *pItem = m_pFirstChildItem;
358 for (int i=m_nChildMenus; i < m_nCurSel; i++)
359 pItem = pItem->m_pNext;
360 size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState;
361
362 wchar_t buf[256];
363
364 MyMenuTextOut(SIMPLE_FONT, WASABI_API_LNGSTRINGW(IDS_USE_UP_DOWN_ARROW_KEYS), MENU_COLOR, &rect, bCalcRect, pCalcRect);
365 swprintf(buf, WASABI_API_LNGSTRINGW(IDS_CURRENT_VALUE_OF_X), pItem->m_szName);
366 MyMenuTextOut(SIMPLE_FONT, buf, MENU_COLOR, &rect, bCalcRect, pCalcRect);
367
368 switch(pItem->m_type)
369 {
370 case MENUITEMTYPE_INT:
371 swprintf(buf, L" %d ", *((int*)(addr)) );
372 break;
373 case MENUITEMTYPE_FLOAT:
374 case MENUITEMTYPE_LOGFLOAT:
375 swprintf(buf, L" %5.3f ", *((float*)(addr)) );
376 break;
377 case MENUITEMTYPE_BLENDABLE:
378 case MENUITEMTYPE_LOGBLENDABLE:
379 swprintf(buf, L" %5.3f ", ((CBlendableFloat*)addr)->eval(-1) );
380 break;
381 default:
382 lstrcpyW(buf, L" ? ");
383 break;
384 }
385
386 MyMenuTextOut(SIMPLE_FONT, buf, MENU_HILITE_COLOR, &rect, bCalcRect, pCalcRect);
387
388 // tooltip:
389 if (g_plugin.m_bShowMenuToolTips && !bCalcRect)
390 {
391 g_plugin.DrawTooltip(pItem->m_szToolTip, xR, yB);
392 }
393 }
394 }
395
OnWaitStringAccept(wchar_t * szNewString)396 void CMilkMenu::OnWaitStringAccept(wchar_t *szNewString)
397 {
398 m_bEditingCurSel = false;
399
400 // find the item
401 CMilkMenuItem *pItem = m_pFirstChildItem;
402 for (int i=m_nChildMenus; i < m_nCurSel; i++)
403 pItem = pItem->m_pNext;
404 size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState;
405
406 assert(pItem->m_type == MENUITEMTYPE_STRING);
407
408 // apply the edited string
409 lstrcpyW((wchar_t *)(addr), szNewString);
410
411 // if user gave us a callback function pointer, call it now
412 if (pItem->m_pCallbackFn)
413 {
414 pItem->m_pCallbackFn(0, 0);
415 }
416
417 // remember the last cursor position
418 pItem->m_nLastCursorPos = g_plugin.m_waitstring.nCursorPos;
419 }
420
421 //----------------------------------------
422
HandleKeydown(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)423 LRESULT CMilkMenu::HandleKeydown(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
424 {
425 // all WM_KEYDOWNS that your app gets when a menu is up should be handled here,
426 // by the menu that is currently active.
427
428 // return value: FALSE if it handled the key; TRUE if it didn't
429
430 int nRepeat = LOWORD(lParam);
431 int rep;
432
433 if (!m_bEditingCurSel)
434 {
435 switch(wParam)
436 {
437 case VK_UP:
438 for (rep=0; rep<nRepeat; rep++)
439 {
440 if (m_nCurSel==0)
441 break;
442 do {
443 m_nCurSel--;
444 } while (m_nCurSel > 0 && !ItemIsEnabled(m_nCurSel));
445 }
446 if (m_nCurSel < 0) m_nCurSel = 0;//m_nChildMenus + m_nChildItems - 1;
447 while (m_nCurSel < m_nChildMenus + m_nChildItems - 1 && !ItemIsEnabled(m_nCurSel))
448 m_nCurSel++;
449 return 0; // we processed (or absorbed) the key
450
451 case VK_DOWN:
452 for (rep=0; rep<nRepeat; rep++)
453 {
454 if (m_nCurSel == m_nChildMenus + m_nChildItems - 1)
455 break;
456 do {
457 m_nCurSel++;
458 } while (m_nCurSel < m_nChildMenus + m_nChildItems - 1 && !ItemIsEnabled(m_nCurSel));
459 }
460 if (m_nCurSel >= m_nChildMenus + m_nChildItems) m_nCurSel = m_nChildMenus + m_nChildItems - 1;//0;
461 while (m_nCurSel > 0 && !ItemIsEnabled(m_nCurSel))
462 m_nCurSel--;
463 return 0; // we processed (or absorbed) the key
464
465 case VK_HOME:
466 m_nCurSel = 0;
467 return 0; // we processed (or absorbed) the key
468
469 case VK_END:
470 m_nCurSel = m_nChildMenus + m_nChildItems - 1;
471 return 0; // we processed (or absorbed) the key
472
473 case VK_ESCAPE:
474 g_plugin.m_UI_mode = UI_REGULAR;
475 return 0; // we processed (or absorbed) the key
476
477 case VK_BACK:
478 case VK_LEFT:
479 if (m_pParentMenu)
480 g_plugin.m_pCurMenu = m_pParentMenu;
481 else
482 g_plugin.m_UI_mode = UI_REGULAR; // exit the menu
483 return 0; // we processed (or absorbed) the key
484
485 case VK_RETURN:
486 case VK_RIGHT:
487 case VK_SPACE:
488 if (m_nCurSel < m_nChildMenus)
489 {
490 // go to sub-menu
491 g_plugin.m_pCurMenu = m_ppChildMenu[m_nCurSel];
492 }
493 else
494 {
495 // find the item
496 CMilkMenuItem *pItem = GetCurItem();
497 size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState;
498
499 float fTemp;
500
501 // begin editing the item
502
503 switch(pItem->m_type)
504 {
505 case MENUITEMTYPE_UIMODE:
506 g_plugin.m_UI_mode = (ui_mode)pItem->m_wParam;
507
508 if (g_plugin.m_UI_mode==UI_IMPORT_WAVE ||
509 g_plugin.m_UI_mode==UI_EXPORT_WAVE ||
510 g_plugin.m_UI_mode==UI_IMPORT_SHAPE ||
511 g_plugin.m_UI_mode==UI_EXPORT_SHAPE)
512 {
513 g_plugin.m_bPresetLockedByCode = true;
514
515 // enter WaitString mode
516 g_plugin.m_waitstring.bActive = true;
517 g_plugin.m_waitstring.bFilterBadChars = false;
518 g_plugin.m_waitstring.bDisplayAsCode = false;
519 g_plugin.m_waitstring.nSelAnchorPos = -1;
520 g_plugin.m_waitstring.nMaxLen = min(sizeof(g_plugin.m_waitstring.szText)-1, MAX_PATH - wcslen(g_plugin.GetPresetDir()) - 6); // 6 for the extension + null char. We set this because win32 LoadFile, MoveFile, etc. barf if the path+filename+ext are > MAX_PATH chars.
521 swprintf(g_plugin.m_waitstring.szText, L"%sfile.dat", g_plugin.m_szPresetDir);
522 if (g_plugin.m_UI_mode==UI_IMPORT_WAVE || g_plugin.m_UI_mode==UI_IMPORT_SHAPE)
523 WASABI_API_LNGSTRINGW_BUF(IDS_LOAD_FROM_FILE,g_plugin.m_waitstring.szPrompt,512);
524 else
525 WASABI_API_LNGSTRINGW_BUF(IDS_SAVE_TO_FILE,g_plugin.m_waitstring.szPrompt,512);
526 g_plugin.m_waitstring.szToolTip[0] = 0;
527 g_plugin.m_waitstring.nCursorPos = wcslen(g_plugin.m_waitstring.szText); // set the starting edit position
528 }
529 break;
530 case MENUITEMTYPE_BOOL:
531 *((bool *)addr) = !(*((bool *)addr));
532 break;
533 case MENUITEMTYPE_INT:
534 m_bEditingCurSel = true;
535 pItem->m_original_value = (LPARAM)(*((int*)(addr)));
536 break;
537 case MENUITEMTYPE_FLOAT:
538 case MENUITEMTYPE_LOGFLOAT:
539 m_bEditingCurSel = true;
540 pItem->m_original_value = (LPARAM)(*((float*)(addr))*10000L);
541 break;
542 case MENUITEMTYPE_BLENDABLE:
543 case MENUITEMTYPE_LOGBLENDABLE:
544 m_bEditingCurSel = true;
545 {
546 //CBlendableFloat *p = (CBlendableFloat*)(pItem->m_pVariable);
547 //*p = 0.99f;
548 fTemp = ((CBlendableFloat*)addr)->eval(-1);//p->eval(-1);
549 }
550 pItem->m_original_value = (LPARAM)(fTemp*10000L);
551 break;
552 case MENUITEMTYPE_STRING:
553 // enter waitstring mode. ***This function will cease to receive keyboard input
554 // while the string is being edited***
555 g_plugin.m_UI_mode = UI_EDIT_MENU_STRING;
556 g_plugin.m_waitstring.bActive = true;
557 g_plugin.m_waitstring.bFilterBadChars = false;
558 g_plugin.m_waitstring.bDisplayAsCode = true;
559 g_plugin.m_waitstring.nSelAnchorPos = -1;
560 g_plugin.m_waitstring.nMaxLen = pItem->m_wParam ? pItem->m_wParam : 8190;
561 g_plugin.m_waitstring.nMaxLen = min(g_plugin.m_waitstring.nMaxLen, sizeof(g_plugin.m_waitstring.szText)-16);
562 //lstrcpyW(g_plugin.m_waitstring.szText, (wchar_t *)addr);
563 lstrcpyA((char*)g_plugin.m_waitstring.szText, (char*)addr);
564 swprintf(g_plugin.m_waitstring.szPrompt, WASABI_API_LNGSTRINGW(IDS_ENTER_THE_NEW_STRING), pItem->m_szName);
565 lstrcpyW(g_plugin.m_waitstring.szToolTip, pItem->m_szToolTip);
566 g_plugin.m_waitstring.nCursorPos = strlen/*wcslen*/((char*)g_plugin.m_waitstring.szText);
567 if (pItem->m_nLastCursorPos < g_plugin.m_waitstring.nCursorPos)
568 g_plugin.m_waitstring.nCursorPos = pItem->m_nLastCursorPos;
569 break;
570 /*
571 case MENUITEMTYPE_OSC:
572 m_bEditingCurSel = true;
573 pItem->m_bEditingSubSel = false;
574 break;
575 */
576 }
577 }
578 return 0; // we processed (or absorbed) the key
579
580 default:
581 // key wasn't handled
582 return TRUE;
583 break;
584 }
585 }
586 else // m_bEditingCurSel
587 {
588 float fMult = 1.0f;
589 bool bDec;
590
591 // find the item
592 CMilkMenuItem *pItem = m_pFirstChildItem;
593 for (int i=m_nChildMenus; i < m_nCurSel; i++)
594 pItem = pItem->m_pNext;
595 size_t addr = pItem->m_var_offset + (size_t)g_plugin.m_pState;
596
597 switch(wParam)
598 {
599 case VK_ESCAPE: // exit Edit mode & restore original value
600
601 switch(pItem->m_type)
602 {
603 case MENUITEMTYPE_INT:
604 m_bEditingCurSel = false;
605 *((int *)addr) = (int)pItem->m_original_value;
606 break;
607 case MENUITEMTYPE_FLOAT:
608 m_bEditingCurSel = false;
609 *((float *)addr) = ((float)pItem->m_original_value)*0.0001f;
610 break;
611 case MENUITEMTYPE_LOGFLOAT:
612 m_bEditingCurSel = false;
613 *((float *)addr) = ((float)pItem->m_original_value)*0.0001f;
614 break;
615 case MENUITEMTYPE_BLENDABLE:
616 m_bEditingCurSel = false;
617 *((CBlendableFloat *)(addr)) = ((float)(pItem->m_original_value))*0.0001f;
618 break;
619 case MENUITEMTYPE_LOGBLENDABLE:
620 m_bEditingCurSel = false;
621 *((CBlendableFloat *)(addr)) = ((float)(pItem->m_original_value))*0.0001f;
622 break;
623 //case MENUITEMTYPE_STRING:
624 // won't ever happen - see OnWaitStringCancel()
625 }
626 return 0;
627
628 case VK_RETURN:
629
630 //if (pItem->m_type == MENUITEMTYPE_STRING)
631 // ... won't ever happen - see OnWaitStringAccept()
632
633 m_bEditingCurSel = false;
634 return 0;
635
636
637 case VK_NEXT:
638 case VK_PRIOR:
639 fMult *= 10.0f;
640 // break intentionally left out here...
641 case VK_UP:
642 case VK_DOWN:
643
644 {
645 USHORT mask = 1 << (sizeof(USHORT)*8 - 1); // we want the highest-order bit
646 bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0;
647 //bool bCtrlHeldDown = (GetKeyState(VK_CONTROL) & mask) != 0;
648 if (bShiftHeldDown && (wParam==VK_UP || wParam==VK_DOWN))
649 fMult *= 0.1f;
650 }
651
652 bDec = (wParam == VK_DOWN || wParam == VK_NEXT);
653
654 switch(pItem->m_type)
655 {
656 case MENUITEMTYPE_INT:
657 {
658 int *pInt = ((int *)addr);
659 if (fMult<1) fMult=1;
660 (*pInt) += (int)((bDec) ? -fMult : fMult);
661 if (*pInt < pItem->m_fMin) *pInt = (int)pItem->m_fMin;
662 if (*pInt > pItem->m_fMax) *pInt = (int)pItem->m_fMax;
663 }
664 break;
665 case MENUITEMTYPE_FLOAT:
666 {
667 float *pFloat = ((float *)addr);
668 float fInc = (pItem->m_fMax - pItem->m_fMin)*0.01f*fMult;
669 (*pFloat) += (bDec) ? -fInc : fInc;
670 if (*pFloat < pItem->m_fMin) *pFloat = pItem->m_fMin;
671 if (*pFloat > pItem->m_fMax) *pFloat = pItem->m_fMax;
672 }
673 break;
674 case MENUITEMTYPE_LOGFLOAT:
675 {
676 float *pFloat = ((float *)addr);
677 (*pFloat) *= (bDec) ? powf(1.0f/1.01f, fMult) : powf(1.01f, fMult);
678 if (*pFloat < pItem->m_fMin) *pFloat = pItem->m_fMin;
679 if (*pFloat > pItem->m_fMax) *pFloat = pItem->m_fMax;
680 }
681 break;
682 case MENUITEMTYPE_BLENDABLE:
683 {
684 CBlendableFloat *pBlend = ((CBlendableFloat *)addr);
685 float fInc = (pItem->m_fMax - pItem->m_fMin)*0.01f*fMult;
686 (*pBlend) += (bDec) ? -fInc : fInc;
687 if (pBlend->eval(-1) < pItem->m_fMin) *pBlend = pItem->m_fMin;
688 if (pBlend->eval(-1) > pItem->m_fMax) *pBlend = pItem->m_fMax;
689 }
690 break;
691 case MENUITEMTYPE_LOGBLENDABLE:
692 {
693 CBlendableFloat *pBlend = ((CBlendableFloat *)addr);
694 (*pBlend) *= (bDec) ? powf(1.0f/1.01f, fMult) : powf(1.01f, fMult);
695 if (pBlend->eval(-1) < pItem->m_fMin) *pBlend = pItem->m_fMin;
696 if (pBlend->eval(-1) > pItem->m_fMax) *pBlend = pItem->m_fMax;
697 }
698 break;
699 /*
700 case MENUITEMTYPE_OSC:
701 if (pItem->m_bEditingSubSel)
702 {
703 if (wParam == VK_UP)
704 {
705 pItem->m_nSubSel--;
706 if (pItem->m_nSubSel < 0) pItem->m_nSubSel = 4;
707 }
708 else if (wParam == VK_DOWN)
709 {
710 pItem->m_nSubSel++;
711 if (pItem->m_nSubSel > 4) pItem->m_nSubSel = 0;
712 }
713 }
714 else
715 {
716 switch(pItem->m_nSubSel)
717 {
718 also to do: make 'drawtext' draw it properly
719
720 case 0:
721 fixme - what are the bounds for each type? and are incs constant or log?
722 break;
723 case 1:
724 fixme
725 break;
726 case 2:
727 fixme
728 break;
729 case 3:
730 fixme
731 break;
732 case 4:
733 fixme
734 break;
735 }
736 }
737 break;
738 */
739 }
740 return 0;
741
742 default:
743 // key wasn't handled
744 return TRUE;
745 break;
746 }
747 }
748
749 return TRUE;
750 }