Gui.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. struct QueuedMsgBox // queue these commands for thread-safety, this is so that 'Gui.msgBox' does not require 'Gui.cs' lock, this is important in case for example the main thread is deleting a thread inside a 'Gui.update' callback "Gui.update -> thread.del()" while that thread is "if(thread.wantStop())Gui.msgBox(failed)" calling 'Gui.msgBox' would require 'Gui.cs' lock which is already locked on the main thread
  6. {
  7. Str title, text;
  8. TextStylePtr text_style;
  9. void set(C Str &title, C Str &text, C TextStylePtr &text_style) {T.title=title; T.text=text; T.text_style=text_style;}
  10. };
  11. static Memc<QueuedMsgBox> QueuedMsgBoxs;
  12. static SyncLock QueuedMsgBoxLock;
  13. /******************************************************************************/
  14. STRUCT(MsgBox , Dialog)
  15. //{
  16. static Memx<MsgBox> MsgBoxs;
  17. static void Del (MsgBox &mb) {SyncLocker locker(Gui._lock); MsgBoxs.removeData(&mb);}
  18. static void Close(MsgBox &mb) {if(Gui.window_fade)mb.fadeOut();else Del(mb);}
  19. static MsgBox* Find(CPtr id) {REPA(MsgBoxs){MsgBox &mb=MsgBoxs[i]; if(mb.id==id)return &mb;} return null;}
  20. CPtr id;
  21. MsgBox& create(C Str &title, C Str &text, C TextStylePtr &text_style, CPtr id)
  22. {
  23. T.id=id;
  24. Gui+=super::create(title, text, Memt<Str>().add("OK"), text_style).level(65536);
  25. buttons[0].func(Close, T);
  26. if(Gui.window_fade){super::hide(); fadeIn();}
  27. return T;
  28. }
  29. virtual MsgBox& hide() {Del(T); return T;}
  30. };
  31. Memx<MsgBox> MsgBox::MsgBoxs;
  32. /******************************************************************************/
  33. GUI Gui;
  34. /******************************************************************************/
  35. // GUI
  36. /******************************************************************************/
  37. GUI::GUI() : _desktops(4), default_skin(3649875776, 1074192063, 580730756, 799774185)
  38. {
  39. allow_window_fade=true;
  40. window_fade=false;
  41. desc_delay=0.3f;
  42. resize_radius=0.022f;
  43. click_sound_id.zero();
  44. draw_keyboard_highlight=DrawKeyboardHighlight;
  45. draw_description =DrawDescription;
  46. draw_imm =DrawIMM;
  47. window_fade_in_speed =9;
  48. window_fade_out_speed=6;
  49. window_fade_scale =0.85f;
  50. dialog_padd =0.03f;
  51. dialog_button_height=0.06f;
  52. dialog_button_padd =dialog_button_height*2;
  53. dialog_button_margin=dialog_button_height;
  54. _window_buttons_right=!OSMac(); // check for 'OSMac' instead of 'MAC' so it can be detected on WEB too, check for Mac instead of Apple, because iOS is also Apple, but since it's touchscreen based, prefer right side because most people are right-handed and it's easier to have the buttons on the right side
  55. _drag_want=_dragging=false;
  56. _drag_user =null;
  57. _drag_start =null;
  58. _drag_cancel=null;
  59. _drag_finish=null;
  60. _pass_char='*';
  61. _kb=_ms=_ms_src=_ms_lit=_wheel=_desc=_touch_desc=null;
  62. _menu=null;
  63. _window=_window_lit=null;
  64. _desktop=null;
  65. }
  66. /******************************************************************************/
  67. void GUI::screenChanged(Flt old_width, Flt old_height)
  68. {
  69. FREPAO(_desktops).rect(D.rect());
  70. if(Menu *menu=Gui.menu())
  71. if(GuiObj *owner=menu->Owner())
  72. if(owner->type()==GO_MENU_BAR && owner->parent()->is(GO_DESKTOP))
  73. menu->move(Vec2(old_width-D.w(), 0));
  74. }
  75. /******************************************************************************/
  76. Bool GUI::Switch()
  77. {
  78. if(Kb.alt())
  79. {
  80. // switch windows
  81. }else
  82. {
  83. // switch in window
  84. if(GuiObj *c=kb())
  85. if(GuiObj *p=c->parent())
  86. {
  87. switch(c->type())
  88. {
  89. case GO_MENU :
  90. case GO_CUSTOM :
  91. case GO_DESKTOP :
  92. case GO_VIEWPORT:
  93. case GO_REGION :
  94. case GO_TEXTBOX :
  95. case GO_WINDOW : return false;
  96. case GO_LIST : if(p->type()==GO_MENU )return false; c=p; p=c->parent(); if(!p)return false; break;
  97. case GO_TEXTLINE: if(p->type()==GO_COMBOBOX){ c=p; p=c->parent(); if(!p)return false;} break;
  98. }
  99. Bool next=!Kb.k.shift();
  100. switch(p->type())
  101. {
  102. case GO_DESKTOP: return p->asDesktop()._children.Switch(*c, next);
  103. case GO_REGION : return p->asRegion ()._children.Switch(*c, next);
  104. case GO_TAB : return p->asTab ()._children.Switch(*c, next);
  105. case GO_WINDOW : return p->asWindow ()._children.Switch(*c, next);
  106. case GO_TABS : {Tabs &tabs=p->asTabs(); if(InRange(tabs(), tabs))return tabs.tab(tabs())._children.Switch(*c, next);} break;
  107. }
  108. }
  109. }
  110. return false;
  111. }
  112. /******************************************************************************/
  113. void GUI::setText()
  114. {
  115. REPAO(_desktops).setText();
  116. }
  117. /******************************************************************************/
  118. GuiObj* GUI::objAtPos(C Vec2 &pos)C
  119. {
  120. GuiObj *mouse_wheel=null;
  121. return desktop() ? desktop()->asDesktop().test(pos, mouse_wheel) : null;
  122. }
  123. /******************************************************************************/
  124. Color GUI::backgroundColor()C {if(GuiSkin *skin=Gui.skin())return skin->background_color; return WHITE;}
  125. Color GUI:: borderColor()C {if(GuiSkin *skin=Gui.skin())return skin-> border_color; return Color(0, 112);}
  126. /******************************************************************************/
  127. TextLine* GUI::overlayTextLine(Vec2 &offset)
  128. {
  129. Rect kb_rect; if(Kb.softCoverage(kb_rect) && kb()->is(GO_TEXTLINE))
  130. {
  131. TextLine &tl=kb()->asTextLine();
  132. Rect_LU tl_rect(tl.screenPos(), tl.size());
  133. if(Cuts(tl_rect, kb_rect) || tl_rect.min.y<-D.h())
  134. {
  135. // try to move above kb rect first (because when typing with fingers the hands are usually downwards, so they would occlude what's below them)
  136. if(kb_rect.max.y+tl_rect.h()<=D.h()) // if it fits in the visible screen area
  137. {
  138. offset=kb_rect.up()+tl_rect.size()*Vec2(-0.5f, 1.0f)-tl.pos();
  139. }else // move at the bottom of the screen
  140. {
  141. offset=Vec2(0, -D.h())+tl_rect.size()*Vec2(-0.5f, 1.0f)-tl.pos();
  142. }
  143. return &tl;
  144. }
  145. }
  146. return null;
  147. }
  148. /******************************************************************************/
  149. void GUI::msgBox(C Str &title, C Str &text, C TextStylePtr &text_style)
  150. {
  151. SyncLocker locker(QueuedMsgBoxLock);
  152. REPA(QueuedMsgBoxs)
  153. {
  154. QueuedMsgBox &qmb=QueuedMsgBoxs[i];
  155. if(Equal(qmb.title, title, true) && Equal(qmb.text, text, true) && qmb.text_style==text_style)return; // if already exists then do nothing
  156. }
  157. QueuedMsgBoxs.New().set(title, text, text_style);
  158. }
  159. Dialog& GUI::getMsgBox(CPtr id)
  160. {
  161. SyncLocker locker(_lock);
  162. if(id)if(MsgBox *mb=MsgBox::Find(id))return *mb;
  163. return MsgBox::MsgBoxs.New().create(S, S, null, id); // always create to set the 'id' and 'Window.level'
  164. }
  165. Dialog* GUI:: findMsgBox(CPtr id) {if(id){SyncLocker locker(_lock); return MsgBox::Find(id);} return null;}
  166. void GUI:: delMsgBox(CPtr id) {if(id){SyncLocker locker(_lock); if(MsgBox *mb=MsgBox::Find(id))MsgBox::MsgBoxs.removeData(mb);}}
  167. void GUI::fadeOutMsgBox(CPtr id) {if(id){SyncLocker locker(_lock); if(MsgBox *mb=MsgBox::Find(id))mb->fadeOut();}}
  168. void GUI:: closeMsgBox(CPtr id) {if(id){SyncLocker locker(_lock); if(MsgBox *mb=MsgBox::Find(id))MsgBox::Close(*mb);}}
  169. /******************************************************************************/
  170. GUI& GUI::passwordChar(Char c) // Warning: this is not thread-safe
  171. {
  172. if(_pass_char!=c)
  173. {
  174. _pass_char=c;
  175. _pass_temp.clear();
  176. }
  177. return T;
  178. }
  179. C Str& GUI::passTemp(Int length) // Warning: this is not thread-safe
  180. {
  181. if( length<_pass_temp.length() )_pass_temp.clip(length);else
  182. for(; length>_pass_temp.length(); )_pass_temp+=_pass_char;
  183. return _pass_temp;
  184. }
  185. /******************************************************************************/
  186. static void SetWindowButtons(GuiObj &go)
  187. {
  188. if(go.type()==GO_WINDOW)go.asWindow().setButtons();
  189. REP(go.childNum())if(GuiObj *child=go.child(i))SetWindowButtons(*child);
  190. }
  191. GUI& GUI::windowButtonsRight(Bool right)
  192. {
  193. if(_window_buttons_right!=right)
  194. {
  195. _window_buttons_right=right;
  196. REPA(_desktops)SetWindowButtons(_desktops[i]);
  197. }
  198. return T;
  199. }
  200. /******************************************************************************/
  201. void GUI::playClickSound()C
  202. {
  203. SoundPlay(click_sound_id, 1, VOLUME_UI);
  204. }
  205. /******************************************************************************/
  206. Vec2 GUI::dragPos()C
  207. {
  208. if(dragging())
  209. {
  210. Touch *touch=FindTouch(_drag_touch_id);
  211. return touch ? touch->pos() : Ms.pos();
  212. }
  213. return 0;
  214. }
  215. void GUI::dragCancel()
  216. {
  217. if(_drag_cancel){if(dragging())_drag_cancel(_drag_user); _drag_cancel=null;} // call cancel only if actually started dragging
  218. _drag_want=_dragging=false;
  219. }
  220. void GUI::drag(C Str &name, Touch *touch)
  221. {
  222. dragCancel();
  223. if(_drag_want=true) // previously this checked for "if(_drag_want=name.is())" however empty names are now allowed
  224. {
  225. if(touch)touch->_scrolling=false; // when dragging is initiated, then unmark touch from scrolling
  226. _drag_touch_id=(touch ? touch->id () : 0);
  227. _drag_pos =(touch ? touch->pos() : Ms.pos());
  228. _drag_name =name;
  229. _drag_user =null;
  230. _drag_start =null;
  231. _drag_cancel =null;
  232. _drag_finish =null;
  233. }
  234. }
  235. void GUI::drag(void finish(Ptr user, GuiObj *obj, C Vec2 &screen_pos), Ptr user, Touch *touch, void start(Ptr user), void cancel(Ptr user))
  236. {
  237. dragCancel();
  238. if(_drag_want=true) // previously this checked for "if(_drag_want=(finish!=null))" however empty functions are now allowed
  239. {
  240. if(touch)touch->_scrolling=false; // when dragging is initiated, then unmark touch from scrolling
  241. _drag_touch_id=(touch ? touch->id () : 0);
  242. _drag_pos =(touch ? touch->pos() : Ms.pos());
  243. _drag_name .clear();
  244. _drag_user =user;
  245. _drag_start =start;
  246. _drag_cancel =cancel;
  247. _drag_finish =finish;
  248. }
  249. }
  250. void GUI::dragDraw()
  251. {
  252. if(dragging())if(Image *image=image_drag())image->draw(Rect_D(dragPos(), Vec2(0.05f*image->aspect(), 0.05f)));
  253. }
  254. /******************************************************************************/
  255. void GUI::addFuncCall(void func( ) ) {_callbacks.add(func );}
  256. void GUI::addFuncCall(void func(Ptr user), Ptr user) {_callbacks.add(func, user);}
  257. /******************************************************************************/
  258. void GUI::update()
  259. {
  260. Dbl t=Time.curTime();
  261. //_time_d_fade_in =Time.ad()*60;
  262. _time_d_fade_out=Time.ad()*14;
  263. SyncLocker locker(_lock);
  264. // test
  265. _ms_lit =null;
  266. _wheel =null;
  267. _overlay_textline=overlayTextLine(_overlay_textline_offset);
  268. if(Ms.detected() && Ms.visible() && Ms._on_client && desktop())_ms_lit=desktop()->asDesktop().test(Ms.pos(), _wheel); // don't set 'msLit' if mouse is not detected or hidden or on another window (do checks if mouse was focused on other window but now moves onto our window, and with buttons pressed in case for drag and drop detection and we would want to highlight the target gui object at which we're gonna drop the files)
  269. Byte ms_button=0; REPA(Ms._button)ms_button|=Ms._button[i];
  270. if(!(ms_button&(BS_ON|BS_RELEASED)))_ms=_ms_src=msLit();
  271. if(App.active())
  272. {
  273. if((ms_button&BS_PUSHED) && msLit())msLit()->activate();
  274. REPA(Touches)if(Touches[i].pd())if(GuiObj *go=Touches[i].guiObj())go->activate();
  275. if(Kb.k(KB_TAB))if(Switch())Kb.eatKey();
  276. }
  277. _window_lit=&msLit()->first(GO_WINDOW)->asWindow();
  278. // update
  279. FREPAO(_desktops).update();
  280. // callbacks
  281. _callbacks.update();
  282. // add message boxes after update and callbacks, so they're immediately displayed when created
  283. if(QueuedMsgBoxs.elms())
  284. {
  285. SyncLocker locker(QueuedMsgBoxLock);
  286. FREPA(QueuedMsgBoxs) // process in order
  287. {
  288. C QueuedMsgBox &qmb=QueuedMsgBoxs[i];
  289. REPA(MsgBox::MsgBoxs)
  290. {
  291. C MsgBox &mb=MsgBox::MsgBoxs[i];
  292. if(Equal(mb.title, qmb.title, true) && Equal(mb.text(), qmb.text, true) && mb.text.text_style==qmb.text_style)goto skip; // if already exists then do nothing
  293. }
  294. // create new one
  295. MsgBox::MsgBoxs.New().create(qmb.title, qmb.text, qmb.text_style, null);
  296. skip:;
  297. }
  298. QueuedMsgBoxs.clear();
  299. }
  300. // mouse description
  301. if(_desc!=ms()) // if there is a new object under mouse than previous description
  302. {
  303. if(!Ms.pixelDelta().any())_desc=null;else // set it only if we've moved the mouse (to eliminate showing description by elements activated with keyboard, touch or programatically)
  304. {
  305. _desc =ms();
  306. _desc_time=Time.appTime();
  307. }
  308. }else
  309. if(Ms.pixelDelta().any() || (ms_button&(BS_ON|BS_PUSHED|BS_RELEASED)))_desc_time=Time.appTime(); // if there was a mouse action then reset the timer
  310. // touch description
  311. Touch *stylus=null; REPA(Touches){Touch &touch=Touches[i]; if(touch.stylus() && !touch.on() && !touch.rs()){stylus=&touch; break;}}
  312. GuiObj *stylus_obj=(stylus ? stylus->guiObj() : null);
  313. if(_touch_desc!=stylus_obj) // if there is a new object under stylus than previous description
  314. {
  315. _touch_desc =stylus_obj;
  316. _touch_desc_time=Time.appTime();
  317. }
  318. // drag !! process after objects update, because '_List.update' requires that 'Gui.dragging()' is still active at the moment of dragging release !!
  319. if(_drag_want)
  320. {
  321. Touch *touch=FindTouch(_drag_touch_id);
  322. if(!_drag_touch_id && Ms.bp(1))dragCancel();else // if mouse dragging and RMB pressed then cancel dragging
  323. if( _drag_touch_id ? (!touch || touch->rs()) : (!Ms.b(0) || Ms.br(0))) // finish dragging
  324. {
  325. if(dragging())
  326. if(GuiObj *lit=(touch ? objAtPos(touch->pos()) : msLit()))
  327. {
  328. if(_drag_name.is() && App.drop){Memc<Str> names; names.add(_drag_name); App.drop( names , lit, touch ? touch->pos() : Ms.pos());} // don't use 'Memt' here, because that would reduce the stack memory, and in this method all gui object updates are called, so it's best to give them as much as possible, and also this is called only on drag finish, so once in a long time
  329. if(_drag_finish ) _drag_finish(_drag_user, lit, touch ? touch->pos() : Ms.pos());
  330. _drag_cancel=null; // clear cancel so we won't call it, because we've already called finish
  331. if(!menu()) // if menu was not activated during custom function calls
  332. if(lit=(touch ? objAtPos(touch->pos()) : msLit())) // detect lit again because previous may got deleted during custom function calls
  333. lit->activate(); // activate object at which we've drag and dropped
  334. }
  335. dragCancel(); // clear drag related members
  336. }else // start dragging
  337. if(!dragging() && (touch ? touch->dragging() : Ms.dragging()))
  338. {
  339. _dragging=true;
  340. if(_drag_start)_drag_start(_drag_user);
  341. }
  342. }
  343. _update_time=Time.curTime()-t;
  344. }
  345. /******************************************************************************/
  346. static void DrawPanelText(C Panel *panel, C Color &panel_color, Flt padding, C TextStyleParams &ts, C Vec2 &pos, CChar *text, Bool mouse)
  347. {
  348. if(Is(text))
  349. {
  350. Set(Tls16, text, ts, D.w2()-padding*2, AUTO_LINE_SPACE_SPLIT);
  351. Flt width =0,
  352. height=Tls16.elms()*ts.lineHeight();
  353. REPA(Tls16){TextLineSplit16 &t=Tls16[i]; MAX(width, ts.textWidth(t.text, t.length));}
  354. Rect_LU r(pos, width, height); r.extend(padding); if(mouse)
  355. {
  356. Int height=32; // default mouse cursor height
  357. if(Ms._image)height=Ms._image->h()-Ms._hot_spot.y;
  358. Flt y=D.pixelToScreenSize().y*height;
  359. r.min.y-=y;
  360. r.max.y-=y;
  361. }
  362. if(r.max.x> D.w()){r.min.x-=r.max.x-D.w(); r.max.x=D.w();} if(r.min.x<-D.w()){r.max.x+=-D.w()-r.min.x; r.min.x=-D.w();}
  363. if(r.min.y<-D.h()){r+=Vec2(0, pos.y-r.min.y+padding) ;} if(r.max.y> D.h()){r.min.y-= r.max.y-D.h(); r.max.y= D.h();}
  364. if(panel )panel->draw(panel_color, r);else
  365. if(panel_color.a) r.draw(panel_color);
  366. ts.drawSplit(r.extend(-padding), Tls16, null, 0);
  367. }
  368. }
  369. static void DrawDescriptionObj(GuiObj &obj, C Vec2 &pos, Flt start_time, Bool mouse)
  370. {
  371. Bool immediate=false;
  372. CChar *text=obj.desc();
  373. switch(obj.type())
  374. {
  375. case GO_LIST:
  376. {
  377. _List &list=obj.asList();
  378. immediate=FlagTest(list.flag, LIST_IMMEDIATE_DESC);
  379. if(list._desc_offset>=0)
  380. if(Ptr data=list.screenToData(pos))text=*(Char**)((Byte*)data+list._desc_offset);
  381. }break;
  382. }
  383. if(Is(text) && (immediate || Time.appTime()-start_time>=Gui.desc_delay) && Gui.draw_description)Gui.draw_description(&obj, pos, text, mouse);
  384. }
  385. /******************************************************************************/
  386. void DrawKeyboardHighlight(GuiObj *obj, C Rect &rect, C GuiSkin *skin)
  387. {
  388. if(skin && skin->keyboard_highlight_color.a)
  389. rect.draw(skin->keyboard_highlight_color, false);
  390. }
  391. void DrawDescription(GuiObj *obj, C Vec2 &pos, CChar *text, Bool mouse)
  392. {
  393. if(Gui.skin)
  394. if(TextStyle *text_style=Gui.skin->desc.text_style())
  395. DrawPanelText(Gui.skin->desc.normal(), Gui.skin->desc.normal_color, Gui.skin->desc.padding, *text_style, pos, text, mouse);
  396. }
  397. void DrawIMM(GuiObj *obj)
  398. {
  399. if((Kb.immBuffer().is() || Kb.immCandidate().elms()) && obj && obj->type()==GO_TEXTLINE)
  400. if(Gui.skin)
  401. if(TextStyle *text_style=Gui.skin->imm.text_style())
  402. {
  403. TextLine &textline=obj->asTextLine();
  404. TextEdit edit; edit.cur=Kb.immCursor(); if(Kb.immCandidate().elms())edit.sel=Kb.immSelection().y;
  405. TextStyleParams ts=*text_style; if(Kb.immBuffer().is())ts.edit=&edit;
  406. Str t=Kb.immBuffer(); if(Kb.immCandidate().elms()){if(t.is())t+='\n'; FREPA(Kb.immCandidate())t.space()+=S+(i+1)%10+Kb.immCandidate()[i];} // use %10 so "10" will be displayed as "0" (because pressing 0 button activates that candidate)
  407. DrawPanelText(Gui.skin->imm.normal(), Gui.skin->imm.normal_color, Gui.skin->imm.padding, ts, textline.screenPos()+Vec2(0, -textline.rect().h()), t, false);
  408. }
  409. }
  410. /******************************************************************************/
  411. void GUI::draw()
  412. {
  413. SyncLocker locker(_lock);
  414. if(_desktop)
  415. {
  416. _desktop->asDesktop().draw();
  417. D.clip(); // reset clip after drawing all gui objects
  418. // show description
  419. if(draw_description)
  420. {
  421. if( _desc) DrawDescriptionObj(* _desc, Ms .pos(), _desc_time, true );
  422. if(_touch_desc)REPA(Touches){Touch &touch=Touches[i]; if(touch.stylus() && touch.guiObj()==_touch_desc){DrawDescriptionObj(*_touch_desc, touch.pos(), _touch_desc_time, false); break;}}
  423. }
  424. // show imm
  425. if(draw_imm && kb()->is(GO_TEXTLINE))draw_imm(kb());
  426. }
  427. }
  428. /******************************************************************************/
  429. void GUI::del()
  430. {
  431. #if 0
  432. image_shadow .clear();
  433. image_drag .clear();
  434. image_resize_x .clear();
  435. image_resize_y .clear();
  436. image_resize_ld.clear();
  437. image_resize_lu.clear();
  438. image_resize_ru.clear();
  439. image_resize_rd.clear();
  440. skin.clear();
  441. #endif
  442. MsgBox::MsgBoxs.del();
  443. _desktops .del();
  444. _callbacks .del();
  445. Tls8 .del();
  446. Tls16 .del();
  447. GuiSkins .del();
  448. Panels .del();
  449. PanelImages .del();
  450. }
  451. void GUI::create()
  452. {
  453. if(LogInit)LogN("GUI.create");
  454. if(D._can_draw) // will cause Exit on Linux without XDisplay, so skip loading if can't draw
  455. if(skin=default_skin)
  456. {
  457. EmptyGuiSkin.list. cursor_color=skin->list. cursor_color;
  458. EmptyGuiSkin.list.highlight_color=skin->list.highlight_color;
  459. EmptyGuiSkin.list.selection_color=skin->list.selection_color;
  460. }
  461. EmptyGuiSkin.region.normal_color.a=0;
  462. image_shadow .get("Gui/shadow.img");
  463. image_drag .get("Gui/drag.img");
  464. image_resize_x .get("Gui/resize_x.img");
  465. image_resize_y .get("Gui/resize_y.img");
  466. image_resize_ld.get("Gui/resize_ru.img");
  467. image_resize_lu.get("Gui/resize_rd.img");
  468. image_resize_ru.get("Gui/resize_ru.img");
  469. image_resize_rd.get("Gui/resize_rd.img");
  470. _desktops.New().activate();
  471. }
  472. /******************************************************************************/
  473. }
  474. /******************************************************************************/