<commit_before>// Scintilla source code edit control
/** @file LexAda.cxx
 ** Lexer for Ada 95
 **/
// Copyright 2002 by Sergey Koshcheyev <sergey.k@seznam.cz>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>

#include "Platform.h"

#include "Accessor.h"
#include "StyleContext.h"
#include "PropSet.h"
#include "KeyWords.h"
#include "SciLexer.h"
#include "SString.h"

/*
 * Interface
 */

static void ColouriseDocument(
    unsigned int startPos,
    int length,
    int initStyle,
    WordList *keywordlists[],
    Accessor &styler);

static const char * const adaWordListDesc[] = {
	"Keywords",
	0
};

LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada", NULL, adaWordListDesc);

/*
 * Implementation
 */

// Functions that have apostropheStartsAttribute as a parameter set it according to whether
// an apostrophe encountered after processing the current token will start an attribute or
// a character literal.
static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL);
static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);

static inline bool IsDelimiterCharacter(int ch);
static inline bool IsNumberStartCharacter(int ch);
static inline bool IsNumberCharacter(int ch);
static inline bool IsSeparatorOrDelimiterCharacter(int ch);
static bool IsValidIdentifier(const SString& identifier);
static bool IsValidNumber(const SString& number);
static inline bool IsWordStartCharacter(int ch);
static inline bool IsWordCharacter(int ch);

static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = true;

	sc.SetState(SCE_ADA_CHARACTER);

	// Skip the apostrophe and one more character (so that '' is shown as non-terminated and '''
	// is handled correctly)
	sc.Forward();
	sc.Forward();

	ColouriseContext(sc, '\'', SCE_ADA_CHARACTEREOL);
}

static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL) {
	while (!sc.atLineEnd && !sc.Match(chEnd)) {
		sc.Forward();
	}

	if (!sc.atLineEnd) {
		sc.ForwardSetState(SCE_ADA_DEFAULT);
	} else {
		sc.ChangeState(stateEOL);
	}
}

static void ColouriseComment(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
	// Apostrophe meaning is not changed, but the parameter is present for uniformity

	sc.SetState(SCE_ADA_COMMENTLINE);

	while (!sc.atLineEnd) {
		sc.Forward();
	}
}

static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = sc.Match (')');
	sc.SetState(SCE_ADA_DELIMITER);
	sc.ForwardSetState(SCE_ADA_DEFAULT);
}

static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = false;

	sc.SetState(SCE_ADA_LABEL);

	// Skip "<<"
	sc.Forward();
	sc.Forward();

	SString identifier;

	while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
		identifier += static_cast<char>(tolower(sc.ch));
		sc.Forward();
	}

	// Skip ">>"
	if (sc.Match('>', '>')) {
		sc.Forward();
		sc.Forward();
	} else {
		sc.ChangeState(SCE_ADA_ILLEGAL);
	}

	// If the name is an invalid identifier or a keyword, then make it invalid label
	if (!IsValidIdentifier(identifier) || keywords.InList(identifier.c_str())) {
		sc.ChangeState(SCE_ADA_ILLEGAL);
	}

	sc.SetState(SCE_ADA_DEFAULT);

}

static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = true;

	SString number;
	sc.SetState(SCE_ADA_NUMBER);

	// Get all characters up to a delimiter or a separator, including points, but excluding
	// double points (ranges).
	while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
		number += static_cast<char>(sc.ch);
		sc.Forward();
	}

	// Special case: exponent with sign
	if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
	        (sc.ch == '+' || sc.ch == '-')) {
		number += static_cast<char>(sc.ch);
		sc.Forward ();

		while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
			number += static_cast<char>(sc.ch);
			sc.Forward();
		}
	}

	if (!IsValidNumber(number)) {
		sc.ChangeState(SCE_ADA_ILLEGAL);
	}

	sc.SetState(SCE_ADA_DEFAULT);
}

static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = true;

	sc.SetState(SCE_ADA_STRING);
	sc.Forward();

	ColouriseContext(sc, '"', SCE_ADA_STRINGEOL);
}

static void ColouriseWhiteSpace(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
	// Apostrophe meaning is not changed, but the parameter is present for uniformity
	sc.SetState(SCE_ADA_DEFAULT);
	sc.ForwardSetState(SCE_ADA_DEFAULT);
}

static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = true;
	sc.SetState(SCE_ADA_IDENTIFIER);

	SString word;

	while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
		word += static_cast<char>(tolower(sc.ch));
		sc.Forward();
	}

	if (!IsValidIdentifier(word)) {
		sc.ChangeState(SCE_ADA_ILLEGAL);

	} else if (keywords.InList(word.c_str())) {
		sc.ChangeState(SCE_ADA_WORD);

		if (word != "all") {
			apostropheStartsAttribute = false;
		}
	}

	sc.SetState(SCE_ADA_DEFAULT);
}

//
// ColouriseDocument
//

static void ColouriseDocument(
    unsigned int startPos,
    int length,
    int initStyle,
    WordList *keywordlists[],
    Accessor &styler) {
	WordList &keywords = *keywordlists[0];

	StyleContext sc(startPos, length, initStyle, styler);

	int lineCurrent = styler.GetLine(startPos);
	bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;

	while (sc.More()) {
		if (sc.atLineEnd) {
			// Go to the next line
			sc.Forward();
			lineCurrent++;

			// Remember the line state for future incremental lexing
			styler.SetLineState(lineCurrent, apostropheStartsAttribute);

			// Don't continue any styles on the next line
			sc.SetState(SCE_ADA_DEFAULT);
		}

		// Comments
		if (sc.Match('-', '-')) {
			ColouriseComment(sc, apostropheStartsAttribute);

		// Strings
		} else if (sc.Match('"')) {
			ColouriseString(sc, apostropheStartsAttribute);

		// Characters
		} else if (sc.Match('\'') && !apostropheStartsAttribute) {
			ColouriseCharacter(sc, apostropheStartsAttribute);

		// Labels
		} else if (sc.Match('<', '<')) {
			ColouriseLabel(sc, keywords, apostropheStartsAttribute);

		// Whitespace
		} else if (isspace(sc.ch)) {
			ColouriseWhiteSpace(sc, apostropheStartsAttribute);

		// Delimiters
		} else if (IsDelimiterCharacter(sc.ch)) {
			ColouriseDelimiter(sc, apostropheStartsAttribute);

		// Numbers
		} else if (isdigit(sc.ch) || sc.ch == '#') {
			ColouriseNumber(sc, apostropheStartsAttribute);

		// Keywords or identifiers
		} else {
			ColouriseWord(sc, keywords, apostropheStartsAttribute);
		}
	}

	sc.Complete();
}

static inline bool IsDelimiterCharacter(int ch) {
	switch (ch) {
	case '&':
	case '\'':
	case '(':
	case ')':
	case '*':
	case '+':
	case ',':
	case '-':
	case '.':
	case '/':
	case ':':
	case ';':
	case '<':
	case '=':
	case '>':
	case '|':
		return true;
	default:
		return false;
	}
}

static inline bool IsNumberCharacter(int ch) {
	return IsNumberStartCharacter(ch) ||
	       ch == '_' ||
	       ch == '.' ||
	       ch == '#' ||
	       (ch >= 'a' && ch <= 'f') ||
	       (ch >= 'A' && ch <= 'F');
}

static inline bool IsNumberStartCharacter(int ch) {
	return isdigit(ch) != 0;
}

static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
	return isspace(ch) || IsDelimiterCharacter(ch);
}

static bool IsValidIdentifier(const SString& identifier) {
	// First character can't be '_', so initialize the flag to true
	bool lastWasUnderscore = true;

	size_t length = identifier.length();

	// Zero-length identifiers are not valid (these can occur inside labels)
	if (length == 0) {
		return false;
	}

	// Check for valid character at the start
	if (!IsWordStartCharacter(identifier[0])) {
		return false;
	}

	// Check for only valid characters and no double underscores
	for (size_t i = 0; i < length; i++) {
		if (!IsWordCharacter(identifier[i]) ||
		        (identifier[i] == '_' && lastWasUnderscore)) {
			return false;
		}
		lastWasUnderscore = identifier[i] == '_';
	}

	// Check for underscore at the end
	if (lastWasUnderscore == true) {
		return false;
	}

	// All checks passed
	return true;
}

static bool IsValidNumber(const SString& number) {
	int hashPos = number.search("#");
	bool seenDot = false;

	size_t i = 0;
	size_t length = number.length();

	if (length == 0)
		return false; // Just in case

	// Decimal number
	if (hashPos == -1) {
		bool canBeSpecial = false;

		for (; i < length; i++) {
			if (number[i] == '_') {
				if (!canBeSpecial) {
					return false;
				}
				canBeSpecial = false;
			} else if (number[i] == '.') {
				if (!canBeSpecial || seenDot) {
					return false;
				}
				canBeSpecial = false;
				seenDot = true;
			} else if (isdigit(number[i])) {
				canBeSpecial = true;
			} else {
				break;
			}
		}

		if (!canBeSpecial)
			return false;
	} else {
		// Based number
		bool canBeSpecial = false;
		int base = 0;

		// Parse base
		for (; i < length; i++) {
			int ch = number[i];
			if (ch == '_') {
				if (!canBeSpecial)
					return false;
				canBeSpecial = false;
			} else if (isdigit (ch)) {
				base = base * 10 + (ch - '0');
				if (base > 16)
					return false;
				canBeSpecial = true;
			} else if (ch == '#' && canBeSpecial) {
				break;
			} else {
				return false;
			}
		}

		if (base < 2)
			return false;
		if (i == length)
			return false;

		i++; // Skip over '#'

		// Parse number
		canBeSpecial = false;

		for (; i < length; i++) {
			int ch = tolower(number[i]);

			if (ch == '_') {
				if (!canBeSpecial) {
					return false;
				}
				canBeSpecial = false;

			} else if (ch == '.') {
				if (!canBeSpecial || seenDot) {
					return false;
				}
				canBeSpecial = false;
				seenDot = true;

			} else if (isdigit (ch)) {
				if (ch - '0' >= base) {
					return false;
				}
				canBeSpecial = true;

			} else if (ch >= 'a' && ch <= 'f') {
				if (ch - 'a' + 10 >= base) {
					return false;
				}
				canBeSpecial = true;

			} else if (ch == '#' && canBeSpecial) {
				break;

			} else {
				return false;
			}
		}

		if (i == length) {
			return false;
		}

		i++;
	}

	// Exponent (optional)
	if (i < length) {
		if (number[i] != 'e' && number[i] != 'E')
			return false;

		i++; // Move past 'E'

		if (i == length) {
			return false;
		}

		if (number[i] == '+')
			i++;
		else if (number[i] == '-') {
			if (seenDot) {
				i++;
			} else {
				return false; // Integer literals should not have negative exponents
			}
		}

		if (i == length) {
			return false;
		}

		bool canBeSpecial = false;

		for (; i < length; i++) {
			if (number[i] == '_') {
				if (!canBeSpecial) {
					return false;
				}
				canBeSpecial = false;
			} else if (isdigit(number[i])) {
				canBeSpecial = true;
			} else {
				return false;
			}
		}

		if (!canBeSpecial)
			return false;
	}

	// if i == length, number was parsed successfully.
	return i == length;
}

static inline bool IsWordCharacter(int ch) {
	return IsWordStartCharacter(ch) || isdigit(ch);
}

