Beispiel #1
0
/* TextEditor::setupFoldMargin
 * Sets up the code folding margin
 *******************************************************************/
void TextEditor::setupFoldMargin(TextStyle* margin_style)
{
	if (!txed_fold_enable)
	{
		SetMarginWidth(1, 0);
		return;
	}

	wxColour col_fg, col_bg;
	if (margin_style)
	{
		col_fg = WXCOL(margin_style->getForeground());
		col_bg = WXCOL(margin_style->getBackground());
	}
	else
	{
		col_fg = WXCOL(StyleSet::currentSet()->getStyle("foldmargin")->getForeground());
		col_bg = WXCOL(StyleSet::currentSet()->getStyle("foldmargin")->getBackground());
	}

	SetMarginType(1, wxSTC_MARGIN_SYMBOL);
	SetMarginWidth(1, 16);
	SetMarginSensitive(1, true);
	SetMarginMask(1, wxSTC_MASK_FOLDERS);
	SetFoldMarginColour(true, col_bg);
	SetFoldMarginHiColour(true, col_bg);
	MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, col_bg, col_fg);
	MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, col_bg, col_fg);
	MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE, col_bg, col_fg);
	MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, col_bg, col_fg);
	MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED, col_bg, col_fg);
	MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUSCONNECTED, col_bg, col_fg);
	MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_TCORNER, col_bg, col_fg);
}
Beispiel #2
0
/* TextEditor::setup
 * Sets up text editor properties depending on cvars and the current
 * text styleset/style
 *******************************************************************/
void TextEditor::setup()
{
	// General settings
	SetBufferedDraw(true);
	SetUseAntiAliasing(true);
	SetMouseDwellTime(500);
	AutoCompSetIgnoreCase(true);
	SetIndentationGuides(txed_indent_guides);
	StyleSetBackground(wxSTC_STYLE_INDENTGUIDE, WXCOL(col_edge_line));

	// Right margin line
	SetEdgeColour(WXCOL(col_edge_line));
	SetEdgeColumn(txed_edge_column);
	if (txed_edge_column == 0)
		SetEdgeMode(wxSTC_EDGE_NONE);
	else
		SetEdgeMode(wxSTC_EDGE_LINE);

	// Apply default style
	StyleSet::applyCurrent(this);
	CallTipUseStyle(10);
	StyleSetChangeable(wxSTC_STYLE_CALLTIP, true);
	wxFont font_ct(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
	StyleSetFont(wxSTC_STYLE_CALLTIP, font_ct);
	CallTipSetForegroundHighlight(WXCOL(StyleSet::currentSet()->getStyle("calltip_hl")->getForeground()));

	// Set lexer
	if (txed_syntax_hilight)
		SetLexer(wxSTC_LEX_CPPNOCASE);
	else
		SetLexer(wxSTC_LEX_NULL);

	// Re-colour text
	Colourise(0, GetTextLength());
}
Beispiel #3
0
/* TextureXListView::updateItemAttr
 * Called when widget requests the attributes (text colour /
 * background colour / font) for [item]
 *******************************************************************/
void TextureXListView::updateItemAttr(long item, long column, long index) const
{
	// Check texture list exists
	if (!texturex)
		return;

	// Check index is ok
	if (index < 0 || (unsigned)index > texturex->nTextures())
		return;

	// Get associated texture
	CTexture* tex = texturex->getTexture(index);

	// Init attributes
	item_attr->SetTextColour(WXCOL(ColourConfiguration::getColour("error")));

	// If texture doesn't exist, return error colour
	if (!tex)
		return;

	// Set colour depending on entry state
	switch (tex->getState())
	{
	case 1:
		item_attr->SetTextColour(WXCOL(ColourConfiguration::getColour("modified")));
		break;
	case 2:
		item_attr->SetTextColour(WXCOL(ColourConfiguration::getColour("new")));
		break;
	default:
		item_attr->SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT));
		break;
	};
}
Beispiel #4
0
/* GraphicsPrefsPanel::GraphicsPrefsPanel
 * GraphicsPrefsPanel class constructor
 *******************************************************************/
