1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4 
5 #include "uibitmapscontroller.h"
6 
7 #if VSTGUI_LIVE_EDITING
8 
9 #include "uibasedatasource.h"
10 #include "uieditcontroller.h"
11 #include "uidialogcontroller.h"
12 #include "uiviewcreatecontroller.h"
13 #include "../cstream.h"
14 #include "../detail/uiviewcreatorattributes.h"
15 #include "../../lib/cbitmap.h"
16 #include "../../lib/cbitmapfilter.h"
17 #include "../../lib/cdropsource.h"
18 #include "../../lib/cfileselector.h"
19 #include "../../lib/idatapackage.h"
20 #include "../../lib/dragging.h"
21 #include "../../lib/cvstguitimer.h"
22 #include "../../lib/controls/ccolorchooser.h"
23 #include "../../lib/controls/ctextedit.h"
24 #include "../../lib/controls/csearchtextedit.h"
25 #include "../../lib/platform/iplatformbitmap.h"
26 
27 namespace VSTGUI {
28 //----------------------------------------------------------------------------------------------------
29 class UIBitmapView : public CView
30 {
31 public:
UIBitmapView(CBitmap * bitmap=nullptr)32 	UIBitmapView (CBitmap* bitmap = nullptr)
33 	: CView (CRect (0, 0, 0, 0))
34 	, zoom (1.)
35 	{
36 		setBackground (bitmap);
37 	}
38 
draw(CDrawContext * context)39 	void draw (CDrawContext* context) override
40 	{
41 		if (CBitmap* bitmap = getBackground ())
42 		{
43 			CGraphicsTransform matrix;
44 			matrix.scale (zoom, zoom);
45 			CDrawContext::Transform transform (*context, matrix);
46 			CRect r (getViewSize ());
47 			matrix.inverse ().transform (r);
48 			bitmap->CBitmap::draw (context, r);
49 			auto* nptBitmap = dynamic_cast<CNinePartTiledBitmap*>(bitmap);
50 			if (nptBitmap)
51 			{
52 				static const CCoord kDefaultOnOffDashLength2[] = {2, 2};
53 				const CLineStyle kLineOnOffDash2 (CLineStyle::kLineCapButt, CLineStyle::kLineJoinMiter, 0, 2, kDefaultOnOffDashLength2);
54 
55 				const CNinePartTiledDescription& offsets = nptBitmap->getPartOffsets ();
56 
57 				CRect r2;
58 				r2.setWidth (nptBitmap->getWidth());
59 				r2.setHeight (nptBitmap->getHeight());
60 				CPoint p = getViewSize ().getTopLeft ();
61 				matrix.inverse ().transform (p);
62 				r2.offset (p.x, p.y);
63 
64 				context->setDrawMode (kAntiAliasing);
65 				context->setFrameColor (kBlueCColor);
66 				context->setLineWidth (1);
67 				context->setLineStyle (kLineSolid);
68 
69 				context->drawLine (CPoint (r2.left, r2.top + offsets.top), CPoint (r2.right, r2.top + offsets.top));
70 				context->drawLine (CPoint (r2.left, r2.bottom - offsets.bottom), CPoint (r2.right, r2.bottom - offsets.bottom));
71 				context->drawLine (CPoint (r2.left + offsets.left, r2.top), CPoint (r2.left + offsets.left, r2.bottom));
72 				context->drawLine (CPoint (r2.right - offsets.right, r2.top), CPoint (r2.right - offsets.right, r2.bottom));
73 
74 				context->setFrameColor (kRedCColor);
75 				context->setLineWidth (1);
76 				context->setLineStyle (kLineOnOffDash2);
77 
78 				context->drawLine (CPoint (r2.left, r2.top + offsets.top), CPoint (r2.right, r2.top + offsets.top));
79 				context->drawLine (CPoint (r2.left, r2.bottom - offsets.bottom), CPoint (r2.right, r2.bottom - offsets.bottom));
80 				context->drawLine (CPoint (r2.left + offsets.left, r2.top), CPoint (r2.left + offsets.left, r2.bottom));
81 				context->drawLine (CPoint (r2.right - offsets.right, r2.top), CPoint (r2.right - offsets.right, r2.bottom));
82 			}
83 		}
84 	}
85 
setZoom(CCoord factor)86 	void setZoom (CCoord factor)
87 	{
88 		if (factor <= 0. || factor == zoom)
89 			return;
90 		zoom = factor;
91 		updateSize ();
92 	}
93 
updateSize()94 	void updateSize ()
95 	{
96 		if (CBitmap* bitmap = getBackground ())
97 		{
98 			CCoord width = bitmap ? bitmap->getWidth () : 0;
99 			CCoord height = bitmap ? bitmap->getHeight () : 0;
100 			CRect r (getViewSize ());
101 
102 			CGraphicsTransform ().scale (zoom, zoom).transform (width, height);
103 			width = std::floor (width + 0.5);
104 			height = std::floor (height + 0.5);
105 			r.setWidth (width);
106 			r.setHeight (height);
107 
108 			if (getViewSize () != r)
109 			{
110 				setViewSize (r);
111 				setMouseableArea (r);
112 			}
113 		}
114 	}
115 
setBackground(CBitmap * background)116 	void setBackground (CBitmap *background) override
117 	{
118 		auto platformBitmap = background ? background->getPlatformBitmap () : nullptr;
119 		if (platformBitmap && platformBitmap->getScaleFactor () != 1.)
120 		{
121 			// get rid of the scale factor
122 			auto buffer = IPlatformBitmap::createMemoryPNGRepresentation (platformBitmap);
123 			if (!buffer.empty ())
124 			{
125 				auto newPlatformBitmap = IPlatformBitmap::createFromMemory (buffer.data (), static_cast<uint32_t> (buffer.size ()));
126 				CView::setBackground (makeOwned<CBitmap> (newPlatformBitmap));
127 			}
128 		}
129 		else
130 			CView::setBackground (background);
131 		updateSize ();
132 	}
133 
134 protected:
135 	CCoord zoom;
136 };
137 
138 //----------------------------------------------------------------------------------------------------
139 class UIBitmapsDataSource : public UIBaseDataSource
140 {
141 public:
142 	UIBitmapsDataSource (UIDescription* description, IActionPerformer* actionPerformer, GenericStringListDataBrowserSourceSelectionChanged* delegate);
143 
144 	CBitmap* getSelectedBitmap ();
145 	UTF8StringPtr getSelectedBitmapName ();
146 
147 	bool add () override;
148 protected:
149 	void onUIDescBitmapChanged (UIDescription* desc) override;
150 	void getNames (std::list<const std::string*>& names) override;
151 	bool addItem (UTF8StringPtr name) override;
152 	bool removeItem (UTF8StringPtr name) override;
153 	bool performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
getDefaultsName()154 	UTF8StringPtr getDefaultsName () override { return "UIBitmapsDataSource"; }
155 
156 	bool addBitmap (UTF8StringPtr path, std::string& outName);
157 
158 	void dbDrawCell (CDrawContext* context, const CRect& size, int32_t row, int32_t column, int32_t flags, CDataBrowser* browser) override;
159 	void dbCellSetupTextEdit (int32_t row, int32_t column, CTextEdit* control, CDataBrowser* browser) override;
160 	void dbOnDragEnterBrowser (IDataPackage* drag, CDataBrowser* browser) override;
161 	void dbOnDragExitBrowser (IDataPackage* drag, CDataBrowser* browser) override;
162 	DragOperation dbOnDragEnterCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser) override;
163 	void dbOnDragExitCell (int32_t row, int32_t column, IDataPackage* drag, CDataBrowser* browser) override;
164 	bool dbOnDropInCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser) override;
165 
166 	CMouseEventResult dbOnMouseDown (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser) override;
167 	CMouseEventResult dbOnMouseMoved (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser) override;
168 
169 	SharedPointer<CColorChooser> colorChooser;
170 	DragStartMouseObserver dragStartMouseObserver;
171 	bool dragContainsBitmaps;
172 };
173 
174 //----------------------------------------------------------------------------------------------------
UIBitmapsDataSource(UIDescription * description,IActionPerformer * actionPerformer,GenericStringListDataBrowserSourceSelectionChanged * delegate)175 UIBitmapsDataSource::UIBitmapsDataSource (UIDescription* description, IActionPerformer* actionPerformer, GenericStringListDataBrowserSourceSelectionChanged* delegate)
176 : UIBaseDataSource (description, actionPerformer, delegate)
177 , dragContainsBitmaps (false)
178 {
179 }
180 
181 //----------------------------------------------------------------------------------------------------
onUIDescBitmapChanged(UIDescription * desc)182 void UIBitmapsDataSource::onUIDescBitmapChanged (UIDescription* desc)
183 {
184 	onUIDescriptionUpdate ();
185 }
186 
187 //----------------------------------------------------------------------------------------------------
dbDrawCell(CDrawContext * context,const CRect & size,int32_t row,int32_t column,int32_t flags,CDataBrowser * browser)188 void UIBitmapsDataSource::dbDrawCell (CDrawContext* context, const CRect& size, int32_t row, int32_t column, int32_t flags, CDataBrowser* browser)
189 {
190 	auto drawWidth = size.getHeight ();
191 	GenericStringListDataBrowserSource::drawRowBackground (context, size, row, flags, browser);
192 	CRect r (size);
193 	r.right -= drawWidth;
194 	GenericStringListDataBrowserSource::drawRowString (context, r, row, flags, browser);
195 	if (auto bitmap = description->getBitmap (names.at (static_cast<uint32_t> (row)).data ()))
196 	{
197 		r = size;
198 		r.left = r.right - drawWidth;
199 		r.inset (2, 2);
200 		auto bitmapSize = bitmap->getSize ();
201 		auto scaleX = r.getWidth () / bitmapSize.x;
202 		auto scaleY = r.getHeight () / bitmapSize.y;
203 		CGraphicsTransform matrix;
204 		matrix.scale (scaleX, scaleY);
205 		CDrawContext::Transform t (*context, matrix);
206 		matrix.inverse ().transform (r);
207 		bitmap->CBitmap::draw (context, r);
208 	}
209 }
210 
211 //----------------------------------------------------------------------------------------------------
dbCellSetupTextEdit(int32_t row,int32_t column,CTextEdit * control,CDataBrowser * browser)212 void UIBitmapsDataSource::dbCellSetupTextEdit (int32_t row, int32_t column, CTextEdit* control, CDataBrowser* browser)
213 {
214 	UIBaseDataSource::dbCellSetupTextEdit (row, column, control, browser);
215 	CRect r (control->getViewSize ());
216 	auto drawWidth = r.getHeight ();
217 	r.right -= drawWidth;
218 	control->setViewSize (r);
219 }
220 
221 //----------------------------------------------------------------------------------------------------
dbOnMouseDown(const CPoint & where,const CButtonState & buttons,int32_t row,int32_t column,CDataBrowser * browser)222 CMouseEventResult UIBitmapsDataSource::dbOnMouseDown (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser)
223 {
224 	if (buttons.isDoubleClick () && row >= 0 && row < static_cast<int32_t> (names.size ()))
225 	{
226 		auto r = browser->getCellBounds ({row, column});
227 		auto drawWidth = r.getHeight ();
228 		r.left = r.right - drawWidth;
229 		if (r.pointInside (where))
230 		{
231 			delegate->dbRowDoubleClick (row, this);
232 			return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
233 		}
234 	}
235 	dragStartMouseObserver.init (where);
236 	UIBaseDataSource::dbOnMouseDown (where, buttons, row, column, browser);
237 	return kMouseEventHandled;
238 }
239 
240 //----------------------------------------------------------------------------------------------------
dbOnMouseMoved(const CPoint & where,const CButtonState & buttons,int32_t row,int32_t column,CDataBrowser * browser)241 CMouseEventResult UIBitmapsDataSource::dbOnMouseMoved (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser)
242 {
243 	if (buttons.isLeftButton () && dragStartMouseObserver.shouldStartDrag (where))
244 	{
245 		if (auto bitmap = getSelectedBitmap ())
246 		{
247 			UIAttributes attr;
248 			attr.setAttribute (UIViewCreator::kAttrBitmap, getSelectedBitmapName ());
249 			attr.setPointAttribute (UIViewCreator::kAttrSize, bitmap->getSize ());
250 			const auto factory =
251 			    dynamic_cast<const UIViewFactory*> (description->getViewFactory ());
252 			if (auto selection = createSelectionFromViewName (UIViewCreator::kCView, factory,
253 			                                                  description, &attr))
254 			{
255 				CMemoryStream stream (1024, 1024, false);
256 				if (selection->store (stream, description))
257 				{
258 					stream.end ();
259 					auto dropSource = CDropSource::create (stream.getBuffer (),
260 					                                       static_cast<uint32_t> (stream.tell ()),
261 					                                       CDropSource::kText);
262 					browser->doDrag (DragDescription (dropSource, {}, bitmap));
263 					return kMouseMoveEventHandledButDontNeedMoreEvents;
264 				}
265 			}
266 		}
267 	}
268 	return kMouseEventHandled;
269 }
270 
271 //----------------------------------------------------------------------------------------------------
dbOnDragEnterBrowser(IDataPackage * drag,CDataBrowser * browser)272 void UIBitmapsDataSource::dbOnDragEnterBrowser (IDataPackage* drag, CDataBrowser* browser)
273 {
274 	uint32_t index = 0;
275 	IDataPackage::Type type;
276 	const void* item = nullptr;
277 	while (drag->getData (index, item, type) > 0)
278 	{
279 		if (type == IDataPackage::kFilePath)
280 		{
281 			const char* ext = strrchr (static_cast<const char*> (item), '.');
282 			if (ext)
283 			{
284 				std::string extStr (ext);
285 				std::transform (extStr.begin (), extStr.end (), extStr.begin (), ::tolower);
286 				if (extStr == ".png" || extStr == ".bmp" || extStr == ".jpg" || extStr == ".jpeg")
287 				{
288 					dragContainsBitmaps = true;
289 					break;
290 				}
291 			}
292 		}
293 		index++;
294 	}
295 	if (dragContainsBitmaps)
296 		browser->getFrame ()->setCursor (kCursorCopy);
297 }
298 
299 //----------------------------------------------------------------------------------------------------
dbOnDragExitBrowser(IDataPackage * drag,CDataBrowser * browser)300 void UIBitmapsDataSource::dbOnDragExitBrowser (IDataPackage* drag, CDataBrowser* browser)
301 {
302 	if (dragContainsBitmaps)
303 		browser->getFrame ()->setCursor (kCursorNotAllowed);
304 }
305 
306 //----------------------------------------------------------------------------------------------------
dbOnDragEnterCell(int32_t row,int32_t column,const CPoint & where,IDataPackage * drag,CDataBrowser * browser)307 DragOperation UIBitmapsDataSource::dbOnDragEnterCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser)
308 {
309 	return dragContainsBitmaps ? DragOperation::Copy : DragOperation::None;
310 }
311 
312 //----------------------------------------------------------------------------------------------------
dbOnDragExitCell(int32_t row,int32_t column,IDataPackage * drag,CDataBrowser * browser)313 void UIBitmapsDataSource::dbOnDragExitCell (int32_t row, int32_t column, IDataPackage* drag, CDataBrowser* browser)
314 {
315 }
316 
317 //----------------------------------------------------------------------------------------------------
dbOnDropInCell(int32_t row,int32_t column,const CPoint & where,IDataPackage * drag,CDataBrowser * browser)318 bool UIBitmapsDataSource::dbOnDropInCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser)
319 {
320 	if (!dragContainsBitmaps)
321 		return false;
322 
323 	bool didBeganGroupAction = false;
324 	uint32_t index = 0;
325 	IDataPackage::Type type;
326 	const void* item = nullptr;
327 	UTF8String firstNewBitmapName;
328 	while (drag->getData (index++, item, type) > 0)
329 	{
330 		if (type == IDataPackage::kFilePath)
331 		{
332 			auto path = static_cast<UTF8StringPtr> (item);
333 			const char* ext = strrchr (path, '.');
334 			if (ext)
335 			{
336 				std::string extStr (ext);
337 				std::transform (extStr.begin (), extStr.end (), extStr.begin (), ::tolower);
338 				if (extStr == ".png" || extStr == ".bmp" || extStr == ".jpg" || extStr == ".jpeg")
339 				{
340 					if (!didBeganGroupAction)
341 					{
342 						actionPerformer->beginGroupAction ("Add Bitmaps");
343 						didBeganGroupAction = true;
344 					}
345 					std::string name;
346 					addBitmap (path, name);
347 					if (firstNewBitmapName.empty ())
348 						firstNewBitmapName = name;
349 				}
350 			}
351 		}
352 	}
353 	if (didBeganGroupAction)
354 	{
355 		actionPerformer->finishGroupAction ();
356 		vstgui_assert (!firstNewBitmapName.empty ());
357 		selectName (firstNewBitmapName);
358 	}
359 	dragContainsBitmaps = false;
360 	return true;
361 }
362 
363 //----------------------------------------------------------------------------------------------------
getNames(std::list<const std::string * > & names)364 void UIBitmapsDataSource::getNames (std::list<const std::string*>& names)
365 {
366 	description->collectBitmapNames (names);
367 }
368 
369 //----------------------------------------------------------------------------------------------------
addItem(UTF8StringPtr name)370 bool UIBitmapsDataSource::addItem (UTF8StringPtr name)
371 {
372 	actionPerformer->performBitmapChange (name, nullptr);
373 	return true;
374 }
375 
376 //----------------------------------------------------------------------------------------------------
removeItem(UTF8StringPtr name)377 bool UIBitmapsDataSource::removeItem (UTF8StringPtr name)
378 {
379 	actionPerformer->performBitmapChange (name, nullptr, true);
380 	return true;
381 }
382 
383 //----------------------------------------------------------------------------------------------------
performNameChange(UTF8StringPtr oldName,UTF8StringPtr newName)384 bool UIBitmapsDataSource::performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
385 {
386 	actionPerformer->performBitmapNameChange (oldName, newName);
387 	return true;
388 }
389 
390 //----------------------------------------------------------------------------------------------------
getSelectedBitmap()391 CBitmap* UIBitmapsDataSource::getSelectedBitmap ()
392 {
393 	int32_t selectedRow = dataBrowser ? dataBrowser->getSelectedRow() : CDataBrowser::kNoSelection;
394 	if (selectedRow != CDataBrowser::kNoSelection && selectedRow < (int32_t)names.size ())
395 		return description->getBitmap (names.at (static_cast<uint32_t> (selectedRow)).data ());
396 	return nullptr;
397 }
398 
399 //----------------------------------------------------------------------------------------------------
getSelectedBitmapName()400 UTF8StringPtr UIBitmapsDataSource::getSelectedBitmapName ()
401 {
402 	int32_t selectedRow = dataBrowser ? dataBrowser->getSelectedRow() : CDataBrowser::kNoSelection;
403 	if (selectedRow != CDataBrowser::kNoSelection && selectedRow < (int32_t)names.size ())
404 		return names.at (static_cast<uint32_t> (selectedRow)).data ();
405 	return nullptr;
406 }
407 
408 //----------------------------------------------------------------------------------------------------
addBitmap(UTF8StringPtr path,std::string & outName)409 bool UIBitmapsDataSource::addBitmap (UTF8StringPtr path, std::string& outName)
410 {
411 	bool result = false;
412 	outName = path;
413 	unixfyPath (outName);
414 	size_t index = outName.find_last_of (unixPathSeparator);
415 	outName.erase (0, index+1);
416 	index = outName.find_last_of ('.');
417 	if (index == std::string::npos)
418 		return false;
419 
420 	outName.erase (index);
421 	if (createUniqueName (outName))
422 	{
423 		std::string pathStr (path);
424 		UTF8StringPtr descPath = description->getFilePath ();
425 		if (descPath && descPath[0] != 0)
426 		{
427 			std::string descPathStr (descPath);
428 			unixfyPath (descPathStr);
429 			if (removeLastPathComponent (descPathStr))
430 			{
431 				if (pathStr.find (descPathStr) == 0)
432 				{
433 					pathStr.erase (0, descPathStr.length () + 1);
434 				}
435 			}
436 		}
437 		actionPerformer->performBitmapChange (outName.data (), pathStr.data ());
438 		result = true;
439 	}
440 	return result;
441 }
442 
443 //----------------------------------------------------------------------------------------------------
add()444 bool UIBitmapsDataSource::add ()
445 {
446 	bool result = false;
447 	auto fs = owned (CNewFileSelector::create (dataBrowser->getFrame ()));
448 	if (fs)
449 	{
450 		fs->addFileExtension (CFileExtension ("PNG", "PNG", "image/png"));
451 		fs->setAllowMultiFileSelection (true);
452 		if (fs->runModal ())
453 		{
454 			auto numFiles = static_cast<uint32_t> (fs->getNumSelectedFiles ());
455 			if (numFiles > 1)
456 				actionPerformer->beginGroupAction ("Add Bitmaps");
457 			for (uint32_t i = 0; i < numFiles; i++)
458 			{
459 				UTF8StringPtr path = fs->getSelectedFile (i);
460 				if (path)
461 				{
462 					std::string newName;
463 					if (addBitmap (path, newName) && i == numFiles - 1)
464 					{
465 						int32_t row = selectName (newName.data ());
466 						if (row != -1)
467 							dbOnMouseDown (CPoint (0, 0), CButtonState (kLButton|kDoubleClick), row, 0, dataBrowser);
468 						result = true;
469 					}
470 				}
471 			}
472 			if (numFiles > 1)
473 				actionPerformer->finishGroupAction ();
474 		}
475 	}
476 	return result;
477 }
478 
479 //----------------------------------------------------------------------------------------------------
480 //----------------------------------------------------------------------------------------------------
481 //----------------------------------------------------------------------------------------------------
482 class UIBitmapSettingsController : public NonAtomicReferenceCounted,
483                                    public IDialogController,
484                                    public IController
485 {
486 public:
487 	UIBitmapSettingsController (CBitmap* bitmap, const std::string& bitmapName, UIDescription* description, IActionPerformer* actionPerformer);
488 	~UIBitmapSettingsController () noexcept override = default;
489 
490 	CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
491 	CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
492 	void valueChanged (CControl* pControl) override;
493 	void controlBeginEdit (CControl* pControl) override;
494 	void controlEndEdit (CControl* pControl) override;
495 
496 	void onDialogButton1Clicked (UIDialogController*) override;
497 	void onDialogButton2Clicked (UIDialogController*) override;
498 	void onDialogShow (UIDialogController*) override;
499 protected:
500 	void updateNinePartTiledControls ();
501 	static bool stringToValue (UTF8StringPtr txt, float& result, CTextEdit::StringToValueUserData* userData);
502 	static bool valueToString (float value, char utf8String[256], CParamDisplay::ValueToStringUserData* userData);
503 
504 	SharedPointer<CBitmap> bitmap;
505 	SharedPointer<UIDescription> editDescription;
506 	SharedPointer<UIBitmapView> bitmapView;
507 	IActionPerformer* actionPerformer;
508 	std::string bitmapName;
509 	CRect origOffsets;
510 
511 	enum {
512 		kBitmapPathTag,
513 		kBitmapWidthTag,
514 		kBitmapHeightTag,
515 		kNinePartTiledTag,
516 		kNinePartTiledLeftTag,
517 		kNinePartTiledTopTag,
518 		kNinePartTiledRightTag,
519 		kNinePartTiledBottomTag,
520 		kZoomTag,
521 		kZoomTextTag,
522 		kNumTags
523 	};
524 	CControl* controls[kNumTags];
525 };
526 
527 //----------------------------------------------------------------------------------------------------
UIBitmapSettingsController(CBitmap * bitmap,const std::string & bitmapName,UIDescription * description,IActionPerformer * actionPerformer)528 UIBitmapSettingsController::UIBitmapSettingsController (CBitmap* bitmap, const std::string& bitmapName, UIDescription* description, IActionPerformer* actionPerformer)
529 : bitmap (bitmap)
530 , editDescription (description)
531 , actionPerformer (actionPerformer)
532 , bitmapName (bitmapName)
533 , origOffsets (10, 10, 10, 10)
534 {
535 	for (auto& control : controls)
536 		control = nullptr;
537 }
538 
539 //----------------------------------------------------------------------------------------------------
updateNinePartTiledControls()540 void UIBitmapSettingsController::updateNinePartTiledControls ()
541 {
542 	auto* nptb = bitmap.cast<CNinePartTiledBitmap> ();
543 	if (nptb)
544 	{
545 		controls[kNinePartTiledTag]->setValueNormalized (1);
546 		const CNinePartTiledDescription& offsets = nptb->getPartOffsets ();
547 		controls[kNinePartTiledLeftTag]->setValue ((float)offsets.left);
548 		controls[kNinePartTiledTopTag]->setValue ((float)offsets.top);
549 		controls[kNinePartTiledRightTag]->setValue ((float)offsets.right);
550 		controls[kNinePartTiledBottomTag]->setValue ((float)offsets.bottom);
551 	}
552 	else
553 	{
554 		controls[kNinePartTiledTag]->setValueNormalized (0.);
555 		for (int32_t i = kNinePartTiledLeftTag; i <= kNinePartTiledBottomTag; i++)
556 		{
557 			auto* label = dynamic_cast<CTextLabel*>(controls[i]);
558 			if (label)
559 				label->setText ("");
560 		}
561 	}
562 	for (int32_t i = kNinePartTiledLeftTag; i <= kNinePartTiledBottomTag; i++)
563 	{
564 		controls[i]->setMouseEnabled (nptb ? true : false);
565 	}
566 }
567 
568 //----------------------------------------------------------------------------------------------------
valueChanged(CControl * control)569 void UIBitmapSettingsController::valueChanged (CControl* control)
570 {
571 	switch (control->getTag ())
572 	{
573 		case kBitmapPathTag:
574 		{
575 			auto* edit = dynamic_cast<CTextEdit*>(control);
576 			if (edit)
577 			{
578 				actionPerformer->performBitmapChange (bitmapName.data (), edit->getText ());
579 				bitmap = editDescription->getBitmap (bitmapName.data ());
580 				bitmapView->setBackground (bitmap);
581 				updateNinePartTiledControls ();
582 			}
583 			break;
584 		}
585 		case kNinePartTiledTag:
586 		{
587 			auto* nptb = bitmap.cast<CNinePartTiledBitmap> ();
588 			if (nptb)
589 			{
590 				origOffsets.left = nptb->getPartOffsets ().left;
591 				origOffsets.top = nptb->getPartOffsets ().top;
592 				origOffsets.right = nptb->getPartOffsets ().right;
593 				origOffsets.bottom = nptb->getPartOffsets ().bottom;
594 			}
595 			bool checked = control->getValue () == control->getMax ();
596 			actionPerformer->performBitmapNinePartTiledChange (bitmapName.data (), checked ? &origOffsets : nullptr);
597 			bitmap = editDescription->getBitmap (bitmapName.data ());
598 			bitmapView->setBackground (bitmap);
599 			updateNinePartTiledControls ();
600 			break;
601 		}
602 		case kNinePartTiledLeftTag:
603 		case kNinePartTiledTopTag:
604 		case kNinePartTiledRightTag:
605 		case kNinePartTiledBottomTag:
606 		{
607 			CRect r;
608 			r.left = controls[kNinePartTiledLeftTag]->getValue ();
609 			r.top = controls[kNinePartTiledTopTag]->getValue ();
610 			r.right = controls[kNinePartTiledRightTag]->getValue ();
611 			r.bottom = controls[kNinePartTiledBottomTag]->getValue ();
612 			actionPerformer->performBitmapNinePartTiledChange (bitmapName.data (), &r);
613 			bitmap = editDescription->getBitmap (bitmapName.data ());
614 			bitmapView->setBackground (bitmap);
615 			updateNinePartTiledControls ();
616 			SharedPointer<CTextEdit> textEdit = SharedPointer<CControl> (control).cast<CTextEdit> ();
617 			if (textEdit && textEdit->bWasReturnPressed)
618 			{
619 				textEdit->getFrame ()->doAfterEventProcessing ([=] () {
620 					textEdit->takeFocus ();
621 				});
622 			}
623 			break;
624 		}
625 		case kZoomTag:
626 		{
627 			CCoord zoom = floor (control->getValue () / 10. + 0.5);
628 			control->setValue ((float)zoom * 10.f);
629 			controls[kZoomTextTag]->setValue ((float)zoom * 10.f);
630 			bitmapView->setZoom (zoom / 10.);
631 			controls[kZoomTextTag]->invalid ();
632 			control->invalid ();
633 			break;
634 		}
635 	}
636 }
637 
638 //----------------------------------------------------------------------------------------------------
controlBeginEdit(CControl * control)639 void UIBitmapSettingsController::controlBeginEdit (CControl* control)
640 {
641 }
642 
643 //----------------------------------------------------------------------------------------------------
controlEndEdit(CControl * control)644 void UIBitmapSettingsController::controlEndEdit (CControl* control)
645 {
646 }
647 
648 //----------------------------------------------------------------------------------------------------
onDialogButton1Clicked(UIDialogController *)649 void UIBitmapSettingsController::onDialogButton1Clicked (UIDialogController*)
650 {
651 }
652 
653 //----------------------------------------------------------------------------------------------------
onDialogButton2Clicked(UIDialogController *)654 void UIBitmapSettingsController::onDialogButton2Clicked (UIDialogController*)
655 {
656 }
657 
658 //----------------------------------------------------------------------------------------------------
onDialogShow(UIDialogController *)659 void UIBitmapSettingsController::onDialogShow (UIDialogController*)
660 {
661 	bitmapView->setBackground (bitmap);
662 	updateNinePartTiledControls ();
663 }
664 
665 //----------------------------------------------------------------------------------------------------
verifyView(CView * view,const UIAttributes & attributes,const IUIDescription * description)666 CView* UIBitmapSettingsController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description)
667 {
668 	auto* control = dynamic_cast<CControl*>(view);
669 	if (control && control->getTag () >= 0 && control->getTag () < kNumTags)
670 	{
671 		controls[control->getTag ()] = control;
672 		switch (control->getTag ())
673 		{
674 			case kBitmapPathTag:
675 			{
676 				auto* bitmapPathEdit = dynamic_cast<CTextEdit*> (control);
677 				if (bitmapPathEdit)
678 					bitmapPathEdit->setText (bitmap->getResourceDescription ().u.name);
679 				break;
680 			}
681 			case kBitmapWidthTag:
682 			{
683 				auto* label = dynamic_cast<CTextLabel*>(control);
684 				if (label)
685 				{
686 					float width = bitmap->getPlatformBitmap () ? (float)bitmap->getPlatformBitmap ()->getSize ().x : 0.f;
687 					label->setPrecision (0);
688 					label->setMax (width);
689 					label->setValue (width);
690 					label->sizeToFit ();
691 				}
692 				break;
693 			}
694 			case kBitmapHeightTag:
695 			{
696 				auto* label = dynamic_cast<CTextLabel*>(control);
697 				if (label)
698 				{
699 					float height = bitmap->getPlatformBitmap () ? (float)bitmap->getPlatformBitmap ()->getSize ().y : 0.f;
700 					label->setPrecision (0);
701 					label->setMax (height);
702 					label->setValue (height);
703 					label->sizeToFit ();
704 					if (controls[kBitmapWidthTag])
705 					{
706 						CRect r = control->getViewSize ();
707 						if (controls[kBitmapWidthTag]->getWidth () > r.getWidth ())
708 						{
709 							r.setWidth (controls[kBitmapWidthTag]->getWidth ());
710 							control->setViewSize (r);
711 						}
712 						else
713 						{
714 							r = controls[kBitmapWidthTag]->getViewSize ();
715 							r.setWidth (control->getWidth ());
716 							controls[kBitmapWidthTag]->setViewSize (r);
717 						}
718 					}
719 				}
720 				break;
721 			}
722 			case kNinePartTiledLeftTag:
723 			case kNinePartTiledRightTag:
724 			{
725 				auto* textEdit = dynamic_cast<CTextEdit*>(control);
726 				if (textEdit)
727 				{
728 					textEdit->setPrecision (0);
729 					textEdit->setStringToValueFunction (stringToValue);
730 				}
731 				control->setMax ((float)bitmap->getWidth ());
732 				break;
733 			}
734 			case kNinePartTiledTopTag:
735 			case kNinePartTiledBottomTag:
736 			{
737 				auto* textEdit = dynamic_cast<CTextEdit*>(control);
738 				if (textEdit)
739 				{
740 					textEdit->setPrecision (0);
741 					textEdit->setStringToValueFunction (stringToValue);
742 				}
743 				control->setMax ((float)bitmap->getHeight ());
744 				break;
745 			}
746 			case kZoomTag:
747 			{
748 				control->setValue (100);
749 				break;
750 			}
751 			case kZoomTextTag:
752 			{
753 				auto* label = dynamic_cast<CTextLabel*>(control);
754 				if (label)
755 				{
756 					label->setValueToStringFunction (valueToString);
757 				}
758 				control->setValue (100);
759 			}
760 		}
761 	}
762 	return view;
763 }
764 
765 //----------------------------------------------------------------------------------------------------
createView(const UIAttributes & attributes,const IUIDescription * description)766 CView* UIBitmapSettingsController::createView (const UIAttributes& attributes, const IUIDescription* description)
767 {
768 	const std::string* name = attributes.getAttributeValue (IUIDescription::kCustomViewName);
769 	if (name)
770 	{
771 		if (*name == "BitmapView")
772 		{
773 			bitmapView = new UIBitmapView ();
774 			return bitmapView;
775 		}
776 	}
777 	return nullptr;
778 }
779 
780 //----------------------------------------------------------------------------------------------------
valueToString(float value,char utf8String[256],CParamDisplay::ValueToStringUserData * userData)781 bool UIBitmapSettingsController::valueToString (float value, char utf8String[256], CParamDisplay::ValueToStringUserData* userData)
782 {
783 	auto intValue = (int32_t)value;
784 	std::stringstream str;
785 	str << intValue;
786 	str << "%";
787 	std::strcpy (utf8String, str.str ().data ());
788 	return true;
789 }
790 
791 
792 //----------------------------------------------------------------------------------------------------
stringToValue(UTF8StringPtr txt,float & result,CTextEdit::StringToValueUserData * userData)793 bool UIBitmapSettingsController::stringToValue (UTF8StringPtr txt, float& result, CTextEdit::StringToValueUserData* userData)
794 {
795 	int32_t value = txt ? (int32_t)strtol (txt, nullptr, 10) : 0;
796 	result = (float)value;
797 	return true;
798 }
799 
800 //----------------------------------------------------------------------------------------------------
801 //----------------------------------------------------------------------------------------------------
802 //----------------------------------------------------------------------------------------------------
UIBitmapsController(IController * baseController,UIDescription * description,IActionPerformer * actionPerformer)803 UIBitmapsController::UIBitmapsController (IController* baseController, UIDescription* description, IActionPerformer* actionPerformer)
804 : DelegationController (baseController)
805 , editDescription (description)
806 , actionPerformer (actionPerformer)
807 , dataSource (nullptr)
808 {
809 	dataSource = new UIBitmapsDataSource (editDescription, actionPerformer, this);
810 	UIEditController::setupDataSource (dataSource);
811 }
812 
813 //----------------------------------------------------------------------------------------------------
~UIBitmapsController()814 UIBitmapsController::~UIBitmapsController ()
815 {
816 	dataSource->forget ();
817 }
818 
819 //----------------------------------------------------------------------------------------------------
showSettingsDialog()820 void UIBitmapsController::showSettingsDialog ()
821 {
822 	auto* dc = new UIDialogController (this, bitmapPathEdit->getFrame ());
823 	auto fsController = makeOwned<UIBitmapSettingsController> (dataSource->getSelectedBitmap (),
824 	                                                           dataSource->getSelectedBitmapName (),
825 	                                                           editDescription, actionPerformer);
826 	dc->run ("bitmap.settings", "Bitmap Settings", "Close", nullptr, fsController,
827 	         UIEditController::getEditorDescription ());
828 }
829 
830 //----------------------------------------------------------------------------------------------------
createView(const UIAttributes & attributes,const IUIDescription * description)831 CView* UIBitmapsController::createView (const UIAttributes& attributes, const IUIDescription* description)
832 {
833 	const std::string* name = attributes.getAttributeValue (IUIDescription::kCustomViewName);
834 	if (name)
835 	{
836 		if (*name == "BitmapsBrowser")
837 		{
838 			CDataBrowser* dataBrowser = new CDataBrowser (CRect (0, 0, 0, 0), dataSource, CDataBrowser::kDrawRowLines|CScrollView::kHorizontalScrollbar | CScrollView::kVerticalScrollbar);
839 			return dataBrowser;
840 		}
841 		else if (*name == "BitmapView")
842 		{
843 			bitmapView = new UIBitmapView ();
844 			return bitmapView;
845 		}
846 	}
847 	return DelegationController::createView (attributes, description);
848 }
849 
850 //----------------------------------------------------------------------------------------------------
verifyView(CView * view,const UIAttributes & attributes,const IUIDescription * description)851 CView* UIBitmapsController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description)
852 {
853 	auto searchField = dynamic_cast<CSearchTextEdit*>(view);
854 	if (searchField && searchField->getTag () == kSearchTag)
855 	{
856 		dataSource->setSearchFieldControl (searchField);
857 		return searchField;
858 	}
859 	auto* textEdit = dynamic_cast<CTextEdit*>(view);
860 	if (textEdit)
861 	{
862 		switch (textEdit->getTag ())
863 		{
864 			case kBitmapPathTag:
865 			{
866 				bitmapPathEdit = textEdit;
867 				textEdit->setMouseEnabled (false);
868 				break;
869 			}
870 		}
871 	}
872 	else
873 	{
874 		auto* control = dynamic_cast<CControl*> (view);
875 		if (control)
876 		{
877 			if (control->getTag () == kSettingsTag)
878 			{
879 				settingButton = control;
880 				settingButton->setMouseEnabled (false);
881 			}
882 		}
883 	}
884 	return DelegationController::verifyView (view, attributes, description);
885 }
886 
887 //----------------------------------------------------------------------------------------------------
getControlListener(UTF8StringPtr name)888 IControlListener* UIBitmapsController::getControlListener (UTF8StringPtr name)
889 {
890 	return this;
891 }
892 
893 //----------------------------------------------------------------------------------------------------
valueChanged(CControl * pControl)894 void UIBitmapsController::valueChanged (CControl* pControl)
895 {
896 	switch (pControl->getTag ())
897 	{
898 		case kAddTag:
899 		{
900 			if (pControl->getValue () == pControl->getMax ())
901 			{
902 				dataSource->add ();
903 			}
904 			break;
905 		}
906 		case kRemoveTag:
907 		{
908 			if (pControl->getValue () == pControl->getMax ())
909 			{
910 				dataSource->remove ();
911 			}
912 			break;
913 		}
914 		case kBitmapPathTag:
915 		{
916 			UTF8StringPtr bitmapName = dataSource->getSelectedBitmapName ();
917 			if (bitmapName)
918 			{
919 				auto* edit = dynamic_cast<CTextEdit*>(pControl);
920 				if (edit)
921 					actionPerformer->performBitmapChange (bitmapName, edit->getText ());
922 			}
923 			break;
924 		}
925 		case kSettingsTag:
926 		{
927 			if (pControl->getValue () == pControl->getMax ())
928 			{
929 				showSettingsDialog ();
930 			}
931 			break;
932 		}
933 	}
934 }
935 
936 //----------------------------------------------------------------------------------------------------
dbSelectionChanged(int32_t selectedRow,GenericStringListDataBrowserSource * source)937 void UIBitmapsController::dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source)
938 {
939 	if (dataSource)
940 	{
941 		CBitmap* bitmap = dataSource->getSelectedBitmap ();
942 		UTF8StringPtr selectedBitmapName = dataSource->getSelectedBitmapName ();
943 		if (bitmapView)
944 		{
945 			bitmapView->setBackground (bitmap);
946 			if (bitmapView->getParentView ())
947 				bitmapView->getParentView ()->invalid ();
948 		}
949 		if (bitmapPathEdit)
950 		{
951 			bitmapPathEdit->setText (bitmap ? bitmap->getResourceDescription ().u.name : nullptr);
952 			bitmapPathEdit->setMouseEnabled (selectedBitmapName ? true : false);
953 		}
954 		if (settingButton)
955 		{
956 			settingButton->setMouseEnabled (selectedBitmapName ? true : false);
957 		}
958 	}
959 }
960 
961 //----------------------------------------------------------------------------------------------------
dbRowDoubleClick(int32_t row,GenericStringListDataBrowserSource * source)962 void UIBitmapsController::dbRowDoubleClick (int32_t row, GenericStringListDataBrowserSource* source)
963 {
964 	showSettingsDialog ();
965 }
966 
967 //----------------------------------------------------------------------------------------------------
valueToString(float value,char utf8String[256],void * userData)968 bool UIBitmapsController::valueToString (float value, char utf8String[256], void* userData)
969 {
970 	auto intValue = (int32_t)value;
971 	std::stringstream str;
972 	str << intValue;
973 	std::strcpy (utf8String, str.str ().data ());
974 	return true;
975 }
976 
977 //----------------------------------------------------------------------------------------------------
stringToValue(UTF8StringPtr txt,float & result,void * userData)978 bool UIBitmapsController::stringToValue (UTF8StringPtr txt, float& result, void* userData)
979 {
980 	int32_t value = txt ? (int32_t)strtol (txt, nullptr, 10) : 0;
981 	result = (float)value;
982 	return true;
983 }
984 
985 } // VSTGUI
986 
987 #endif // VSTGUI_LIVE_EDITING
988