static inline bool IsWordStartCharacter(int ch) {
	return isalpha(ch) || ch == '_';
}
<commit_msg>Made safe for non-ASCII characters by using character classification functions that accept non-ASCII or checking for ASCII before calling ctype functions.<commit_after>// Scintilla source code edit control
/** @file LexAda.cxx
 ** Lexer for Ada 95
 **/
// Copyright 2002 by Sergey Koshcheyev <sergey.k@seznam.cz>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>

#include "Platform.h"

#include "Accessor.h"
#include "StyleContext.h"
#include "PropSet.h"
#include "KeyWords.h"
#include "SciLexer.h"
#include "SString.h"

/*
 * Interface
 */

static void ColouriseDocument(
    unsigned int startPos,
    int length,
    int initStyle,
    WordList *keywordlists[],
    Accessor &styler);

static const char * const adaWordListDesc[] = {
	"Keywords",
	0
};

LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada", NULL, adaWordListDesc);

/*
 * Implementation
 */

// Functions that have apostropheStartsAttribute as a parameter set it according to whether
// an apostrophe encountered after processing the current token will start an attribute or
// a character literal.
static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL);
static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);

static inline bool IsDelimiterCharacter(int ch);
static inline bool IsNumberStartCharacter(int ch);
static inline bool IsNumberCharacter(int ch);
static inline bool IsSeparatorOrDelimiterCharacter(int ch);
static bool IsValidIdentifier(const SString& identifier);
static bool IsValidNumber(const SString& number);
static inline bool IsWordStartCharacter(int ch);
static inline bool IsWordCharacter(int ch);

static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = true;

	sc.SetState(SCE_ADA_CHARACTER);

	// Skip the apostrophe and one more character (so that '' is shown as non-terminated and '''
	// is handled correctly)
	sc.Forward();
	sc.Forward();

	ColouriseContext(sc, '\'', SCE_ADA_CHARACTEREOL);
}

static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL) {
	while (!sc.atLineEnd && !sc.Match(chEnd)) {
		sc.Forward();
	}

	if (!sc.atLineEnd) {
		sc.ForwardSetState(SCE_ADA_DEFAULT);
	} else {
		sc.ChangeState(stateEOL);
	}
}

static void ColouriseComment(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
	// Apostrophe meaning is not changed, but the parameter is present for uniformity

	sc.SetState(SCE_ADA_COMMENTLINE);

	while (!sc.atLineEnd) {
		sc.Forward();
	}
}

static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = sc.Match (')');
	sc.SetState(SCE_ADA_DELIMITER);
	sc.ForwardSetState(SCE_ADA_DEFAULT);
}

static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = false;

	sc.SetState(SCE_ADA_LABEL);

	// Skip "<<"
	sc.Forward();
	sc.Forward();

	SString identifier;

	while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
		identifier += static_cast<char>(tolower(sc.ch));
		sc.Forward();
	}

	// Skip ">>"
	if (sc.Match('>', '>')) {
		sc.Forward();
		sc.Forward();
	} else {
		sc.ChangeState(SCE_ADA_ILLEGAL);
	}

	// If the name is an invalid identifier or a keyword, then make it invalid label
	if (!IsValidIdentifier(identifier) || keywords.InList(identifier.c_str())) {
		sc.ChangeState(SCE_ADA_ILLEGAL);
	}

	sc.SetState(SCE_ADA_DEFAULT);

}

static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = true;

	SString number;
	sc.SetState(SCE_ADA_NUMBER);

	// Get all characters up to a delimiter or a separator, including points, but excluding
	// double points (ranges).
	while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
		number += static_cast<char>(sc.ch);
		sc.Forward();
	}

	// Special case: exponent with sign
	if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
	        (sc.ch == '+' || sc.ch == '-')) {
		number += static_cast<char>(sc.ch);
		sc.Forward ();

		while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
			number += static_cast<char>(sc.ch);
			sc.Forward();
		}
	}

	if (!IsValidNumber(number)) {
		sc.ChangeState(SCE_ADA_ILLEGAL);
	}

	sc.SetState(SCE_ADA_DEFAULT);
}

static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = true;

	sc.SetState(SCE_ADA_STRING);
	sc.Forward();

	ColouriseContext(sc, '"', SCE_ADA_STRINGEOL);
}

static void ColouriseWhiteSpace(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
	// Apostrophe meaning is not changed, but the parameter is present for uniformity
	sc.SetState(SCE_ADA_DEFAULT);
	sc.ForwardSetState(SCE_ADA_DEFAULT);
}

static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
	apostropheStartsAttribute = true;
	sc.SetState(SCE_ADA_IDENTIFIER);

	SString word;

	while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
		word += static_cast<char>(tolower(sc.ch));
		sc.Forward();
	}

	if (!IsValidIdentifier(word)) {
		sc.ChangeState(SCE_ADA_ILLEGAL);

	} else if (keywords.InList(word.c_str())) {
		sc.ChangeState(SCE_ADA_WORD);

		if (word != "all") {
			apostropheStartsAttribute = false;
		}
	}

	sc.SetState(SCE_ADA_DEFAULT);
}

//
// ColouriseDocument
//

static void ColouriseDocument(
    unsigned int startPos,
    int length,
    int initStyle,
    WordList *keywordlists[],
    Accessor &styler) {
	WordList &keywords = *keywordlists[0];

	StyleContext sc(startPos, length, initStyle, styler);

	int lineCurrent = styler.GetLine(startPos);
	bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;

	while (sc.More()) {
		if (sc.atLineEnd) {
			// Go to the next line
			sc.Forward();
			lineCurrent++;

			// Remember the line state for future incremental lexing
			styler.SetLineState(lineCurrent, apostropheStartsAttribute);

			// Don't continue any styles on the next line
			sc.SetState(SCE_ADA_DEFAULT);
		}

		// Comments
		if (sc.Match('-', '-')) {
			ColouriseComment(sc, apostropheStartsAttribute);

		// Strings
		} else if (sc.Match('"')) {
			ColouriseString(sc, apostropheStartsAttribute);

		// Characters
		} else if (sc.Match('\'') && !apostropheStartsAttribute) {
			ColouriseCharacter(sc, apostropheStartsAttribute);

		// Labels
		} else if (sc.Match('<', '<')) {
			ColouriseLabel(sc, keywords, apostropheStartsAttribute);

		// Whitespace
		} else if (IsASpace(sc.ch)) {
			ColouriseWhiteSpace(sc, apostropheStartsAttribute);

		// Delimiters
		} else if (IsDelimiterCharacter(sc.ch)) {
			ColouriseDelimiter(sc, apostropheStartsAttribute);

		// Numbers
		} else if (IsADigit(sc.ch) || sc.ch == '#') {
			ColouriseNumber(sc, apostropheStartsAttribute);

		// Keywords or identifiers
		} else {
			ColouriseWord(sc, keywords, apostropheStartsAttribute);
		}
	}

	sc.Complete();
}

static inline bool IsDelimiterCharacter(int ch) {
	switch (ch) {
	case '&':
	case '\'':
	case '(':
	case ')':
	case '*':
	case '+':
	case ',':
	case '-':
	case '.':
	case '/':
	case ':':
	case ';':
	case '<':
	case '=':
	case '>':
	case '|':
		return true;
	default:
		return false;
	}
}

static inline bool IsNumberCharacter(int ch) {
	return IsNumberStartCharacter(ch) ||
	       ch == '_' ||
	       ch == '.' ||
	       ch == '#' ||
	       (ch >= 'a' && ch <= 'f') ||
	       (ch >= 'A' && ch <= 'F');
}

static inline bool IsNumberStartCharacter(int ch) {
	return IsADigit(ch);
}

static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
	return IsASpace(ch) || IsDelimiterCharacter(ch);
}

static bool IsValidIdentifier(const SString& identifier) {
	// First character can't be '_', so initialize the flag to true
	bool lastWasUnderscore = true;

	size_t length = identifier.length();

	// Zero-length identifiers are not valid (these can occur inside labels)
	if (length == 0) {
		return false;
	}

	// Check for valid character at the start
	if (!IsWordStartCharacter(identifier[0])) {
		return false;
	}

	// Check for only valid characters and no double underscores
	for (size_t i = 0; i < length; i++) {
		if (!IsWordCharacter(identifier[i]) ||
		        (identifier[i] == '_' && lastWasUnderscore)) {
			return false;
		}
		lastWasUnderscore = identifier[i] == '_';
	}

	// Check for underscore at the end
	if (lastWasUnderscore == true) {
		return false;
	}

	// All checks passed
	return true;
}

static bool IsValidNumber(const SString& number) {
	int hashPos = number.search("#");
	bool seenDot = false;

	size_t i = 0;
	size_t length = number.length();

	if (length == 0)
		return false; // Just in case

	// Decimal number
	if (hashPos == -1) {
		bool canBeSpecial = false;

		for (; i < length; i++) {
			if (number[i] == '_') {
				if (!canBeSpecial) {
					return false;
				}
				canBeSpecial = false;
			} else if (number[i] == '.') {
				if (!canBeSpecial || seenDot) {
					return false;
				}
				canBeSpecial = false;
				seenDot = true;
			} else if (IsADigit(number[i])) {
				canBeSpecial = true;
			} else {
				break;
			}
		}

		if (!canBeSpecial)
			return false;
	} else {
		// Based number
		bool canBeSpecial = false;
		int base = 0;

		// Parse base
		for (; i < length; i++) {
			int ch = number[i];
			if (ch == '_') {
				if (!canBeSpecial)
					return false;
				canBeSpecial = false;
			} else if (IsADigit(ch)) {
				base = base * 10 + (ch - '0');
				if (base > 16)
					return false;
				canBeSpecial = true;
			} else if (ch == '#' && canBeSpecial) {
				break;
			} else {
				return false;
			}
		}

		if (base < 2)
			return false;
		if (i == length)
			return false;

		i++; // Skip over '#'

		// Parse number
		canBeSpecial = false;

		for (; i < length; i++) {
			int ch = tolower(number[i]);

			if (ch == '_') {
				if (!canBeSpecial) {
					return false;
				}
				canBeSpecial = false;

			} else if (ch == '.') {
				if (!canBeSpecial || seenDot) {
					return false;
				}
				canBeSpecial = false;
				seenDot = true;

			} else if (IsADigit(ch)) {
				if (ch - '0' >= base) {
					return false;
				}
				canBeSpecial = true;

			} else if (ch >= 'a' && ch <= 'f') {
				if (ch - 'a' + 10 >= base) {
					return false;
				}
				canBeSpecial = true;

			} else if (ch == '#' && canBeSpecial) {
				break;

			} else {
				return false;
			}
		}

		if (i == length) {
			return false;
		}

		i++;
	}

	// Exponent (optional)
	if (i < length) {
		if (number[i] != 'e' && number[i] != 'E')
			return false;

		i++; // Move past 'E'

		if (i == length) {
			return false;
		}

		if (number[i] == '+')
			i++;
		else if (number[i] == '-') {
			if (seenDot) {
				i++;
			} else {
				return false; // Integer literals should not have negative exponents
			}
		}

		if (i == length) {
			return false;
		}

		bool canBeSpecial = false;

		for (; i < length; i++) {
			if (number[i] == '_') {
				if (!canBeSpecial) {
					return false;
				}
				canBeSpecial = false;
			} else if (IsADigit(number[i])) {
				canBeSpecial = true;
			} else {
				return false;
			}
		}

		if (!canBeSpecial)
			return false;
	}

	// if i == length, number was parsed successfully.
	return i == length;
}

