Home | History | Annotate | Download | only in views
      1 #include "SkWidget.h"
      2 #include "SkCanvas.h"
      3 #include "SkKey.h"
      4 #include "SkParsePaint.h"
      5 #include "SkSystemEventTypes.h"
      6 #include "SkTextBox.h"
      7 
      8 #if 0
      9 
     10 #ifdef SK_DEBUG
     11 	static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[])
     12 	{
     13 		const char* value = dom.findAttr(node, attr);
     14 		if (value)
     15 			SkDebugf("unknown attribute %s=\"%s\"\n", attr, value);
     16 	}
     17 #else
     18 	#define assert_no_attr(dom, node, attr)
     19 #endif
     20 
     21 #include "SkAnimator.h"
     22 #include "SkTime.h"
     23 
     24 ///////////////////////////////////////////////////////////////////////////////
     25 
     26 enum SkinType {
     27 	kPushButton_SkinType,
     28 	kStaticText_SkinType,
     29 
     30 	kSkinTypeCount
     31 };
     32 
     33 struct SkinSuite {
     34 	SkinSuite();
     35 	~SkinSuite()
     36 	{
     37 		for (int i = 0; i < kSkinTypeCount; i++)
     38 			delete fAnimators[i];
     39 	}
     40 
     41 	SkAnimator*	get(SkinType);
     42 
     43 private:
     44 	SkAnimator*	fAnimators[kSkinTypeCount];
     45 };
     46 
     47 SkinSuite::SkinSuite()
     48 {
     49 	static const char kSkinPath[] = "skins/";
     50 
     51 	static const char* gSkinNames[] = {
     52 		"pushbutton_skin.xml",
     53 		"statictext_skin.xml"
     54 	};
     55 
     56 	for (unsigned i = 0; i < SK_ARRAY_COUNT(gSkinNames); i++)
     57 	{
     58 		size_t		len = strlen(gSkinNames[i]);
     59 		SkString	path(sizeof(kSkinPath) - 1 + len);
     60 
     61 		memcpy(path.writable_str(), kSkinPath, sizeof(kSkinPath) - 1);
     62 		memcpy(path.writable_str() + sizeof(kSkinPath) - 1, gSkinNames[i], len);
     63 
     64 		fAnimators[i] = new SkAnimator;
     65 		if (!fAnimators[i]->decodeURI(path.c_str()))
     66 		{
     67 			delete fAnimators[i];
     68 			fAnimators[i] = NULL;
     69 		}
     70 	}
     71 }
     72 
     73 SkAnimator* SkinSuite::get(SkinType st)
     74 {
     75 	SkASSERT((unsigned)st < kSkinTypeCount);
     76 	return fAnimators[st];
     77 }
     78 
     79 static SkinSuite* gSkinSuite;
     80 
     81 static SkAnimator* get_skin_animator(SkinType st)
     82 {
     83 #if 0
     84 	if (gSkinSuite == NULL)
     85 		gSkinSuite = new SkinSuite;
     86 	return gSkinSuite->get(st);
     87 #else
     88 	return NULL;
     89 #endif
     90 }
     91 
     92 ///////////////////////////////////////////////////////////////////////////////
     93 
     94 void SkWidget::Init()
     95 {
     96 }
     97 
     98 void SkWidget::Term()
     99 {
    100 	delete gSkinSuite;
    101 }
    102 
    103 void SkWidget::onEnabledChange()
    104 {
    105 	this->inval(NULL);
    106 }
    107 
    108 void SkWidget::postWidgetEvent()
    109 {
    110 	if (!fEvent.isType("") && this->hasListeners())
    111 	{
    112 		this->prepareWidgetEvent(&fEvent);
    113 		this->postToListeners(fEvent);
    114 	}
    115 }
    116 
    117 void SkWidget::prepareWidgetEvent(SkEvent*)
    118 {
    119 	// override in subclass to add any additional fields before posting
    120 }
    121 
    122 void SkWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node)
    123 {
    124 	this->INHERITED::onInflate(dom, node);
    125 
    126 	if ((node = dom.getFirstChild(node, "event")) != NULL)
    127 		fEvent.inflate(dom, node);
    128 }
    129 
    130 ///////////////////////////////////////////////////////////////////////////////
    131 
    132 size_t SkHasLabelWidget::getLabel(SkString* str) const
    133 {
    134 	if (str)
    135 		*str = fLabel;
    136 	return fLabel.size();
    137 }
    138 
    139 size_t SkHasLabelWidget::getLabel(char buffer[]) const
    140 {
    141 	if (buffer)
    142 		memcpy(buffer, fLabel.c_str(), fLabel.size());
    143 	return fLabel.size();
    144 }
    145 
    146 void SkHasLabelWidget::setLabel(const SkString& str)
    147 {
    148 	this->setLabel(str.c_str(), str.size());
    149 }
    150 
    151 void SkHasLabelWidget::setLabel(const char label[])
    152 {
    153 	this->setLabel(label, strlen(label));
    154 }
    155 
    156 void SkHasLabelWidget::setLabel(const char label[], size_t len)
    157 {
    158 	if (!fLabel.equals(label, len))
    159 	{
    160 		fLabel.set(label, len);
    161 		this->onLabelChange();
    162 	}
    163 }
    164 
    165 void SkHasLabelWidget::onLabelChange()
    166 {
    167 	// override in subclass
    168 }
    169 
    170 void SkHasLabelWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node)
    171 {
    172 	this->INHERITED::onInflate(dom, node);
    173 
    174 	const char* text = dom.findAttr(node, "label");
    175 	if (text)
    176 		this->setLabel(text);
    177 }
    178 
    179 /////////////////////////////////////////////////////////////////////////////////////
    180 
    181 void SkButtonWidget::setButtonState(State state)
    182 {
    183 	if (fState != state)
    184 	{
    185 		fState = state;
    186 		this->onButtonStateChange();
    187 	}
    188 }
    189 
    190 void SkButtonWidget::onButtonStateChange()
    191 {
    192 	this->inval(NULL);
    193 }
    194 
    195 void SkButtonWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node)
    196 {
    197 	this->INHERITED::onInflate(dom, node);
    198 
    199 	int	index;
    200 	if ((index = dom.findList(node, "buttonState", "off,on,unknown")) >= 0)
    201 		this->setButtonState((State)index);
    202 }
    203 
    204 /////////////////////////////////////////////////////////////////////////////////////
    205 
    206 bool SkPushButtonWidget::onEvent(const SkEvent& evt)
    207 {
    208 	if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey)
    209 	{
    210 		this->postWidgetEvent();
    211 		return true;
    212 	}
    213 	return this->INHERITED::onEvent(evt);
    214 }
    215 
    216 static const char* computeAnimatorState(int enabled, int focused, SkButtonWidget::State state)
    217 {
    218 	if (!enabled)
    219 		return "disabled";
    220 	if (state == SkButtonWidget::kOn_State)
    221 	{
    222 		SkASSERT(focused);
    223 		return "enabled-pressed";
    224 	}
    225 	if (focused)
    226 		return "enabled-focused";
    227 	return "enabled";
    228 }
    229 
    230 #include "SkBlurMaskFilter.h"
    231 #include "SkEmbossMaskFilter.h"
    232 
    233 static void create_emboss(SkPaint* paint, SkScalar radius, bool focus, bool pressed)
    234 {
    235 	SkEmbossMaskFilter::Light	light;
    236 
    237 	light.fDirection[0] = SK_Scalar1/2;
    238 	light.fDirection[1] = SK_Scalar1/2;
    239 	light.fDirection[2] = SK_Scalar1/3;
    240 	light.fAmbient		= 0x48;
    241 	light.fSpecular		= 0x80;
    242 
    243 	if (pressed)
    244 	{
    245 		light.fDirection[0] = -light.fDirection[0];
    246 		light.fDirection[1] = -light.fDirection[1];
    247 	}
    248 	if (focus)
    249 		light.fDirection[2] += SK_Scalar1/4;
    250 
    251 	paint->setMaskFilter(new SkEmbossMaskFilter(light, radius))->unref();
    252 }
    253 
    254 void SkPushButtonWidget::onDraw(SkCanvas* canvas)
    255 {
    256 	this->INHERITED::onDraw(canvas);
    257 
    258 	SkString label;
    259 	this->getLabel(&label);
    260 
    261 	SkAnimator* anim = get_skin_animator(kPushButton_SkinType);
    262 
    263 	if (anim)
    264 	{
    265 		SkEvent	evt("user");
    266 
    267 		evt.setString("id", "prime");
    268 		evt.setScalar("prime-width", this->width());
    269 		evt.setScalar("prime-height", this->height());
    270 		evt.setString("prime-text", label);
    271 		evt.setString("prime-state", computeAnimatorState(this->isEnabled(), this->hasFocus(), this->getButtonState()));
    272 
    273 		(void)anim->doUserEvent(evt);
    274 		SkPaint paint;
    275 		anim->draw(canvas, &paint, SkTime::GetMSecs());
    276 	}
    277 	else
    278 	{
    279 		SkRect	r;
    280 		SkPaint	p;
    281 
    282 		r.set(0, 0, this->width(), this->height());
    283 		p.setAntiAliasOn(true);
    284 		p.setColor(SK_ColorBLUE);
    285 		create_emboss(&p, SkIntToScalar(12)/5, this->hasFocus(), this->getButtonState() == kOn_State);
    286 		canvas->drawRoundRect(r, SkScalarHalf(this->height()), SkScalarHalf(this->height()), p);
    287 		p.setMaskFilter(NULL);
    288 
    289 		p.setTextAlign(SkPaint::kCenter_Align);
    290 
    291 		SkTextBox	box;
    292 		box.setMode(SkTextBox::kOneLine_Mode);
    293 		box.setSpacingAlign(SkTextBox::kCenter_SpacingAlign);
    294 		box.setBox(0, 0, this->width(), this->height());
    295 
    296 //		if (this->getButtonState() == kOn_State)
    297 //			p.setColor(SK_ColorRED);
    298 //		else
    299 			p.setColor(SK_ColorWHITE);
    300 
    301 		box.draw(canvas, label.c_str(), label.size(), p);
    302 	}
    303 }
    304 
    305 SkView::Click* SkPushButtonWidget::onFindClickHandler(SkScalar x, SkScalar y)
    306 {
    307 	this->acceptFocus();
    308 	return new Click(this);
    309 }
    310 
    311 bool SkPushButtonWidget::onClick(Click* click)
    312 {
    313 	SkRect	r;
    314 	State	state = kOff_State;
    315 
    316 	this->getLocalBounds(&r);
    317 	if (r.contains(click->fCurr))
    318 	{
    319 		if (click->fState == Click::kUp_State)
    320 			this->postWidgetEvent();
    321 		else
    322 			state = kOn_State;
    323 	}
    324 	this->setButtonState(state);
    325 	return true;
    326 }
    327 
    328 //////////////////////////////////////////////////////////////////////////////////////////
    329 
    330 SkStaticTextView::SkStaticTextView(U32 flags) : SkView(flags)
    331 {
    332 	fMargin.set(0, 0);
    333 	fMode = kFixedSize_Mode;
    334 	fSpacingAlign = SkTextBox::kStart_SpacingAlign;
    335 }
    336 
    337 SkStaticTextView::~SkStaticTextView()
    338 {
    339 }
    340 
    341 void SkStaticTextView::computeSize()
    342 {
    343 	if (fMode == kAutoWidth_Mode)
    344 	{
    345 		SkScalar width = fPaint.measureText(fText.c_str(), fText.size(), NULL, NULL);
    346 		this->setWidth(width + fMargin.fX * 2);
    347 	}
    348 	else if (fMode == kAutoHeight_Mode)
    349 	{
    350 		SkScalar width = this->width() - fMargin.fX * 2;
    351 		int lines = width > 0 ? SkTextLineBreaker::CountLines(fText.c_str(), fText.size(), fPaint, width) : 0;
    352 
    353 		SkScalar	before, after;
    354 		(void)fPaint.measureText(0, NULL, &before, &after);
    355 
    356 		this->setHeight(lines * (after - before) + fMargin.fY * 2);
    357 	}
    358 }
    359 
    360 void SkStaticTextView::setMode(Mode mode)
    361 {
    362 	SkASSERT((unsigned)mode < kModeCount);
    363 
    364 	if (fMode != mode)
    365 	{
    366 		fMode = SkToU8(mode);
    367 		this->computeSize();
    368 	}
    369 }
    370 
    371 void SkStaticTextView::setSpacingAlign(SkTextBox::SpacingAlign align)
    372 {
    373 	fSpacingAlign = SkToU8(align);
    374 	this->inval(NULL);
    375 }
    376 
    377 void SkStaticTextView::getMargin(SkPoint* margin) const
    378 {
    379 	if (margin)
    380 		*margin = fMargin;
    381 }
    382 
    383 void SkStaticTextView::setMargin(SkScalar dx, SkScalar dy)
    384 {
    385 	if (fMargin.fX != dx || fMargin.fY != dy)
    386 	{
    387 		fMargin.set(dx, dy);
    388 		this->computeSize();
    389 		this->inval(NULL);
    390 	}
    391 }
    392 
    393 size_t SkStaticTextView::getText(SkString* text) const
    394 {
    395 	if (text)
    396 		*text = fText;
    397 	return fText.size();
    398 }
    399 
    400 size_t SkStaticTextView::getText(char text[]) const
    401 {
    402 	if (text)
    403 		memcpy(text, fText.c_str(), fText.size());
    404 	return fText.size();
    405 }
    406 
    407 void SkStaticTextView::setText(const SkString& text)
    408 {
    409 	this->setText(text.c_str(), text.size());
    410 }
    411 
    412 void SkStaticTextView::setText(const char text[])
    413 {
    414 	this->setText(text, strlen(text));
    415 }
    416 
    417 void SkStaticTextView::setText(const char text[], size_t len)
    418 {
    419 	if (!fText.equals(text, len))
    420 	{
    421 		fText.set(text, len);
    422 		this->computeSize();
    423 		this->inval(NULL);
    424 	}
    425 }
    426 
    427 void SkStaticTextView::getPaint(SkPaint* paint) const
    428 {
    429 	if (paint)
    430 		*paint = fPaint;
    431 }
    432 
    433 void SkStaticTextView::setPaint(const SkPaint& paint)
    434 {
    435 	if (fPaint != paint)
    436 	{
    437 		fPaint = paint;
    438 		this->computeSize();
    439 		this->inval(NULL);
    440 	}
    441 }
    442 
    443 void SkStaticTextView::onDraw(SkCanvas* canvas)
    444 {
    445 	this->INHERITED::onDraw(canvas);
    446 
    447 	if (fText.isEmpty())
    448 		return;
    449 
    450 	SkTextBox	box;
    451 
    452 	box.setMode(fMode == kAutoWidth_Mode ? SkTextBox::kOneLine_Mode : SkTextBox::kLineBreak_Mode);
    453 	box.setSpacingAlign(this->getSpacingAlign());
    454 	box.setBox(fMargin.fX, fMargin.fY, this->width() - fMargin.fX, this->height() - fMargin.fY);
    455 	box.draw(canvas, fText.c_str(), fText.size(), fPaint);
    456 }
    457 
    458 void SkStaticTextView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
    459 {
    460 	this->INHERITED::onInflate(dom, node);
    461 
    462 	int	index;
    463 	if ((index = dom.findList(node, "mode", "fixed,auto-width,auto-height")) >= 0)
    464 		this->setMode((Mode)index);
    465 	else
    466 		assert_no_attr(dom, node, "mode");
    467 
    468 	if ((index = dom.findList(node, "spacing-align", "start,center,end")) >= 0)
    469 		this->setSpacingAlign((SkTextBox::SpacingAlign)index);
    470 	else
    471 		assert_no_attr(dom, node, "mode");
    472 
    473 	SkScalar s[2];
    474 	if (dom.findScalars(node, "margin", s, 2))
    475 		this->setMargin(s[0], s[1]);
    476 	else
    477 		assert_no_attr(dom, node, "margin");
    478 
    479 	const char* text = dom.findAttr(node, "text");
    480 	if (text)
    481 		this->setText(text);
    482 
    483 	if ((node = dom.getFirstChild(node, "paint")) != NULL)
    484 		SkPaint_Inflate(&fPaint, dom, node);
    485 }
    486 
    487 /////////////////////////////////////////////////////////////////////////////////////////////////////
    488 
    489 #include "SkImageDecoder.h"
    490 
    491 SkBitmapView::SkBitmapView(U32 flags) : SkView(flags)
    492 {
    493 }
    494 
    495 SkBitmapView::~SkBitmapView()
    496 {
    497 }
    498 
    499 bool SkBitmapView::getBitmap(SkBitmap* bitmap) const
    500 {
    501 	if (bitmap)
    502 		*bitmap = fBitmap;
    503 	return fBitmap.getConfig() != SkBitmap::kNo_Config;
    504 }
    505 
    506 void SkBitmapView::setBitmap(const SkBitmap* bitmap, bool viewOwnsPixels)
    507 {
    508 	if (bitmap)
    509 	{
    510 		fBitmap = *bitmap;
    511 		fBitmap.setOwnsPixels(viewOwnsPixels);
    512 	}
    513 }
    514 
    515 bool SkBitmapView::loadBitmapFromFile(const char path[])
    516 {
    517 	SkBitmap	bitmap;
    518 
    519 	if (SkImageDecoder::DecodeFile(path, &bitmap))
    520 	{
    521 		this->setBitmap(&bitmap, true);
    522 		bitmap.setOwnsPixels(false);
    523 		return true;
    524 	}
    525 	return false;
    526 }
    527 
    528 void SkBitmapView::onDraw(SkCanvas* canvas)
    529 {
    530 	if (fBitmap.getConfig() != SkBitmap::kNo_Config &&
    531 		fBitmap.width() && fBitmap.height())
    532 	{
    533 		SkAutoCanvasRestore	restore(canvas, true);
    534 		SkPaint				p;
    535 
    536 		p.setFilterType(SkPaint::kBilinear_FilterType);
    537 		canvas->scale(	this->width() / fBitmap.width(),
    538 						this->height() / fBitmap.height(),
    539 						0, 0);
    540 		canvas->drawBitmap(fBitmap, 0, 0, p);
    541 	}
    542 }
    543 
    544 void SkBitmapView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
    545 {
    546 	this->INHERITED::onInflate(dom, node);
    547 
    548 	const char* src = dom.findAttr(node, "src");
    549 	if (src)
    550 		(void)this->loadBitmapFromFile(src);
    551 }
    552 
    553 #endif
    554 
    555