ColorSelector: Add WarningIcon to add colors to the palette

Simplified the color selector UI. Now RGB/HSV colors are shown correctly
and a new warning icon/button is visible when the color is not part of
the current palette. This button can be used to quickly add the new entry
to the palette.
This commit is contained in:
David Capello 2014-06-01 18:15:11 -03:00
parent f91f41a425
commit ed6c0f986d
12 changed files with 252 additions and 100 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -327,6 +327,7 @@
<part id="drop_pixels_ok_selected" x="176" y="184" w="7" h="8" /> <part id="drop_pixels_ok_selected" x="176" y="184" w="7" h="8" />
<part id="drop_pixels_cancel" x="192" y="176" w="7" h="8" /> <part id="drop_pixels_cancel" x="192" y="176" w="7" h="8" />
<part id="drop_pixels_cancel_selected" x="192" y="184" w="7" h="8" /> <part id="drop_pixels_cancel_selected" x="192" y="184" w="7" h="8" />
<part id="warning_box" x="112" y="80" w="9" h="10" />
</parts> </parts>
<stylesheet> <stylesheet>
@ -545,6 +546,15 @@
<background part="flag_highlight" color="flag_clicked" /> <background part="flag_highlight" color="flag_clicked" />
</style> </style>
<!-- warning_box -->
<style id="warning_box">
<background color="face" />
<icon part="warning_box" align="center" valign="middle" />
</style>
<style id="warning_box:hover">
<background color="hot_face" />
</style>
</stylesheet> </stylesheet>
</skin> </skin>

View File

@ -601,14 +601,10 @@ int Color::getIndex() const
return 0; return 0;
case Color::RgbType: case Color::RgbType:
PRINTF("Getting `index' from a RGB color\n"); // TODO return get_current_palette()->findBestfit(getRed(), getGreen(), getBlue());
ASSERT(false);
break;
case Color::HsvType: case Color::HsvType:
PRINTF("Getting `index' from a HSV color\n"); // TODO return get_current_palette()->findBestfit(getRed(), getGreen(), getBlue());
ASSERT(false);
break;
case Color::GrayType: case Color::GrayType:
return m_value.gray; return m_value.gray;

View File

@ -168,10 +168,7 @@ raster::color_t color_utils::color_for_image(const app::Color& color, PixelForma
c = graya(color.getGray(), 255); c = graya(color.getGray(), 255);
break; break;
case IMAGE_INDEXED: case IMAGE_INDEXED:
if (color.getType() == app::Color::IndexType)
c = color.getIndex(); c = color.getIndex();
else
c = get_current_palette()->findBestfit(color.getRed(), color.getGreen(), color.getBlue());
break; break;
} }

View File