static inline bool IsWordCharacter(int ch) {
	return IsWordStartCharacter(ch) || IsADigit(ch);
}

static inline bool IsWordStartCharacter(int ch) {
	return (isascii(ch) && isalpha(ch)) || ch == '_';
}
<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2014 Peter Tworek
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "Logger.h"

#include <QDebug>

#define LOG_CACHE_SIZE 200

static QString _log_str_arr[] = {
	QString("[DEBUG] "),
	QString("[ERROR] "),
	QString("[WARN]  "),
	QString("[INFO]  ")
};

QtMessageHandler Logger::_original_handler = NULL;
QContiguousCache<QVariantMap> *Logger::_log_cache =
		new QContiguousCache<QVariantMap>(LOG_CACHE_SIZE);

Logger::Logger(QObject *parent)
	: QObject(parent)
{
}

void
Logger::Register()
{
	_original_handler = qInstallMessageHandler(Logger::_messageHandler);
}

QVariant
Logger::getHistory() const
{
	QList<QVariant> list;
	for (int i = _log_cache->firstIndex(); i < _log_cache->lastIndex(); ++i) {
		list.append(_log_cache->at(i));
	}
	return QVariant(list);
}

void
Logger::_log(LogType type, QString message)
{
	const QString& prefix = _log_str_arr[type];
	QString fullMessage = prefix + message;

	QVariantMap entry;
	entry.insert("type", type);
	entry.insert("message", message);
	_log_cache->append(entry);

	switch (type) {
	case LOG_DEBUG:
	case LOG_INFO:
		_original_handler(QtDebugMsg, QMessageLogContext(), fullMessage);
		return;
	case LOG_ERROR:
		_original_handler(QtCriticalMsg, QMessageLogContext(), fullMessage);
		return;
	case LOG_WARN:
		_original_handler(QtWarningMsg, QMessageLogContext(), fullMessage);
		return;
	}
}