GraphicsPrefsPanel::GraphicsPrefsPanel(wxWindow* parent) : PrefsPanelBase(parent)
{
	// Create sizer
	wxBoxSizer* psizer = new wxBoxSizer(wxVERTICAL);
	SetSizer(psizer);

	// Create frame+sizer
	wxStaticBox* frame = new wxStaticBox(this, -1, "Graphics Preferences");
	wxStaticBoxSizer* sizer = new wxStaticBoxSizer(frame, wxVERTICAL);
	psizer->Add(sizer, 1, wxEXPAND|wxALL, 4);

	// Colours for the chequered background texture
	sizer->Add(new wxStaticText(this, -1, "Transparent background colours:"), 0, wxALL, 4);
	wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL);
	cp_colour1 = new wxColourPickerCtrl(this, -1, WXCOL(COL_BLACK), wxDefaultPosition, wxDefaultSize, wxCLRP_SHOW_LABEL|wxCLRP_USE_TEXTCTRL);
	vbox->Add(cp_colour1, 0, wxEXPAND|wxBOTTOM, 4);
	cp_colour2 = new wxColourPickerCtrl(this, -1, WXCOL(COL_BLACK), wxDefaultPosition, wxDefaultSize, wxCLRP_SHOW_LABEL|wxCLRP_USE_TEXTCTRL);
	vbox->Add(cp_colour2, 0, wxEXPAND|wxBOTTOM, 4);

	// Quick colour presets
	wxBoxSizer* hbox = new wxBoxSizer(wxHORIZONTAL);
	vbox->Add(hbox, 0, wxEXPAND|wxBOTTOM, 4);
	string schemes[] = { "Default",
	                     "Black", "Black (Checkered)",
	                     "Cyan", "Cyan (Checkered)",
	                     "Magenta", "Magenta (Checkered)",
	                     "White", "White (Checkered)",
	                     "Yellow", "Yellow (Checkered)",
	                     "Vintage Id Software"
	                   };
	choice_presets = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, 12, schemes);
	hbox->Add(new wxStaticText(this, -1, "Presets:"), 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 4);
	hbox->Add(choice_presets, 1, wxEXPAND);

	sizer->Add(vbox, 0, wxEXPAND|wxALL, 4);

	// 'Show outline around gfx'
	cb_show_border = new wxCheckBox(this, -1, "Show outline around graphics and textures");
	sizer->Add(cb_show_border, 0, wxEXPAND|wxALL, 4);

	// 'Hilight gfx on mouseover'
	cb_hilight_mouseover = new wxCheckBox(this, -1, "Hilight graphics on mouse hover");
	sizer->Add(cb_hilight_mouseover, 0, wxEXPAND|wxALL, 4);

	// 'Extra image conversion options'
	cb_extra_gfxconv = new wxCheckBox(this, -1, "Offer additional conversion options");
	sizer->Add(cb_extra_gfxconv, 0, wxEXPAND|wxALL, 4);

	// Browser background type
	hbox = new wxBoxSizer(wxHORIZONTAL);
	vbox->Add(hbox, 0, wxEXPAND|wxBOTTOM, 4);
	string browser_types[] = { "Transparent background (as above)", "System background", "Black background" };
	choice_browser_bg = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, 3, browser_types);
	hbox->Add(new wxStaticText(this, -1, "Browser Background:"), 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 4);
	hbox->Add(choice_browser_bg, 1, wxEXPAND);

	// Bind events
	choice_presets->Bind(wxEVT_CHOICE, &GraphicsPrefsPanel::onChoicePresetSelected, this);
}
Beispiel #5
0
// ----------------------------------------------------------------------------
// ArchiveEntryList::updateItemAttr
//
// Called when widget requests the attributes
// (text colour / background colour / font) for [item]
// ----------------------------------------------------------------------------
void ArchiveEntryList::updateItemAttr(long item, long column, long index) const
{
	// Get associated entry
	ArchiveEntry* entry = getEntry(item);

	// Init attributes
	wxColour col_bg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX);
	item_attr->SetTextColour(WXCOL(ColourConfiguration::getColour("error")));
	item_attr->SetBackgroundColour(col_bg);

	// If entry doesn't exist, return error colour
	if (!entry)
		return;

	// Set font
	if (elist_name_monospace && !list_font_monospace)
		item_attr->SetFont((column == 0) ? *font_monospace : *font_normal);
	else
		item_attr->SetFont(list_font_monospace ? *font_monospace : *font_normal);

	// Set background colour defined in entry type (if any)
	rgba_t col = entry->getType()->getColour();
	if ((col.r != 255 || col.g != 255 || col.b != 255) && elist_type_bgcol)
	{
		rgba_t bcol;

		bcol.r = (col.r * elist_type_bgcol_intensity) + (col_bg.Red() * (1.0 - elist_type_bgcol_intensity));
		bcol.g = (col.g * elist_type_bgcol_intensity) + (col_bg.Green() * (1.0 - elist_type_bgcol_intensity));
		bcol.b = (col.b * elist_type_bgcol_intensity) + (col_bg.Blue() * (1.0 - elist_type_bgcol_intensity));

		item_attr->SetBackgroundColour(WXCOL(bcol));
	}

	// Alternating row colour
	if (elist_alt_row_colour && item % 2 > 0)
	{
		wxColour dark = item_attr->GetBackgroundColour().ChangeLightness(95);
		item_attr->SetBackgroundColour(dark);
	}

	// Set colour depending on entry state
	switch (entry->getState())
	{
	case 1:
		item_attr->SetTextColour(WXCOL(ColourConfiguration::getColour("modified")));
		break;
	case 2:
		item_attr->SetTextColour(WXCOL(ColourConfiguration::getColour("new")));
		break;
	default:
		item_attr->SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT));
		break;
	};

	// Locked state overrides others
	if (entry->isLocked())
		item_attr->SetTextColour(WXCOL(ColourConfiguration::getColour("locked")));
}
Beispiel #6
0
// -----------------------------------------------------------------------------
// Draws function 'spec' text for [context] at [left,top].
// Returns a rect of the bounds of the drawn text
// -----------------------------------------------------------------------------
wxRect SCallTip::drawFunctionSpec(wxDC& dc, const TLFunction::Context& context, int left, int top) const
{
	wxRect rect{ left, top, 0, 0 };
	int    rect_left = left;

	// Draw deprecated message
	if (!context.deprecated_v.empty() || !context.deprecated_f.empty())
	{
		wxString deprecated_msg = "[ Deprecated";
		if (!context.deprecated_v.empty())
			deprecated_msg = wxString::Format("%s v%s", deprecated_msg, context.deprecated_v);
		if (!context.deprecated_f.empty())
			deprecated_msg = wxString::Format("%s, use \'%s()\'", deprecated_msg, context.deprecated_f);
		deprecated_msg = wxString::Format("%s ] ", deprecated_msg);

		dc.SetTextForeground(*wxRED);
		drawText(dc, deprecated_msg, left, top, &rect);

		top    = rect.GetBottom();
		rect.y = top;
	}

	// Draw function qualifiers
	if (!context.qualifiers.empty())
	{
		dc.SetTextForeground(WXCOL(col_keyword_));
		left = drawText(dc, context.qualifiers, left, top, &rect);
	}

	// Draw function return type
	if (!context.return_type.empty())
	{
		wxString ftype = wxString::Format("%s ", context.return_type);
		dc.SetTextForeground(wxcol_type);
		left = drawText(dc, ftype, left, top, &rect);
	}

	// Draw function context (if any)
	if (!context.context.empty())
	{
		dc.SetTextForeground(wxcol_fg);
		left = drawText(dc, wxString::Format("%s.", context.context), left, top, &rect);
	}

	// Draw function name
	wxString fname = function_->name();
	dc.SetTextForeground(WXCOL(col_func_));
	left = drawText(dc, fname, left, top, &rect);

	// Draw opening bracket
	dc.SetTextForeground(wxcol_fg);
	left = drawText(dc, " (", left, top, &rect);

	return { { rect_left, top }, rect.GetBottomRight() };
}
// -----------------------------------------------------------------------------
// Updates display attributes for [item]
// -----------------------------------------------------------------------------
void UndoListView::updateItemAttr(long item, long column, long index) const
{
	if (!manager_)
		return;

	item_attr_->SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT));

	if (item == manager_->currentIndex())
		item_attr_->SetTextColour(WXCOL(ColRGBA(0, 170, 0)));
	else if (item > manager_->currentIndex())
		item_attr_->SetTextColour(WXCOL(ColRGBA(150, 150, 150)));
}
void UndoListView::updateItemAttr(long item) const {
	if (!manager)
		return;

	item_attr->SetTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT));

	int index = manager->nUndoLevels() - item - 1;
	if (index == manager->getCurrentIndex())
		item_attr->SetTextColour(WXCOL(rgba_t(0, 170, 0)));
	else if (index > manager->getCurrentIndex())
		item_attr->SetTextColour(WXCOL(rgba_t(150, 150, 150)));
}
Beispiel #9
0
// -----------------------------------------------------------------------------
// Called when the control is to be (re)painted
// -----------------------------------------------------------------------------
void SCallTip::onPaint(wxPaintEvent& e)
{
	// Create device context
	wxAutoBufferedPaintDC dc(this);

	// Determine border colours
	wxColour bg = WXCOL(col_bg_);
	wxColour border, border2;
	if (col_bg_.greyscale().r < 128)
	{
		auto c  = col_bg_.amp(50, 50, 50, 0);
		border  = WXCOL(c);
		c       = col_bg_.amp(20, 20, 20, 0);
		border2 = WXCOL(c);
	}
	else
	{
		auto c  = col_bg_.amp(-50, -50, -50, 0);
		border  = WXCOL(c);
		c       = col_bg_.amp(-20, -20, -20, 0);
		border2 = WXCOL(c);
	}

	// Draw background
	dc.SetBrush(wxBrush(bg));
	dc.SetPen(*wxTRANSPARENT_PEN);
	dc.DrawRectangle(0, 0, GetSize().x, GetSize().y);

	// Draw text
#ifdef __WXOSX__
	// Not sure if it's an osx or high-dpi issue (or both),
	// but for some reason wx does not properly scale the bitmap when drawing it,
	// so just draw the entire calltip again in this case
	drawCallTip(dc, 12, 8);
#else
	dc.DrawBitmap(buffer_, UI::scalePx(12), UI::scalePx(8), true);
#endif

	// Draw border
	dc.SetBrush(*wxTRANSPARENT_BRUSH);
	dc.SetPen(wxPen(border));
	dc.DrawRectangle(0, 0, GetSize().x, GetSize().y);
	dc.SetPen(wxPen(border2));
	dc.DrawPoint(0, 0);
	dc.DrawPoint(0, GetSize().y - 1);
	dc.DrawPoint(GetSize().x - 1, GetSize().y - 1);
	dc.DrawPoint(GetSize().x - 1, 0);
	dc.DrawPoint(1, 1);
	dc.DrawPoint(1, GetSize().y - 2);
	dc.DrawPoint(GetSize().x - 2, GetSize().y - 2);
	dc.DrawPoint(GetSize().x - 2, 1);
}
Beispiel #10
0
/* TextStyle::applyTo
 * Applies the style settings to the scintilla text control [stc]
 *******************************************************************/
void TextStyle::applyTo(TextEditor* stc)
{
	for (unsigned a = 0; a < wx_styles.size(); a++)
	{
		// Set font face
		if (txed_override_font != "")
			stc->StyleSetFaceName(wx_styles[a], txed_override_font);
		else if (!font.IsEmpty())
			stc->StyleSetFaceName(wx_styles[a], font);

		// Set font size
		if (txed_override_font_size > 0)
			stc->StyleSetSize(wx_styles[a], txed_override_font_size);
		else if (size > 0)
			stc->StyleSetSize(wx_styles[a], size);

		// Set foreground
		if (fg_defined)
			stc->StyleSetForeground(wx_styles[a], WXCOL(foreground));

		// Set background
		if (bg_defined)
			stc->StyleSetBackground(wx_styles[a], WXCOL(background));

		// Set bold
		if (bold > 0)
			stc->StyleSetBold(wx_styles[a], true);
		else if (bold == 0)
			stc->StyleSetBold(wx_styles[a], false);

		// Set italic
		if (italic > 0)
			stc->StyleSetItalic(wx_styles[a], true);
		else if (italic == 0)
			stc->StyleSetItalic(wx_styles[a], false);

		// Set underlined
		if (underlined > 0)
			stc->StyleSetUnderline(wx_styles[a], true);
		else if (underlined == 0)
			stc->StyleSetUnderline(wx_styles[a], false);
	}
}
Beispiel #11
0
	void onPaint(wxPaintEvent& e)
	{
		wxPaintDC dc(this);

		// Get system colours needed
		wxColour col_background = Drawing::getPanelBGColour();
		rgba_t bg(col_background.Red(), col_background.Green(), col_background.Blue());
		wxColour col_light = WXCOL(bg.amp(50, 50, 50, 0));
		wxColour col_dark = WXCOL(bg.amp(-50, -50, -50, 0));

		// Draw background
		dc.SetBackground(wxBrush(col_background));
		dc.Clear();

		// Draw separator lines
		int height = (toolbar_size / 16.0) * 11;
		dc.GradientFillLinear(wxRect(1, 0, 1, height), col_background, col_dark, wxSOUTH);
		dc.GradientFillLinear(wxRect(1, height, 1, height), col_background, col_dark, wxNORTH);
		dc.GradientFillLinear(wxRect(2, 0, 1, height), col_background, col_light, wxSOUTH);
		dc.GradientFillLinear(wxRect(2, height, 1, height), col_background, col_light, wxNORTH);
	}
Beispiel #12
0
/* StyleSet::applyTo
 * Applies all the styles in this set to the text styles in scintilla
 * text control [stc]
 *******************************************************************/
void StyleSet::applyTo(TextEditor* stc)
{
	// Set default style
	ts_default.applyTo(stc);

	// Apply default style to all
	stc->StyleClearAll();

	// Apply other styles
	for (unsigned a = 0; a < styles.size(); a++)
		styles[a]->applyTo(stc);

	// Set selection background if customised
	if (ts_selection.hasBackground())
		stc->SetSelBackground(true, WXCOL(ts_selection.background));
	else
		stc->SetSelBackground(false, wxColour("red"));

	// Set selection foreground if customised
	if (ts_selection.hasForeground())
		stc->SetSelForeground(true, WXCOL(ts_selection.foreground));
	else
		stc->SetSelForeground(false, wxColour("red"));

	// Set caret colour to text foreground colour
	stc->SetCaretForeground(WXCOL(ts_default.foreground));

	// Update code folding margin
	stc->setupFoldMargin(getStyle("foldmargin"));

	// Set indent and right margin line colour
	stc->SetEdgeColour(WXCOL(getStyle("guides")->getForeground()));
	stc->StyleSetBackground(wxSTC_STYLE_INDENTGUIDE, WXCOL(getStyleBackground("guides")));
	stc->StyleSetForeground(wxSTC_STYLE_INDENTGUIDE, WXCOL(getStyleForeground("guides")));
}
Beispiel #13
0
/* SCallTip::onPaint
 * Called when the control is to be (re)painted
 *******************************************************************/
