1 /*
2 ** colorpickermenu.cpp
3 ** The color picker menu
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 2010 Christoph Oelckers
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34 #include <float.h>
35
36 #include "menu/menu.h"
37 #include "c_dispatch.h"
38 #include "w_wad.h"
39 #include "sc_man.h"
40 #include "v_font.h"
41 #include "g_level.h"
42 #include "d_player.h"
43 #include "v_video.h"
44 #include "gi.h"
45 #include "i_system.h"
46 #include "c_bind.h"
47 #include "v_palette.h"
48 #include "d_event.h"
49 #include "d_gui.h"
50
51 #define NO_IMP
52 #include "menu/optionmenuitems.h"
53
54 class DColorPickerMenu : public DOptionMenu
55 {
56 DECLARE_CLASS(DColorPickerMenu, DOptionMenu)
57
58 float mRed;
59 float mGreen;
60 float mBlue;
61
62 int mGridPosX;
63 int mGridPosY;
64
65 int mStartItem;
66
67 FColorCVar *mCVar;
68
69 public:
70
DColorPickerMenu(DMenu * parent,const char * name,FOptionMenuDescriptor * desc,FColorCVar * cvar)71 DColorPickerMenu(DMenu *parent, const char *name, FOptionMenuDescriptor *desc, FColorCVar *cvar)
72 {
73 mStartItem = desc->mItems.Size();
74 mRed = (float)RPART(DWORD(*cvar));
75 mGreen = (float)GPART(DWORD(*cvar));
76 mBlue = (float)BPART(DWORD(*cvar));
77 mGridPosX = 0;
78 mGridPosY = 0;
79 mCVar = cvar;
80
81 // This menu uses some featurs that are hard to implement in an external control lump
82 // so it creates its own list of menu items.
83 desc->mItems.Resize(mStartItem+8);
84 desc->mItems[mStartItem+0] = new FOptionMenuItemStaticText(name, false);
85 desc->mItems[mStartItem+1] = new FOptionMenuItemStaticText(" ", false);
86 desc->mItems[mStartItem+2] = new FOptionMenuSliderVar("Red", &mRed, 0, 255, 15, 0);
87 desc->mItems[mStartItem+3] = new FOptionMenuSliderVar("Green", &mGreen, 0, 255, 15, 0);
88 desc->mItems[mStartItem+4] = new FOptionMenuSliderVar("Blue", &mBlue, 0, 255, 15, 0);
89 desc->mItems[mStartItem+5] = new FOptionMenuItemStaticText(" ", false);
90 desc->mItems[mStartItem+6] = new FOptionMenuItemCommand("Undo changes", "undocolorpic");
91 desc->mItems[mStartItem+7] = new FOptionMenuItemStaticText(" ", false);
92 desc->mSelectedItem = mStartItem + 2;
93 Init(parent, desc);
94 desc->mIndent = 0;
95 desc->CalcIndent();
96 }
97
Destroy()98 void Destroy()
99 {
100 if (mStartItem >= 0)
101 {
102 for(unsigned i=0;i<8;i++)
103 {
104 delete mDesc->mItems[mStartItem+i];
105 mDesc->mItems.Resize(mStartItem);
106 }
107 UCVarValue val;
108 val.Int = MAKERGB(int(mRed), int(mGreen), int(mBlue));
109 if (mCVar != NULL) mCVar->SetGenericRep (val, CVAR_Int);
110 mStartItem = -1;
111 }
112 }
113
Reset()114 void Reset()
115 {
116 mRed = (float)RPART(DWORD(*mCVar));
117 mGreen = (float)GPART(DWORD(*mCVar));
118 mBlue = (float)BPART(DWORD(*mCVar));
119 }
120
121 //=============================================================================
122 //
123 //
124 //
125 //=============================================================================
126
MenuEvent(int mkey,bool fromcontroller)127 bool MenuEvent (int mkey, bool fromcontroller)
128 {
129 int &mSelectedItem = mDesc->mSelectedItem;
130
131 switch (mkey)
132 {
133 case MKEY_Down:
134 if (mSelectedItem == mStartItem+6) // last valid item
135 {
136 S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
137 mGridPosY = 0;
138 // let it point to the last static item so that the super class code still has a valid item
139 mSelectedItem = mStartItem+7;
140 return true;
141 }
142 else if (mSelectedItem == mStartItem+7)
143 {
144 if (mGridPosY < 15)
145 {
146 S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
147 mGridPosY++;
148 }
149 return true;
150 }
151 break;
152
153 case MKEY_Up:
154 if (mSelectedItem == mStartItem+7)
155 {
156 if (mGridPosY > 0)
157 {
158 S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
159 mGridPosY--;
160 }
161 else
162 {
163 S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
164 mSelectedItem = mStartItem+6;
165 }
166 return true;
167 }
168 break;
169
170 case MKEY_Left:
171 if (mSelectedItem == mStartItem+7)
172 {
173 S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
174 if (--mGridPosX < 0) mGridPosX = 15;
175 return true;
176 }
177 break;
178
179 case MKEY_Right:
180 if (mSelectedItem == mStartItem+7)
181 {
182 S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
183 if (++mGridPosX > 15) mGridPosX = 0;
184 return true;
185 }
186 break;
187
188 case MKEY_Enter:
189 if (mSelectedItem == mStartItem+7)
190 {
191 // Choose selected palette entry
192 int index = mGridPosX + mGridPosY * 16;
193 mRed = GPalette.BaseColors[index].r;
194 mGreen = GPalette.BaseColors[index].g;
195 mBlue = GPalette.BaseColors[index].b;
196 S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
197 return true;
198 }
199 break;
200 }
201 if (mSelectedItem >= 0 && mSelectedItem < mStartItem+7)
202 {
203 if (mDesc->mItems[mDesc->mSelectedItem]->MenuEvent(mkey, fromcontroller)) return true;
204 }
205 return Super::MenuEvent(mkey, fromcontroller);
206 }
207
208 //=============================================================================
209 //
210 //
211 //
212 //=============================================================================
213
MouseEvent(int type,int mx,int my)214 bool MouseEvent(int type, int mx, int my)
215 {
216 int olditem = mDesc->mSelectedItem;
217 bool res = Super::MouseEvent(type, mx, my);
218
219 if (mDesc->mSelectedItem == -1 || mDesc->mSelectedItem == mStartItem+7)
220 {
221 int y = (-mDesc->mPosition + BigFont->GetHeight() + mDesc->mItems.Size() * OptionSettings.mLinespacing) * CleanYfac_1;
222 int h = (screen->GetHeight() - y) / 16;
223 int fh = OptionSettings.mLinespacing * CleanYfac_1;
224 int w = fh;
225 int yy = y + 2 * CleanYfac_1;
226 int indent = (screen->GetWidth() / 2);
227
228 if (h > fh) h = fh;
229 else if (h < 4) return res; // no space to draw it.
230
231 int box_y = y - 2 * CleanYfac_1;
232 int box_x = indent - 16*w;
233
234 if (mx >= box_x && mx < box_x + 16*w && my >= box_y && my < box_y + 16*h)
235 {
236 int cell_x = (mx - box_x) / w;
237 int cell_y = (my - box_y) / h;
238
239 if (olditem != mStartItem+7 || cell_x != mGridPosX || cell_y != mGridPosY)
240 {
241 mGridPosX = cell_x;
242 mGridPosY = cell_y;
243 //S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
244 }
245 mDesc->mSelectedItem = mStartItem+7;
246 if (type == MOUSE_Release)
247 {
248 MenuEvent(MKEY_Enter, true);
249 if (m_use_mouse == 2) mDesc->mSelectedItem = -1;
250 }
251 res = true;
252 }
253 }
254 return res;
255 }
256
257 //=============================================================================
258 //
259 //
260 //
261 //=============================================================================
262
Drawer()263 void Drawer()
264 {
265 Super::Drawer();
266
267 if (mCVar == NULL) return;
268 int y = (-mDesc->mPosition + BigFont->GetHeight() + mDesc->mItems.Size() * OptionSettings.mLinespacing) * CleanYfac_1;
269 int h = (screen->GetHeight() - y) / 16;
270 int fh = OptionSettings.mLinespacing * CleanYfac_1;
271 int w = fh;
272 int yy = y;
273
274 if (h > fh) h = fh;
275 else if (h < 4) return; // no space to draw it.
276
277 int indent = (screen->GetWidth() / 2);
278 int p = 0;
279
280 for(int i = 0; i < 16; i++, y += h)
281 {
282 int box_x, box_y;
283 int x1;
284
285 box_y = y - 2 * CleanYfac_1;
286 box_x = indent - 16*w;
287 for (x1 = 0; x1 < 16; ++x1, p++)
288 {
289 screen->Clear (box_x, box_y, box_x + w, box_y + h, p, 0);
290 if ((mDesc->mSelectedItem == mStartItem+7) &&
291 (/*p == CurrColorIndex ||*/ (i == mGridPosY && x1 == mGridPosX)))
292 {
293 int r, g, b;
294 DWORD col;
295 double blinky;
296 if (i == mGridPosY && x1 == mGridPosX)
297 {
298 r = 255, g = 128, b = 0;
299 }
300 else
301 {
302 r = 200, g = 200, b = 255;
303 }
304 // Make sure the cursors stand out against similar colors
305 // by pulsing them.
306 blinky = fabs(sin(I_MSTime()/1000.0)) * 0.5 + 0.5;
307 col = MAKEARGB(255,int(r*blinky),int(g*blinky),int(b*blinky));
308
309 screen->Clear (box_x, box_y, box_x + w, box_y + 1, -1, col);
310 screen->Clear (box_x, box_y + h-1, box_x + w, box_y + h, -1, col);
311 screen->Clear (box_x, box_y, box_x + 1, box_y + h, -1, col);
312 screen->Clear (box_x + w - 1, box_y, box_x + w, box_y + h, -1, col);
313 }
314 box_x += w;
315 }
316 }
317 y = yy;
318 DWORD newColor = MAKEARGB(255, int(mRed), int(mGreen), int(mBlue));
319 DWORD oldColor = DWORD(*mCVar) | 0xFF000000;
320
321 int x = screen->GetWidth()*2/3;
322
323 screen->Clear (x, y, x + 48*CleanXfac_1, y + 48*CleanYfac_1, -1, oldColor);
324 screen->Clear (x + 48*CleanXfac_1, y, x + 48*2*CleanXfac_1, y + 48*CleanYfac_1, -1, newColor);
325
326 y += 49*CleanYfac_1;
327 screen->DrawText (SmallFont, CR_GRAY, x+(24-SmallFont->StringWidth("Old")/2)*CleanXfac_1, y,
328 "Old", DTA_CleanNoMove_1, true, TAG_DONE);
329 screen->DrawText (SmallFont, CR_WHITE, x+(48+24-SmallFont->StringWidth("New")/2)*CleanXfac_1, y,
330 "New", DTA_CleanNoMove_1, true, TAG_DONE);
331 }
332 };
333
334 IMPLEMENT_ABSTRACT_CLASS(DColorPickerMenu)
335
CCMD(undocolorpic)336 CCMD(undocolorpic)
337 {
338 if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DColorPickerMenu)))
339 {
340 static_cast<DColorPickerMenu*>(DMenu::CurrentMenu)->Reset();
341 }
342 }
343
344
StartPickerMenu(DMenu * parent,const char * name,FColorCVar * cvar)345 DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar)
346 {
347 FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Colorpickermenu);
348 if (desc != NULL && (*desc)->mType == MDESC_OptionsMenu)
349 {
350 return new DColorPickerMenu(parent, name, (FOptionMenuDescriptor*)(*desc), cvar);
351 }
352 else
353 {
354 return NULL;
355 }
356 }
357
358