void
Logger::_messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
	QVariantMap entry;
	entry.insert("type", LOG_DEBUG);
	entry.insert("message", msg);
	_log_cache->append(entry);

	_original_handler(type, context, msg);
}
<commit_msg>LogViewer: Make sure to display all available logs<commit_after>/*-
 * Copyright (c) 2014 Peter Tworek
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "Logger.h"

#include <QDebug>

#define LOG_CACHE_SIZE 200

static QString _log_str_arr[] = {
	QString("[DEBUG] "),
	QString("[ERROR] "),
	QString("[WARN]  "),
	QString("[INFO]  ")
};

QtMessageHandler Logger::_original_handler = NULL;
QContiguousCache<QVariantMap> *Logger::_log_cache =
		new QContiguousCache<QVariantMap>(LOG_CACHE_SIZE);

Logger::Logger(QObject *parent)
	: QObject(parent)
{
}

void
Logger::Register()
{
	_original_handler = qInstallMessageHandler(Logger::_messageHandler);
}

QVariant
Logger::getHistory() const
{
	QList<QVariant> list;
	for (int i = _log_cache->firstIndex(); i <= _log_cache->lastIndex(); ++i) {
		list.append(_log_cache->at(i));
	}
	return QVariant(list);
}

void
Logger::_log(LogType type, QString message)
{
	const QString& prefix = _log_str_arr[type];
	QString fullMessage = prefix + message;

	QVariantMap entry;
	entry.insert("type", type);
	entry.insert("message", message);
	_log_cache->append(entry);

	switch (type) {
	case LOG_DEBUG:
	case LOG_INFO:
		_original_handler(QtDebugMsg, QMessageLogContext(), fullMessage);
		return;
	case LOG_ERROR:
		_original_handler(QtCriticalMsg, QMessageLogContext(), fullMessage);
		return;
	case LOG_WARN:
		_original_handler(QtWarningMsg, QMessageLogContext(), fullMessage);
		return;
	}
}

void
Logger::_messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
	QVariantMap entry;
	entry.insert("type", LOG_DEBUG);
	entry.insert("message", msg);
	_log_cache->append(entry);

	_original_handler(type, context, msg);
}
<|endoftext|>


<commit_before>#include "Octree.h"

const float Octree::THETA = 0.5f;

// http://stackoverflow.com/a/13717283/3598299
static bool overlaps(glm::vec3 l1, glm::vec3 h1, glm::vec3 l2, glm::vec3 h2) {
   return std::max(l1.x, l2.x) <= std::min(h1.x, h2.x) &&
          std::max(l1.y, l2.y) <= std::min(h1.y, h2.y) &&
          std::max(l1.z, l2.z) <= std::min(h1.z, h2.z);
}

Octree::Octree(const glm::vec3 &low, const glm::vec3 &high) {
   children = NULL;
   parent = NULL;

   this->low = low;
   this->high = high;
   middle = 0.5f * low + 0.5f * high;
   width = std::min(high.x - low.x, std::min(high.y - low.y, high.z - low.z));

   centerOfMass = glm::vec3(0.0f);
   totalMass = 0.0f;

   mass = NULL;
}

Octree::Octree(const glm::vec3 &low, const glm::vec3 &high, const Octree *parent) {
   children = NULL;
   this->parent = parent;

   this->low = low;
   this->high = high;
   middle = 0.5f * low + 0.5f * high;
   width = std::min(high.x - low.x, std::min(high.y - low.y, high.z - low.z));

   centerOfMass = glm::vec3(0.0f);
   totalMass = 0.0f;

   mass = NULL;
}

Octree::~Octree() {
   if (children) {
      for (int i = 0; i < TOT; i++) {
         if (children[i]) {
            delete children[i];
         }
      }

      delete[] children;
   }
}

Octree* Octree::makeChild(int child) const {
   glm::vec3 l;
   glm::vec3 h;

   if (child & XHI) {
      l.x = middle.x;
      h.x = high.x;
   } else {
      l.x = low.x;
      h.x = middle.x;
   }

   if (child & YHI) {
      l.y = middle.y;
      h.y = high.y;
   } else {
      l.y = low.y;
      h.y = middle.y;
   }

   if (child & ZHI) {
      l.z = middle.z;
      h.z = high.z;
   } else {
      l.z = low.z;
      h.z = middle.z;
   }

   return new Octree(l, h, this);
}

int Octree::pickChild(const glm::vec3 &pos) const {
   int child = 0;
   if (pos.x >= middle.x)
      child += XHI;
   if (pos.y >= middle.y)
      child += YHI;
   if (pos.z >= middle.z)
      child += ZHI;
   return child;
}

void Octree::insertChild(Mass *m) {
   int child = pickChild(m->getPosition());
   if (! children[child]) {
      children[child] = makeChild(child);
   }
   children[child]->addMass(m);
}

void Octree::addMass(Mass *m) {
   totalMass += m->getMass();
   centerOfMass += m->getMass() * m->getPosition();

   if (!mass && !children) {
      mass = m;
   } else if (children) {
      insertChild(m);
   } else {
      children = new Octree*[TOT]();
      insertChild(mass);
      insertChild(m);
      mass = NULL;
   }
}

void Octree::calcCOM() {
   centerOfMass /= totalMass;
   if (children) {
      for (int i = 0; i < TOT; i++) {
         if (children[i]) {
            children[i]->calcCOM();
         }
      }
   }
}

glm::vec3 Octree::getCOM() const {
   return centerOfMass;
}

float Octree::getMass() const {
   return totalMass;
}

bool Octree::isLeaf() const {
   return !children;
}

Octree* Octree::getChild(int ndx) const {
   return children ? children[ndx] : NULL;
}

const Octree* Octree::getParent() const {
   return parent;
}

float Octree::getWidth() const {
   return width;
}

void Octree::addForce(float force, glm::vec3 direction) const {
   if (mass) {
      mass->addForce(force, direction);
   }
}

BoxNode* Octree::getLeafList() const {
   BoxNode *list = NULL;
   BoxNode *last = NULL;
   BoxNode *curr = NULL;
   OctreeIterator iter(this);

   while (! iter.atEnd()) {
      if (iter.get()->isLeaf()) {
         curr = getNode(iter.get()->low, iter.get()->high);

         if (last) {
            last->next = curr;
         } else {
            list = curr;
         }

         last = curr;
      }

      iter.next();
   }

   return list;
}

void Octree::removeMass(Mass *m) {
   if (mass != m) {
      int child = pickChild(m->getPosition());
      if (children && children[child]) {
         bool last = (children[child]->mass = m);
         children[child]->removeMass(m);
         if (last) {
            delete children[child];
            children[child] = NULL;
         }
      }
   } else {
      mass = NULL;
      float mMass = m->getMass();
      Octree *o = this;
      while (o) {
         totalMass -= mMass;
         centerOfMass -= m->getPosition() * m->getMass();
         o = (Octree*) o->parent;
      }
   }
}

Mass* Octree::findCollision(Mass *m) const {
   float d = m->getRadius();
   glm::vec3 p = m->getPosition();
   glm::vec3 l(p.x - d, p.y - d, p.z - d);
   glm::vec3 h(p.x + d, p.y + d, p.z + d);
   OctreeIterator iter(this);

   while (! iter.atEnd()) {
      const Octree *o = iter.get();

      if (o->mass == m) {
         iter.next();
      } else if (overlaps(l, h, o->low, o->high)) {
         if (o->mass) {
            if (m->squaredDist(*(o->mass)) <= d*d) {
               return o->mass;
            }
         }
         iter.next();
      } else {
         iter.nextSkipChildren();
      }
   }

   return NULL;
}

OctreeIterator::OctreeIterator(const Octree *tree) {
   current = tree;
   currentIndex = -1;
}

void OctreeIterator::next() {
   if (! current)
      return;

   Octree *child;
   for (++currentIndex; currentIndex < TOT; currentIndex++) {
      if ((child = current->getChild(currentIndex))) {
         indices.push(currentIndex);
         current = child;
         currentIndex = -1;
         return;
      }
   }

   if ((current = current->getParent())) {
      currentIndex = indices.top();
      indices.pop();
      next();
   }
}

void OctreeIterator::nextSkipChildren() {
   if (! current)
      return;

   if ((current = current->getParent())) {
      currentIndex = indices.top();
      indices.pop();
      next();
   }
}

const Octree* OctreeIterator::get() const {
   return current;
}

bool OctreeIterator::atEnd() const {
   return !current;
}
<commit_msg>such a bad bug<commit_after>#include "Octree.h"

const float Octree::THETA = 0.5f;

// http://stackoverflow.com/a/13717283/3598299
static bool overlaps(glm::vec3 l1, glm::vec3 h1, glm::vec3 l2, glm::vec3 h2) {
   return std::max(l1.x, l2.x) <= std::min(h1.x, h2.x) &&
          std::max(l1.y, l2.y) <= std::min(h1.y, h2.y) &&
          std::max(l1.z, l2.z) <= std::min(h1.z, h2.z);
}

Octree::Octree(const glm::vec3 &low, const glm::vec3 &high) {
   children = NULL;
   parent = NULL;

   this->low = low;
   this->high = high;
   middle = 0.5f * low + 0.5f * high;
   width = std::min(high.x - low.x, std::min(high.y - low.y, high.z - low.z));

   centerOfMass = glm::vec3(0.0f);
   totalMass = 0.0f;

   mass = NULL;
}

Octree::Octree(const glm::vec3 &low, const glm::vec3 &high, const Octree *parent) {
   children = NULL;
   this->parent = parent;

   this->low = low;
   this->high = high;
   middle = 0.5f * low + 0.5f * high;
   width = std::min(high.x - low.x, std::min(high.y - low.y, high.z - low.z));

   centerOfMass = glm::vec3(0.0f);
   totalMass = 0.0f;

   mass = NULL;
}

Octree::~Octree() {
   if (children) {
      for (int i = 0; i < TOT; i++) {
         if (children[i]) {
            delete children[i];
         }
      }

      delete[] children;
   }
}

Octree* Octree::makeChild(int child) const {
   glm::vec3 l;
   glm::vec3 h;

   if (child & XHI) {
      l.x = middle.x;
      h.x = high.x;
   } else {
      l.x = low.x;
      h.x = middle.x;
   }

   if (child & YHI) {
      l.y = middle.y;
      h.y = high.y;
   } else {
      l.y = low.y;
      h.y = middle.y;
   }

   if (child & ZHI) {
      l.z = middle.z;
      h.z = high.z;
   } else {
      l.z = low.z;
      h.z = middle.z;
   }

   return new Octree(l, h, this);
}

int Octree::pickChild(const glm::vec3 &pos) const {
   int child = 0;
   if (pos.x >= middle.x)
      child += XHI;
   if (pos.y >= middle.y)
      child += YHI;
   if (pos.z >= middle.z)
      child += ZHI;
   return child;
}

void Octree::insertChild(Mass *m) {
   int child = pickChild(m->getPosition());
   if (! children[child]) {
      children[child] = makeChild(child);
   }
   children[child]->addMass(m);
}

void Octree::addMass(Mass *m) {
   totalMass += m->getMass();
   centerOfMass += m->getMass() * m->getPosition();

   if (!mass && !children) {
      mass = m;
   } else if (children) {
      insertChild(m);
   } else {
      children = new Octree*[TOT]();
      insertChild(mass);
      insertChild(m);
      mass = NULL;
   }
}

void Octree::calcCOM() {
   centerOfMass /= totalMass;
   if (children) {
      for (int i = 0; i < TOT; i++) {
         if (children[i]) {
            children[i]->calcCOM();
         }
      }
   }
}

glm::vec3 Octree::getCOM() const {
   return centerOfMass;
}

float Octree::getMass() const {
   return totalMass;
}

bool Octree::isLeaf() const {
   return !children;
}

Octree* Octree::getChild(int ndx) const {
   return children ? children[ndx] : NULL;
}

const Octree* Octree::getParent() const {
   return parent;
}

float Octree::getWidth() const {
   return width;
}

void Octree::addForce(float force, glm::vec3 direction) const {
   if (mass) {
      mass->addForce(force, direction);
   }
}

BoxNode* Octree::getLeafList() const {
   BoxNode *list = NULL;
   BoxNode *last = NULL;
   BoxNode *curr = NULL;
   OctreeIterator iter(this);

   while (! iter.atEnd()) {
      if (iter.get()->isLeaf()) {
         curr = getNode(iter.get()->low, iter.get()->high);

         if (last) {
            last->next = curr;
         } else {
            list = curr;
         }

         last = curr;
      }

      iter.next();
   }

   return list;
}

void Octree::removeMass(Mass *m) {
   if (mass != m) {
      int child = pickChild(m->getPosition());
      if (children && children[child]) {
         bool last = (children[child]->mass == m);
         children[child]->removeMass(m);
         if (last) {
            delete children[child];
            children[child] = NULL;
         }
      }
   } else {
      mass = NULL;
      float mMass = m->getMass();
      Octree *o = this;
      while (o) {
         totalMass -= mMass;
         centerOfMass -= m->getPosition() * m->getMass();
         o = (Octree*) o->parent;
      }
   }
}

Mass* Octree::findCollision(Mass *m) const {
   float d = m->getRadius();
   glm::vec3 p = m->getPosition();
   glm::vec3 l(p.x - d, p.y - d, p.z - d);
   glm::vec3 h(p.x + d, p.y + d, p.z + d);
   OctreeIterator iter(this);

   while (! iter.atEnd()) {
      const Octree *o = iter.get();

      if (o->mass == m) {
         iter.next();
      } else if (overlaps(l, h, o->low, o->high)) {
         if (o->mass) {
            if (m->squaredDist(*(o->mass)) <= d*d) {
               return o->mass;
            }
         }
         iter.next();
      } else {
         iter.nextSkipChildren();
      }
   }

   return NULL;
}

OctreeIterator::OctreeIterator(const Octree *tree) {
   current = tree;
   currentIndex = -1;
}

void OctreeIterator::next() {
   if (! current)
      return;

   Octree *child;
   for (++currentIndex; currentIndex < TOT; currentIndex++) {
      if ((child = current->getChild(currentIndex))) {
         indices.push(currentIndex);
         current = child;
         currentIndex = -1;
         return;
      }
   }

   if ((current = current->getParent())) {
      currentIndex = indices.top();
      indices.pop();
      next();
   }
}

void OctreeIterator::nextSkipChildren() {
   if (! current)
      return;

   if ((current = current->getParent())) {
      currentIndex = indices.top();
      indices.pop();
      next();
   }
}

const Octree* OctreeIterator::get() const {
   return current;
}

bool OctreeIterator::atEnd() const {
   return !current;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    OglrLgt.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <math.h>
#include "OglrRen.hh"
#include "OglrLgt.hh"

// Description:
// Implement base class method.
void vtkOglrLight::Render(vtkLight *lgt, vtkRenderer *ren,int light_index)
{
  this->Render(lgt, (vtkOglrRenderer *)ren,light_index);
}

// Description:
// Actual light render method.
void vtkOglrLight::Render(vtkLight *lgt, vtkOglrRenderer *ren,int light_index)
{
  float	dx, dy, dz;
  float	color[4];
  float *Color, *Position, *FocalPoint;
  float Intensity;
  float Info[4];

  // get required info from light
  Intensity = lgt->GetIntensity();
  Color = lgt->GetColor();
  color[0] = Intensity * Color[0];
  color[1] = Intensity * Color[1];
  color[2] = Intensity * Color[2];
  color[3] = 1.0;

  FocalPoint = lgt->GetFocalPoint();
  Position   = lgt->GetPosition();
  dx = FocalPoint[0] - Position[0];
  dy = FocalPoint[1] - Position[1];
  dz = FocalPoint[2] - Position[2];

  glLightfv((enum GLenum)light_index, GL_DIFFUSE, color);
  glLightfv((enum GLenum)light_index, GL_SPECULAR, color);

  if( ren->GetBackLight())
  {
  glLightfv((enum GLenum)(light_index+1), GL_DIFFUSE, color);
  glLightfv((enum GLenum)(light_index+1), GL_SPECULAR, color);
  }

  // define the light source
  if (!lgt->GetPositional())
    {
    Info[0]  = -dx;
    Info[1]  = -dy;
    Info[2]  = -dz;
    Info[3]  = 0.0;
    glLightfv((enum GLenum)light_index, GL_POSITION, Info );
    // define another mirror light if backlit is on
    if (ren->GetBackLight())
      {
      Info[0]  = dx;
      Info[1]  = dy;
      Info[2]  = dz;
      Info[3]  = 0.0;
      glLightfv((enum GLenum)(light_index + 1), GL_POSITION, Info );
      }
    }
  else
    {
    Info[0]  = Position[0];
    Info[1]  = Position[1];
    Info[2]  = Position[2];
    Info[3]  = 1.0;
    glLightfv((enum GLenum)light_index, GL_POSITION, Info );

    Info[0] = dx;
    Info[1] = dy;
    Info[2] = dz;
    glLightfv((enum GLenum)light_index, GL_SPOT_DIRECTION, Info );

    glLightf((enum GLenum)light_index, GL_SPOT_EXPONENT, lgt->GetExponent());
    glLightf((enum GLenum)light_index, GL_SPOT_CUTOFF, lgt->GetConeAngle());

    float *AttenuationValues = lgt->GetAttenuationValues();
    glLightf((enum GLenum)light_index,
	     GL_CONSTANT_ATTENUATION, AttenuationValues[0]);
    glLightf((enum GLenum)light_index,
	     GL_LINEAR_ATTENUATION, AttenuationValues[1]);
    glLightf((enum GLenum)light_index,
	     GL_QUADRATIC_ATTENUATION, AttenuationValues[2]);
    }

}

<commit_msg>FIXED UP<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    OglrLgt.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include <math.h>
#include "OglrRen.hh"
#include "OglrLgt.hh"

// Description:
// Implement base class method.
void vtkOglrLight::Render(vtkLight *lgt, vtkRenderer *ren,int light_index)
{
  this->Render(lgt, (vtkOglrRenderer *)ren,light_index);
}

// Description:
// Actual light render method.
void vtkOglrLight::Render(vtkLight *lgt, vtkOglrRenderer *ren,int light_index)
{
  float	dx, dy, dz;
  float	color[4];
  float *Color, *Position, *FocalPoint;
  float Intensity;
  float Info[4];

  // get required info from light
  Intensity = lgt->GetIntensity();
  Color = lgt->GetColor();
  color[0] = Intensity * Color[0];
  color[1] = Intensity * Color[1];
  color[2] = Intensity * Color[2];
  color[3] = 1.0;

  FocalPoint = lgt->GetFocalPoint();
  Position   = lgt->GetPosition();
  dx = FocalPoint[0] - Position[0];
  dy = FocalPoint[1] - Position[1];
  dz = FocalPoint[2] - Position[2];

  glLightfv((GLenum)light_index, GL_DIFFUSE, color);
  glLightfv((GLenum)light_index, GL_SPECULAR, color);

  if( ren->GetBackLight())
  {
  glLightfv((GLenum)(light_index+1), GL_DIFFUSE, color);
  glLightfv((GLenum)(light_index+1), GL_SPECULAR, color);
  }

  // define the light source
  if (!lgt->GetPositional())
    {
    Info[0]  = -dx;
    Info[1]  = -dy;
    Info[2]  = -dz;
    Info[3]  = 0.0;
    glLightfv((GLenum)light_index, GL_POSITION, Info );
    // define another mirror light if backlit is on
    if (ren->GetBackLight())
      {
      Info[0]  = dx;
      Info[1]  = dy;
      Info[2]  = dz;
      Info[3]  = 0.0;
      glLightfv((GLenum)(light_index + 1), GL_POSITION, Info );
      }
    }
  else
    {
    Info[0]  = Position[0];
    Info[1]  = Position[1];
    Info[2]  = Position[2];
    Info[3]  = 1.0;
    glLightfv((GLenum)light_index, GL_POSITION, Info );

    Info[0] = dx;
    Info[1] = dy;
    Info[2] = dz;
    glLightfv((GLenum)light_index, GL_SPOT_DIRECTION, Info );

    glLightf((GLenum)light_index, GL_SPOT_EXPONENT, lgt->GetExponent());
    glLightf((GLenum)light_index, GL_SPOT_CUTOFF, lgt->GetConeAngle());

    float *AttenuationValues = lgt->GetAttenuationValues();
    glLightf((GLenum)light_index,
	     GL_CONSTANT_ATTENUATION, AttenuationValues[0]);
    glLightf((GLenum)light_index,
	     GL_LINEAR_ATTENUATION, AttenuationValues[1]);
    glLightf((GLenum)light_index,
	     GL_QUADRATIC_ATTENUATION, AttenuationValues[2]);
    }

}

<|endoftext|>


<commit_before>#include "REvent.h"
#include "RAtomicInteger.h"

REvent::REvent()
{
}

REvent::~REvent()
{
}

void
REvent::accept()
{
  setAccepted(true);
}

void
REvent::ignore()
{
  setAccepted(false);
}

bool
REvent::isAccepted() const
{
  return mIsAccepted;
}

void
REvent::setAccepted(bool accepted)
{
  mIsAccepted = accepted;
}

rcount
REvent::type() const
{
  return 0;
}

rcount
REvent::registerEventType()
{
  static RAtomicInteger<rcount> previousType = 0;

  // FIXME: If type value exceed the type size, we should report error!
  return ++previousType;
}
<commit_msg>Fixed mIsAccepted not initialized<commit_after>#include "REvent.h"
#include "RAtomicInteger.h"

REvent::REvent() : mIsAccepted(false)
{
}

REvent::~REvent()
{
}

void
REvent::accept()
{
  setAccepted(true);
}

void
REvent::ignore()
{
  setAccepted(false);
}

bool
REvent::isAccepted() const
{
  return mIsAccepted;
}

void
REvent::setAccepted(bool accepted)
{
  mIsAccepted = accepted;
}

rcount
REvent::type() const
{
  return 0;
}

rcount
REvent::registerEventType()
{
  static RAtomicInteger<rcount> previousType = 0;

  // FIXME: If type value exceed the type size, we should report error!
  return ++previousType;
}
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include "Shader.h"

#include <fstream>
#include <Utility/Assert.h>

/* libgles-omap3-dev_4.03.00.02-r15.6 on BeagleBoard/Ångström linux 2011.3 doesn't have GLchar */
#ifdef MAGNUM_TARGET_GLES
typedef char GLchar;
#endif