void SCallTip::onPaint(wxPaintEvent& e)
{
	// Create device context
	wxAutoBufferedPaintDC dc(this);

	// Determine border colours
	wxColour bg = WXCOL(col_bg);
	wxColour border, border2;
	if (col_bg.greyscale().r < 128)
	{
		rgba_t c = col_bg.amp(50, 50, 50, 0);
		border = WXCOL(c);
		c = col_bg.amp(20, 20, 20, 0);
		border2 = WXCOL(c);
	}
	else
	{
		rgba_t c = col_bg.amp(-50, -50, -50, 0);
		border = WXCOL(c);
		c = col_bg.amp(-20, -20, -20, 0);
		border2 = WXCOL(c);
	}

	// Draw border
	dc.SetBrush(wxBrush(bg));
	dc.SetPen(wxPen(border));
	dc.DrawRectangle(0, 0, GetSize().x, GetSize().y);
	dc.SetPen(wxPen(border2));
	dc.DrawPoint(0, 0);
	dc.DrawPoint(0, GetSize().y - 1);
	dc.DrawPoint(GetSize().x - 1, GetSize().y - 1);
	dc.DrawPoint(GetSize().x - 1, 0);
	dc.DrawPoint(1, 1);
	dc.DrawPoint(1, GetSize().y - 2);
	dc.DrawPoint(GetSize().x - 2, GetSize().y - 2);
	dc.DrawPoint(GetSize().x - 2, 1);

	// Draw text
	dc.DrawBitmap(buffer, 12, 8);
}
Beispiel #14
0
/* TextStyle::applyTo
 * Applies the style settings to [style] in the scintilla text
 * control [stc]
 *******************************************************************/
void TextStyle::applyTo(wxStyledTextCtrl* stc, int style)
{
	// Set font face
	if (!font.IsEmpty())
		stc->StyleSetFaceName(style, font);

	// Set font size
	if (size > 0)
		stc->StyleSetSize(style, size);

	// Set foreground
	if (fg_defined)
		stc->StyleSetForeground(style, WXCOL(foreground));

	// Set background
	if (bg_defined)
		stc->StyleSetBackground(style, WXCOL(background));

	// Set bold
	if (bold > 0)
		stc->StyleSetBold(style, true);
	else if (bold == 0)
		stc->StyleSetBold(style, false);

	// Set italic
	if (italic > 0)
		stc->StyleSetItalic(style, true);
	else if (italic == 0)
		stc->StyleSetItalic(style, false);

	// Set underlined
	if (underlined > 0)
		stc->StyleSetUnderline(style, true);
	else if (underlined == 0)
		stc->StyleSetUnderline(style, false);
}
Beispiel #15
0
/* TextEditor::setup
 * Sets up text editor properties depending on cvars and the current
 * text styleset/style
 *******************************************************************/
