Merge pull request #113 from tesselode/fix-multi-targets
[wdl/wdl-ol.git] / WDL / wingui / virtwnd-iconbutton.cpp
bloba1b866feb0e9a18e16988fd5d6b7565d9771684d
1 /*
2 WDL - virtwnd-iconbutton.cpp
3 Copyright (C) 2006 and later Cockos Incorporated
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
22 Implementation for virtual window icon buttons, icons, combo boxes, and static text controls.
26 #include <ctype.h>
27 #include "virtwnd-controls.h"
28 #include "../lice/lice.h"
30 #ifdef _WIN32
31 #define WDL_WIN32_UTF8_IMPL static
32 #define WDL_WIN32_UTF8_NO_UI_IMPL
33 #include "../win32_utf8.c"
34 #endif
36 WDL_VirtualIconButton::WDL_VirtualIconButton()
38 m_alpha=1.0;
39 m_checkstate=-1;
40 m_textfont=0;
41 m_textfontv=0;
42 m_textalign=0;
43 m_bgcol1_msg=0;
44 m_is_button=true;
45 m_pressed=0;
46 m_iconCfg=0;
47 m_en=true;
48 m_grayed = false;
49 m_forceborder=false;
50 m_forcetext=false;
51 m_forcetext_color=0;
52 m_ownsicon=false;
53 m_immediate=false;
54 m_margin_r = m_margin_l = 0;
55 m_margin_t = m_margin_b = 0;
58 WDL_VirtualIconButton::~WDL_VirtualIconButton()
60 if (m_ownsicon && m_iconCfg)
62 delete m_iconCfg->image;
63 delete m_iconCfg->olimage;
64 delete m_iconCfg;
68 void WDL_VirtualIconButton::SetTextLabel(const char *text)
70 m_textlbl.Set(text);
71 if (!m_iconCfg || m_forcetext) RequestRedraw(NULL);
74 void WDL_VirtualIconButton::SetTextLabel(const char *text, int align, LICE_IFont *font)
76 if (font) m_textfont=font;
77 m_textalign=align;
78 m_textlbl.Set(text);
79 if (!m_iconCfg || m_forcetext) RequestRedraw(NULL);
82 void WDL_VirtualIconButton::SetCheckState(char state)
84 if (state != m_checkstate)
86 m_checkstate=state;
87 RequestRedraw(NULL);
91 void WDL_VirtualIconButton::SetIcon(WDL_VirtualIconButton_SkinConfig *cfg, float alpha, bool buttonownsicon)
93 if (m_iconCfg != cfg || m_alpha != alpha)
95 bool combineRects=false;
96 RECT r;
97 if (m_iconCfg && m_iconCfg != cfg && m_iconCfg->olimage)
99 combineRects=true;
100 GetPositionPaintExtent(&r,WDL_VWND_SCALEBASE);
101 if (WantsPaintOver())
103 RECT r3;
104 GetPositionPaintOverExtent(&r3,WDL_VWND_SCALEBASE);
105 if (r3.left<r.left) r.left=r3.left;
106 if (r3.top<r.top) r.top=r3.top;
107 if (r3.right>r.right) r.right=r3.right;
108 if (r3.bottom>r.bottom) r.bottom=r3.bottom;
111 if (m_ownsicon && m_iconCfg && m_iconCfg != cfg)
113 delete m_iconCfg->image;
114 delete m_iconCfg->olimage;
115 delete m_iconCfg;
117 m_alpha=alpha;
118 m_iconCfg=cfg;
120 if (combineRects)
122 RECT r3;
123 GetPositionPaintExtent(&r3,WDL_VWND_SCALEBASE);
124 if (r3.left<r.left) r.left=r3.left;
125 if (r3.top<r.top) r.top=r3.top;
126 if (r3.right>r.right) r.right=r3.right;
127 if (r3.bottom>r.bottom) r.bottom=r3.bottom;
129 if (WantsPaintOver())
131 GetPositionPaintOverExtent(&r3,WDL_VWND_SCALEBASE);
132 if (r3.left<r.left) r.left=r3.left;
133 if (r3.top<r.top) r.top=r3.top;
134 if (r3.right>r.right) r.right=r3.right;
135 if (r3.bottom>r.bottom) r.bottom=r3.bottom;
138 r.left -= m_position.left;
139 r.right -= m_position.left;
140 r.top -= m_position.top;
141 r.bottom -= m_position.top;
142 RequestRedraw(&r);
144 else
146 RequestRedraw(NULL);
149 m_ownsicon = buttonownsicon;
152 void WDL_VirtualIconButton::OnPaintOver(LICE_IBitmap *drawbm, int origin_x, int origin_y, RECT *cliprect, int rscale)
154 if (m_iconCfg && m_iconCfg->olimage)
156 int sx=0;
157 int sy=0;
158 int w=m_iconCfg->olimage->getWidth();
159 int h=m_iconCfg->olimage->getHeight();
160 if (m_iconCfg->image_ltrb_used.flags&1) { w-=2; h-= 2; sx++,sy++; }
162 w/=3;
164 if (w>0 && h>0)
166 if (m_is_button)
168 if ((m_pressed&2)) sx+=(m_pressed&1) ? w*2 : w;
171 if (m_iconCfg->image_ltrb_used.flags&2) // use main image's stretch areas (outer areas become unstretched)
173 WDL_VirtualWnd_BGCfg cfg={0,};
174 LICE_SubBitmap sb(m_iconCfg->olimage,sx,sy,w,h);
175 cfg.bgimage = &sb;
176 cfg.bgimage_lt[0] = m_iconCfg->image_ltrb_main[0]+1; // image_ltrb_main expects 1-based number
177 cfg.bgimage_lt[1] = m_iconCfg->image_ltrb_main[1]+1;
178 cfg.bgimage_rb[0] = m_iconCfg->image_ltrb_main[2]+1;
179 cfg.bgimage_rb[1] = m_iconCfg->image_ltrb_main[3]+1;
180 cfg.bgimage_lt_out[0] = m_iconCfg->image_ltrb_ol[0]+1;
181 cfg.bgimage_lt_out[1] = m_iconCfg->image_ltrb_ol[1]+1;
182 cfg.bgimage_rb_out[0] = m_iconCfg->image_ltrb_ol[2]+1;
183 cfg.bgimage_rb_out[1] = m_iconCfg->image_ltrb_ol[3]+1;
184 cfg.bgimage_noalphaflags=0;
186 RECT r=m_position,r2;
187 ScaleRect(&r,rscale);
188 GetPositionPaintOverExtent(&r2,rscale);
189 WDL_VirtualWnd_ScaledBlitBG(drawbm,&cfg,
190 r.left+origin_x,r.top+origin_y,r.right-r.left,r.bottom-r.top,
191 r2.left+origin_x,r2.top+origin_y,r2.right-r2.left,r2.bottom-r2.top,
192 m_alpha,LICE_BLIT_MODE_COPY|LICE_BLIT_FILTER_BILINEAR|LICE_BLIT_USE_ALPHA);
194 else
196 RECT r;
197 GetPositionPaintOverExtent(&r,rscale);
198 LICE_ScaledBlit(drawbm,m_iconCfg->olimage,r.left+origin_x,r.top+origin_y,
199 r.right-r.left,
200 r.bottom-r.top,
201 (float)sx,(float)sy,(float)w,(float)h, m_alpha, // m_grayed?
202 LICE_BLIT_MODE_COPY|LICE_BLIT_FILTER_BILINEAR|LICE_BLIT_USE_ALPHA);
209 void WDL_VirtualIconButton::OnPaint(LICE_IBitmap *drawbm, int origin_x, int origin_y, RECT *cliprect, int rscale)
211 int col;
213 float alpha = (m_grayed ? 0.25f : 1.0f) * m_alpha;
215 bool isdown = !!(m_pressed&1);
216 bool ishover = !!(m_pressed&2);
218 if (m_iconCfg && m_iconCfg->image && !m_iconCfg->image_issingle)
220 bool swapupdown = (m_checkstate > 0);
221 bool isdownimg = (swapupdown != isdown);
223 RECT r=m_position;
224 ScaleRect(&r,rscale);
226 int sx=0;
227 int sy=0;
228 int w=m_iconCfg->image->getWidth();
229 int h=m_iconCfg->image->getHeight();
231 if (w>0 && (m_iconCfg->image_ltrb_used.flags&2))
232 w-=2;
234 w/=3;
235 if (w>0 && h > 0)
237 if (m_is_button)
239 if (isdownimg) sx += w*2;
240 else if (ishover) sx += w;
244 if (m_iconCfg->image_ltrb_used.flags&2)
246 WDL_VirtualWnd_BGCfg cfg={0,};
247 LICE_SubBitmap sb(m_iconCfg->image,sx+1,sy+1,w,h-2);
248 cfg.bgimage = &sb;
249 cfg.bgimage_lt[0] = m_iconCfg->image_ltrb_main[0]+1; // image_ltrb_main expects 1-based number
250 cfg.bgimage_lt[1] = m_iconCfg->image_ltrb_main[1]+1;
251 cfg.bgimage_rb[0] = m_iconCfg->image_ltrb_main[2]+1;
252 cfg.bgimage_rb[1] = m_iconCfg->image_ltrb_main[3]+1;
253 cfg.bgimage_noalphaflags=0;
255 WDL_VirtualWnd_ScaledBlitBG(drawbm,&cfg,
256 r.left+origin_x,r.top+origin_y,r.right-r.left,r.bottom-r.top,
257 r.left+origin_x,r.top+origin_y,r.right-r.left,r.bottom-r.top,
258 alpha,LICE_BLIT_MODE_COPY|LICE_BLIT_FILTER_BILINEAR|LICE_BLIT_USE_ALPHA);
261 else
262 LICE_ScaledBlit(drawbm,m_iconCfg->image,r.left+origin_x,r.top+origin_y,
263 r.right-r.left,
264 r.bottom-r.top,
265 (float)sx,(float)sy,(float)w,(float)h, alpha,
266 LICE_BLIT_MODE_COPY|LICE_BLIT_FILTER_BILINEAR|LICE_BLIT_USE_ALPHA);
269 else
271 RECT r=m_position;
272 ScaleRect(&r,rscale);
273 r.left+=origin_x;
274 r.right+=origin_x;
275 r.top+=origin_y;
276 r.bottom+=origin_y;
277 if (m_is_button)
279 if (WDL_STYLE_WantGlobalButtonBackground(&col))
281 LICE_FillRect(drawbm,r.left,r.top,r.right-r.left,r.bottom-r.top,LICE_RGBA_FROMNATIVE(col,255),alpha,LICE_BLIT_MODE_COPY);
284 if (ishover || m_forceborder || WDL_STYLE_WantGlobalButtonBorders())
286 int cidx=isdown?COLOR_3DSHADOW:COLOR_3DHILIGHT;
288 int pencol = GSC(cidx);
289 pencol = LICE_RGBA_FROMNATIVE(pencol,255);
291 LICE_Line(drawbm,r.left,r.bottom-1,r.left,r.top,pencol,alpha,LICE_BLIT_MODE_COPY,false);
292 LICE_Line(drawbm,r.left,r.top,r.right-1,r.top,pencol,alpha,LICE_BLIT_MODE_COPY,false);
293 cidx = isdown?COLOR_3DHILIGHT:COLOR_3DSHADOW;
294 pencol = GSC(cidx);
295 pencol = LICE_RGBA_FROMNATIVE(pencol,255);
296 LICE_Line(drawbm,r.right-1,r.top,r.right-1,r.bottom-1,pencol,alpha,LICE_BLIT_MODE_COPY,false);
297 LICE_Line(drawbm,r.right-1,r.bottom-1,r.left,r.bottom-1,pencol,alpha,LICE_BLIT_MODE_COPY,false);
300 if (m_iconCfg && m_iconCfg->image)
302 int sz=16,sz2=16;
303 WDL_STYLE_ScaleImageCoords(&sz,&sz2);
305 //if (m_position.right-m_position.left > 24) sz=m_position.right-m_position.left-8;
307 int x=r.left+((r.right-r.left)-sz)/2;
308 int y=r.top+((r.bottom-r.top)-sz2)/2;
309 if (m_is_button)
311 if (isdown && ishover) { x++; y++; }
314 LICE_ScaledBlit(drawbm,m_iconCfg->image,x,y,sz,sz2,0.0f,0.0f,
315 (float)m_iconCfg->image->getWidth(),
316 (float)m_iconCfg->image->getHeight(),alpha,LICE_BLIT_MODE_COPY|LICE_BLIT_FILTER_BILINEAR|LICE_BLIT_USE_ALPHA);
321 if (!m_iconCfg || m_forcetext)
323 RECT r2=m_position;
324 ScaleRect(&r2,rscale);
325 r2.left+=origin_x;
326 r2.right+=origin_x;
327 r2.top+=origin_y;
328 r2.bottom+=origin_y;
330 if (m_checkstate>=0 && !m_iconCfg)
332 RECT tr=r2;
333 int sz=tr.bottom-tr.top;
334 int adj = 2*rscale/WDL_VWND_SCALEBASE;
335 r2.left+=sz+adj;
337 tr.top+=adj;
338 tr.bottom-=adj;
339 sz-=adj*2;
340 sz&=~1;
341 LICE_FillRect(drawbm ,tr.left,tr.top,sz,sz,LICE_RGBA(255,255,255,255),alpha,LICE_BLIT_MODE_COPY);
342 LICE_Line(drawbm,tr.left,tr.top,tr.left+sz,tr.top,LICE_RGBA(128,128,128,255),alpha,LICE_BLIT_MODE_COPY,false);
343 LICE_Line(drawbm,tr.left+sz,tr.top,tr.left+sz,tr.bottom,LICE_RGBA(128,128,128,255),alpha,LICE_BLIT_MODE_COPY,false);
344 LICE_Line(drawbm,tr.left+sz,tr.bottom,tr.left,tr.bottom,LICE_RGBA(128,128,128,255),alpha,LICE_BLIT_MODE_COPY,false);
345 LICE_Line(drawbm,tr.left,tr.bottom,tr.left,tr.top,LICE_RGBA(128,128,128,255),alpha,LICE_BLIT_MODE_COPY,false);
346 int nl = (m_checkstate>0) ? 3:0;
347 if (isdown) nl ^= 2;
349 if (nl&1)
350 LICE_Line(drawbm,tr.left+2,tr.bottom-2,tr.left+sz-2,tr.top+2,LICE_RGBA(0,0,0,255),alpha,LICE_BLIT_MODE_COPY,false);
351 if (nl&2)
352 LICE_Line(drawbm,tr.left+2,tr.top+2,tr.left+sz-2,tr.bottom-2,LICE_RGBA(0,0,0,255),alpha,LICE_BLIT_MODE_COPY,false);
357 LICE_IFont *font = m_textfont;
358 bool isVert=false;
359 if (font && m_textfontv && m_position.right-m_position.left < m_position.bottom - m_position.top)
361 isVert=true;
362 font = m_textfontv;
364 // draw text
365 if (font&&m_textlbl.Get()[0])
367 int fgc=m_forcetext_color ? m_forcetext_color : LICE_RGBA_FROMNATIVE(GSC(COLOR_BTNTEXT),255);
368 //font->SetCombineMode(LICE_BLIT_MODE_COPY, alpha); // this affects the glyphs that get cached
369 font->SetBkMode(TRANSPARENT);
370 font->SetTextColor(fgc);
372 r2.left += m_margin_l;
373 r2.right -= m_margin_r;
374 r2.top += m_margin_t;
375 r2.bottom -= m_margin_b;
377 if (isdown)
379 if (m_textalign<0) r2.left+=1;
380 else if (m_textalign>0) r2.right+=1;
381 else r2.left+=2;
382 r2.top+=2;
384 int f = DT_SINGLELINE|DT_NOPREFIX;
385 if (isVert)
387 if (m_textalign == 0)
389 RECT mr={0,};
390 font->DrawText(drawbm,m_textlbl.Get(),-1,&mr,f|DT_CALCRECT);
391 f |= (mr.bottom < r2.bottom-r2.top) ? DT_VCENTER : DT_TOP;
393 else
394 f |= m_textalign<0?DT_TOP:DT_BOTTOM;
396 f |= DT_CENTER;
398 else
400 if (m_textalign == 0)
402 RECT mr={0,};
403 font->DrawText(drawbm,m_textlbl.Get(),-1,&mr,f|DT_CALCRECT);
404 f |= (mr.right < r2.right-r2.left) ? DT_CENTER : DT_LEFT;
406 else
407 f |= m_textalign<0?DT_LEFT:DT_RIGHT;
409 f |= DT_VCENTER;
411 font->DrawText(drawbm,m_textlbl.Get(),-1,&r2,f);
416 if (m_bgcol1_msg)
418 int brcol=-100;
419 SendCommand(m_bgcol1_msg,(INT_PTR)&brcol,GetID(),this);
420 if (brcol != -100)
422 RECT r=m_position;
424 int bh=(r.bottom-r.top)/5;
425 if (bh<1) bh=1;
426 int bw=(r.right-r.left)/5;
427 if (bw<1) bw=1;
429 LICE_FillRect(drawbm,
430 r.left+origin_x,r.top+origin_y,
431 r.right-r.left,
432 bh,LICE_RGBA_FROMNATIVE(brcol,255),0.75,LICE_BLIT_MODE_COPY);
434 LICE_FillRect(drawbm,
435 r.left+origin_x,r.top+origin_y+bh,
437 r.bottom-r.top-bh*2,LICE_RGBA_FROMNATIVE(brcol,255),0.75,LICE_BLIT_MODE_COPY);
439 LICE_FillRect(drawbm,
440 r.right+origin_x-bw,r.top+origin_y+bh,
442 r.bottom-r.top-bh*2,LICE_RGBA_FROMNATIVE(brcol,255),0.75,LICE_BLIT_MODE_COPY);
444 LICE_FillRect(drawbm,
445 r.left+origin_x,r.bottom+origin_y-bh,
446 r.right-r.left,
447 bh,LICE_RGBA_FROMNATIVE(brcol,255),0.75,LICE_BLIT_MODE_COPY);
454 void WDL_VirtualIconButton::OnMouseMove(int xpos, int ypos)
456 if (m_en&&m_is_button)
458 int wp=m_pressed;
460 WDL_VWnd *parhit = GetParent();
461 if (parhit)
463 parhit = parhit->VirtWndFromPoint(m_position.left+xpos,m_position.top+ypos,0);
465 else if (!parhit)
467 // special case if no parent
468 if (xpos >= 0 && xpos < m_position.right-m_position.left && ypos >= 0 && ypos < m_position.bottom-m_position.top) parhit=this;
471 if (parhit == this)
473 m_pressed|=2;
475 else
477 m_pressed&=~2;
480 if ((m_pressed&3)!=(wp&3))
482 RequestRedraw(NULL);
487 int WDL_VirtualIconButton::OnMouseDown(int xpos, int ypos)
489 if (m_en&&m_is_button)
491 m_pressed=3;
492 RequestRedraw(NULL);
493 if (m__iaccess) m__iaccess->OnFocused();
495 if (m_immediate)
497 DoSendCommand(xpos, ypos);
500 return 1;
502 return 0;
505 bool WDL_VirtualIconButton::OnMouseDblClick(int xpos, int ypos)
507 if (m_is_button)
509 DoSendCommand(xpos, ypos);
510 return true;
512 return false;
515 void WDL_VirtualIconButton::OnMouseUp(int xpos, int ypos)
517 if (!m_is_button) return;
519 int waspress=!!m_pressed;
520 m_pressed&=~1;
521 RequestRedraw(NULL);
523 if (waspress && !m_immediate)
525 DoSendCommand(xpos, ypos);
529 void WDL_VirtualIconButton::DoSendCommand(int xpos, int ypos)
531 if (m_en &&
532 xpos >= 0 &&
533 xpos < m_position.right-m_position.left &&
534 ypos >= 0 &&
535 ypos < m_position.bottom-m_position.top)
537 int code=GetID();
538 if (!m_iconCfg && m_textlbl.Get()[0] && m_checkstate >= 0)
540 if (xpos < m_position.bottom-m_position.top)
542 code|=600<<16;
545 WDL_VWND_DCHK(a);
546 SendCommand(WM_COMMAND,code,0,this);
547 if (a.isOK() && m__iaccess && m_checkstate>=0) m__iaccess->OnStateChange();
552 WDL_VirtualComboBox::WDL_VirtualComboBox()
554 m_font=0;
555 m_align=-1;
556 m_curitem=-1;
559 WDL_VirtualComboBox::~WDL_VirtualComboBox()
561 m_items.Empty(true,free);
565 static void GenSubMenu(HMENU menu, int *x, WDL_PtrList<char> *items, int curitem)
567 int pos=0;
568 while (*x < items->GetSize())
570 MENUITEMINFO mi={sizeof(mi),MIIM_ID|MIIM_STATE|MIIM_TYPE,MFT_STRING, 0,1000u + *x,NULL,NULL,NULL,0};
571 mi.dwTypeData = (char *)items->Get(*x);
572 mi.fState = curitem == *x ?MFS_CHECKED:0;
574 (*x) ++; // advance to next item
576 if (!strcmp(mi.dwTypeData,"<SEP>")) mi.fType=MFT_SEPARATOR;
577 else if (!strcmp(mi.dwTypeData,"</SUB>")) break; // done!
578 else if (!strncmp(mi.dwTypeData,"<SUB>",5))
580 mi.hSubMenu= CreatePopupMenu();
581 GenSubMenu(mi.hSubMenu,x,items,curitem);
582 mi.fMask |= MIIM_SUBMENU;
583 mi.dwTypeData += 5; // skip <SUB>
585 InsertMenuItem(menu,pos++,TRUE,&mi);
589 int WDL_VirtualComboBox::OnMouseDown(int xpos, int ypos)
591 if (m__iaccess) m__iaccess->OnFocused();
592 if (m_items.GetSize())
594 //SendCommand(WM_COMMAND, GetID()|(CBN_DROPDOWN<<16), 0, this);
596 HMENU menu=CreatePopupMenu();
597 int x=0;
598 GenSubMenu(menu,&x,&m_items,m_curitem);
600 HWND h=GetRealParent();
601 POINT p={0,};
602 WDL_VirtualWnd *w=this;
603 while (w)
605 RECT r;
606 w->GetPosition(&r);
607 p.x+=r.left;
608 p.y+=w==this?r.bottom:r.top;
609 w=w->GetParent();
611 if (h)
613 ClientToScreen(h,&p);
614 //SetFocus(h);
617 WDL_VWND_DCHK(a);
619 int ret=TrackPopupMenu(menu,TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RETURNCMD|TPM_NONOTIFY,p.x,p.y,0,h,NULL);
621 DestroyMenu(menu);
623 if (ret>=1000 && a.isOK())
625 m_curitem=ret-1000;
626 RequestRedraw(NULL);
627 // track menu
628 SendCommand(WM_COMMAND,GetID() | (CBN_SELCHANGE<<16),0,this);
629 if (a.isOK() && m__iaccess) m__iaccess->OnStateChange();
632 return -1;
635 void WDL_VirtualComboBox::OnPaint(LICE_IBitmap *drawbm, int origin_x, int origin_y, RECT *cliprect, int rscale)
638 if (m_font) m_font->SetBkMode(TRANSPARENT);
640 RECT r;
641 WDL_VWnd::GetPositionPaintExtent(&r,rscale);
642 r.left+=origin_x;
643 r.right+=origin_x;
644 r.top+=origin_y;
645 r.bottom+=origin_y;
647 int col=GSC(COLOR_WINDOW);
648 col = LICE_RGBA_FROMNATIVE(col,255);
649 LICE_FillRect(drawbm,r.left,r.top,r.right-r.left,r.bottom-r.top,col,1.0f,LICE_BLIT_MODE_COPY);
652 RECT tr=r;
653 tr.left=tr.right-(tr.bottom-tr.top);
654 //int col2=GSC(COLOR_BTNFACE);
655 // col2 = LICE_RGBA_FROMNATIVE(col2,255);
657 LICE_FillRect(drawbm,tr.left,tr.top,tr.right-tr.left,tr.bottom-tr.top,col,1.0f,LICE_BLIT_MODE_COPY);
661 int tcol=GSC(COLOR_BTNTEXT);
662 tcol=LICE_RGBA_FROMNATIVE(tcol,255);
663 if (m_font && m_items.Get(m_curitem)&&m_items.Get(m_curitem)[0])
665 RECT tr=r;
666 tr.left+=2;
667 tr.right-=16;
668 m_font->SetTextColor(tcol);
669 if (m_align == 0)
671 RECT r2={0,};
672 m_font->DrawText(drawbm,m_items.Get(m_curitem),-1,&tr,DT_SINGLELINE|DT_CALCRECT|DT_NOPREFIX);
673 m_font->DrawText(drawbm,m_items.Get(m_curitem),-1,&tr,DT_SINGLELINE|DT_VCENTER|(r2.right < tr.right-tr.left ? DT_CENTER : DT_LEFT)|DT_NOPREFIX);
675 else
676 m_font->DrawText(drawbm,m_items.Get(m_curitem),-1,&tr,DT_SINGLELINE|DT_VCENTER|(m_align<0?DT_LEFT:DT_RIGHT)|DT_NOPREFIX);
680 // pen3=tcol
681 int pencol = GSC(COLOR_3DSHADOW);
682 pencol = LICE_RGBA_FROMNATIVE(pencol,255);
683 int pencol2 = GSC(COLOR_3DHILIGHT);
684 pencol2 = LICE_RGBA_FROMNATIVE(pencol2,255);
686 // draw the down arrow button
688 int bs=(r.bottom-r.top);
689 int l=r.right-bs;
691 int a=(bs/4)&~1;
693 LICE_Line(drawbm,l,r.top,l,r.bottom-1,pencol,1.0f,LICE_BLIT_MODE_COPY,false);
694 LICE_Line(drawbm,l-1,r.top,l-1,r.bottom-1,pencol2,1.0f,LICE_BLIT_MODE_COPY,false);
696 LICE_Line(drawbm,l+bs/2-a,r.top+bs/2-a/2,
697 l+bs/2,r.top+bs/2+a/2,tcol,1.0f,LICE_BLIT_MODE_COPY,true);
698 LICE_Line(drawbm,l+bs/2,r.top+bs/2+a/2,
699 l+bs/2+a,r.top+bs/2-a/2, tcol,1.0f,LICE_BLIT_MODE_COPY,true);
704 // draw the border
705 LICE_Line(drawbm,r.left,r.bottom-1,r.left,r.top,pencol,1.0f,0,false);
706 LICE_Line(drawbm,r.left,r.top,r.right-1,r.top,pencol,1.0f,0,false);
707 LICE_Line(drawbm,r.right-1,r.top,r.right-1,r.bottom-1,pencol2,1.0f,0,false);
708 LICE_Line(drawbm,r.left,r.bottom-1,r.right-1,r.bottom-1,pencol2,1.0f,0,false);
715 WDL_VirtualStaticText::WDL_VirtualStaticText()
717 m_dotint=false;
718 m_bkbm=0;
719 m_margin_r=m_margin_l=0;
720 m_margin_t=m_margin_b=0;
721 m_fg=m_bg=0;
722 m_wantborder=false;
723 m_vfont=m_font=0;
724 m_align=-1;
725 m_wantsingle=false;
726 m_didvert=0;
727 m_didalign=-1;
728 m_wantabbr=false;
731 WDL_VirtualStaticText::~WDL_VirtualStaticText()
735 void WDL_VirtualStaticText::SetText(const char *text)
737 if (strcmp(m_text.Get(),text?text:""))
739 m_text.Set(text?text:"");
740 if (m_font) RequestRedraw(NULL);
744 void WDL_VirtualStaticText::SetWantPreserveTrailingNumber(bool abbreviate)
746 m_wantabbr=abbreviate;
747 if (m_font) RequestRedraw(NULL);
750 void WDL_VirtualStaticText::GetPositionPaintExtent(RECT *r, int rscale)
752 // overridden in case m_bkbm has outer areas
753 WDL_VWnd::GetPositionPaintExtent(r,rscale);
754 if (m_bkbm && m_bkbm->bgimage)
756 if (m_bkbm->bgimage_lt[0]>0 &&
757 m_bkbm->bgimage_lt[1]>0 &&
758 m_bkbm->bgimage_rb[0]>0 &&
759 m_bkbm->bgimage_rb[1]>0 &&
760 m_bkbm->bgimage_lt_out[0]>0 &&
761 m_bkbm->bgimage_lt_out[1]>0 &&
762 m_bkbm->bgimage_rb_out[0]>0 &&
763 m_bkbm->bgimage_rb_out[1]>0)
765 r->left -= m_bkbm->bgimage_lt_out[0]-1;
766 r->top -= m_bkbm->bgimage_lt_out[1]-1;
767 r->right += m_bkbm->bgimage_rb_out[0]-1;
768 r->bottom += m_bkbm->bgimage_rb_out[1]-1;
773 int WDL_VirtualStaticText::OnMouseDown(int xpos, int ypos)
775 int a = WDL_VWnd::OnMouseDown(xpos,ypos);
776 if (a) return a;
778 if (m__iaccess) m__iaccess->OnFocused();
780 if (m_wantsingle)
782 SendCommand(WM_COMMAND,GetID() | (STN_CLICKED<<16),0,this);
783 return -1;
785 return 0;
788 void WDL_VirtualStaticText::OnPaint(LICE_IBitmap *drawbm, int origin_x, int origin_y, RECT *cliprect, int rscale)
790 RECT r=m_position;
791 ScaleRect(&r,rscale);
792 r.left+=origin_x;
793 r.right+=origin_x;
794 r.top += origin_y;
795 r.bottom += origin_y;
797 if (m_bkbm && m_bkbm->bgimage)
799 WDL_VirtualWnd_ScaledBlitBG(drawbm,m_bkbm,
800 r.left,r.top,r.right-r.left,r.bottom-r.top,
801 r.left,r.top,r.right-r.left,r.bottom-r.top,
802 1.0,LICE_BLIT_MODE_COPY|LICE_BLIT_FILTER_BILINEAR|LICE_BLIT_USE_ALPHA);
804 if (m_dotint && LICE_GETA(m_bg))
806 float amt = LICE_GETA(m_bg)/255.0f;
808 // todo: apply amt
810 float rv=LICE_GETR(m_bg)/255.0f;
811 float gv=LICE_GETG(m_bg)/255.0f;
812 float bv=LICE_GETB(m_bg)/255.0f;
814 float avg=(rv+gv+bv)*0.33333f;
815 if (avg<0.05f)avg=0.05f;
817 float sc=0.5f*amt;
818 float sc2 = (amt-sc)/avg;
820 float sc3=32.0f * amt;
821 float sc4=64.0f*(avg-0.5f) * amt;
823 // tint
824 LICE_MultiplyAddRect(drawbm,
825 r.left,r.top,
826 r.right-r.left,
827 r.bottom-r.top,
828 sc+rv*sc2 + (1.0f-amt),
829 sc+gv*sc2 + (1.0f-amt),
830 sc+bv*sc2 + (1.0f-amt),
831 1.0f,
832 (rv-avg)*sc3+sc4,
833 (gv-avg)*sc3+sc4,
834 (bv-avg)*sc3+sc4,
835 0.0f);
838 else
840 if (LICE_GETA(m_bg))
842 LICE_FillRect(drawbm,r.left,r.top,r.right-r.left,r.bottom-r.top,m_bg,LICE_GETA(m_bg)/255.0f,LICE_BLIT_MODE_COPY);
845 if (m_wantborder)
847 int cidx=COLOR_3DSHADOW;
849 int pencol = GSC(cidx);
850 pencol = LICE_RGBA_FROMNATIVE(pencol,255);
852 LICE_Line(drawbm,r.left,r.bottom-1,r.left,r.top,pencol,1.0f,LICE_BLIT_MODE_COPY,false);
853 LICE_Line(drawbm,r.left,r.top,r.right-1,r.top,pencol,1.0f,LICE_BLIT_MODE_COPY,false);
854 cidx=COLOR_3DHILIGHT;
855 pencol = GSC(cidx);
856 pencol = LICE_RGBA_FROMNATIVE(pencol,255);
857 LICE_Line(drawbm,r.right-1,r.top,r.right-1,r.bottom-1,pencol,1.0f,LICE_BLIT_MODE_COPY,false);
858 LICE_Line(drawbm,r.right-1,r.bottom-1,r.left,r.bottom-1,pencol,1.0f,LICE_BLIT_MODE_COPY,false);
860 r.left++;
861 r.bottom--;
862 r.top++;
863 r.right--;
868 if (m_text.Get()[0])
870 r.left += m_margin_l;
871 r.right -= m_margin_r;
872 r.top += m_margin_t;
873 r.bottom -= m_margin_b;
875 m_didvert=m_vfont && (r.right-r.left)<(r.bottom-r.top)/2;
876 LICE_IFont *font = m_didvert ? m_vfont : m_font;
878 if (font)
880 font->SetBkMode(TRANSPARENT);
882 m_didalign=m_align;
883 if (m_didalign==0)
885 RECT r2={0,0,0,0};
886 font->DrawText(drawbm,m_text.Get(),-1,&r2,DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT);
887 if (m_didvert)
889 if (r2.bottom > r.bottom-r.top) m_didalign=-1;
891 else
893 if (r2.right > r.right-r.left) m_didalign=-1;
897 int dtflags=DT_SINGLELINE|DT_NOPREFIX;
899 if (m_didvert)
901 dtflags |= DT_CENTER;
902 if (m_didalign < 0) dtflags |= DT_TOP;
903 else if (m_didalign > 0) dtflags |= DT_BOTTOM;
904 else dtflags |= DT_VCENTER;
906 else
908 dtflags|=DT_VCENTER;
910 if (m_didalign < 0) dtflags |= DT_LEFT;
911 else if (m_didalign > 0) dtflags |= DT_RIGHT;
912 else dtflags |= DT_CENTER;
914 const char* txt=m_text.Get();
915 const int len = m_text.GetLength();
917 int abbrx=0;
918 char abbrbuf[64];
919 abbrbuf[0]=0;
921 if (m_wantabbr)
923 if (len && txt[len-1] > 0 && isdigit(txt[len-1]))
925 RECT tr = { 0, 0, 0, 0 };
926 font->DrawText(drawbm, txt, -1, &tr, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT);
927 if (m_didvert ? (tr.bottom > r.bottom-r.top) : (tr.right > r.right-r.left))
929 strcpy(abbrbuf, "..");
930 int i;
931 for (i=len-1; i >= 0; --i)
933 if (txt[i] < 0 || !isdigit(txt[i]) || len-i > 4) break;
935 strcat(abbrbuf, txt+i+1);
937 int f=dtflags&~(DT_TOP|DT_VCENTER|DT_BOTTOM|DT_LEFT|DT_CENTER|DT_RIGHT);
938 RECT tr2 = { 0, 0, 0, 0 };
939 if (m_didvert)
941 font->DrawText(drawbm, abbrbuf, -1, &tr2, f|DT_CALCRECT);
942 abbrx=tr2.bottom;
944 else
946 font->DrawText(drawbm, abbrbuf, -1, &tr2, f|DT_CALCRECT);
947 abbrx=tr2.right;
953 int tcol=m_fg ? m_fg : LICE_RGBA_FROMNATIVE(GSC(COLOR_BTNTEXT));
954 font->SetTextColor(tcol);
955 if (m_fg && LICE_GETA(m_fg) != 0xff) font->SetCombineMode(LICE_BLIT_MODE_COPY,LICE_GETA(m_fg)/255.0f);
957 if (abbrx && abbrbuf[0])
959 if (m_didvert)
961 int f=dtflags&~(DT_TOP|DT_VCENTER|DT_BOTTOM);
962 RECT r1 = { r.left, r.top, r.right, r.bottom-abbrx };
963 font->DrawText(drawbm, txt, -1, &r1, f|DT_TOP);
964 RECT r2 = { r.left, r.bottom-abbrx, r.right, r.bottom };
965 font->DrawText(drawbm, abbrbuf, -1, &r2, f|DT_BOTTOM);
967 else
969 int f=dtflags&~(DT_LEFT|DT_CENTER|DT_RIGHT);
970 RECT r1 = { r.left, r.top, r.right-abbrx, r.bottom };
971 font->DrawText(drawbm, txt, -1, &r1, f|DT_LEFT);
972 RECT r2 = { r.right-abbrx, r.top, r.right, r.bottom };
973 font->DrawText(drawbm, abbrbuf, -1, &r2, f|DT_RIGHT);
976 else
978 font->DrawText(drawbm,txt,-1,&r,dtflags);
981 if (m_fg && LICE_GETA(m_fg) != 0xff) font->SetCombineMode(LICE_BLIT_MODE_COPY,1.0f);
986 WDL_VWnd::OnPaint(drawbm,origin_x,origin_y,cliprect,rscale);
990 int WDL_VirtualStaticText::GetCharFromCoord(int xpos, int ypos)
992 LICE_IFont *font = (m_didvert ? m_vfont : m_font);
993 if (!font) return -1;
995 const char* str = m_text.Get();
996 const int len = m_text.GetLength();
997 if (!len) return -1;
999 // for align left/right, we could DT_CALCRECT with 1 char, then 2, etc, but that won't work for align center
1000 // so we'll just estimate
1001 RECT tr = { 0, 0, m_position.right-m_position.left, m_position.bottom-m_position.top };
1002 font->DrawText(0, str, len, &tr, DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT);
1003 int tw = tr.right;
1004 int th = tr.bottom;
1006 RECT r = m_position;
1007 if (m_wantborder)
1009 r.left++;
1010 r.top++;
1011 r.right--;
1012 r.bottom--;
1014 r.left += m_margin_l;
1015 r.top += m_margin_t;
1016 r.right -= m_margin_r;
1017 r.bottom -= m_margin_b;
1018 int w = r.right-r.left;
1019 int h = r.bottom-r.top;
1021 if (m_didvert)
1023 r.left += (w-tw)/2;
1024 r.right -= (w-tw)/2;
1026 else
1028 r.top += (h-th)/2;
1029 r.bottom -= (h-th)/2;
1032 if (m_didalign < 0)
1034 if (m_didvert) r.bottom = r.top+th;
1035 else r.right = r.left+tw;
1037 else if (m_didalign > 0)
1039 if (m_didvert) r.top = r.bottom-th;
1040 else r.left = r.right-tw;
1042 else
1044 if (m_didvert)
1046 r.top += (h-th)/2;
1047 r.bottom -= (h-th)/2;
1049 else
1051 r.left += (w-tw)/2;
1052 r.right -= (w-tw)/2;
1056 int c=-1;
1057 if (m_didvert)
1059 if (ypos < r.top) c=-1;
1060 else if (ypos > r.bottom) c=len;
1061 else c = (int)((double)len*(double)(ypos-r.top)/(double)(r.bottom-r.top));
1063 else
1065 if (xpos < r.left) c=-1;
1066 else if (xpos > r.right) c=len;
1067 else c = (int)((double)len*(double)(xpos-r.left)/(double)(r.right-r.left));
1070 return c;
1074 bool WDL_VirtualStaticText::OnMouseDblClick(int xpos, int ypos)
1076 if (!WDL_VWnd::OnMouseDblClick(xpos,ypos))
1078 SendCommand(WM_COMMAND,GetID() | (STN_DBLCLK<<16),0,this);
1081 return true;
1085 bool WDL_VirtualIconButton::WantsPaintOver()
1087 return /*m_is_button && */m_iconCfg && m_iconCfg->image && m_iconCfg->olimage;
1090 void WDL_VirtualIconButton::GetPositionPaintOverExtent(RECT *r, int rscale)
1092 WDL_VWnd::GetPositionPaintOverExtent(r,rscale);
1093 if (m_iconCfg && m_iconCfg->image && m_iconCfg->olimage && (m_iconCfg->image_ltrb_used.flags&1))
1095 if (m_iconCfg->image_ltrb_used.flags&2) // main image has pink lines, use 1:1 pixel for outer area size
1097 r->left -= m_iconCfg->image_ltrb_ol[0];
1098 r->top -= m_iconCfg->image_ltrb_ol[1];
1099 r->right += m_iconCfg->image_ltrb_ol[2];
1100 r->bottom += m_iconCfg->image_ltrb_ol[3];
1102 else
1104 int w=(m_iconCfg->olimage->getWidth()-2)/3-m_iconCfg->image_ltrb_ol[0]-m_iconCfg->image_ltrb_ol[2];
1105 if (w<1)w=1;
1106 double wsc=(r->right-r->left)/(double)w;
1108 int h=m_iconCfg->olimage->getHeight()-2-m_iconCfg->image_ltrb_ol[1]-m_iconCfg->image_ltrb_ol[3];
1109 if (h<1)h=1;
1110 double hsc=(r->bottom-r->top)/(double)h;
1112 r->left-=(int) (m_iconCfg->image_ltrb_ol[0]*wsc);
1113 r->top-=(int) (m_iconCfg->image_ltrb_ol[1]*hsc);
1114 r->right+=(int) (m_iconCfg->image_ltrb_ol[2]*wsc);
1115 r->bottom+=(int) (m_iconCfg->image_ltrb_ol[3]*hsc);
1119 void WDL_VirtualIconButton_PreprocessSkinConfig(WDL_VirtualIconButton_SkinConfig *a)
1121 if (a && a->image)
1123 a->image_ltrb_used.flags=0;
1124 int wi;
1125 for(wi=0;wi<2;wi++)
1127 LICE_IBitmap *srcimg = wi ? a->image : a->olimage;
1128 if (!srcimg) continue;
1129 int w=srcimg->getWidth();
1130 int h=srcimg->getHeight();
1132 if (LICE_GetPixel(srcimg,0,0)==LICE_RGBA(255,0,255,255)&&
1133 LICE_GetPixel(srcimg,w-1,h-1)==LICE_RGBA(255,0,255,255))
1135 int lext=0,rext=0,bext=0,text=0;
1136 int x;
1137 for (x = 1; x < w/3 && LICE_GetPixel(srcimg,x,0)==LICE_RGBA(255,0,255,255); x ++);
1138 lext=x-1;
1139 for (x = 1; x < h && LICE_GetPixel(srcimg,0,x)==LICE_RGBA(255,0,255,255); x ++);
1140 text=x-1;
1142 for (x = w-2; x >= (w*2/3) && LICE_GetPixel(srcimg,x,h-1)==LICE_RGBA(255,0,255,255); x --);
1143 rext=w-2-x;
1144 for (x = h-2; x >= text && LICE_GetPixel(srcimg,w-1,x)==LICE_RGBA(255,0,255,255); x --);
1145 bext=h-2-x;
1146 if (lext||text||rext||bext)
1148 a->image_ltrb_used.flags |= 1 << wi;
1149 short *buf = wi ? a->image_ltrb_main : a->image_ltrb_ol;
1150 buf[0]=lext;
1151 buf[1]=text;
1152 buf[2]=rext;
1153 buf[3]=bext;