namespace Magnum {

namespace {

std::string shaderName(const Shader::Type type) {
    switch(type) {
        case Shader::Type::Vertex:                  return "vertex";
        #ifndef MAGNUM_TARGET_GLES
        case Shader::Type::Geometry:                return "geometry";
        case Shader::Type::TessellationControl:     return "tessellation control";
        case Shader::Type::TessellationEvaluation:  return "tessellation evaluation";
        case Shader::Type::Compute:                 return "compute";
        #endif
        case Shader::Type::Fragment:                return "fragment";
    }

    CORRADE_ASSERT_UNREACHABLE();
}

}

Shader::Shader(const Version version, const Type type): _type(type), _id(0) {
    _id = glCreateShader(static_cast<GLenum>(_type));

    switch(version) {
        #ifndef MAGNUM_TARGET_GLES
        case Version::GL210: addSource("#version 120\n"); return;
        case Version::GL300: addSource("#version 130\n"); return;
        case Version::GL310: addSource("#version 140\n"); return;
        case Version::GL320: addSource("#version 150\n"); return;
        case Version::GL330: addSource("#version 330\n"); return;
        case Version::GL400: addSource("#version 400\n"); return;
        case Version::GL410: addSource("#version 410\n"); return;
        case Version::GL420: addSource("#version 420\n"); return;
        case Version::GL430: addSource("#version 430\n"); return;
        #else
        case Version::GLES200: addSource("#version 100\n"); return;
        case Version::GLES300: addSource("#version 300\n"); return;
        #endif

        case Version::None:
            CORRADE_ASSERT(false, "Shader::Shader(): unsupported version" << version, );
    }

    CORRADE_ASSERT_UNREACHABLE();
}

Shader::Shader(Shader&& other): _type(other._type), _id(other._id), sources(std::move(other.sources)) {
    other._id = 0;
}

Shader::~Shader() {
    if(_id) glDeleteShader(_id);
}

Shader& Shader::operator=(Shader&& other) {
    glDeleteShader(_id);

    _type = other._type;
    sources = std::move(other.sources);
    _id = other._id;

    other._id = 0;

    return *this;
}

Shader& Shader::addSource(std::string source) {
    if(!source.empty()) {
        /* Fix line numbers, so line 41 of third added file is marked as 3(41).
           Source 0 is the #version string added in constructor. */
        sources.push_back("#line 1 " + std::to_string(sources.size()) + '\n');
        sources.push_back(std::move(source));
    }

    return *this;
}

Shader& Shader::addFile(const std::string& filename) {
    /* Open file */
    std::ifstream file(filename.c_str());
    CORRADE_ASSERT(file.good(), "Shader file " << '\'' + filename + '\'' << " cannot be opened.", *this);

    /* Get size of shader and initialize buffer */
    file.seekg(0, std::ios::end);
    std::string source(file.tellg(), '\0');

    /* Read data, close */
    file.seekg(0, std::ios::beg);
    file.read(&source[0], source.size());
    file.close();

    /* Move to sources */
    addSource(std::move(source));

    return *this;
}

bool Shader::compile() {
    CORRADE_ASSERT(sources.size() > 1, "Shader::compile(): no files added", false);

    /* Array of sources */
    const GLchar** _sources = new const GLchar*[sources.size()];
    for(std::size_t i = 0; i != sources.size(); ++i)
        _sources[i] = static_cast<const GLchar*>(sources[i].c_str());

    /* Create shader and set its source */
    glShaderSource(_id, sources.size(), _sources, nullptr);

    /* Compile shader */
    glCompileShader(_id);
    delete _sources;

    /* Check compilation status */
    GLint success, logLength;
    glGetShaderiv(_id, GL_COMPILE_STATUS, &success);
    glGetShaderiv(_id, GL_INFO_LOG_LENGTH, &logLength);

    /* Error or warning message. The string is returned null-terminated, scrap
       the \0 at the end afterwards */
    std::string message(logLength, '\0');
    if(!message.empty()) {
        glGetShaderInfoLog(_id, message.size(), nullptr, &message[0]);
        message.resize(logLength-1);
    }

    /* Show error log */
    if(!success) {
        Error out;
        out.setFlag(Debug::NewLineAtTheEnd, false);
        out.setFlag(Debug::SpaceAfterEachValue, false);
        out << "Shader: " << shaderName(_type)
            << " shader failed to compile with the following message:\n"
            << message;

    /* Or just message, if any */
    } else if(!message.empty()) {
        Error out;
        out.setFlag(Debug::NewLineAtTheEnd, false);
        out.setFlag(Debug::SpaceAfterEachValue, false);
        out << "Shader: " << shaderName(_type)
            << " shader was successfully compiled with the following message:\n"
            << message;
    }

    return success;
}

}
<commit_msg>No need to add `#line` directive also before `#version` line.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include "Shader.h"

#include <fstream>
#include <Utility/Assert.h>

/* libgles-omap3-dev_4.03.00.02-r15.6 on BeagleBoard/Ångström linux 2011.3 doesn't have GLchar */
#ifdef MAGNUM_TARGET_GLES
typedef char GLchar;
#endif

namespace Magnum {

namespace {

std::string shaderName(const Shader::Type type) {
    switch(type) {
        case Shader::Type::Vertex:                  return "vertex";
        #ifndef MAGNUM_TARGET_GLES
        case Shader::Type::Geometry:                return "geometry";
        case Shader::Type::TessellationControl:     return "tessellation control";
        case Shader::Type::TessellationEvaluation:  return "tessellation evaluation";
        case Shader::Type::Compute:                 return "compute";
        #endif
        case Shader::Type::Fragment:                return "fragment";
    }

    CORRADE_ASSERT_UNREACHABLE();
}

}

Shader::Shader(const Version version, const Type type): _type(type), _id(0) {
    _id = glCreateShader(static_cast<GLenum>(_type));

    switch(version) {
        #ifndef MAGNUM_TARGET_GLES
        case Version::GL210: sources.push_back("#version 120\n"); return;
        case Version::GL300: sources.push_back("#version 130\n"); return;
        case Version::GL310: sources.push_back("#version 140\n"); return;
        case Version::GL320: sources.push_back("#version 150\n"); return;
        case Version::GL330: sources.push_back("#version 330\n"); return;
        case Version::GL400: sources.push_back("#version 400\n"); return;
        case Version::GL410: sources.push_back("#version 410\n"); return;
        case Version::GL420: sources.push_back("#version 420\n"); return;
        case Version::GL430: sources.push_back("#version 430\n"); return;
        #else
        case Version::GLES200: sources.push_back("#version 100\n"); return;
        case Version::GLES300: sources.push_back("#version 300\n"); return;
        #endif

        case Version::None:
            CORRADE_ASSERT(false, "Shader::Shader(): unsupported version" << version, );
    }

    CORRADE_ASSERT_UNREACHABLE();
}

Shader::Shader(Shader&& other): _type(other._type), _id(other._id), sources(std::move(other.sources)) {
    other._id = 0;
}

Shader::~Shader() {
    if(_id) glDeleteShader(_id);
}

Shader& Shader::operator=(Shader&& other) {
    glDeleteShader(_id);

    _type = other._type;
    sources = std::move(other.sources);
    _id = other._id;

    other._id = 0;

    return *this;
}

Shader& Shader::addSource(std::string source) {
    if(!source.empty()) {
        /* Fix line numbers, so line 41 of third added file is marked as 3(41).
           Source 0 is the #version string added in constructor. */
        sources.push_back("#line 1 " + std::to_string(sources.size()) + '\n');
        sources.push_back(std::move(source));
    }

    return *this;
}

Shader& Shader::addFile(const std::string& filename) {
    /* Open file */
    std::ifstream file(filename.c_str());
    CORRADE_ASSERT(file.good(), "Shader file " << '\'' + filename + '\'' << " cannot be opened.", *this);

    /* Get size of shader and initialize buffer */
    file.seekg(0, std::ios::end);
    std::string source(file.tellg(), '\0');

    /* Read data, close */
    file.seekg(0, std::ios::beg);
    file.read(&source[0], source.size());
    file.close();

    /* Move to sources */
    addSource(std::move(source));

    return *this;
}

bool Shader::compile() {
    CORRADE_ASSERT(sources.size() > 1, "Shader::compile(): no files added", false);

    /* Array of sources */
    const GLchar** _sources = new const GLchar*[sources.size()];
    for(std::size_t i = 0; i != sources.size(); ++i)
        _sources[i] = static_cast<const GLchar*>(sources[i].c_str());

    /* Create shader and set its source */
    glShaderSource(_id, sources.size(), _sources, nullptr);

    /* Compile shader */
    glCompileShader(_id);
    delete _sources;

    /* Check compilation status */
    GLint success, logLength;
    glGetShaderiv(_id, GL_COMPILE_STATUS, &success);
    glGetShaderiv(_id, GL_INFO_LOG_LENGTH, &logLength);

    /* Error or warning message. The string is returned null-terminated, scrap
       the \0 at the end afterwards */
    std::string message(logLength, '\0');
    if(!message.empty()) {
        glGetShaderInfoLog(_id, message.size(), nullptr, &message[0]);
        message.resize(logLength-1);
    }

    /* Show error log */
    if(!success) {
        Error out;
        out.setFlag(Debug::NewLineAtTheEnd, false);
        out.setFlag(Debug::SpaceAfterEachValue, false);
        out << "Shader: " << shaderName(_type)
            << " shader failed to compile with the following message:\n"
            << message;

    /* Or just message, if any */
    } else if(!message.empty()) {
        Error out;
        out.setFlag(Debug::NewLineAtTheEnd, false);
        out.setFlag(Debug::SpaceAfterEachValue, false);
        out << "Shader: " << shaderName(_type)
            << " shader was successfully compiled with the following message:\n"
            << message;
    }

    return success;
}

}
<|endoftext|>


