1 /**
2 The root widget to inherit from for a flat UI.
3 
4 Copyright: Guillaume Piolat 2015-2018.
5 Copyright: Ethan Reker 2017.
6 License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 */
8 module dplug.flatwidgets.flatbackgroundgui;
9 
10 import dplug.math.box;
11 import dplug.core.nogc;
12 import dplug.core.file;
13 import dplug.graphics;
14 
15 import dplug.core.nogc;
16 import dplug.gui.graphics;
17 import dplug.gui.element;
18 public import dplug.gui.sizeconstraints;
19 
20 
21 /// FlatBackgroundGUI provides a background that is loaded from a PNG or JPEG
22 /// image. The string for backgroundPath should be in "stringImportPaths"
23 /// specified in dub.json
24 class FlatBackgroundGUI(string backgroundPath,
25                         string absoluteGfxDirectory = null // for UI development only
26                         ) : GUIGraphics
27 {
28 public:
29 nothrow:
30 @nogc:
31 
32     this(int width, int height)
33     {
34         this(makeSizeConstraintsFixed(width, height));
35     }
36 
37     this(SizeConstraints sizeConstraints)
38     {
39         super(sizeConstraints, flagRaw | flagAnimated);
40         _backgroundImageResized = mallocNew!(OwnedImage!RGBA)();
41         loadBackgroundImageFromStaticData();
42     }
43     
44     ~this()
45     {
46         freeBackgroundImage();
47         _backgroundImageResized.destroyFree();
48     }
49     
50     override void reflow()
51     {
52     }
53     
54     override void onDrawRaw(ImageRef!RGBA rawMap, box2i[] dirtyRects)
55     {
56         // Resize resources to match actual size.
57         {
58             int W = position.width;
59             int H = position.height;
60             if (_forceResizeUpdate || _backgroundImageResized.w != W || _backgroundImageResized.h != H)
61             {
62                 _backgroundImageResized.size(W, H);
63                 ImageResizer resizer;
64                 resizer.resizeImage_sRGBNoAlpha(_backgroundImage.toRef, _backgroundImageResized.toRef);
65                 _forceResizeUpdate = false;
66             }
67         }
68 
69         ImageRef!RGBA backgroundRef = _backgroundImageResized.toRef();
70 
71         foreach(dirtyRect; dirtyRects)
72         {
73             ImageRef!RGBA croppedRawIn = backgroundRef.cropImageRef(dirtyRect);
74             ImageRef!RGBA croppedRawOut = rawMap.cropImageRef(dirtyRect);
75             croppedRawIn.blitTo(croppedRawOut);
76         }
77     }
78 
79     // Development purposes.
80     // If this version is enabled, you could press ENTER to
81     // reload the backgrounds. Do not ship this!
82     version(Dplug_EnterReloadBackgrounds)
83     {
84         override bool onKeyDown(Key key)
85         {
86             if (super.onKeyDown(key))
87                 return true;
88 
89             if (key == Key.enter)
90             {
91                 reloadImageAtRuntime();
92                 return true;
93             }
94 
95             return false;
96         }
97     }
98 
99 private:
100     OwnedImage!RGBA _backgroundImage, _backgroundImageResized;
101 
102     /// Where pixel data is taken in the image, expressed in _background coordinates.
103     box2i _sourceRect;
104 
105     /// Where it is deposited. Same size than _sourceRect. Expressed in _position coordinates.
106     box2i _destRect;
107 
108     /// Offset from source to dest.
109     vec2i _offset;
110 
111     /// Force resize of source image in order to display changes while editing files.
112     bool _forceResizeUpdate;
113 
114     static immutable string backgroundPathAbs = absoluteGfxDirectory ~ backgroundPath;
115 
116     final void loadBackgroundImageFromStaticData()
117     {
118         auto backgroundData = cast(ubyte[])(import(backgroundPath));
119         loadBackgroundImage(backgroundData);
120     }
121 
122     // Reloads image for UI development.
123     final void reloadImageAtRuntime()
124     {
125         // reading images with an absolute path since we don't know 
126         // which is the current directory from the host
127         ubyte[] backgroundData = readFile(backgroundPathAbs);
128 
129         if (backgroundData)
130         {
131             // Reload images from disk and update the UI
132             freeBackgroundImage();
133             loadBackgroundImage(backgroundData);
134             _forceResizeUpdate = true;
135             setDirtyWhole();
136         }
137         else
138         {
139             // Note: if you fail here, the absolute path you provided in your gui.d was incorrect.
140             // The background files cannot be loaded at runtime, and you have to fix your pathes.
141             assert(false);
142         }
143 
144         freeSlice(backgroundData);
145     }
146 
147     final void loadBackgroundImage(ubyte[] backgroundData)
148     {
149         _backgroundImage = loadOwnedImage(backgroundData);
150     }
151 
152     void freeBackgroundImage()
153     {
154         if (_backgroundImage)
155         {
156             _backgroundImage.destroyFree();
157             _backgroundImage = null;
158         }
159     }
160 }