1 module theme.manager;
2 
3 import theme.layout;
4 import gui.font;
5 import config;
6 import cboxapp;
7 import window;
8 import types;
9 import gui.bar;
10 import kernel;
11 
12 import std.algorithm;
13 import std.c..string;
14 import deimos.X11.X;
15 import deimos.X11.Xlib;
16 import deimos.X11.keysymdef;
17 import deimos.X11.Xutil;
18 import deimos.X11.Xatom;
19 
20 /* color schemes */
21 enum 
22 { 
23     SchemeNorm, 
24     SchemeSel, 
25     SchemeLast 
26 }; 
27 
28 /// The colour scheme to use
29 struct ClrScheme 
30 {
31     Clr *fg;
32     Clr *bg;
33     Clr *border;
34 }
35 
36 class ThemeManager 
37 {   
38   
39   ClrScheme[SchemeLast] scheme;
40 
41   static ThemeManager instance() 
42   {
43     if (!instantiated_) {
44       synchronized {
45         if (instance_ is null) {
46           instance_ = new ThemeManager;
47         }
48         instantiated_ = true;
49       }
50     }
51     return instance_;
52   }
53 
54   void setlayout(const Arg *arg) 
55   {
56         if(!arg || !arg.v || arg.v != selmon.lt[selmon.sellt])
57             selmon.sellt ^= 1;
58 
59         if(arg && arg.v) {
60             selmon.lt[selmon.sellt] = cast(Layout *)arg.v;
61         }
62 
63         selmon.ltsymbol = selmon.lt[selmon.sellt].symbol;
64 
65         if(selmon.sel)
66             arrange(selmon);
67         else
68             drawbar(selmon);
69     }
70 
71   ClrScheme getScheme(int type)
72   {
73      return this.scheme[type];
74   }
75 
76 
77  private:
78   this() 
79   {
80         /* init appearance */
81         scheme[SchemeNorm].border = new Clr(drw, normbordercolor);
82         scheme[SchemeNorm].bg = new Clr(drw, normbgcolor);
83         scheme[SchemeNorm].fg = new Clr(drw, normfgcolor);
84         scheme[SchemeSel].border = new Clr(drw, selbordercolor);
85         scheme[SchemeSel].bg = new Clr(drw, selbgcolor);
86         scheme[SchemeSel].fg = new Clr(drw, selfgcolor);  
87   }
88 
89   static bool instantiated_;  // Thread local
90   __gshared ThemeManager instance_;
91 
92  }
93 
94 /**
95  * Drw provides an interface for working with drawable surfaces.
96  */
97 struct Drw 
98 {
99     uint w, h; /// The width and height of the drawable area
100     Display *dpy; /// The X display
101     int screen; /// The X screen ID
102     Window root; /// The root window for this drawable
103     Drawable drawable; /// The X drawable encapsulated by this.
104     XGC gc; /// The X graphic context
105     ClrScheme *scheme; /// The colour scheme to use
106     Fnt *font; /// The X font to use for rendering text.
107 
108     /**
109      * Ctor to initialise the draw object
110      * Params:
111      *  dpy=        X display to render with.
112      *  screen=     X screen id
113      *  root=       Root X window for this drawable
114      *  w=          Width of the drawable
115      *  h=          Height of the drawable
116      * Example:
117      * ---
118      * drw = new Drw(AppDisplay.instance().dpy, screen, root, sw, sh);
119      * ---
120      */
121     this(Display* dpy, int screen, Window root, uint w, uint h) 
122     {
123         this.dpy = dpy;
124         this.screen = screen;
125         this.root = root;
126         this.w = w;
127         this.h = h;
128         this.drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
129         this.gc = XCreateGC(dpy, root, 0, null);
130         XSetLineAttributes(dpy, this.gc, 1, LineSolid, CapButt, JoinMiter);
131 
132     }
133 
134     /**
135      * Resize the drawable to a new width and height
136      * Params:
137      *  w=      Width
138      *  h=      Height
139      * Example:
140      * ---
141      * drw.resize(100, 100);
142      * ---
143      */
144     void resize(uint w, uint h)
145      {
146         this.w = w;
147         this.h = h;
148         if(this.drawable != 0) {
149             XFreePixmap(this.dpy, this.drawable);
150         }
151         this.drawable = XCreatePixmap(this.dpy, this.root, w, h, DefaultDepth(this.dpy, this.screen));
152     }
153 
154     /**
155      * Set the font to use for rendering.
156      * Params:
157      *  font=       Pointer to the font to use.
158      */
159     void setfont(Fnt *font) 
160     {
161         this.font = font;
162     }
163 
164     /**
165      * Set the scheme for this drawable
166      * Params:
167      *  scheme = Pointer to the scheme to use
168      */
169     void setscheme(ClrScheme *scheme)
170     {
171         if(scheme)
172             this.scheme = scheme;
173     }
174 
175     /**
176      * Draw a rectangle to the X display using the current settings. Note that
177      * filled and empty are not mutually exclusive.
178      * Params:
179      *  x=      Left edge of the rect
180      *  y=      Top edge of the rect
181      *  w=      Width of the rect
182      *  h=      Height of the rect
183      *  filled= If true the rect will be filled
184      *  empty=  If true the rect will be empty
185      *  invert= If true the colours will be inverted.
186      * Example:
187      * ---
188      * drw.rect(10, 10, 90, 90, true, false, false);
189      * ---
190      */
191     void rect(int x, int y, uint w, uint h, int filled, int empty, int invert) 
192     {
193         int dx;
194 
195         if(!this.font || !this.scheme)
196             return;
197         XSetForeground(this.dpy, this.gc, invert ? this.scheme.bg.rgb : this.scheme.fg.rgb);
198         dx = (this.font.ascent + this.font.descent + 2) / 4;
199         if(filled)
200             XFillRectangle(this.dpy, this.drawable, this.gc, x+1, y+1, dx+1, dx+1);
201         else if(empty)
202             XDrawRectangle(this.dpy, this.drawable, this.gc, x+1, y+1, dx, dx);
203     }
204 
205     /**
206      * Render some text to the display using the current font.
207      * Params:
208      *  x=      Left edge of the text area
209      *  y=      Top of the text area
210      *  w=      Width of the text area
211      *  h=      Height of the text area
212      *  text=   Text to write
213      *  invert= true the text bg/fg coluors will be inverted
214      * Example:
215      * ---
216      * drw.text(10, 10, 100, 100, "this is a test", false);
217      * ---
218      */
219     void text(int x, int y, uint w, uint h, in string text, int invert) 
220     {
221         char[256] buf;
222         Extnts tex;
223 
224         if(!this.scheme) {
225             return;
226         }
227         XSetForeground(this.dpy, this.gc, invert ? this.scheme.fg.rgb : this.scheme.bg.rgb);
228         XFillRectangle(this.dpy, this.drawable, this.gc, x, y, w, h);
229         if(!text || !this.font) {
230             return;
231         }
232         this.font.getexts(text, &tex);
233         auto th = this.font.ascent + this.font.descent;
234         auto ty = y + (h / 2) - (th / 2) + this.font.ascent;
235         auto tx = x + (h / 2);
236         /* shorten text if necessary */
237         auto len = min(text.length, buf.sizeof);        
238         for(; len && (tex.w > w - tex.h || w < tex.h); len--) {
239             this.font.getexts(text[0..len], &tex);
240         }
241         if(!len) {
242             return;
243         }
244         memcpy(buf.ptr, text.ptr, len);
245 
246         XSetForeground(this.dpy, this.gc, invert ? this.scheme.bg.rgb : this.scheme.fg.rgb);
247         if(this.font.set)
248             XmbDrawString(this.dpy, this.drawable, this.font.set, this.gc, tx, ty, buf.ptr, cast(uint)(len));
249         else
250             XDrawString(this.dpy, this.drawable, this.gc, tx, ty, buf.ptr, cast(int)len);
251     }
252 
253     /**
254      * Copy the drawable area to a window.
255      * Params:
256      *  win= Destination to copy to.
257      *  x=      Left edge of area to copy
258      *  y=      Top of area to copy
259      *  w=      Width of area to copy
260      *  h=      Height of area to copy
261      * Example:
262      * ---
263      * drw.map(win, 10, 10, 100, 100);
264      * ---
265      */
266     void map(Window win, int x, int y, uint w, uint h) 
267     {
268         XCopyArea(this.dpy, this.drawable, win, this.gc, x, y, w, h, x, y);
269         XSync(this.dpy, false);
270     }
271 
272     /**
273      * Release the GC memory used for the Drw object
274      * Params:
275      *  drw = Drw object to release
276      */
277     static void free(Drw* drw) 
278     {
279         drw.destroy;
280         DGC.free(drw);
281     }
282 
283     /**
284      * Destroy the X resources used by this drawable.
285      */
286     void destroy() 
287     {
288         XFreePixmap(this.dpy, this.drawable);
289         XFreeGC(this.dpy, this.gc);
290     }
291 
292 }