<commit_before>/* GG is a GUI for SDL and OpenGL.
   Copyright (C) 2003-2008 T. Zachary Laine

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1
   of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA

   If you do not wish to comply with the terms of the LGPL please
   contact the author as other terms are available for a fee.

   Zach Laine
   whatwasthataddress@gmail.com */

#include <GG/Slider.h>

#include <GG/Button.h>
#include <GG/DrawUtil.h>
#include <GG/StyleFactory.h>
#include <GG/WndEditor.h>
#include <GG/WndEvent.h>

using namespace GG;

namespace {
    struct SlidEcho
    {
        SlidEcho(const std::string& name) : m_name(name) {}
        void operator()(int pos, int min, int max)
            {
                std::cerr << "GG SIGNAL : " << m_name
                          << "(pos=" << pos << " min=" << min << " max=" << max << ")\n";
            }
        std::string m_name;
    };
}

const std::size_t Slider::INVALID_PAGE_SIZE = std::numeric_limits<std::size_t>::max();

Slider::Slider() :
    Control(),
    m_posn(0),
    m_range_min(0),
    m_range_max(99),
    m_page_sz(INVALID_PAGE_SIZE),
    m_orientation(VERTICAL),
    m_line_width(5),
    m_tab_width(5),
    m_line_style(RAISED),
    m_tab_drag_offset(-1),
    m_tab(0),
    m_dragging_tab(false)
{}

Slider::Slider(X x, Y y, X w, Y h, int min, int max, Orientation orientation, SliderLineStyle style,
               Clr color, int unsigned tab_width, int unsigned line_width/* = 5*/,
               Flags<WndFlag> flags/* = INTERACTIVE*/) :
    Control(x, y, w, h, flags),
    m_posn(min),
    m_range_min(min),
    m_range_max(max),
    m_page_sz(INVALID_PAGE_SIZE),
    m_orientation(orientation),
    m_line_width(line_width),
    m_tab_width(tab_width),
    m_line_style(style),
    m_tab_drag_offset(-1),
    m_tab(m_orientation == VERTICAL ?
          GetStyleFactory()->NewVSliderTabButton(X0, Y0, Width(), Y(m_tab_width), "", boost::shared_ptr<Font>(), color) :
          GetStyleFactory()->NewHSliderTabButton(X0, Y0, X(m_tab_width), Height(), "", boost::shared_ptr<Font>(), color)),
    m_dragging_tab(false)
{
    Control::SetColor(color);
    AttachChild(m_tab);
    m_tab->InstallEventFilter(this);
    SizeMove(UpperLeft(), LowerRight());

    if (INSTRUMENT_ALL_SIGNALS) {
        Connect(SlidSignal, SlidEcho("Slider::SlidSignal"));
        Connect(SlidAndStoppedSignal, SlidEcho("Slider::SlidAndStoppedSignal"));
    }
}

Pt Slider::MinUsableSize() const
{
    Pt tab_min = m_tab->MinUsableSize();
    return Pt(m_orientation == VERTICAL ? tab_min.x : 3 * tab_min.x,
              m_orientation == VERTICAL ? 3 * tab_min.y : tab_min.y);
}

int Slider::Posn() const
{ return m_posn; }

std::pair<int, int> Slider::SliderRange() const
{ return std::pair<int, int>(m_range_min, m_range_max); }

unsigned int Slider::PageSize() const
{ return m_page_sz != INVALID_PAGE_SIZE ? m_page_sz : (m_range_max - m_range_min) / 10; }

Orientation Slider::GetOrientation() const
{ return m_orientation; }

unsigned int Slider::TabWidth() const
{ return m_tab_width; }

unsigned int Slider::LineWidth() const
{ return m_line_width; }

SliderLineStyle Slider::LineStyle() const
{ return m_line_style; }

void Slider::Render()
{
    const Pt UL = UpperLeft();
    const Pt LR = LowerRight();
    Clr color_to_use = Disabled() ? DisabledColor(Color()) : Color();
    int tab_width = m_orientation == VERTICAL ? Value(m_tab->Height()) : Value(m_tab->Width());
    Pt ul, lr;
    if (m_orientation == VERTICAL) {
        ul.x = ((LR.x + UL.x) - static_cast<int>(m_line_width)) / 2;
        lr.x = ul.x + static_cast<int>(m_line_width);
        ul.y = UL.y + tab_width / 2;
        lr.y = LR.y - tab_width / 2;
    } else {
        ul.x = UL.x + tab_width / 2;
        lr.x = LR.x - tab_width / 2;
        ul.y = ((LR.y + UL.y) - static_cast<int>(m_line_width)) / 2;
        lr.y = ul.y + static_cast<int>(m_line_width);
    }
    switch (m_line_style) {
    case FLAT:
        FlatRectangle(ul, lr, color_to_use, CLR_BLACK, 1);
        break;
    case RAISED:
        BeveledRectangle(ul, lr, color_to_use, color_to_use, true, m_line_width / 2);
        break;
    case GROOVED:
        BeveledRectangle(ul, lr, color_to_use, color_to_use, false, m_line_width / 2);
        break;
    }
}

void Slider::SizeMove(const Pt& ul, const Pt& lr)
{
    Wnd::SizeMove(ul, lr);
    if (m_orientation == VERTICAL)
        m_tab->SizeMove(Pt(), Pt(lr.x - ul.x, Y(m_tab_width)));
    else
        m_tab->SizeMove(Pt(), Pt(X(m_tab_width), lr.y - ul.y));
    MoveTabToPosn();
}

void Slider::Disable(bool b/* = true*/)
{
    Control::Disable(b);
    m_tab->Disable(b);
}

void Slider::SetColor(Clr c)
{
    Control::SetColor(c);
    m_tab->SetColor(c);
}

void Slider::SizeSlider(int min, int max)
{
    assert(m_range_min != m_range_max);
    m_range_min = min;
    m_range_max = max;
    if (m_posn < m_range_min)
        SlideToImpl(m_range_min, false);
    else if (m_range_max < m_posn)
        SlideToImpl(m_range_max, false);
    else
        MoveTabToPosn();
}

void Slider::SetMax(int max)
{ SizeSlider(m_range_min, max); }

void Slider::SetMin(int min)
{ SizeSlider(min, m_range_max); }

void Slider::SlideTo(int p)
{ SlideToImpl(p, false); }

void Slider::SetPageSize(unsigned int size)
{ m_page_sz = size; }

void Slider::SetLineStyle(SliderLineStyle style)
{ m_line_style = style; }

void Slider::DefineAttributes(WndEditor* editor)
{
    if (!editor)
        return;
    Control::DefineAttributes(editor);
    editor->Label("Slider");
    editor->Attribute("Range Min", m_range_min);
    editor->Attribute("Range Max", m_range_max);
    editor->Attribute("Line Width", m_line_width);
    editor->Attribute("Tab Width", m_tab_width);
    editor->Attribute("Line Style", m_line_style,
                      FLAT, GROOVED);
}

Button* Slider::Tab() const
{ return m_tab; }

int Slider::PtToPosn(const Pt& pt) const
{
    Pt ul = UpperLeft(), lr = LowerRight();
    int line_min = 0;
    int line_max = 0;
    int pixel_nearest_to_pt_on_line = 0;
    if (m_orientation == VERTICAL) {
        line_min = Value(m_tab->Height() / 2);
        line_max = Value(Height() - (m_tab->Height() - m_tab->Height() / 2));
        pixel_nearest_to_pt_on_line = std::max(line_min, std::min(Value(pt.y - lr.y), line_max));
    } else {
        line_min = Value(m_tab->Width() / 2);
        line_max = Value(Width() - (m_tab->Width() - m_tab->Width() / 2));
        pixel_nearest_to_pt_on_line = std::max(line_min, std::min(Value(pt.x - ul.x), line_max));
    }
    double fractional_distance = static_cast<double>(pixel_nearest_to_pt_on_line) / (line_max - line_min);
    return m_range_min + static_cast<int>((m_range_max - m_range_min) * fractional_distance);
}

void Slider::LClick(const Pt& pt, Flags<ModKey> mod_keys)
{ SlideToImpl(m_posn < PtToPosn(pt) ? m_posn + PageSize() : m_posn - PageSize(), true); }

void Slider::KeyPress(Key key, boost::uint32_t key_code_point, Flags<ModKey> mod_keys)
{
    if (!Disabled()) {
        switch (key) {
        case GGK_HOME:
            SlideToImpl(m_range_min, true);
            break;
        case GGK_END:
            SlideToImpl(m_range_max, true);
            break;
        case GGK_UP:
            if (m_orientation != HORIZONTAL)
                SlideToImpl(m_posn + (0 < (m_range_max - m_range_min) ? 1 : -1), true);
            break;
        case GGK_RIGHT:
            if (m_orientation != VERTICAL)
                SlideToImpl(m_posn + (0 < (m_range_max - m_range_min) ? 1 : -1), true);
            break;
        case GGK_DOWN:
            if (m_orientation != HORIZONTAL)
                SlideToImpl(m_posn - (0 < (m_range_max - m_range_min) ? 1 : -1), true);
            break;
        case GGK_LEFT:
            if (m_orientation != VERTICAL)
                SlideToImpl(m_posn - (0 < (m_range_max - m_range_min) ? 1 : -1), true);
            break;
        case GGK_PLUS:
        case GGK_KP_PLUS:
            SlideToImpl(m_posn + 1, true);
            break;
        case GGK_MINUS:
        case GGK_KP_MINUS:
            SlideToImpl(m_posn - 1, true);
            break;
        default:
            Control::KeyPress(key, key_code_point, mod_keys);
            break;
        }
    } else {
        Control::KeyPress(key, key_code_point, mod_keys);
    }
}

bool Slider::EventFilter(Wnd* w, const WndEvent& event)
{
    if (w == m_tab) {
        switch (event.Type()) {
        case WndEvent::LDrag: {
            if (!Disabled()) {
                Pt new_ul = m_tab->RelativeUpperLeft() + event.DragMove();
                if (m_orientation == VERTICAL) {
                    new_ul.x = m_tab->RelativeUpperLeft().x;
                    new_ul.y = std::max(Y0, std::min(new_ul.y, ClientHeight() - m_tab->Height()));
                } else {
                    new_ul.x = std::max(X0, std::min(new_ul.x, ClientWidth() - m_tab->Width()));
                    new_ul.y = m_tab->RelativeUpperLeft().y;
                }
                m_tab->MoveTo(new_ul);
                UpdatePosn();
            }
            return true;
        }
        case WndEvent::LButtonDown:
            m_dragging_tab = true;
            break;
        case WndEvent::LButtonUp:
        case WndEvent::LClick: {
            if (!Disabled())
                SlidAndStoppedSignal(m_posn, m_range_min, m_range_max);
            m_dragging_tab = false;
            break;
        }
        case WndEvent::MouseLeave:
            return m_dragging_tab;
        default:
            break;
        }
    }
    return false;
}