void TextEditor::setup()
{
	// General settings
	SetBufferedDraw(true);
	SetUseAntiAliasing(true);
	SetMouseDwellTime(500);
	AutoCompSetIgnoreCase(true);
	SetIndentationGuides(txed_indent_guides);

	// Right margin line
	SetEdgeColumn(txed_edge_column);
	if (txed_edge_column == 0)
		SetEdgeMode(wxSTC_EDGE_NONE);
	else
		SetEdgeMode(wxSTC_EDGE_LINE);

	// Apply default style
	StyleSet::applyCurrent(this);
	CallTipUseStyle(10);
	StyleSetChangeable(wxSTC_STYLE_CALLTIP, true);
	wxFont font_ct(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
	StyleSetFont(wxSTC_STYLE_CALLTIP, font_ct);
	CallTipSetForegroundHighlight(WXCOL(StyleSet::currentSet()->getStyle("calltip_hl")->getForeground()));

	// Set folding options
	setupFolding();

	// Re-colour text
	Colourise(0, GetTextLength());

	// Set word wrapping
	if (txed_word_wrap)
		SetWrapMode(wxSTC_WRAP_WORD);
	else
		SetWrapMode(wxSTC_WRAP_NONE);

	// Set word match indicator style
	SetIndicatorCurrent(8);
	IndicatorSetStyle(8, wxSTC_INDIC_ROUNDBOX);
	IndicatorSetUnder(8, true);
	IndicatorSetOutlineAlpha(8, 60);
	IndicatorSetAlpha(8, 40);
}
Beispiel #16
0
/* StyleSet::applyTo
 * Applies all the styles in this set to the text styles in scintilla
 * text control [stc]
 *******************************************************************/
void StyleSet::applyTo(wxStyledTextCtrl* stc)
{
	// Set default style
	ts_default.applyTo(stc, wxSTC_STYLE_DEFAULT);

	// Apply default style to all
	stc->StyleClearAll();

	// Apply other styles
	ts_preprocessor.applyTo(stc, wxSTC_C_PREPROCESSOR);
	ts_comment.applyTo(stc, wxSTC_C_COMMENT);
	ts_comment.applyTo(stc, wxSTC_C_COMMENTLINE);
	ts_string.applyTo(stc, wxSTC_C_STRING);
	ts_character.applyTo(stc, wxSTC_C_CHARACTER);
	ts_keyword.applyTo(stc, wxSTC_C_WORD);
	ts_constant.applyTo(stc, wxSTC_C_GLOBALCLASS);
	ts_function.applyTo(stc, wxSTC_C_WORD2);
	ts_bracematch.applyTo(stc, wxSTC_STYLE_BRACELIGHT);
	ts_bracebad.applyTo(stc, wxSTC_STYLE_BRACEBAD);

	// Set caret colour to text foreground colour
	stc->SetCaretForeground(WXCOL(ts_default.foreground));
}
/* ColourPrefsPanel::refreshPropGrid
 * Refreshes the colour configuration wxPropertyGrid
 *******************************************************************/
void ColourPrefsPanel::refreshPropGrid()
{
	// Clear grid
	pg_colours->Clear();

	// Get (sorted) list of colours
	vector<string> colours;
	ColourConfiguration::getColourNames(colours);
	std::sort(colours.begin(), colours.end());

	// Add colours to property grid
	for (unsigned a = 0; a < colours.size(); a++)
	{
		// Get colour definition
		cc_col_t cdef = ColourConfiguration::getColDef(colours[a]);

		// Get/create group
		wxPGProperty* group = pg_colours->GetProperty(cdef.group);
		if (!group)
			group = pg_colours->Append(new wxPropertyCategory(cdef.group));

		// Add colour
		wxPGProperty* colour = pg_colours->AppendIn(group, new wxColourProperty(cdef.name, colours[a], WXCOL(cdef.colour)));

		// Add extra colour properties
		wxPGProperty* opacity = pg_colours->AppendIn(colour, new wxIntProperty("Opacity (0-255)", "alpha", cdef.colour.a));
		pg_colours->AppendIn(colour, new wxBoolProperty("Additive", "additive", (cdef.colour.blend == 1)));
		pg_colours->Collapse(colour);

		// Set opacity limits
		opacity->SetAttribute("Max", 255);
		opacity->SetAttribute("Min", 0);
	}

	// Set all bool properties to use checkboxes
	pg_colours->SetPropertyAttributeAll(wxPG_BOOL_USE_CHECKBOX, true);
}
/* TextStylePrefsPanel::updateStyleControls
 * Updates style-related controls to reflect the currently selected
 * style in the list
 *******************************************************************/
void TextStylePrefsPanel::updateStyleControls()
{
	if (!ts_current)
		return;

	// Get default style
	TextStyle* style_default = ss_current.getStyle("default");

	// Reset UI stuff
	cb_override_font_face->SetValue(true);
	cb_override_font_size->SetValue(true);
	cb_override_font_bold->SetValue(true);
	cb_override_font_italic->SetValue(true);
	cb_override_font_underlined->SetValue(true);
	cb_override_foreground->SetValue(true);
	cb_override_background->SetValue(true);

	// Disable override checkboxes if default style
	bool enable = (ts_current != style_default);
	cb_override_font_face->Enable(enable);
	cb_override_font_size->Enable(enable);
	cb_override_font_bold->Enable(enable);
	cb_override_font_italic->Enable(enable);
	cb_override_font_underlined->Enable(enable);
	cb_override_foreground->Enable(enable);
	cb_override_background->Enable(enable);

	// Update style properties
	wxFont font = fp_font->GetSelectedFont();

	// Font face
	string font_face = ts_current->getFontFace();
	if (font_face.IsEmpty())
	{
		font_face = style_default->getFontFace();
		cb_override_font_face->SetValue(false);
	}
	font.SetFaceName(font_face);

	// Font size
	int font_size = ts_current->getFontSize();
	if (font_size <= 0)
	{
		font_size = style_default->getFontSize();
		cb_override_font_size->SetValue(false);
	}
	font.SetPointSize(font_size);

	// Bold
	bool bold = false;
	if (ts_current->getBold() > 0)
		bold = true;
	else if (ts_current->getBold() < 0)
	{
		bold = !!style_default->getBold();
		cb_override_font_bold->SetValue(false);
	}
	if (bold)
		font.SetWeight(wxFONTWEIGHT_BOLD);
	else
		font.SetWeight(wxFONTWEIGHT_NORMAL);

	// Italic
	bool italic = false;
	if (ts_current->getItalic() > 0)
		italic = true;
	else if (ts_current->getItalic() < 0)
	{
		italic = !!style_default->getItalic();
		cb_override_font_italic->SetValue(false);
	}
	if (italic)
		font.SetStyle(wxFONTSTYLE_ITALIC);
	else
		font.SetStyle(wxFONTSTYLE_NORMAL);

	// Underlined
	bool underlined = false;
	if (ts_current->getUnderlined() > 0)
		underlined = true;
	else if (ts_current->getUnderlined() < 0)
	{
		underlined = !!style_default->getUnderlined();
		cb_override_font_underlined->SetValue(false);
	}
	font.SetUnderlined(underlined);

	// Foreground
	rgba_t col_foreground;
	if (ts_current->hasForeground())
		col_foreground.set(ts_current->getForeground());
	else
	{
		col_foreground.set(style_default->getForeground());
		cb_override_foreground->SetValue(false);
	}
	cp_foreground->SetColour(WXCOL(col_foreground));

	// Background
	rgba_t col_background;
	if (ts_current->hasBackground())
		col_background.set(ts_current->getBackground());
	else
	{
		col_background.set(style_default->getBackground());
		cb_override_background->SetValue(false);
	}
	cp_background->SetColour(WXCOL(col_background));

	// Apply font
	fp_font->SetSelectedFont(font);
}
Beispiel #19
0
void PaletteEntryPanel::analysePalettes()
{
	if (palettes.size() < PALETTECHECK + 1)
		return;
#ifdef GPALCOMPANALYSIS
	int devR, devG, devB;
	int minR, minG, minB;
	int maxR, maxG, maxB;
	int wrongcount;
#else
	unsigned int reds[256];
	unsigned int greens[256];
	unsigned int blues[256];
#endif
	string report = "\n";
#ifdef GPALCOMPANALYSIS
	int i = PALETTECHECK;
	if (i)
	{
		report += S_FMT("Deviation between palettes 0 and %i:\n\n", i);
		devR = devG = devB = 0;
		maxR = maxG = maxB = -1;
		minR = minG = minB = 256;
		wrongcount = 0;
#else
	report += S_FMT("Changes between %u palettes compared to the first:\n\n", palettes.size());
	for (size_t i = 1; i < palettes.size(); ++i)
	{
		for (int j = 0; j < 256; ++j)
			reds[j] = blues[j] = greens[j] = 999;
#endif
		report += S_FMT("\n==============\n= Palette %02u =\n==============\n", i);
		for (size_t c = 0; c < 256; ++c)
		{
			rgba_t ref1 = palettes[0]->colour(c);
			rgba_t cmp1 = palettes[i]->colour(c);
			hsl_t  ref2 = Misc::rgbToHsl(ref1);
			hsl_t  cmp2 = Misc::rgbToHsl(cmp1);
#ifdef GPALCOMPANALYSIS
			int r, g, b;
			double h, s, l;
			r = cmp1.r - ref1.r;
			g = cmp1.g - ref1.g;
			b = cmp1.b - ref1.b;
			h = cmp2.h - ref2.h;
			s = cmp2.s - ref2.s;
			l = cmp2.l - ref2.l;
			devR += r;
			devG += g;
			devB += b;
			if (r > maxR) maxR = r; if (r < minR) minR = r;
			if (g > maxG) maxG = g; if (g < minG) minG = g;
			if (b > maxB) maxB = b; if (b < minB) minB = b;
			if (r | g | b)
			{
				++wrongcount;
				report += S_FMT("Index %003u: [%003i %003i %003i | %1.3f %1.3f %1.3f]->[%003i %003i %003i | %1.3f %1.3f %1.3f]\t\tR %+003i\tG %+003i\tB %+003i\t\t\tH %+1.3f\tS %+1.3f\tL %+1.3f\n",
				                c,
				                ref1.r, ref1.g, ref1.b, ref2.h, ref2.s, ref2.l,
				                cmp1.r, cmp1.g, cmp1.b, cmp2.h, cmp2.s, cmp2.l,
				                r, g, b, h, s, l);
			}
#else
			if (reds[ref1.r] != cmp1.r && reds[ref1.r] != 999)
				DPrintf("Discrepency for red channel at index %i, value %i: %d vs. %d set before",
				        c, ref1.r, cmp1.r, reds[ref1.r]);
			if (greens[ref1.g] != cmp1.g && greens[ref1.g] != 999)
				DPrintf("Discrepency for green channel at index %i, value %i: %d vs. %d set before",
				        c, ref1.g, cmp1.g, greens[ref1.g]);
			if (blues[ref1.b] != cmp1.b && blues[ref1.b] != 999)
				DPrintf("Discrepency for blue channel at index %i, value %i: %d vs. %d set before",
				        c, ref1.b, cmp1.b, blues[ref1.b]);
			reds[ref1.r] = cmp1.r;
			greens[ref1.g] = cmp1.g;
			blues[ref1.b] = cmp1.b;
#endif
		}
#ifdef GPALCOMPANALYSIS
		report += S_FMT("Deviation sigma: R %+003i G %+003i B %+003i\t%s\n", devR, devG, devB, entry->getName(true));
		report += S_FMT("Min R %+003i Min G %+003i Min B %+003i Max R %+003i Max G %+003i Max B %+003i \nError count: %i\n",
		                minR, minG, minB, maxR, maxG, maxB, wrongcount);
#else
		report += "Shift table for existing channel values:\n|  I  |  R  |  G  |  B  |\n";
		for (size_t i = 0; i < 256; ++i)
		{
			if (reds[i] < 999 || greens[i] < 999 || blues[i] < 999)
				report += S_FMT("| %003d | %003d | %003d | %003d |\n", i, reds[i], greens[i], blues[i]);
		}
		report.Replace("999", "   ");
#endif
	}

	wxLogMessage(report);

}

/*******************************************************************
 * PALETTEENTRYPANEL CLASS EVENTS
 *******************************************************************/

/* PaletteEntryPanel::onPalCanvasMouseEvent
 * Called when a mouse event happens within the palette canvas (eg.
 * button clicked, pointer moved, etc)
 *******************************************************************/
void PaletteEntryPanel::onPalCanvasMouseEvent(wxMouseEvent& e)
{
	// Update colour info label with selected colour (if any)
	if (e.LeftDown())
	{
		// Send to palette canvas
		pal_canvas->onMouseLeftDown(e);

		// Update status bar
		updateStatus();
	}
	else if (e.RightDown())
	{
		// Would this be better if the colour picking was handled by
		// the canvas' onMouseRightDown() function? The problem here
		// being that the canvas processes its events after the panel.
		// So for the left click we can afford to call it from there
		// first and let it harmlessly process it again, but for the
		// right click it would result in the colour box being shown
		// twice to the user, the second time being ignored. So it is
		// preferrable to handle all this on this side rather than try
		// to make the canvas do the work.
		// Pretend there was a left click to get the selected colour.
		pal_canvas->onMouseLeftDown(e);
		int sel = pal_canvas->getSelectionStart();

		// There actually was a colour selected
		if (sel > -1)
		{
			rgba_t col = pal_canvas->getSelectedColour();
			// Open a colour dialog
			wxColour cd = wxGetColourFromUser(GetParent(), WXCOL(col));

			if (cd.Ok())
			{
				col.r = cd.Red();
				col.g = cd.Green();
				col.b = cd.Blue();

				palettes[cur_palette]->setColour(sel, col);
				setModified();
				showPalette(cur_palette);
			}
		}
	}
}
/* TextStylePrefsPanel::TextStylePrefsPanel
 * TextStylePrefsPanel class constructor
 *******************************************************************/
TextStylePrefsPanel::TextStylePrefsPanel(wxWindow* parent) : PrefsPanelBase(parent)
{
	// Init variables
	ss_current.copySet(StyleSet::currentSet());
	ts_current = ss_current.getStyle("default");

	// Create main sizer
	wxBoxSizer* psizer = new wxBoxSizer(wxVERTICAL);
	SetSizer(psizer);

	// Create frame+sizer
	wxStaticBox* frame = new wxStaticBox(this, -1, "Text Editor Fonts and Colours");
	wxStaticBoxSizer* sizer = new wxStaticBoxSizer(frame, wxVERTICAL);
	psizer->Add(sizer, 1, wxEXPAND|wxALL, 4);

	// Styleset font override
	wxBoxSizer* hbox = new wxBoxSizer(wxHORIZONTAL);
	sizer->Add(hbox, 0, wxEXPAND | wxALL, 4);
	cb_font_override = new wxCheckBox(this, -1, "Override Default Font");
	cb_font_override->SetToolTip("Always use the selected font in the text editor, instead of the style's font below");
	hbox->Add(cb_font_override, 0, wxEXPAND | wxALL, 4);
	fp_font_override = new wxFontPickerCtrl(this, -1);
	hbox->Add(fp_font_override, 1, wxEXPAND | wxALL, 4);

	// Styleset controls
	hbox = new wxBoxSizer(wxHORIZONTAL);
	sizer->Add(hbox, 0, wxEXPAND|wxALL, 4);

	// Styleset selection dropdown
	wxArrayString style_sets;
	for (unsigned a = 0; a < StyleSet::numSets(); a++)
		style_sets.Add(StyleSet::getName(a));
	choice_styleset = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, style_sets);
	hbox->Add(new wxStaticText(this, -1, "Style Set:"), 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 4);
	hbox->Add(choice_styleset, 1, wxEXPAND|wxRIGHT, 4);


	// Style configuration controls
	hbox = new wxBoxSizer(wxHORIZONTAL);
	sizer->Add(hbox, 1, wxEXPAND|wxALL, 4);
	wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL);
	hbox->Add(vbox, 0, wxEXPAND|wxALL, 4);

	// Style list
	wxArrayString style_names;
	style_names.Add("Default");
	style_names.Add("Selection");
	for (unsigned a = 0; a < ss_current.nStyles(); a++)
		style_names.Add(ss_current.getStyle(a)->getDescription());
	list_styles = new wxListBox(this, -1, wxDefaultPosition, wxDefaultSize, style_names);
	vbox->Add(list_styles, 1, wxEXPAND|wxBOTTOM, 4);

	// 'Save Set' button
	btn_savestyleset = new wxButton(this, -1, "Save Set");
	vbox->Add(btn_savestyleset, 0, wxEXPAND);


	// Style settings
	vbox = new wxBoxSizer(wxVERTICAL);
	hbox->Add(vbox, 1, wxEXPAND|wxALL, 4);

	// Font picker
	vbox->Add(new wxStaticText(this, -1, "Font:"), 0, wxBOTTOM, 2);
	fp_font = new wxFontPickerCtrl(this, -1);
	vbox->Add(fp_font, 0, wxEXPAND|wxBOTTOM, 4);

	// Font property overrides
	wxGridBagSizer* sizer_gb = new wxGridBagSizer(4, 4);
	vbox->Add(sizer_gb, 0, wxEXPAND|wxBOTTOM, 4);
	sizer_gb->Add(new wxStaticText(this, -1, "Override default font properties:"), wxGBPosition(0, 0), wxGBSpan(1, 3));
	cb_override_font_face = new wxCheckBox(this, -1, "Face");
	cb_override_font_size = new wxCheckBox(this, -1, "Size");
	cb_override_font_bold = new wxCheckBox(this, -1, "Bold");
	cb_override_font_italic = new wxCheckBox(this, -1, "Italic");
	cb_override_font_underlined = new wxCheckBox(this, -1, "Underlined");
	sizer_gb->Add(cb_override_font_face, wxGBPosition(1, 0));
	sizer_gb->Add(cb_override_font_size, wxGBPosition(1, 1));
	sizer_gb->Add(cb_override_font_bold, wxGBPosition(2, 0));
	sizer_gb->Add(cb_override_font_italic, wxGBPosition(2, 1));
	sizer_gb->Add(cb_override_font_underlined, wxGBPosition(2, 2));

	// Foreground colour
	vbox->Add(new wxStaticLine(this, -1, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL), 0, wxEXPAND|wxALL, 4);
	hbox = new wxBoxSizer(wxHORIZONTAL);
	vbox->Add(hbox, 0, wxEXPAND|wxBOTTOM, 4);
	hbox->Add(new wxStaticText(this, -1, "Foreground:"), 1, wxALIGN_CENTER_VERTICAL);
	cb_override_foreground = new wxCheckBox(this, -1, "Override Default");
	hbox->Add(cb_override_foreground, 1, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT);
	cp_foreground = new wxColourPickerCtrl(this, -1, WXCOL(COL_BLACK), wxDefaultPosition, wxDefaultSize, wxCLRP_SHOW_LABEL|wxCLRP_USE_TEXTCTRL);
	vbox->Add(cp_foreground, 0, wxEXPAND|wxBOTTOM, 4);

	// Background colour
	hbox = new wxBoxSizer(wxHORIZONTAL);
	vbox->Add(hbox, 0, wxEXPAND|wxBOTTOM, 4);
	hbox->Add(new wxStaticText(this, -1, "Background:"), 1, wxALIGN_CENTER_VERTICAL);
	cb_override_background = new wxCheckBox(this, -1, "Override Default");
	hbox->Add(cb_override_background, 1, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT);
	cp_background = new wxColourPickerCtrl(this, -1, WXCOL(COL_BLACK), wxDefaultPosition, wxDefaultSize, wxCLRP_SHOW_LABEL|wxCLRP_USE_TEXTCTRL);
	vbox->Add(cp_background, 0, wxEXPAND);

	// Preview
	te_preview = new TextEditor(this, -1);
	vbox->Add(te_preview, 1, wxEXPAND | wxTOP, 8);


	// Bind events
	list_styles->Bind(wxEVT_LISTBOX, &TextStylePrefsPanel::onStyleSelected, this);
	cb_override_font_face->Bind(wxEVT_CHECKBOX, &TextStylePrefsPanel::onCBOverrideFontFace, this);
	cb_override_font_size->Bind(wxEVT_CHECKBOX, &TextStylePrefsPanel::onCBOverrideFontSize, this);
	cb_override_font_bold->Bind(wxEVT_CHECKBOX, &TextStylePrefsPanel::onCBOverrideFontBold, this);
	cb_override_font_italic->Bind(wxEVT_CHECKBOX, &TextStylePrefsPanel::onCBOverrideFontItalic, this);
	cb_override_font_underlined->Bind(wxEVT_CHECKBOX, &TextStylePrefsPanel::onCBOverrideFontUnderlined, this);
	cb_override_foreground->Bind(wxEVT_CHECKBOX, &TextStylePrefsPanel::onCBOverrideForeground, this);
	cb_override_background->Bind(wxEVT_CHECKBOX, &TextStylePrefsPanel::onCBOverrideBackground, this);
	fp_font->Bind(wxEVT_FONTPICKER_CHANGED, &TextStylePrefsPanel::onFontChanged, this);
	cp_foreground->Bind(wxEVT_COLOURPICKER_CHANGED, &TextStylePrefsPanel::onForegroundChanged, this);
	cp_background->Bind(wxEVT_COLOURPICKER_CHANGED, &TextStylePrefsPanel::onBackgroundChanged, this);
	btn_savestyleset->Bind(wxEVT_BUTTON, &TextStylePrefsPanel::onBtnSaveStyleSet, this);
	choice_styleset->Bind(wxEVT_CHOICE, &TextStylePrefsPanel::onStyleSetSelected, this);
	cb_font_override->Bind(wxEVT_CHECKBOX, &TextStylePrefsPanel::onCBOverrideFont, this);
	fp_font_override->Bind(wxEVT_FONTPICKER_CHANGED, &TextStylePrefsPanel::onFontOverrideChanged, this);

	// Init controls
	if (txed_override_font != "")
	{
		cb_font_override->SetValue(true);
		fp_font_override->SetSelectedFont(
			wxFont(
				txed_override_font_size == 0 ? 10 : txed_override_font_size,
				wxFONTFAMILY_MODERN,
				wxFONTSTYLE_NORMAL,
				wxFONTWEIGHT_NORMAL,
				false,
				txed_override_font
				)
			);
		fp_font_override->Enable(true);
	}
	else
	{
		cb_font_override->SetValue(false);
		fp_font_override->SetSelectedFont(wxFont(10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
		fp_font_override->Enable(false);
	}

	// Select default style
	init_done = false;
	list_styles->SetSelection(0);
	updateStyleControls();
	init_done = true;
}
/* TranslationEditorDialog::openRange
 * Opens the translation range [index] from the current translation
 *******************************************************************/
void TranslationEditorDialog::openRange(int index)
{
	// Check index
	if (index < 0 || index >= (int)translation.nRanges())
		return;

	// Get translation range to open
	TransRange* tr = translation.getRange(index);

	// Set origin selection
	pal_canvas_original->setSelection(tr->oStart(), tr->oEnd());
	pal_canvas_original->Refresh();

	// Check translation range type
	if (tr->getType() == TRANS_PALETTE)
	{
		// Palette range
		TransRangePalette* tpr = (TransRangePalette*)tr;

		// Select palette type radiobox
		rb_type_palette->SetValue(true);
		showPaletteTarget();

		// Set target range selection
		if (tpr->dStart() <= tpr->dEnd())
		{
			pal_canvas_target->setSelection(tpr->dStart(), tpr->dEnd());
			cb_target_reverse->SetValue(false);
		}
		else
		{
			pal_canvas_target->setSelection(tpr->dEnd(), tpr->dStart());
			cb_target_reverse->SetValue(true);
		}
		pal_canvas_target->Refresh();
	}
	else if (tr->getType() == TRANS_COLOUR)
	{
		// Colour gradient
		TransRangeColour* tcr = (TransRangeColour*)tr;

		// Select colour type radiobox
		rb_type_colour->SetValue(true);
		showGradientTarget();

		// Set beginning colour
		gb_gradient->setStartCol(tcr->dStart());
		cp_range_begin->SetColour(WXCOL(tcr->dStart()));

		// Set ending colour
		gb_gradient->setEndCol(tcr->dEnd());
		cp_range_end->SetColour(WXCOL(tcr->dEnd()));

		// Update UI
		gb_gradient->Refresh();
	}
	else if (tr->getType() == TRANS_DESAT)
	{
		// Desaturated colour gradient
		TransRangeDesat* tdr = (TransRangeDesat*)tr;

		// Select desaturated colour type radiobox
		rb_type_desaturate->SetValue(true);
		showGradientTarget();

		// Set beginning colour
		rgba_t col;
		col.r = MathStuff::clamp(tdr->dSr() * 128, 0, 255);
		col.g = MathStuff::clamp(tdr->dSg() * 128, 0, 255);
		col.b = MathStuff::clamp(tdr->dSb() * 128, 0, 255);
		cp_range_begin->SetColour(WXCOL(col));
		gb_gradient->setStartCol(col);

		// Set ending colour
		col.r = MathStuff::clamp(tdr->dEr() * 128, 0, 255);
		col.g = MathStuff::clamp(tdr->dEg() * 128, 0, 255);
		col.b = MathStuff::clamp(tdr->dEb() * 128, 0, 255);
		cp_range_end->SetColour(WXCOL(col));
		gb_gradient->setEndCol(col);

		// Update UI
		gb_gradient->Refresh();
	}
}
/* TranslationEditorDialog::TranslationEditorDialog
 * TranslationEditorDialog class constructor
 *******************************************************************/
TranslationEditorDialog::TranslationEditorDialog(wxWindow* parent, Palette8bit* pal, string title, SImage* preview_image)
	: wxDialog(parent, -1, title)
{
	// Init variables
	palette = pal;

	// Setup preview image
	if (preview_image)
	{
		image_preview.copyImage(preview_image);
		if (preview_image->hasPalette())
			palette = preview_image->getPalette();
	}

	// Set dialog icon
	wxIcon icon;
	icon.CopyFromBitmap(getIcon("t_remap"));
	SetIcon(icon);

	// Create sizer
	wxBoxSizer* mainsizer = new wxBoxSizer(wxVERTICAL);
	wxGridBagSizer* sizer = new wxGridBagSizer(4, 4);
	mainsizer->Add(sizer, 1, wxEXPAND|wxALL, 10);
	SetSizer(mainsizer);


	// --- Top half (translation origin) ---

	// Translations list
	wxStaticBox* frame = new wxStaticBox(this, -1, "Translation Ranges");
	wxStaticBoxSizer* framesizer = new wxStaticBoxSizer(frame, wxHORIZONTAL);
	sizer->Add(framesizer, wxGBPosition(0, 0), wxDefaultSpan, wxEXPAND);

	list_translations = new wxListBox(this, -1);
	framesizer->Add(list_translations, 1, wxEXPAND|wxALL, 4);

	// Add translation button
	wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL);
	framesizer->Add(vbox, 0, wxEXPAND|wxTOP|wxBOTTOM|wxRIGHT, 4);

	btn_add = new wxBitmapButton(this, -1, getIcon("t_plus"));
	vbox->Add(btn_add, 0, wxEXPAND|wxBOTTOM, 4);

	// Remove translation button
	btn_remove = new wxBitmapButton(this, -1, getIcon("t_minus"));
	vbox->Add(btn_remove, 0, wxEXPAND|wxBOTTOM, 4);

	// Move up button
	btn_up = new wxBitmapButton(this, -1, getIcon("t_up"));
	vbox->Add(btn_up, 0, wxEXPAND|wxBOTTOM, 4);

	// Move down button
	btn_down = new wxBitmapButton(this, -1, getIcon("t_down"));
	vbox->Add(btn_down, 0, wxEXPAND);


	// Origin range
	frame = new wxStaticBox(this, -1, "Origin Range");
	framesizer = new wxStaticBoxSizer(frame, wxVERTICAL);
	sizer->Add(framesizer, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND);

	// Origin palette
	pal_canvas_original = new PaletteCanvas(this, -1);
	pal_canvas_original->doubleWidth(true);
	pal_canvas_original->setPalette(palette);
	pal_canvas_original->SetInitialSize(wxSize(448, 112));
	pal_canvas_original->allowSelection(2);
	framesizer->Add(pal_canvas_original->toPanel(this), 1, wxALL|wxEXPAND, 4);


	// --- Bottom half (translation target) ---

	// Target type
	frame = new wxStaticBox(this, -1, "Target Range Type");
	framesizer = new wxStaticBoxSizer(frame, wxVERTICAL);
	sizer->Add(framesizer, wxGBPosition(1, 0), wxDefaultSpan, wxEXPAND);

	// Palette range
	rb_type_palette = new wxRadioButton(this, -1, "Palette Range", wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
	framesizer->Add(rb_type_palette, 0, wxEXPAND|wxALL, 4);

	// Colour gradient
	rb_type_colour = new wxRadioButton(this, -1, "Colour Gradient");
	framesizer->Add(rb_type_colour, 0, wxEXPAND|wxLEFT|wxRIGHT, 4);

	// Desaturated colour gradient
	rb_type_desaturate = new wxRadioButton(this, -1, "Desaturated Colour Gradient");
	framesizer->Add(rb_type_desaturate, 0, wxEXPAND|wxALL, 4);


	// Target range
	frame = new wxStaticBox(this, -1, "Target Range");
	framesizer = new wxStaticBoxSizer(frame, wxVERTICAL);
	sizer->Add(framesizer, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND);


	// Target palette range panel
	panel_target_palette = new wxPanel(this, -1);
	vbox = new wxBoxSizer(wxVERTICAL);
	panel_target_palette->SetSizer(vbox);

	// Target palette
	pal_canvas_target = new PaletteCanvas(panel_target_palette, -1);
	pal_canvas_target->doubleWidth(true);
	pal_canvas_target->setPalette(palette);
	pal_canvas_target->SetInitialSize(wxSize(448, 112));
	pal_canvas_target->allowSelection(2);
	vbox->Add(pal_canvas_target->toPanel(panel_target_palette), 1, wxEXPAND);

	// Reverse origin range
	cb_target_reverse = new wxCheckBox(panel_target_palette, -1, "Reverse Selection");
	vbox->Add(cb_target_reverse, 0, wxTOP, 4);


	// Target colour gradient panel
	panel_target_gradient = new wxPanel(this, -1);
	vbox = new wxBoxSizer(wxVERTICAL);
	panel_target_gradient->SetSizer(vbox);

	// Start colour
	vbox->AddStretchSpacer();
	wxBoxSizer* hbox = new wxBoxSizer(wxHORIZONTAL);
	vbox->Add(hbox, 0, wxEXPAND|wxBOTTOM, 4);

	cp_range_begin = new wxColourPickerCtrl(panel_target_gradient, -1, WXCOL(COL_BLACK));
	hbox->Add(cp_range_begin, 0, wxEXPAND|wxRIGHT, 4);
	hbox->Add(new wxStaticText(panel_target_gradient, -1, "From"), 0, wxALIGN_CENTER_VERTICAL);

	// End colour
	cp_range_end = new wxColourPickerCtrl(panel_target_gradient, -1, WXCOL(COL_WHITE));
	hbox->AddStretchSpacer();
	hbox->Add(new wxStaticText(panel_target_gradient, -1, "To"), 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 4);
	hbox->Add(cp_range_end, 0, wxEXPAND);

	// Gradient preview
	gb_gradient = new GradientBox(panel_target_gradient);
	vbox->Add(gb_gradient->toPanel(panel_target_gradient), 0, wxEXPAND);
	vbox->AddStretchSpacer();

	// Show initial target panel (palette)
	framesizer->Add(panel_target_palette, 1, wxEXPAND|wxALL, 4);
	panel_target_gradient->Show(false);


	// --- Preview section ---
	hbox = new wxBoxSizer(wxHORIZONTAL);
	sizer->Add(hbox, wxGBPosition(2, 0), wxGBSpan(1, 2), wxEXPAND);

	// Palette preview
	frame = new wxStaticBox(this, -1, "Resulting Palette");
	framesizer = new wxStaticBoxSizer(frame, wxVERTICAL);
	hbox->Add(framesizer, 0, wxEXPAND|wxRIGHT, 4);

	pal_canvas_preview = new PaletteCanvas(this, -1);
	pal_canvas_preview->SetInitialSize(wxSize(224, 224));
	pal_canvas_preview->setPalette(palette);
	framesizer->Add(pal_canvas_preview->toPanel(this), 1, wxEXPAND|wxALL, 4);

	// Image preview
	frame = new wxStaticBox(this, -1, "Preview");
	framesizer = new wxStaticBoxSizer(frame, wxVERTICAL);
	hbox->Add(framesizer, 1, wxEXPAND);

	gfx_preview = new GfxCanvas(this, -1);
	gfx_preview->setPalette(palette);
	gfx_preview->setViewType(GFXVIEW_CENTERED);
	gfx_preview->getImage()->copyImage(&image_preview);
	framesizer->Add(gfx_preview->toPanel(this), 1, wxEXPAND|wxALL, 4);


	// --- Translation string ---
	hbox = new wxBoxSizer(wxHORIZONTAL);
	sizer->Add(hbox, wxGBPosition(3, 0), wxGBSpan(1, 2), wxEXPAND|wxLEFT|wxRIGHT, 4);

	text_string = new wxTextCtrl(this, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_READONLY);
	hbox->Add(new wxStaticText(this, -1, "Translation String:"), 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 4);
	hbox->Add(text_string, 1, wxEXPAND);


	// --- Dialog buttons ---
	wxSizer* buttonsizer = CreateButtonSizer(wxOK|wxCANCEL);
	sizer->Add(buttonsizer, wxGBPosition(4, 0), wxGBSpan(1, 2), wxEXPAND);

	// Load button
	btn_load = new wxButton(this, -1, "Load from File");
	buttonsizer->InsertStretchSpacer(0);
	buttonsizer->Insert(0, btn_load, 0, wxLEFT|wxRIGHT, 4);

	// Save button
	btn_save = new wxButton(this, -1, "Save to File");
	buttonsizer->Insert(1, btn_save, 0, wxLEFT, 4);

	// Truecolor checkbox
	cb_truecolor = new wxCheckBox(this, -1, "Truecolor");
	buttonsizer->Insert(2, cb_truecolor, 0, wxLEFT, 4);

	// Bind events
	Bind(wxEVT_SIZE, &TranslationEditorDialog::onSize, this);
	list_translations->Bind(wxEVT_LISTBOX, &TranslationEditorDialog::onTranslationListItemSelected, this);
	rb_type_palette->Bind(wxEVT_RADIOBUTTON, &TranslationEditorDialog::onRBPaletteSelected, this);
	rb_type_colour->Bind(wxEVT_RADIOBUTTON, &TranslationEditorDialog::onRBColourSelected, this);
	rb_type_desaturate->Bind(wxEVT_RADIOBUTTON, &TranslationEditorDialog::onRBDesaturateSelected, this);
	cp_range_begin->Bind(wxEVT_COLOURPICKER_CHANGED, &TranslationEditorDialog::onBeginColourChanged, this);
	cp_range_end->Bind(wxEVT_COLOURPICKER_CHANGED, &TranslationEditorDialog::onEndColourChanged, this);
	pal_canvas_original->Bind(wxEVT_LEFT_UP, &TranslationEditorDialog::onPalOriginLeftUp, this);
	pal_canvas_target->Bind(wxEVT_LEFT_UP, &TranslationEditorDialog::onPalTargetLeftUp, this);
	btn_add->Bind(wxEVT_BUTTON, &TranslationEditorDialog::onBtnAdd, this);
	btn_remove->Bind(wxEVT_BUTTON, &TranslationEditorDialog::onBtnRemove, this);
	btn_up->Bind(wxEVT_BUTTON, &TranslationEditorDialog::onBtnUp, this);
	btn_down->Bind(wxEVT_BUTTON, &TranslationEditorDialog::onBtnDown, this);
	btn_load->Bind(wxEVT_BUTTON, &TranslationEditorDialog::onBtnLoad, this);
	btn_save->Bind(wxEVT_BUTTON, &TranslationEditorDialog::onBtnSave, this);
	gfx_preview->Bind(wxEVT_MOTION, &TranslationEditorDialog::onGfxPreviewMouseMotion, this);
	cb_target_reverse->Bind(wxEVT_CHECKBOX, &TranslationEditorDialog::onCBTargetReverse, this);
	cb_truecolor->Bind(wxEVT_CHECKBOX, &TranslationEditorDialog::onCBTruecolor, this);

	// Setup layout
	Layout();
	SetInitialSize(wxSize(-1, -1));
	SetMinSize(GetSize());
	CenterOnParent();
	list_translations->SetSizeHints(list_translations->GetSize(), list_translations->GetSize());
}
Beispiel #23
0
// -----------------------------------------------------------------------------
// Using [dc], draw the calltip contents at [xoff,yoff].
// Returns the dimensions of the drawn calltip text
// -----------------------------------------------------------------------------
wxSize SCallTip::drawCallTip(wxDC& dc, int xoff, int yoff)
{
	wxSize ct_size;
	auto   bold = font_.Bold();

	// Setup faded text colour
	ColRGBA faded;
	if (txed_calltips_dim_optional)
		faded = ColRGBA(
			(uint8_t)round((col_fg_.r + col_bg_.r) * 0.5),
			(uint8_t)round((col_fg_.g + col_bg_.g) * 0.5),
			(uint8_t)round((col_fg_.b + col_bg_.b) * 0.5));
	else
		faded = col_fg_;

	// Clear
	dc.SetPen(*wxTRANSPARENT_PEN);
	dc.SetBrush(wxBrush(WXCOL(col_bg_)));
	dc.DrawRectangle(0, 0, 1000, 1000);

	// Wx Colours (to avoid creating them multiple times)
	wxcol_fg         = WXCOL(col_fg_);
	wxcol_fg_hl      = WXCOL(col_fg_hl);
	wxcol_type       = WXCOL(col_type_);
	auto wxcol_faded = WXCOL(faded);

	if (function_)
	{
		dc.SetFont(font_);
		dc.SetTextForeground(wxcol_fg);

		wxRect rect;
		int    left      = xoff;
		int    max_right = 0;
		int    bottom    = yoff;

		// Context switching calltip
		if (switch_contexts_)
		{
			// up-filled	\xE2\x96\xB2
			// up-empty		\xE2\x96\xB3
			// down-filled	\xE2\x96\xBC
			// down-empty	\xE2\x96\xBD

			// Up arrow
			dc.SetTextForeground((btn_mouse_over_ == 2) ? wxcol_fg_hl : wxcol_fg);
			dc.DrawLabel(
				wxString::FromUTF8("\xE2\x96\xB2"), wxNullBitmap, wxRect(xoff, yoff, 100, 100), 0, -1, &rect_btn_up_);

			// Arg set
			int width = dc.GetTextExtent("X/X").x;
			dc.SetTextForeground(wxcol_fg);
			dc.DrawLabel(
				wxString::Format("%lu/%lu", context_current_ + 1, function_->contexts().size()),
				wxNullBitmap,
				wxRect(rect_btn_up_.GetRight() + UI::scalePx(4), yoff, width, 900),
				wxALIGN_CENTER_HORIZONTAL);

			// Down arrow
			dc.SetTextForeground((btn_mouse_over_ == 1) ? wxcol_fg_hl : wxcol_fg);
			dc.DrawLabel(
				wxString::FromUTF8("\xE2\x96\xBC"),
				wxNullBitmap,
				wxRect(rect_btn_up_.GetRight() + width + UI::scalePx(8), yoff, 900, 900),
				0,
				-1,
				&rect_btn_down_);

			left = rect_btn_down_.GetRight() + UI::scalePx(8);
			rect_btn_up_.Offset(WxUtils::scaledPoint(12, 8));
			rect_btn_down_.Offset(WxUtils::scaledPoint(12, 8));

			// Draw function (current context)
			rect      = drawFunctionContext(dc, context_, left, yoff, wxcol_faded, bold);
			max_right = rect.GetRight();
			bottom    = rect.GetBottom();
		}

		// Normal calltip - show (potentially) multiple contexts
		else
		{
			// Determine separator colour
			wxColour col_sep;
			if (col_bg_.greyscale().r < 128)
				col_sep = WXCOL(col_bg_.amp(30, 30, 30, 0));
			else
				col_sep = WXCOL(col_bg_.amp(-30, -30, -30, 0));

			bool first = true;
			auto num   = std::min<unsigned long>(function_->contexts().size(), 12u);
			for (auto a = 0u; a < num; a++)
			{
				auto& context = function_->contexts()[a];

				if (!first)
				{
					dc.SetPen(wxPen(col_sep));
					dc.DrawLine(xoff, bottom + 5, 2000, bottom + 5);
				}

				rect = drawFunctionContext(
					dc, context, xoff, bottom + (first ? 0 : UI::scalePx(11)), wxcol_faded, bold);
				bottom    = (int)round(rect.GetBottom() + UI::scaleFactor());
				max_right = std::max(max_right, rect.GetRight());
				first     = false;
			}

			// Show '... # more' if there are too many contexts
			if (function_->contexts().size() > num)
			{
				dc.SetTextForeground(wxcol_faded);
				drawText(
					dc,
					wxString::Format("... %lu more", function_->contexts().size() - num),
					xoff,
					bottom + UI::scalePx(11),
					&rect);
				bottom = (int)round(rect.GetBottom() + UI::scaleFactor());
			}

			if (num > 1)
				bottom--;
		}

		if (!rect.IsEmpty() && !context_.description.empty())
		{
			auto rect_desc = drawFunctionDescription(dc, context_.description, left, rect.GetBottom());
			max_right      = std::max(max_right, rect_desc.GetRight());
			bottom         = rect_desc.GetBottom();
		}

		// Size buffer bitmap to fit
		ct_size.SetWidth((int)round(max_right + UI::scaleFactor()));
		ct_size.SetHeight((int)round(bottom + UI::scaleFactor()));
	}
	else
	{
		// No function, empty buffer
		ct_size.SetWidth(16);
		ct_size.SetHeight(16);
	}

	return ct_size;
}
/* ZTextureEditorPanel::updatePatchControls
 * Updates all patch editing controls with values from the currently
 * selected patch. Behaves differently depending on the number of
 * patches selected
 *******************************************************************/
void ZTextureEditorPanel::updatePatchControls()
{
	// Get selected patches
	wxArrayInt selection = list_patches->selectedItems();

	// If nothing is selected, disable patch controls
	if (selection.size() == 0)
	{
		spin_patch_left->Enable(false);
		spin_patch_top->Enable(false);
		cb_flipx->Enable(false);
		cb_flipy->Enable(false);
		cb_useofs->Enable(false);
		choice_rotation->Enable(false);
		spin_alpha->Enable(false);
		choice_style->Enable(false);
		rb_pc_normal->Enable(false);
		rb_pc_blend->Enable(false);
		rb_pc_tint->Enable(false);
		rb_pc_translation->Enable(false);
		cp_blend_col->Enable(false);
		spin_tint_amount->Enable(false);
		text_translation->Enable(false);
		btn_edit_translation->Enable(false);
	}
	else
	{
		// Something is selected, enable the controls
		spin_patch_left->Enable(true);
		spin_patch_top->Enable(true);
		cb_flipx->Enable(true);
		cb_flipy->Enable(true);
		cb_useofs->Enable(true);
		choice_rotation->Enable(true);
		spin_alpha->Enable(true);
		choice_style->Enable(true);
		rb_pc_normal->Enable(true);
		rb_pc_blend->Enable(true);
		rb_pc_tint->Enable(true);
		rb_pc_translation->Enable(true);
		cp_blend_col->Enable(true);
		spin_tint_amount->Enable(true);
		text_translation->Enable(true);
		btn_edit_translation->Enable(true);

		// If only 1 patch is selected, just set the controls to this patch
		if (selection.size() == 1)
		{
			CTPatchEx* patch = (CTPatchEx*)tex_current->getPatch(selection[0]);
			if (!patch)
			{
				wxLogMessage("Error: Selected patch does not exist in texture");
				return;
			}

			spin_patch_left->SetValue(patch->xOffset());
			spin_patch_top->SetValue(patch->yOffset());
			cb_flipx->SetValue(patch->flipX());
			cb_flipy->SetValue(patch->flipY());
			cb_useofs->SetValue(patch->useOffsets());
			spin_alpha->SetValue(patch->getAlpha());
			choice_style->SetStringSelection(patch->getStyle());
			cp_blend_col->SetColour(WXCOL(patch->getColour()));
			spin_tint_amount->SetValue((double)patch->getColour().a / 255.0);
			text_translation->SetValue(patch->getTranslation().asText());

			switch (patch->getRotation())
			{
			case 0: choice_rotation->SetSelection(0); break;
			case 90: choice_rotation->SetSelection(1); break;
			case 180: choice_rotation->SetSelection(2); break;
			case -90: choice_rotation->SetSelection(3); break;
			default: choice_rotation->SetSelection(-1); break;
			};

			// Update patch colour controls
			switch (patch->getBlendType())
			{
			case 1:
				rb_pc_translation->SetValue(true);
				enableTranslationControls(true);
				enableBlendControls(false);
				break;
			case 2:
				rb_pc_blend->SetValue(true);
				enableBlendControls(true);
				enableTranslationControls(false);
				break;
			case 3:
				rb_pc_tint->SetValue(true);
				enableBlendControls(true, true);
				enableTranslationControls(false);
				break;
			default:
				rb_pc_normal->SetValue(true);
				enableTranslationControls(false);
				enableBlendControls(false);
				break;
			}
		}
		else
		{
			// Multiple selection, only enable some controls
			spin_patch_left->Enable(false);
			spin_patch_top->Enable(false);
		}
	}
}
Beispiel #25
0
/* SCallTip::updateBuffer
 * Redraws the calltip text to the buffer image, setting the buffer
 * image size to the exact dimensions of the text
 *******************************************************************/
void SCallTip::updateBuffer()
{
	buffer.SetWidth(1000);
	buffer.SetHeight(1000);
	wxFont bold = font.Bold();

	// Setup faded text colour
	rgba_t faded;
	if (txed_calltips_dim_optional)
		faded = rgba_t(
			col_fg.r * 0.5 + col_bg.r * 0.5,
			col_fg.g * 0.5 + col_bg.g * 0.5,
			col_fg.b * 0.5 + col_bg.b * 0.5
		);
	else
		faded = col_fg;

	wxMemoryDC dc(buffer);

	// Clear
	dc.SetPen(*wxTRANSPARENT_PEN);
	dc.SetBrush(wxBrush(WXCOL(col_bg)));
	dc.DrawRectangle(0, 0, 1000, 1000);

	if (function)
	{
		dc.SetFont(font);
		dc.SetTextForeground(WXCOL(col_fg));

		// Draw arg set switching stuff
		int left = 0;
		if (switch_args)
		{
			// up-filled	\xE2\x96\xB2
			// up-empty		\xE2\x96\xB3
			// down-filled	\xE2\x96\xBC
			// down-empty	\xE2\x96\xBD

			// Up arrow
			dc.SetTextForeground((btn_mouse_over == 2) ? WXCOL(col_fg_hl) : WXCOL(col_fg));
			dc.DrawLabel(
				wxString::FromUTF8("\xE2\x96\xB2"),
				wxNullBitmap,
				wxRect(0, 0, 100, 100),
				0,
				-1,
				&rect_btn_up);

			// Arg set
			int width = dc.GetTextExtent("X/X").x;
			dc.SetTextForeground(WXCOL(col_fg));
			dc.DrawLabel(
				S_FMT("%d/%d", arg_set_current + 1, function->nArgSets()),
				wxNullBitmap,
				wxRect(rect_btn_up.GetRight() + 4, 0, width, 900),
				wxALIGN_CENTER_HORIZONTAL);

			// Down arrow
			dc.SetTextForeground((btn_mouse_over == 1) ? WXCOL(col_fg_hl) : WXCOL(col_fg));
			dc.DrawLabel(
				wxString::FromUTF8("\xE2\x96\xBC"),
				wxNullBitmap,
				wxRect(rect_btn_up.GetRight() + width + 8, 0, 900, 900),
				0,
				-1,
				&rect_btn_down);

			left = rect_btn_down.GetRight() + 8;
			rect_btn_up.Offset(12, 8);
			rect_btn_down.Offset(12, 8);
		}

		// Draw function name
		string fname = function->getName();
		wxRect rect;
		dc.SetTextForeground(WXCOL(col_func));
		dc.DrawLabel(fname, wxNullBitmap, wxRect(left, 0, 900, 900), 0, -1, &rect);

		// Draw opening bracket
		dc.SetTextForeground(WXCOL(col_fg));
		left = drawText(dc, "(", rect.GetRight() + 1, rect.GetTop(), &rect);

		// Draw args
		int top = rect.GetTop();
		int max_right = 0;
		int args_left = left;
		for (unsigned a = 0; a < args.size(); a++)
		{
			// Go down to next line if current is too long
			if (left > SCALLTIP_MAX_WIDTH)
			{
				left = args_left;
				top = rect.GetBottom() + 2;
			}

			// Set highlight colour if current arg
			if (a == arg_current)
			{
				dc.SetTextForeground(WXCOL(col_fg_hl));
				dc.SetFont(bold);
			}

			// Optional opening bracket
			if (args[a].optional && !txed_calltips_dim_optional)
				left = drawText(dc, "[", left, top, &rect);

			// Type
			if (!args[a].type.empty())
			{
				if (a != arg_current) dc.SetTextForeground(WXCOL(col_type));
				left = drawText(dc, args[a].type + " ", left, top, &rect);
			}

			// Name
			if (a != arg_current)
				dc.SetTextForeground(args[a].optional ? WXCOL(faded) : WXCOL(col_fg));	// Faded text if optional
			left = drawText(dc, args[a].name, left, top, &rect);

			// Optional closing bracket
			if (args[a].optional && !txed_calltips_dim_optional)
				left = drawText(dc, "]", left, top, &rect);

			// Comma (if needed)
			dc.SetFont(font);
			dc.SetTextForeground(WXCOL(col_fg));
			if (a < args.size() - 1)
				left = drawText(dc, ", ", left, top, &rect);

			// Update max width
			if (rect.GetRight() > max_right)
				max_right = rect.GetRight();
		}

		// Draw closing bracket
		left = drawText(dc, ")", left, top, &rect);

		// Draw overloads number
		if (function->nArgSets() > 1 && !switch_args)
			dc.DrawLabel(
				S_FMT(" (+%d)", function->nArgSets() - 1),
				wxNullBitmap,
				wxRect(left, top, 900, 900),
				0,
				-1,
				&rect);

		// Update max width
		if (rect.GetRight() > max_right)
			max_right = rect.GetRight();

		// Description
		string desc = function->getDescription();
		if (!desc.IsEmpty())
		{
			wxFont italic = font.Italic();
			dc.SetFont(italic);
			if (dc.GetTextExtent(desc).x > SCALLTIP_MAX_WIDTH)
			{
				// Description is too long, split into multiple lines
				vector<string> desc_lines;
				string line = desc;
				wxArrayInt extents;
				while (true)
				{
					dc.GetPartialTextExtents(line, extents);
					bool split = false;
					for (unsigned a = 0; a < extents.size(); a++)
					{
						if (extents[a] > SCALLTIP_MAX_WIDTH)
						{
							int eol = line.SubString(0, a).Last(' ');
							desc_lines.push_back(line.SubString(0, eol));
							line = line.SubString(eol + 1, line.Length());
							split = true;
							break;
						}
					}

					if (!split)
					{
						desc_lines.push_back(line);
						break;
					}
				}

				int bottom = rect.GetBottom() + 8;
				for (unsigned a = 0; a < desc_lines.size(); a++)
				{
					drawText(dc, desc_lines[a], 0, bottom, &rect);
					bottom = rect.GetBottom();
					if (rect.GetRight() > max_right)
						max_right = rect.GetRight();
				}
			}
			else
			{
				drawText(dc, desc, 0, rect.GetBottom() + 8, &rect);
				if (rect.GetRight() > max_right)
					max_right = rect.GetRight();
			}
		}

		// Size buffer bitmap to fit
		buffer.SetWidth(max_right + 1);
		buffer.SetHeight(rect.GetBottom() + 1);
	}
	else
	{
		// No function, empty buffer
		buffer.SetWidth(16);
		buffer.SetHeight(16);
	}
}