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