void Slider::MoveTabToPosn()
{
    assert(m_range_min <= m_posn && m_posn <= m_range_max ||
           m_range_max <= m_posn && m_posn <= m_range_min);
    double fractional_distance = static_cast<double>(m_posn - m_range_min) / (m_range_max - m_range_min);
    int tab_width = m_orientation == VERTICAL ? Value(m_tab->Height()) : Value(m_tab->Width());
    int line_length = (m_orientation == VERTICAL ? Value(Height()) : Value(Width())) - tab_width;
    int pixel_distance = static_cast<int>(line_length * fractional_distance);
    if (m_orientation == VERTICAL)
        m_tab->MoveTo(Pt(m_tab->RelativeUpperLeft().x, Height() - tab_width - pixel_distance));
    else
        m_tab->MoveTo(Pt(X(pixel_distance), m_tab->RelativeUpperLeft().y));
}

void Slider::UpdatePosn()
{
    int old_posn = m_posn;
    int line_length = m_orientation == VERTICAL ? Value(Height() - m_tab->Height()) : Value(Width() - m_tab->Width());
    int tab_posn = (m_orientation == VERTICAL ? Value(Height() - m_tab->RelativeLowerRight().y) : Value(m_tab->RelativeUpperLeft().x));
    double fractional_distance = static_cast<double>(tab_posn) / line_length;
    m_posn = m_range_min + static_cast<int>((m_range_max - m_range_min) * fractional_distance);
    if (m_posn != old_posn)
        SlidSignal(m_posn, m_range_min, m_range_max);
}

void Slider::SlideToImpl(int p, bool signal)
{
    int old_posn = m_posn;
    if (0 < (m_range_max - m_range_min) ? p < m_range_min : p > m_range_min)
        m_posn = m_range_min;
    else if (0 < (m_range_max - m_range_min) ? m_range_max < p : m_range_max > p)
        m_posn = m_range_max;
    else
        m_posn = p;
    MoveTabToPosn();
    if (signal && m_posn != old_posn) {
        SlidSignal(m_posn, m_range_min, m_range_max);
        SlidAndStoppedSignal(m_posn, m_range_min, m_range_max);
    }
}
<commit_msg>Fixed two problems with Slider.  PtToPosn() was always returning a lower value vertical case.  After that fix, clicks to either side of the tab (vertical or horizontal case) were moving the tab in the wrong direction.<commit_after>/* GG is a GUI for SDL and OpenGL.
   Copyright (C) 2003-2008 T. Zachary Laine

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1
   of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA

   If you do not wish to comply with the terms of the LGPL please
   contact the author as other terms are available for a fee.

   Zach Laine
   whatwasthataddress@gmail.com */

#include <GG/Slider.h>

#include <GG/Button.h>
#include <GG/DrawUtil.h>
#include <GG/StyleFactory.h>
#include <GG/WndEditor.h>
#include <GG/WndEvent.h>

using namespace GG;

namespace {
    struct SlidEcho
    {
        SlidEcho(const std::string& name) : m_name(name) {}
        void operator()(int pos, int min, int max)
            {
                std::cerr << "GG SIGNAL : " << m_name
                          << "(pos=" << pos << " min=" << min << " max=" << max << ")\n";
            }
        std::string m_name;
    };
}

const std::size_t Slider::INVALID_PAGE_SIZE = std::numeric_limits<std::size_t>::max();

Slider::Slider() :
    Control(),
    m_posn(0),
    m_range_min(0),
    m_range_max(99),
    m_page_sz(INVALID_PAGE_SIZE),
    m_orientation(VERTICAL),
    m_line_width(5),
    m_tab_width(5),
    m_line_style(RAISED),
    m_tab_drag_offset(-1),
    m_tab(0),
    m_dragging_tab(false)
{}

Slider::Slider(X x, Y y, X w, Y h, int min, int max, Orientation orientation, SliderLineStyle style,
               Clr color, int unsigned tab_width, int unsigned line_width/* = 5*/,
               Flags<WndFlag> flags/* = INTERACTIVE*/) :
    Control(x, y, w, h, flags),
    m_posn(min),
    m_range_min(min),
    m_range_max(max),
    m_page_sz(INVALID_PAGE_SIZE),
    m_orientation(orientation),
    m_line_width(line_width),
    m_tab_width(tab_width),
    m_line_style(style),
    m_tab_drag_offset(-1),
    m_tab(m_orientation == VERTICAL ?
          GetStyleFactory()->NewVSliderTabButton(X0, Y0, Width(), Y(m_tab_width), "", boost::shared_ptr<Font>(), color) :
          GetStyleFactory()->NewHSliderTabButton(X0, Y0, X(m_tab_width), Height(), "", boost::shared_ptr<Font>(), color)),
    m_dragging_tab(false)
{
    Control::SetColor(color);
    AttachChild(m_tab);
    m_tab->InstallEventFilter(this);
    SizeMove(UpperLeft(), LowerRight());

    if (INSTRUMENT_ALL_SIGNALS) {
        Connect(SlidSignal, SlidEcho("Slider::SlidSignal"));
        Connect(SlidAndStoppedSignal, SlidEcho("Slider::SlidAndStoppedSignal"));
    }
}

Pt Slider::MinUsableSize() const
{
    Pt tab_min = m_tab->MinUsableSize();
    return Pt(m_orientation == VERTICAL ? tab_min.x : 3 * tab_min.x,
              m_orientation == VERTICAL ? 3 * tab_min.y : tab_min.y);
}

int Slider::Posn() const
{ return m_posn; }

std::pair<int, int> Slider::SliderRange() const
{ return std::pair<int, int>(m_range_min, m_range_max); }

unsigned int Slider::PageSize() const
{ return m_page_sz != INVALID_PAGE_SIZE ? m_page_sz : (m_range_max - m_range_min) / 10; }

Orientation Slider::GetOrientation() const
{ return m_orientation; }

unsigned int Slider::TabWidth() const
{ return m_tab_width; }

unsigned int Slider::LineWidth() const
{ return m_line_width; }

SliderLineStyle Slider::LineStyle() const
{ return m_line_style; }

void Slider::Render()
{
    const Pt UL = UpperLeft();
    const Pt LR = LowerRight();
    Clr color_to_use = Disabled() ? DisabledColor(Color()) : Color();
    int tab_width = m_orientation == VERTICAL ? Value(m_tab->Height()) : Value(m_tab->Width());
    Pt ul, lr;
    if (m_orientation == VERTICAL) {
        ul.x = ((LR.x + UL.x) - static_cast<int>(m_line_width)) / 2;
        lr.x = ul.x + static_cast<int>(m_line_width);
        ul.y = UL.y + tab_width / 2;
        lr.y = LR.y - tab_width / 2;
    } else {
        ul.x = UL.x + tab_width / 2;
        lr.x = LR.x - tab_width / 2;
        ul.y = ((LR.y + UL.y) - static_cast<int>(m_line_width)) / 2;
        lr.y = ul.y + static_cast<int>(m_line_width);
    }
    switch (m_line_style) {
    case FLAT:
        FlatRectangle(ul, lr, color_to_use, CLR_BLACK, 1);
        break;
    case RAISED:
        BeveledRectangle(ul, lr, color_to_use, color_to_use, true, m_line_width / 2);
        break;
    case GROOVED:
        BeveledRectangle(ul, lr, color_to_use, color_to_use, false, m_line_width / 2);
        break;
    }
}

void Slider::SizeMove(const Pt& ul, const Pt& lr)
{
    Wnd::SizeMove(ul, lr);
    if (m_orientation == VERTICAL)
        m_tab->SizeMove(Pt(), Pt(lr.x - ul.x, Y(m_tab_width)));
    else
        m_tab->SizeMove(Pt(), Pt(X(m_tab_width), lr.y - ul.y));
    MoveTabToPosn();
}

void Slider::Disable(bool b/* = true*/)
{
    Control::Disable(b);
    m_tab->Disable(b);
}

void Slider::SetColor(Clr c)
{
    Control::SetColor(c);
    m_tab->SetColor(c);
}

void Slider::SizeSlider(int min, int max)
{
    assert(m_range_min != m_range_max);
    m_range_min = min;
    m_range_max = max;
    if (m_posn < m_range_min)
        SlideToImpl(m_range_min, false);
    else if (m_range_max < m_posn)
        SlideToImpl(m_range_max, false);
    else
        MoveTabToPosn();
}

void Slider::SetMax(int max)
{ SizeSlider(m_range_min, max); }

void Slider::SetMin(int min)
{ SizeSlider(min, m_range_max); }

void Slider::SlideTo(int p)
{ SlideToImpl(p, false); }

void Slider::SetPageSize(unsigned int size)
{ m_page_sz = size; }

void Slider::SetLineStyle(SliderLineStyle style)
{ m_line_style = style; }

void Slider::DefineAttributes(WndEditor* editor)
{
    if (!editor)
        return;
    Control::DefineAttributes(editor);
    editor->Label("Slider");
    editor->Attribute("Range Min", m_range_min);
    editor->Attribute("Range Max", m_range_max);
    editor->Attribute("Line Width", m_line_width);
    editor->Attribute("Tab Width", m_tab_width);
    editor->Attribute("Line Style", m_line_style,
                      FLAT, GROOVED);
}

Button* Slider::Tab() const
{ return m_tab; }

int Slider::PtToPosn(const Pt& pt) const
{
    Pt ul = UpperLeft(), lr = LowerRight();
    int line_min = 0;
    int line_max = 0;
    int pixel_nearest_to_pt_on_line = 0;
    if (m_orientation == VERTICAL) {
        line_min = Value(m_tab->Height() / 2);
        line_max = Value(Height() - (m_tab->Height() - m_tab->Height() / 2));
        pixel_nearest_to_pt_on_line = std::max(line_min, std::min(Value(lr.y - pt.y), line_max));
    } else {
        line_min = Value(m_tab->Width() / 2);
        line_max = Value(Width() - (m_tab->Width() - m_tab->Width() / 2));
        pixel_nearest_to_pt_on_line = std::max(line_min, std::min(Value(pt.x - ul.x), line_max));
    }
    double fractional_distance = static_cast<double>(pixel_nearest_to_pt_on_line) / (line_max - line_min);
    return m_range_min + static_cast<int>((m_range_max - m_range_min) * fractional_distance);
}

void Slider::LClick(const Pt& pt, Flags<ModKey> mod_keys)
{ SlideToImpl(PtToPosn(pt) < m_posn ? m_posn + PageSize() : m_posn - PageSize(), true); }

void Slider::KeyPress(Key key, boost::uint32_t key_code_point, Flags<ModKey> mod_keys)
{
    if (!Disabled()) {
        switch (key) {
        case GGK_HOME:
            SlideToImpl(m_range_min, true);
            break;
        case GGK_END:
            SlideToImpl(m_range_max, true);
            break;
        case GGK_UP:
            if (m_orientation != HORIZONTAL)
                SlideToImpl(m_posn + (0 < (m_range_max - m_range_min) ? 1 : -1), true);
            break;
        case GGK_RIGHT:
            if (m_orientation != VERTICAL)
                SlideToImpl(m_posn + (0 < (m_range_max - m_range_min) ? 1 : -1), true);
            break;
        case GGK_DOWN:
            if (m_orientation != HORIZONTAL)
                SlideToImpl(m_posn - (0 < (m_range_max - m_range_min) ? 1 : -1), true);
            break;
        case GGK_LEFT:
            if (m_orientation != VERTICAL)
                SlideToImpl(m_posn - (0 < (m_range_max - m_range_min) ? 1 : -1), true);
            break;
        case GGK_PLUS:
        case GGK_KP_PLUS:
            SlideToImpl(m_posn + 1, true);
            break;
        case GGK_MINUS:
        case GGK_KP_MINUS:
            SlideToImpl(m_posn - 1, true);
            break;
        default:
            Control::KeyPress(key, key_code_point, mod_keys);
            break;
        }
    } else {
        Control::KeyPress(key, key_code_point, mod_keys);
    }
}