@ -195,13 +195,12 @@ static void rectgrid(ui::Graphics* g, const gfx::Rect& rc, const gfx::Size& tile
} }
} }
static void draw_color(ui::Graphics* g, const Rect& rc, PixelFormat pixelFormat, const app::Color& color) static void draw_color(ui::Graphics* g, const Rect& rc, const app::Color& color)
{ {
if (rc.w < 1 || rc.h < 1) if (rc.w < 1 || rc.h < 1)
return; return;
app::Color::Type type = color.getType(); app::Color::Type type = color.getType();
BITMAP* graph;
if (type == app::Color::MaskType) { if (type == app::Color::MaskType) {
rectgrid(g, rc, gfx::Size(rc.w/4, rc.h/2)); rectgrid(g, rc, gfx::Size(rc.w/4, rc.h/2));
@ -222,59 +221,12 @@ static void draw_color(ui::Graphics* g, const Rect& rc, PixelFormat pixelFormat,
return; return;
} }
switch (pixelFormat) { g->fillRect(color_utils::color_for_ui(color), rc);
case IMAGE_INDEXED:
g->fillRect(
color_utils::color_for_ui(
app::Color::fromIndex(
color_utils::color_for_image(color, pixelFormat))),
rc);
break;
case IMAGE_RGB:
graph = create_bitmap_ex(32, rc.w, rc.h);
if (!graph)
return;
{
raster::color_t rgb_bitmap_color = color_utils::color_for_image(color, pixelFormat);
app::Color color2 = app::Color::fromRgb(rgba_getr(rgb_bitmap_color),
rgba_getg(rgb_bitmap_color),
rgba_getb(rgb_bitmap_color));
rectfill(graph, 0, 0, rc.w-1, rc.h-1,
color_utils::color_for_allegro(color2, 32));
}
g->blit(graph, 0, 0, rc.x, rc.y, rc.w, rc.h);
destroy_bitmap(graph);
break;
case IMAGE_GRAYSCALE:
graph = create_bitmap_ex(32, rc.w, rc.h);
if (!graph)
return;
{
int gray_bitmap_color = color_utils::color_for_image(color, pixelFormat);
app::Color color2 = app::Color::fromGray(graya_getv(gray_bitmap_color));
rectfill(graph, 0, 0, rc.w-1, rc.h-1,
color_utils::color_for_allegro(color2, 32));
}
g->blit(graph, 0, 0, rc.x, rc.y, rc.w, rc.h);
destroy_bitmap(graph);
break;
}
} }
void draw_color_button(ui::Graphics* g, void draw_color_button(ui::Graphics* g,
const Rect& rc, const Rect& rc, const app::Color& color,
bool outer_nw, bool outer_n, bool outer_ne, bool outer_e, bool hot, bool drag)
bool outer_se, bool outer_s, bool outer_sw, bool outer_w,
PixelFormat pixelFormat, const app::Color& color, bool hot, bool drag)
{ {
SkinTheme* theme = (SkinTheme*)ui::CurrentTheme::get(); SkinTheme* theme = (SkinTheme*)ui::CurrentTheme::get();
int scale = ui::jguiscale(); int scale = ui::jguiscale();
@ -283,20 +235,20 @@ void draw_color_button(ui::Graphics* g,
draw_color(g, draw_color(g,
Rect(rc.x+1*scale, Rect(rc.x+1*scale,
rc.y+1*scale, rc.y+1*scale,
rc.w-((outer_e) ? 2*scale: 1*scale), rc.w-2*scale,
rc.h-((outer_s) ? 2*scale: 1*scale)), pixelFormat, color); rc.h-2*scale), color);
// Draw opaque border // Draw opaque border
{ {
int parts[8] = { int parts[8] = {
outer_nw ? PART_COLORBAR_0_NW: PART_COLORBAR_3_NW, PART_COLORBAR_0_NW,
outer_n ? PART_COLORBAR_0_N : PART_COLORBAR_2_N, PART_COLORBAR_0_N,
outer_ne ? PART_COLORBAR_1_NE: (outer_e ? PART_COLORBAR_3_NE: PART_COLORBAR_2_NE), PART_COLORBAR_1_NE,
outer_e ? PART_COLORBAR_1_E : PART_COLORBAR_0_E, PART_COLORBAR_1_E,
outer_se ? PART_COLORBAR_3_SE: (outer_s ? PART_COLORBAR_2_SE: (outer_e ? PART_COLORBAR_1_SE: PART_COLORBAR_0_SE)), PART_COLORBAR_3_SE,
outer_s ? PART_COLORBAR_2_S : PART_COLORBAR_0_S, PART_COLORBAR_2_S,
outer_sw ? PART_COLORBAR_2_SW: (outer_s ? PART_COLORBAR_3_SW: PART_COLORBAR_1_SW), PART_COLORBAR_2_SW,
outer_w ? PART_COLORBAR_0_W : PART_COLORBAR_1_W, PART_COLORBAR_0_W
}; };
theme->draw_bounds_array(g, rc, parts); theme->draw_bounds_array(g, rc, parts);
} }
@ -304,7 +256,7 @@ void draw_color_button(ui::Graphics* g,
// Draw hot // Draw hot
if (hot) { if (hot) {
theme->draw_bounds_nw(g, theme->draw_bounds_nw(g,
gfx::Rect(rc.x, rc.y, rc.w, rc.h-1 - (outer_s ? 1*scale: 0)), gfx::Rect(rc.x, rc.y, rc.w, rc.h-1 - 1*scale),
PART_COLORBAR_BORDER_HOTFG_NW); PART_COLORBAR_BORDER_HOTFG_NW);
} }
} }

View File

@ -35,10 +35,7 @@ namespace app {
void dotted_mode(int offset); void dotted_mode(int offset);
void draw_color_button(ui::Graphics* g, void draw_color_button(ui::Graphics* g,
const gfx::Rect& rc, const gfx::Rect& rc, const app::Color& color,
bool outer_nw, bool outer_n, bool outer_ne, bool outer_e,
bool outer_se, bool outer_s, bool outer_sw, bool outer_w,
PixelFormat pixelFormat, const app::Color& color,
bool hot, bool drag); bool hot, bool drag);
} // namespace app } // namespace app

View File

@ -197,11 +197,7 @@ void ColorButton::onPaint(PaintEvent& ev)
color = m_color; color = m_color;
draw_color_button(g, rc, draw_color_button(g, rc,
true, true, true, true, color, hasMouseOver(), false);
true, true, true, true,
m_pixelFormat,
color,
hasMouseOver(), false);
// Draw text // Draw text
std::string str = m_color.toHumanReadableString(m_pixelFormat, std::string str = m_color.toHumanReadableString(m_pixelFormat,

View File

@ -1,5 +1,5 @@
/* Aseprite /* Aseprite
* Copyright (C) 2001-2013 David Capello * Copyright (C) 2001-2014 David Capello
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -25,21 +25,68 @@
#include "app/app.h" #include "app/app.h"
#include "app/color.h" #include "app/color.h"
#include "app/console.h"
#include "app/context.h"
#include "app/context_access.h"
#include "app/document.h"
#include "app/modules/gfx.h" #include "app/modules/gfx.h"
#include "app/modules/gui.h" #include "app/modules/gui.h"
#include "app/modules/palettes.h" #include "app/modules/palettes.h"
#include "app/ui/color_selector.h" #include "app/ui/color_selector.h"
#include "app/ui/palette_view.h" #include "app/ui/palette_view.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/skin/style.h"
#include "app/ui_context.h"
#include "app/undo_transaction.h"
#include "app/undoers/set_palette_colors.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/scoped_value.h"
#include "gfx/border.h" #include "gfx/border.h"
#include "gfx/size.h" #include "gfx/size.h"
#include "raster/image.h" #include "raster/image.h"
#include "raster/image_bits.h"
#include "raster/palette.h" #include "raster/palette.h"
#include "raster/sprite.h"
#include "raster/stock.h"
#include "ui/ui.h" #include "ui/ui.h"
namespace app { namespace app {
using namespace ui; using namespace ui;
using namespace raster;
class ColorSelector::WarningIcon : public Button {
public:
WarningIcon() : Button("") {
}
private:
skin::Style* style() {
return skin::get_style("warning_box");
}
bool onProcessMessage(Message* msg) OVERRIDE {
switch (msg->type()) {
case kSetCursorMessage:
jmouse_set_cursor(kHandCursor);
return true;
}
return Button::onProcessMessage(msg);
}
void onPreferredSize(PreferredSizeEvent& ev) OVERRIDE {
ev.setPreferredSize(
style()->preferredSize(NULL, skin::Style::State()) + 4*jguiscale());
}
void onPaint(PaintEvent& ev) OVERRIDE {
Graphics* g = ev.getGraphics();
skin::Style::State state;
if (hasMouse()) state += skin::Style::hover();
if (isSelected()) state += skin::Style::clicked();
style()->paint(g, getClientBounds(), NULL, state);
}
};
ColorSelector::ColorSelector() ColorSelector::ColorSelector()
: PopupWindowPin("Color Selector", PopupWindow::kCloseOnClickInOtherWindow) : PopupWindowPin("Color Selector", PopupWindow::kCloseOnClickInOtherWindow)
@ -53,6 +100,7 @@ ColorSelector::ColorSelector()
, m_grayButton("Gray", 1, kButtonWidget) , m_grayButton("Gray", 1, kButtonWidget)
, m_maskButton("Mask", 1, kButtonWidget) , m_maskButton("Mask", 1, kButtonWidget)
, m_maskLabel("Transparent Color Selected") , m_maskLabel("Transparent Color Selected")
, m_warningIcon(new WarningIcon)
, m_disableHexUpdate(false) , m_disableHexUpdate(false)
{ {
m_topBox.setBorder(gfx::Border(0)); m_topBox.setBorder(gfx::Border(0));
@ -75,6 +123,7 @@ ColorSelector::ColorSelector()
m_topBox.addChild(&m_grayButton); m_topBox.addChild(&m_grayButton);
m_topBox.addChild(&m_maskButton); m_topBox.addChild(&m_maskButton);
m_topBox.addChild(&m_hexColorEntry); m_topBox.addChild(&m_hexColorEntry);
m_topBox.addChild(m_warningIcon);
{ {
Box* miniVbox = new Box(JI_VERTICAL); Box* miniVbox = new Box(JI_VERTICAL);
miniVbox->addChild(getPin()); miniVbox->addChild(getPin());
@ -94,6 +143,7 @@ ColorSelector::ColorSelector()
m_hsvButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this); m_hsvButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this);
m_grayButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this); m_grayButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this);
m_maskButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this); m_maskButton.Click.connect(&ColorSelector::onColorTypeButtonClick, this);
m_warningIcon->Click.connect(&ColorSelector::onFixWarningClick, this);
m_colorPalette.IndexChange.connect(&ColorSelector::onColorPaletteIndexChange, this); m_colorPalette.IndexChange.connect(&ColorSelector::onColorPaletteIndexChange, this);
m_rgbSliders.ColorChange.connect(&ColorSelector::onColorSlidersChange, this); m_rgbSliders.ColorChange.connect(&ColorSelector::onColorSlidersChange, this);
@ -107,6 +157,8 @@ ColorSelector::ColorSelector()
m_onPaletteChangeSlot = m_onPaletteChangeSlot =
App::instance()->PaletteChange.connect(&ColorSelector::onPaletteChange, this); App::instance()->PaletteChange.connect(&ColorSelector::onPaletteChange, this);
m_tooltips.addTooltipFor(m_warningIcon, "This color isn't in the palette\nPress here to add it.", JI_BOTTOM);
initTheme(); initTheme();
} }
@ -135,6 +187,14 @@ void ColorSelector::setColor(const app::Color& color, SetColorOptions options)
if (options == ChangeType) if (options == ChangeType)
selectColorType(m_color.getType()); selectColorType(m_color.getType());
int index = get_current_palette()->findExactMatch(
m_color.getRed(),
m_color.getGreen(),
m_color.getBlue());
m_warningIcon->setVisible(index < 0);
m_warningIcon->getParent()->layout();
} }
app::Color ColorSelector::getColor() const app::Color ColorSelector::getColor() const
@ -168,14 +228,116 @@ void ColorSelector::onColorHexEntryChange(const app::Color& color)
void ColorSelector::onColorTypeButtonClick(Event& ev) void ColorSelector::onColorTypeButtonClick(Event& ev)
{ {
RadioButton* source = static_cast<RadioButton*>(ev.getSource()); RadioButton* source = static_cast<RadioButton*>(ev.getSource());
app::Color newColor;
if (source == &m_indexButton) selectColorType(app::Color::IndexType); if (source == &m_indexButton) newColor = app::Color::fromIndex(getColor().getIndex());
else if (source == &m_rgbButton) selectColorType(app::Color::RgbType); else if (source == &m_rgbButton) newColor = app::Color::fromRgb(getColor().getRed(), getColor().getGreen(), getColor().getBlue());
else if (source == &m_hsvButton) selectColorType(app::Color::HsvType); else if (source == &m_hsvButton) newColor = app::Color::fromHsv(getColor().getHue(), getColor().getSaturation(), getColor().getValue());
else if (source == &m_grayButton) selectColorType(app::Color::GrayType); else if (source == &m_grayButton) newColor = app::Color::fromGray(getColor().getGray());
else if (source == &m_maskButton) { else if (source == &m_maskButton) newColor = app::Color::fromMask();
// Select mask color directly when the radio button is pressed
setColorWithSignal(app::Color::fromMask()); setColorWithSignal(newColor);
}
void ColorSelector::onFixWarningClick(ui::Event& ev)
{
try {
Palette* newPalette = get_current_palette(); // System current pal
color_t newColor = rgba(
m_color.getRed(),
m_color.getGreen(),
m_color.getBlue());
int index = newPalette->findExactMatch(
m_color.getRed(),
m_color.getGreen(),
m_color.getBlue());
// It should be -1, because the user has pressed the warning
// button that is available only when the color isn't in the
// palette.
ASSERT(index < 0);
if (index >= 0)
return;
int lastUsed = -1;
ContextWriter writer(UIContext::instance());
Document* document(writer.document());
Sprite* sprite = NULL;
if (document) {
sprite = writer.sprite();
// Find used entries in all stock images. In this way we can start
// looking for duplicated color entries in the palette from the
// last used one.
if (sprite->getPixelFormat() == IMAGE_INDEXED) {
lastUsed = sprite->getTransparentColor();
Stock* stock = sprite->getStock();
for (int i=0; i<(int)stock->size(); ++i) {
Image* image = stock->getImage(i);
if (!image)
continue;
const LockImageBits<IndexedTraits> bits(image);
for (LockImageBits<IndexedTraits>::const_iterator it=bits.begin(); it!=bits.end(); ++it) {
if (lastUsed < *it)
lastUsed = *it;
}
}
}
}
for (int i=lastUsed+1; i<(int)newPalette->size(); ++i) {
color_t c = newPalette->getEntry(i);
int altI = newPalette->findExactMatch(
rgba_getr(c), rgba_getg(c), rgba_getb(c));
if (altI < i) {
index = i;
break;
}
}
if (index < 0) {
if (newPalette->size() < Palette::MaxColors) {
newPalette->addEntry(newColor);
index = newPalette->size()-1;
}
if (index < 0) {
Alert::show(
"Error<<The palette is full."
"<<You cannot have more than %d colors.<<&OK",
Palette::MaxColors);
return;
}
}
else {
newPalette->setEntry(index, newColor);
}
if (document) {
FrameNumber frame = writer.frame();
UndoTransaction undoTransaction(writer.context(), "Add palette entry", undo::ModifyDocument);
undoTransaction.pushUndoer
(new undoers::SetPaletteColors(undoTransaction.getObjects(),
sprite, sprite->getPalette(frame),
frame, index, index));
sprite->setPalette(newPalette, false);
undoTransaction.commit();
}
set_current_palette(newPalette, false);
ui::Manager::getDefault()->invalidate();
m_warningIcon->setVisible(index < 0);
m_warningIcon->getParent()->layout();
}
catch (base::Exception& e) {
Console::showException(e);
} }
} }

View File

@ -29,6 +29,7 @@
#include "ui/button.h" #include "ui/button.h"
#include "ui/grid.h" #include "ui/grid.h"
#include "ui/label.h" #include "ui/label.h"
#include "ui/tooltips.h"
#include "ui/view.h" #include "ui/view.h"
namespace app { namespace app {
@ -54,6 +55,7 @@ namespace app {
void onColorSlidersChange(ColorSlidersChangeEvent& ev); void onColorSlidersChange(ColorSlidersChangeEvent& ev);
void onColorHexEntryChange(const app::Color& color); void onColorHexEntryChange(const app::Color& color);
void onColorTypeButtonClick(ui::Event& ev); void onColorTypeButtonClick(ui::Event& ev);
void onFixWarningClick(ui::Event& ev);
void onPaletteChange(); void onPaletteChange();
private: private:
@ -61,6 +63,9 @@ namespace app {
void setColorWithSignal(const app::Color& color); void setColorWithSignal(const app::Color& color);
void findBestfitIndex(const app::Color& color); void findBestfitIndex(const app::Color& color);
class WarningIcon;
ui::TooltipManager m_tooltips;
ui::Box m_vbox; ui::Box m_vbox;
ui::Box m_topBox; ui::Box m_topBox;
app::Color m_color; app::Color m_color;
@ -76,6 +81,7 @@ namespace app {
HsvSliders m_hsvSliders; HsvSliders m_hsvSliders;
GraySlider m_graySlider; GraySlider m_graySlider;
ui::Label m_maskLabel; ui::Label m_maskLabel;
WarningIcon* m_warningIcon;
Signal0<void>::SlotType* m_onPaletteChangeSlot; Signal0<void>::SlotType* m_onPaletteChangeSlot;
// This variable is used to avoid updating the m_hexColorEntry text // This variable is used to avoid updating the m_hexColorEntry text

View File

@ -165,6 +165,23 @@ void Rules::paint(ui::Graphics* g,
if (m_text) m_text->paint(g, bounds, text); if (m_text) m_text->paint(g, bounds, text);
} }
gfx::Size Rules::preferredSize(const char* text)
{
gfx::Size sz(0, 0);
if (m_icon) {
sz.w += m_icon->getPart()->getBitmap(0)->w;
sz.h = m_icon->getPart()->getBitmap(0)->h;
}
if (m_text && text) {
ui::ScreenGraphics g;
gfx::Size textSize = g.measureString(text);
//if (sz.w > 0) sz.w += 2; // TODO text separation
sz.w += textSize.w;
sz.h = MAX(sz.h, textSize.h);
}
return sz;
}
Style::Style(css::Sheet& sheet, const std::string& id) Style::Style(css::Sheet& sheet, const std::string& id)
: m_id(id) : m_id(id)
, m_compoundStyle(sheet.compoundStyle(id)) , m_compoundStyle(sheet.compoundStyle(id))
@ -179,10 +196,7 @@ Style::~Style()
} }
} }
void Style::paint(ui::Graphics* g, Rules* Style::getRulesFromState(const State& state)
const gfx::Rect& bounds,
const char* text,
const State& state)
{ {
Rules* rules = NULL; Rules* rules = NULL;
@ -195,7 +209,22 @@ void Style::paint(ui::Graphics* g,
m_rules[state] = rules; m_rules[state] = rules;
} }
rules->paint(g, bounds, text); return rules;
}
void Style::paint(ui::Graphics* g,
const gfx::Rect& bounds,
const char* text,
const State& state)
{
getRulesFromState(state)->paint(g, bounds, text);
}
gfx::Size Style::preferredSize(
const char* text,
const State& state)
{
return getRulesFromState(state)->preferredSize(text);
} }
} // namespace skin } // namespace skin

View File

@ -94,6 +94,8 @@ namespace app {
void setAlign(int align) { m_align = align; } void setAlign(int align) { m_align = align; }
void setPart(const SkinPartPtr& part) { m_part = part; } void setPart(const SkinPartPtr& part) { m_part = part; }
SkinPartPtr getPart() { return m_part; }
protected: protected:
void onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text) OVERRIDE; void onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text) OVERRIDE;
@ -111,6 +113,8 @@ namespace app {
const gfx::Rect& bounds, const gfx::Rect& bounds,
const char* text); const char* text);
gfx::Size preferredSize(const char* text);
private: private:
BackgroundRule* m_background; BackgroundRule* m_background;
TextRule* m_text; TextRule* m_text;
@ -135,11 +139,17 @@ namespace app {
const char* text, const char* text,
const State& state); const State& state);
gfx::Size preferredSize(
const char* text,
const State& state);
const std::string& id() const { return m_id; } const std::string& id() const { return m_id; }
private: private:
typedef std::map<State, Rules*> RulesMap; typedef std::map<State, Rules*> RulesMap;
Rules* getRulesFromState(const State& state);
std::string m_id; std::string m_id;
css::CompoundStyle m_compoundStyle; css::CompoundStyle m_compoundStyle;
RulesMap m_rules; RulesMap m_rules;

View File

@ -499,10 +499,7 @@ void StatusBar::onPaint(ui::PaintEvent& ev)
// Draw color // Draw color
draw_color_button(g, gfx::Rect(x, rc.y, 32*jguiscale(), rc.h), draw_color_button(g, gfx::Rect(x, rc.y, 32*jguiscale(), rc.h),
true, true, true, true, m_color, false, false);
true, true, true, true,
app_get_current_pixel_format(), m_color,
false, false);
x += (32+4)*jguiscale(); x += (32+4)*jguiscale();