bool Slider::EventFilter(Wnd* w, const WndEvent& event)
{
    if (w == m_tab) {
        switch (event.Type()) {
        case WndEvent::LDrag: {
            if (!Disabled()) {
                Pt new_ul = m_tab->RelativeUpperLeft() + event.DragMove();
                if (m_orientation == VERTICAL) {
                    new_ul.x = m_tab->RelativeUpperLeft().x;
                    new_ul.y = std::max(Y0, std::min(new_ul.y, ClientHeight() - m_tab->Height()));
                } else {
                    new_ul.x = std::max(X0, std::min(new_ul.x, ClientWidth() - m_tab->Width()));
                    new_ul.y = m_tab->RelativeUpperLeft().y;
                }
                m_tab->MoveTo(new_ul);
                UpdatePosn();
            }
            return true;
        }
        case WndEvent::LButtonDown:
            m_dragging_tab = true;
            break;
        case WndEvent::LButtonUp:
        case WndEvent::LClick: {
            if (!Disabled())
                SlidAndStoppedSignal(m_posn, m_range_min, m_range_max);
            m_dragging_tab = false;
            break;
        }
        case WndEvent::MouseLeave:
            return m_dragging_tab;
        default:
            break;
        }
    }
    return false;
}

void Slider::MoveTabToPosn()
{
    assert(m_range_min <= m_posn && m_posn <= m_range_max ||
           m_range_max <= m_posn && m_posn <= m_range_min);
    double fractional_distance = static_cast<double>(m_posn - m_range_min) / (m_range_max - m_range_min);
    int tab_width = m_orientation == VERTICAL ? Value(m_tab->Height()) : Value(m_tab->Width());
    int line_length = (m_orientation == VERTICAL ? Value(Height()) : Value(Width())) - tab_width;
    int pixel_distance = static_cast<int>(line_length * fractional_distance);
    if (m_orientation == VERTICAL)
        m_tab->MoveTo(Pt(m_tab->RelativeUpperLeft().x, Height() - tab_width - pixel_distance));
    else
        m_tab->MoveTo(Pt(X(pixel_distance), m_tab->RelativeUpperLeft().y));
}

void Slider::UpdatePosn()
{
    int old_posn = m_posn;
    int line_length = m_orientation == VERTICAL ? Value(Height() - m_tab->Height()) : Value(Width() - m_tab->Width());
    int tab_posn = (m_orientation == VERTICAL ? Value(Height() - m_tab->RelativeLowerRight().y) : Value(m_tab->RelativeUpperLeft().x));
    double fractional_distance = static_cast<double>(tab_posn) / line_length;
    m_posn = m_range_min + static_cast<int>((m_range_max - m_range_min) * fractional_distance);
    if (m_posn != old_posn)
        SlidSignal(m_posn, m_range_min, m_range_max);
}

void Slider::SlideToImpl(int p, bool signal)
{
    int old_posn = m_posn;
    if (0 < (m_range_max - m_range_min) ? p < m_range_min : p > m_range_min)
        m_posn = m_range_min;
    else if (0 < (m_range_max - m_range_min) ? m_range_max < p : m_range_max > p)
        m_posn = m_range_max;
    else
        m_posn = p;
    MoveTabToPosn();
    if (signal && m_posn != old_posn) {
        SlidSignal(m_posn, m_range_min, m_range_max);
        SlidAndStoppedSignal(m_posn, m_range_min, m_range_max);
    }
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#include "SubmatrixCalculator.cpp"

#define BLANK_CHAR '-'

using namespace std;

vector<vector<string > > final_columns;
vector<vector<string > > final_rows;

string string_a, string_b;

int submatrix_dim;
int row_num;
int column_num;

void pad_string()
{

}

void initialize_edit_matrix()
{
    final_columns.resize(row_num+1, vector<string>(row_num+1, ""));
    final_rows.resize(column_num+1, vector<string>(column_num+1, ""));

    string initial_string = SubmatrixCalculator::stepsToString(vector<int>(submatrix_dim+1, 1));

    for (int submatrix_i=1; submatrix_i<=row_num; submatrix_i++)
        final_columns[submatrix_i][0] = initial_string;

    for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++)
        final_rows[0][submatrix_j] = initial_string;

    final_columns[1][0][0] -= 1;
    final_rows[0][1][0] -= 1;
}

void fill_edit_matrix(SubmatrixCalculator subm_calc)
{
    for (int submatrix_i=1; submatrix_i<=row_num; submatrix_i++) {
        for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++) {

            pair<string, string> final_steps = subm_calc.getFinalSteps(
                                    string_a.substr((submatrix_i-1)*submatrix_dim, submatrix_dim),
                                    string_b.substr((submatrix_j-1)*submatrix_dim, submatrix_dim),
                                    final_columns[submatrix_i][submatrix_j-1].substr(1),
                                    final_rows[submatrix_i-1][submatrix_j].substr(1));

            final_columns[submatrix_i][submatrix_j] = final_steps.second;
            final_rows[submatrix_i][submatrix_j] = final_steps.first;
        }
    }
}

int calc_edit_distance(SubmatrixCalculator subm_calc)
{
    int edit_distance = 0;

    for (int submatrix_i=1; submatrix_i<=row_num; submatrix_i++) {
        edit_distance += subm_calc.sumSteps(final_columns[submatrix_i][0]);
    }
    for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++) {
        edit_distance += subm_calc.sumSteps(final_rows[row_num][submatrix_j]);
    }

    return edit_distance;
}

int main() {
    //read strings a and b
    string_a = "atccgattaaatccga";
    string_b = "atccgattaaatccaa";

    submatrix_dim = ceil(log(string_a.size()) / log(12));
    cout << "Submatrix dimension: " << submatrix_dim << endl;
    cout << "String A size: " << string_a.size() << endl;
    cout << "String B size: " << string_b.size() << endl;

    // pad strings to fit dimension

    SubmatrixCalculator subm_calc(submatrix_dim, "atgc");
    subm_calc.calculate();

    row_num = string_a.size() / (submatrix_dim);
    column_num = string_b.size() / (submatrix_dim);
    cout << "Submatrices in edit table: " << row_num << "x" << column_num << endl;

    initialize_edit_matrix();
    fill_edit_matrix(subm_calc);

    cout << calc_edit_distance(subm_calc);

    return 0;
}
<commit_msg>Bug fix, still doesn't output correct distance<commit_after>#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#include "SubmatrixCalculator.cpp"

#define BLANK_CHAR '-'

using namespace std;

vector<vector<string > > final_columns;
vector<vector<string > > final_rows;

string string_a, string_b;

int submatrix_dim;
int row_num;
int column_num;

void pad_string()
{

}

void initialize_edit_matrix()
{
    final_columns.resize(row_num+1, vector<string>(row_num+1, ""));
    final_rows.resize(column_num+1, vector<string>(column_num+1, ""));

    string initial_string = SubmatrixCalculator::stepsToString(vector<int>(submatrix_dim+1, 1));

    for (int submatrix_i=1; submatrix_i<=row_num; submatrix_i++)
        final_columns[submatrix_i][0] = initial_string;

    for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++)
        final_rows[0][submatrix_j] = initial_string;

    final_columns[1][0][0] -= 1;
    final_rows[0][1][0] -= 1;
}

void fill_edit_matrix(SubmatrixCalculator subm_calc)
{
    for (int submatrix_i=1; submatrix_i<=row_num; submatrix_i++) {
        for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++) {

            pair<string, string> final_steps = subm_calc.getFinalSteps(
                                    string_a.substr((submatrix_i-1)*submatrix_dim, submatrix_dim),
                                    string_b.substr((submatrix_j-1)*submatrix_dim, submatrix_dim),
                                    final_columns[submatrix_i][submatrix_j-1].substr(1),
                                    final_rows[submatrix_i-1][submatrix_j].substr(1));

            final_columns[submatrix_i][submatrix_j] = final_steps.second;
            final_rows[submatrix_i][submatrix_j] = final_steps.first;
        }
    }
}

int calc_edit_distance(SubmatrixCalculator subm_calc)
{
    int edit_distance = 0;

    for (int submatrix_i=1; submatrix_i<=row_num; submatrix_i++) {
        edit_distance += subm_calc.sumSteps(final_columns[submatrix_i][0].substr(1));
            cout<<edit_distance<<endl;

    }
    cout<<endl;
    for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++) {
        edit_distance += subm_calc.sumSteps(final_rows[row_num][submatrix_j].substr(1));
        cout<<final_rows[row_num][submatrix_j].substr(1)<<endl;
    }

    return edit_distance;
}

int main() {
    //read strings a and b
    string_a = "ATTACC";
    string_b = "TAATCC";

    //submatrix_dim = ceil(log(string_a.size()) / log(12));
    submatrix_dim = 2;

    cout << "Submatrix dimension: " << submatrix_dim << endl;
    cout << "String A size: " << string_a.size() << endl;
    cout << "String B size: " << string_b.size() << endl;

    // pad strings to fit dimension

    SubmatrixCalculator subm_calc(submatrix_dim, "ATGC");
    subm_calc.calculate();

    row_num = string_a.size() / (submatrix_dim);
    column_num = string_b.size() / (submatrix_dim);
    cout << "Submatrices in edit table: " << row_num << "x" << column_num << endl;

    initialize_edit_matrix();
    fill_edit_matrix(subm_calc);

    cout << calc_edit_distance(subm_calc);

    return 0;
}
<|endoftext|>


<commit_before>#ifndef GOON_WINDOW_HPP
#define GOON_WINDOW_HPP

#include <SDL2/SDL.h>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

class Window {
   SDL_Window *mWindow;
   int mWidth;
   int mHeight;
public:
   Window(void);
   ~Window(void) {
      SDL_DestroyWindow(mWindow);
   }
   int Width(void) const { return mWidth; }
   int Height(void) const { return mHeight; }
   void ProcessEvent(const SDL_Event &event);
   SDL_Renderer* CreateRenderer(void) {
      return SDL_CreateRenderer(mWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
   }
};
#endif // GOON_WINDOW_HPP
<commit_msg>#6: Prevent Window from being copied<commit_after>#ifndef GOON_WINDOW_HPP
#define GOON_WINDOW_HPP

#include <SDL2/SDL.h>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

class Window {
   SDL_Window *mWindow;
   int mWidth;
   int mHeight;
public:
   Window(void);
   Window(Window const&) = delete;
   ~Window(void) {
      SDL_DestroyWindow(mWindow);
   }
   Window& operator=(Window const&) = delete;
   int Width(void) const { return mWidth; }
   int Height(void) const { return mHeight; }
   void ProcessEvent(const SDL_Event &event);
   SDL_Renderer* CreateRenderer(void) {
      return SDL_CreateRenderer(mWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
   }
};
#endif // GOON_WINDOW_HPP
<|endoftext|>