Debugger: LUA scripting
This commit is contained in:
parent
8e2f39e3bd
commit
5957bc2d3e
181 changed files with 48489 additions and 103 deletions
12
Core/APU.cpp
12
Core/APU.cpp
|
@ -255,3 +255,15 @@ bool APU::IsApuEnabled()
|
|||
//This is most likely due to the timing of the Frame Counter & DMC IRQs.
|
||||
return _apuEnabled;
|
||||
}
|
||||
|
||||
ApuState APU::GetState()
|
||||
{
|
||||
ApuState state;
|
||||
state.Dmc = _deltaModulationChannel->GetState();
|
||||
state.FrameCounter = _frameCounter->GetState();
|
||||
state.Noise = _noiseChannel->GetState();
|
||||
state.Square1 = _squareChannel[0]->GetState();
|
||||
state.Square2 = _squareChannel[1]->GetState();
|
||||
state.Triangle = _triangleChannel->GetState();
|
||||
return state;
|
||||
}
|
|
@ -62,6 +62,8 @@ class APU : public Snapshotable, public IMemoryHandler
|
|||
void WriteRAM(uint16_t addr, uint8_t value) override;
|
||||
void GetMemoryRanges(MemoryRanges &ranges) override;
|
||||
|
||||
ApuState GetState();
|
||||
|
||||
void Exec();
|
||||
|
||||
__forceinline static void ExecStatic()
|
||||
|
|
|
@ -81,4 +81,16 @@ public:
|
|||
_divider = _volume;
|
||||
}
|
||||
}
|
||||
|
||||
ApuEnvelopeState GetState()
|
||||
{
|
||||
ApuEnvelopeState state;
|
||||
state.ConstantVolume = _constantVolume;
|
||||
state.Counter = _counter;
|
||||
state.Divider = _divider;
|
||||
state.Loop = _lengthCounterHalt;
|
||||
state.StartFlag = _start;
|
||||
state.Volume = _volume;
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -214,4 +214,13 @@ public:
|
|||
CPU::ClearIRQSource(IRQSource::FrameCounter);
|
||||
}
|
||||
}
|
||||
|
||||
ApuFrameCounterState GetState()
|
||||
{
|
||||
ApuFrameCounterState state;
|
||||
state.IrqEnabled = !_inhibitIRQ;
|
||||
state.SequencePosition = _currentStep;
|
||||
state.FiveStepMode = _stepMode == 1;
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -6,11 +6,11 @@ class ApuLengthCounter : public BaseApuChannel
|
|||
{
|
||||
private:
|
||||
uint8_t _lcLookupTable[32] = { 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30 };
|
||||
bool _enabled = false;
|
||||
bool _newHaltValue;
|
||||
static bool _needToRun;
|
||||
|
||||
protected:
|
||||
bool _enabled = false;
|
||||
bool _lengthCounterHalt;
|
||||
uint8_t _lengthCounter;
|
||||
uint8_t _lengthCounterReloadValue;
|
||||
|
@ -112,4 +112,13 @@ public:
|
|||
}
|
||||
_enabled = enabled;
|
||||
}
|
||||
|
||||
ApuLengthCounterState GetState()
|
||||
{
|
||||
ApuLengthCounterState state;
|
||||
state.Counter = _lengthCounter;
|
||||
state.Halt = _lengthCounterHalt;
|
||||
state.ReloadValue = _lengthCounterReloadValue;
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9,12 +9,12 @@ class BaseApuChannel : public IMemoryHandler, public Snapshotable
|
|||
{
|
||||
private:
|
||||
SoundMixer *_mixer;
|
||||
int8_t _lastOutput;
|
||||
uint32_t _previousCycle;
|
||||
AudioChannel _channel;
|
||||
NesModel _nesModel;
|
||||
|
||||
protected:
|
||||
int8_t _lastOutput;
|
||||
uint16_t _timer = 0;
|
||||
uint16_t _period = 0;
|
||||
|
||||
|
|
|
@ -737,6 +737,16 @@ uint8_t BaseMapper::ReadRAM(uint16_t addr)
|
|||
return MemoryManager::GetOpenBus();
|
||||
}
|
||||
|
||||
uint8_t BaseMapper::DebugReadRAM(uint16_t addr)
|
||||
{
|
||||
if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Read) {
|
||||
return _prgPages[addr >> 8][(uint8_t)addr];
|
||||
} else {
|
||||
//assert(false);
|
||||
}
|
||||
return MemoryManager::GetOpenBus();
|
||||
}
|
||||
|
||||
void BaseMapper::WriteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_isWriteRegisterAddr[addr]) {
|
||||
|
@ -749,6 +759,17 @@ void BaseMapper::WriteRAM(uint16_t addr, uint8_t value)
|
|||
}
|
||||
}
|
||||
|
||||
void BaseMapper::DebugWriteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_isWriteRegisterAddr[addr]) {
|
||||
if(_hasBusConflicts) {
|
||||
value &= _prgPages[addr >> 8][(uint8_t)addr];
|
||||
}
|
||||
} else {
|
||||
WritePrgRam(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseMapper::WritePrgRam(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Write) {
|
||||
|
|
|
@ -168,7 +168,9 @@ public:
|
|||
RomFormat GetRomFormat();
|
||||
|
||||
__forceinline uint8_t ReadRAM(uint16_t addr) override;
|
||||
uint8_t DebugReadRAM(uint16_t addr);
|
||||
virtual void WriteRAM(uint16_t addr, uint8_t value) override;
|
||||
void DebugWriteRAM(uint16_t addr, uint8_t value);
|
||||
void WritePrgRam(uint16_t addr, uint8_t value);
|
||||
|
||||
__forceinline uint8_t InternalReadVRAM(uint16_t addr);
|
||||
|
|
|
@ -13,6 +13,11 @@ CheatManager::CheatManager()
|
|||
}
|
||||
}
|
||||
|
||||
CheatManager * CheatManager::GetInstance()
|
||||
{
|
||||
return Instance;
|
||||
}
|
||||
|
||||
uint32_t CheatManager::DecodeValue(uint32_t code, uint32_t* bitIndexes, uint32_t bitCount)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
|
|
@ -41,14 +41,16 @@ private:
|
|||
CodeInfo GetPARCodeInfo(uint32_t parCode);
|
||||
void AddCode(CodeInfo &code);
|
||||
|
||||
public:
|
||||
CheatManager();
|
||||
|
||||
static CheatManager* GetInstance();
|
||||
|
||||
void AddGameGenieCode(string code);
|
||||
void AddProActionRockyCode(uint32_t code);
|
||||
void AddCustomCode(uint32_t address, uint8_t value, int32_t compareValue = -1, bool isRelativeAddress = true);
|
||||
void ClearCodes();
|
||||
|
||||
public:
|
||||
CheatManager();
|
||||
|
||||
static vector<CodeInfo> GetCheats();
|
||||
static void SetCheats(vector<CodeInfo> &cheats);
|
||||
static void SetCheats(CheatInfo cheats[], uint32_t length);
|
||||
|
|
|
@ -287,17 +287,7 @@ void Console::ResetComponents(bool softReset)
|
|||
|
||||
SoundMixer::StopAudio(true);
|
||||
|
||||
if(softReset) {
|
||||
if(_debugger) {
|
||||
auto lock = _debuggerLock.AcquireSafe();
|
||||
StopDebugger();
|
||||
GetDebugger();
|
||||
}
|
||||
|
||||
MessageManager::SendNotification(ConsoleNotificationType::GameReset);
|
||||
} else {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::GameLoaded);
|
||||
}
|
||||
MessageManager::SendNotification(softReset ? ConsoleNotificationType::GameReset : ConsoleNotificationType::GameLoaded);
|
||||
}
|
||||
|
||||
void Console::Stop()
|
||||
|
@ -380,6 +370,10 @@ void Console::Run()
|
|||
_lagCounter++;
|
||||
}
|
||||
|
||||
if(_debugger) {
|
||||
_debugger->ProcessEvent(EventType::StartFrame);
|
||||
}
|
||||
|
||||
_rewindManager->ProcessEndOfFrame();
|
||||
EmulationSettings::DisableOverclocking(_disableOcNextFrame || NsfMapper::GetInstance());
|
||||
_disableOcNextFrame = false;
|
||||
|
@ -485,7 +479,7 @@ void Console::Run()
|
|||
|
||||
bool Console::IsRunning()
|
||||
{
|
||||
return !Instance->_stopLock.IsFree();
|
||||
return !Instance->_stopLock.IsFree() && !Instance->_runLock.IsFree();
|
||||
}
|
||||
|
||||
void Console::UpdateNesModel(bool sendNotification)
|
||||
|
@ -597,7 +591,7 @@ std::shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
|
|||
{
|
||||
auto lock = _debuggerLock.AcquireSafe();
|
||||
if(!_debugger && autoStart) {
|
||||
_debugger.reset(new Debugger(Console::Instance, _cpu, _ppu, _memoryManager, _mapper));
|
||||
_debugger.reset(new Debugger(Console::Instance, _cpu, _ppu, _apu, _memoryManager, _mapper));
|
||||
}
|
||||
return _debugger;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class Console
|
|||
shared_ptr<RewindManager> _rewindManager;
|
||||
shared_ptr<CPU> _cpu;
|
||||
shared_ptr<PPU> _ppu;
|
||||
unique_ptr<APU> _apu;
|
||||
shared_ptr<APU> _apu;
|
||||
shared_ptr<Debugger> _debugger;
|
||||
SimpleLock _debuggerLock;
|
||||
shared_ptr<BaseMapper> _mapper;
|
||||
|
|
|
@ -412,12 +412,20 @@
|
|||
<ClInclude Include="Assembler.h" />
|
||||
<ClInclude Include="AutomaticRomTest.h" />
|
||||
<ClInclude Include="BaseRenderer.h" />
|
||||
<ClInclude Include="DebugHud.h" />
|
||||
<ClInclude Include="DrawCommand.h" />
|
||||
<ClInclude Include="DrawLineCommand.h" />
|
||||
<ClInclude Include="DrawPixelCommand.h" />
|
||||
<ClInclude Include="DrawStringCommand.h" />
|
||||
<ClInclude Include="FceuxMovie.h" />
|
||||
<ClInclude Include="HdAudioDevice.h" />
|
||||
<ClInclude Include="HdBuilderPpu.h" />
|
||||
<ClInclude Include="HdData.h" />
|
||||
<ClInclude Include="HdPackBuilder.h" />
|
||||
<ClInclude Include="HdPackLoader.h" />
|
||||
<ClInclude Include="LuaApi.h" />
|
||||
<ClInclude Include="LuaCallHelper.h" />
|
||||
<ClInclude Include="LuaScriptingContext.h" />
|
||||
<ClInclude Include="Mapper174.h" />
|
||||
<ClInclude Include="OggMixer.h" />
|
||||
<ClInclude Include="OggReader.h" />
|
||||
|
@ -461,6 +469,8 @@
|
|||
<ClInclude Include="MesenMovie.h" />
|
||||
<ClInclude Include="RewindData.h" />
|
||||
<ClInclude Include="RewindManager.h" />
|
||||
<ClInclude Include="ScriptHost.h" />
|
||||
<ClInclude Include="ScriptingContext.h" />
|
||||
<ClInclude Include="SealieComputing.h" />
|
||||
<ClInclude Include="UnlD1038.h" />
|
||||
<ClInclude Include="DaouInfosys.h" />
|
||||
|
@ -780,11 +790,16 @@
|
|||
<ClCompile Include="Assembler.cpp" />
|
||||
<ClCompile Include="AutomaticRomTest.cpp" />
|
||||
<ClCompile Include="BaseRenderer.cpp" />
|
||||
<ClCompile Include="DebugHud.cpp" />
|
||||
<ClCompile Include="DrawRectangleCommand.h" />
|
||||
<ClCompile Include="FceuxMovie.cpp" />
|
||||
<ClCompile Include="HdAudioDevice.cpp" />
|
||||
<ClCompile Include="HdNesPack.cpp" />
|
||||
<ClCompile Include="HdPackBuilder.cpp" />
|
||||
<ClCompile Include="HdPackLoader.cpp" />
|
||||
<ClCompile Include="LuaApi.cpp" />
|
||||
<ClCompile Include="LuaCallHelper.cpp" />
|
||||
<ClCompile Include="LuaScriptingContext.cpp" />
|
||||
<ClCompile Include="OggMixer.cpp" />
|
||||
<ClCompile Include="OggReader.cpp" />
|
||||
<ClCompile Include="RecordedRomTest.cpp" />
|
||||
|
@ -829,6 +844,8 @@
|
|||
<ClCompile Include="RewindData.cpp" />
|
||||
<ClCompile Include="RewindManager.cpp" />
|
||||
<ClCompile Include="RomLoader.cpp" />
|
||||
<ClCompile Include="ScriptHost.cpp" />
|
||||
<ClCompile Include="ScriptingContext.cpp" />
|
||||
<ClCompile Include="ShortcutKeyHandler.cpp" />
|
||||
<ClCompile Include="Snapshotable.cpp" />
|
||||
<ClCompile Include="SoundMixer.cpp" />
|
||||
|
|
|
@ -92,6 +92,15 @@
|
|||
<Filter Include="HdPacks">
|
||||
<UniqueIdentifier>{a6994cb5-f9d2-416c-84ab-c1abe4975eb1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Debugger\Scripting">
|
||||
<UniqueIdentifier>{ee232799-5562-4fea-946b-844786d6fd66}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Debugger\Scripting\DebugHud">
|
||||
<UniqueIdentifier>{9e32ff0a-5fae-47bc-8007-404fd4d0204c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Debugger\Scripting\Lua">
|
||||
<UniqueIdentifier>{e1e8a5d2-aa9a-40e1-94eb-00adec1cdef3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="IAudioDevice.h">
|
||||
|
@ -1201,6 +1210,36 @@
|
|||
<ClInclude Include="OggMixer.h">
|
||||
<Filter>HdPacks</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ScriptHost.h">
|
||||
<Filter>Debugger\Scripting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ScriptingContext.h">
|
||||
<Filter>Debugger\Scripting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DebugHud.h">
|
||||
<Filter>Debugger\Scripting\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawCommand.h">
|
||||
<Filter>Debugger\Scripting\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawStringCommand.h">
|
||||
<Filter>Debugger\Scripting\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawLineCommand.h">
|
||||
<Filter>Debugger\Scripting\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawPixelCommand.h">
|
||||
<Filter>Debugger\Scripting\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LuaApi.h">
|
||||
<Filter>Debugger\Scripting\Lua</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LuaCallHelper.h">
|
||||
<Filter>Debugger\Scripting\Lua</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LuaScriptingContext.h">
|
||||
<Filter>Debugger\Scripting\Lua</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1443,5 +1482,26 @@
|
|||
<ClCompile Include="HdAudioDevice.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DebugHud.cpp">
|
||||
<Filter>Debugger\Scripting\DebugHud</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DrawRectangleCommand.h">
|
||||
<Filter>Debugger\Scripting\DebugHud</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ScriptingContext.cpp">
|
||||
<Filter>Debugger\Scripting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LuaScriptingContext.cpp">
|
||||
<Filter>Debugger\Scripting\Lua</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LuaCallHelper.cpp">
|
||||
<Filter>Debugger\Scripting\Lua</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LuaApi.cpp">
|
||||
<Filter>Debugger\Scripting\Lua</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ScriptHost.cpp">
|
||||
<Filter>Debugger\Scripting</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
67
Core/DebugHud.cpp
Normal file
67
Core/DebugHud.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "stdafx.h"
|
||||
#include "DebugHud.h"
|
||||
#include "DrawCommand.h"
|
||||
#include "DrawLineCommand.h"
|
||||
#include "DrawPixelCommand.h"
|
||||
#include "DrawRectangleCommand.h"
|
||||
#include "DrawStringCommand.h"
|
||||
|
||||
DebugHud* DebugHud::_instance = nullptr;
|
||||
|
||||
DebugHud::DebugHud()
|
||||
{
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
DebugHud::~DebugHud()
|
||||
{
|
||||
_commandLock.Acquire();
|
||||
if(_instance == this) {
|
||||
_instance = nullptr;
|
||||
}
|
||||
_commandLock.Release();
|
||||
}
|
||||
|
||||
DebugHud* DebugHud::GetInstance()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void DebugHud::ClearScreen()
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
_commands.clear();
|
||||
}
|
||||
|
||||
void DebugHud::Draw(uint32_t* argbBuffer, OverscanDimensions &overscan)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
for(shared_ptr<DrawCommand> &command : _commands) {
|
||||
command->Draw(argbBuffer, overscan);
|
||||
}
|
||||
_commands.erase(std::remove_if(_commands.begin(), _commands.end(), [](const shared_ptr<DrawCommand>& c) { return c->Expired(); }), _commands.end());
|
||||
}
|
||||
|
||||
void DebugHud::DrawPixel(int x, int y, int color, int frameCount)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
_commands.push_back(shared_ptr<DrawPixelCommand>(new DrawPixelCommand(x, y, color, frameCount)));
|
||||
}
|
||||
|
||||
void DebugHud::DrawLine(int x, int y, int x2, int y2, int color, int frameCount)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
_commands.push_back(shared_ptr<DrawLineCommand>(new DrawLineCommand(x, y, x2, y2, color, frameCount)));
|
||||
}
|
||||
|
||||
void DebugHud::DrawRectangle(int x, int y, int width, int height, int color, bool fill, int frameCount)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
_commands.push_back(shared_ptr<DrawRectangleCommand>(new DrawRectangleCommand(x, y, width, height, color, fill, frameCount)));
|
||||
}
|
||||
|
||||
void DebugHud::DrawString(int x, int y, string text, int color, int backColor, int frameCount)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
_commands.push_back(shared_ptr<DrawStringCommand>(new DrawStringCommand(x, y, text, color, backColor, frameCount)));
|
||||
}
|
26
Core/DebugHud.h
Normal file
26
Core/DebugHud.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "EmulationSettings.h"
|
||||
class DrawCommand;
|
||||
|
||||
class DebugHud
|
||||
{
|
||||
private:
|
||||
static DebugHud* _instance;
|
||||
vector<shared_ptr<DrawCommand>> _commands;
|
||||
SimpleLock _commandLock;
|
||||
|
||||
public:
|
||||
static DebugHud* GetInstance();
|
||||
DebugHud();
|
||||
~DebugHud();
|
||||
|
||||
void Draw(uint32_t* argbBuffer, OverscanDimensions &overscan);
|
||||
void ClearScreen();
|
||||
|
||||
void DrawPixel(int x, int y, int color, int frameCount);
|
||||
void DrawLine(int x, int y, int x2, int y2, int color, int frameCount);
|
||||
void DrawRectangle(int x, int y, int width, int height, int color, bool fill, int frameCount);
|
||||
void DrawString(int x, int y, string text, int color, int backColor, int frameCount);
|
||||
};
|
|
@ -22,16 +22,19 @@
|
|||
#include "MemoryManager.h"
|
||||
#include "RewindManager.h"
|
||||
#include "DebugBreakHelper.h"
|
||||
#include "ScriptHost.h"
|
||||
#include "DebugHud.h"
|
||||
|
||||
Debugger* Debugger::Instance = nullptr;
|
||||
const int Debugger::BreakpointTypeCount;
|
||||
|
||||
Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<PPU> ppu, shared_ptr<MemoryManager> memoryManager, shared_ptr<BaseMapper> mapper)
|
||||
Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<PPU> ppu, shared_ptr<APU> apu, shared_ptr<MemoryManager> memoryManager, shared_ptr<BaseMapper> mapper)
|
||||
{
|
||||
_romName = Console::GetRomName();
|
||||
_console = console;
|
||||
_cpu = cpu;
|
||||
_ppu = ppu;
|
||||
_apu = apu;
|
||||
_memoryManager = memoryManager;
|
||||
_mapper = mapper;
|
||||
|
||||
|
@ -43,6 +46,7 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
|
|||
_memoryAccessCounter.reset(new MemoryAccessCounter(this));
|
||||
_profiler.reset(new Profiler(this));
|
||||
_traceLogger.reset(new TraceLogger(this, memoryManager, _labelManager));
|
||||
_debugHud.reset(new DebugHud());
|
||||
|
||||
_stepOut = false;
|
||||
_stepCount = -1;
|
||||
|
@ -86,6 +90,9 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
|
|||
_disassembler->Reset();
|
||||
}
|
||||
|
||||
_hasScript = false;
|
||||
_nextScriptId = 0;
|
||||
|
||||
Debugger::Instance = this;
|
||||
}
|
||||
|
||||
|
@ -356,6 +363,8 @@ void Debugger::PrivateProcessInterrupt(uint16_t cpuAddr, uint16_t destCpuAddr, b
|
|||
_callstackAbsolute.push_back(_mapper->ToAbsoluteAddress(destCpuAddr));
|
||||
|
||||
_profiler->StackFunction(-1, _mapper->ToAbsoluteAddress(destCpuAddr));
|
||||
|
||||
ProcessEvent(forNmi ? EventType::Nmi : EventType::Irq);
|
||||
}
|
||||
|
||||
void Debugger::ProcessInterrupt(uint16_t cpuAddr, uint16_t destCpuAddr, bool forNmi)
|
||||
|
@ -382,6 +391,9 @@ void Debugger::PrivateProcessPpuCycle()
|
|||
if(PPU::GetCurrentCycle() == (uint32_t)_ppuViewerCycle && PPU::GetCurrentScanline() == _ppuViewerScanline) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::PpuViewerDisplayFrame);
|
||||
}
|
||||
if(PPU::GetCurrentCycle() == 0 && PPU::GetCurrentScanline() == 241) {
|
||||
ProcessEvent(EventType::EndFrame);
|
||||
}
|
||||
|
||||
OperationInfo operationInfo { 0, 0, MemoryOperationType::DummyRead };
|
||||
if(_hasBreakpoint[BreakpointType::Global] && HasMatchingBreakpoint(BreakpointType::Global, operationInfo)) {
|
||||
|
@ -538,6 +550,8 @@ bool Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &ad
|
|||
_currentReadAddr = nullptr;
|
||||
_currentReadValue = nullptr;
|
||||
|
||||
ProcessCpuOperation(addr, value, type);
|
||||
|
||||
if(type == MemoryOperationType::Write) {
|
||||
if(_frozenAddresses[addr]) {
|
||||
return false;
|
||||
|
@ -563,6 +577,7 @@ bool Debugger::SleepUntilResume()
|
|||
if(_sendNotification) {
|
||||
SoundMixer::StopAudio();
|
||||
MessageManager::SendNotification(ConsoleNotificationType::CodeBreak);
|
||||
ProcessEvent(EventType::CodeBreak);
|
||||
_stepOverAddr = -1;
|
||||
if(CheckFlag(DebuggerFlags::PpuPartialDraw)) {
|
||||
_ppu->DebugSendFrame();
|
||||
|
@ -594,6 +609,8 @@ void Debugger::PrivateProcessVramReadOperation(MemoryOperationType type, uint16_
|
|||
SleepUntilResume();
|
||||
}
|
||||
}
|
||||
|
||||
ProcessPpuOperation(addr, value, MemoryOperationType::Read);
|
||||
}
|
||||
|
||||
void Debugger::PrivateProcessVramWriteOperation(uint16_t addr, uint8_t value)
|
||||
|
@ -606,14 +623,18 @@ void Debugger::PrivateProcessVramWriteOperation(uint16_t addr, uint8_t value)
|
|||
SleepUntilResume();
|
||||
}
|
||||
}
|
||||
|
||||
ProcessPpuOperation(addr, value, MemoryOperationType::Write);
|
||||
}
|
||||
|
||||
void Debugger::GetState(DebugState *state, bool includeMapperInfo)
|
||||
{
|
||||
state->Model = _console->GetModel();
|
||||
state->CPU = _cpu->GetState();
|
||||
state->PPU = _ppu->GetState();
|
||||
if(includeMapperInfo) {
|
||||
state->Cartridge = _mapper->GetState();
|
||||
state->APU = _apu->GetState();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1013,3 +1034,71 @@ void Debugger::SetInputOverride(uint8_t port, uint32_t state)
|
|||
{
|
||||
_inputOverride[port] = state;
|
||||
}
|
||||
|
||||
int Debugger::LoadScript(string content, int32_t scriptId)
|
||||
{
|
||||
DebugBreakHelper helper(this);
|
||||
|
||||
if(scriptId < 0) {
|
||||
shared_ptr<ScriptHost> script(new ScriptHost(_nextScriptId++));
|
||||
script->LoadScript(content, this);
|
||||
_scripts.push_back(script);
|
||||
_hasScript = true;
|
||||
return script->GetScriptId();
|
||||
} else {
|
||||
auto result = std::find_if(_scripts.begin(), _scripts.end(), [=](shared_ptr<ScriptHost> &script) {
|
||||
return script->GetScriptId() == scriptId;
|
||||
});
|
||||
if(result != _scripts.end()) {
|
||||
(*result)->LoadScript(content, this);
|
||||
return scriptId;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Debugger::RemoveScript(int32_t scriptId)
|
||||
{
|
||||
DebugBreakHelper helper(this);
|
||||
_scripts.erase(std::remove_if(_scripts.begin(), _scripts.end(), [=](const shared_ptr<ScriptHost>& script) { return script->GetScriptId() == scriptId; }), _scripts.end());
|
||||
_hasScript = _scripts.size() > 0;
|
||||
}
|
||||
|
||||
const char* Debugger::GetScriptLog(int32_t scriptId)
|
||||
{
|
||||
DebugBreakHelper helper(this);
|
||||
for(shared_ptr<ScriptHost> &script : _scripts) {
|
||||
if(script->GetScriptId() == scriptId) {
|
||||
return script->GetLog();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void Debugger::ProcessCpuOperation(uint16_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
if(_hasScript) {
|
||||
for(shared_ptr<ScriptHost> &script : _scripts) {
|
||||
script->ProcessCpuOperation(addr, value, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::ProcessPpuOperation(uint16_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
if(_hasScript) {
|
||||
for(shared_ptr<ScriptHost> &script : _scripts) {
|
||||
script->ProcessPpuOperation(addr, value, MemoryOperationType::Write);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::ProcessEvent(EventType type)
|
||||
{
|
||||
if(_hasScript) {
|
||||
for(shared_ptr<ScriptHost> &script : _scripts) {
|
||||
script->ProcessEvent(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ using std::unordered_set;
|
|||
#include "DebuggerTypes.h"
|
||||
|
||||
class CPU;
|
||||
class APU;
|
||||
class PPU;
|
||||
class MemoryManager;
|
||||
class Console;
|
||||
|
@ -26,6 +27,8 @@ class MemoryAccessCounter;
|
|||
class Profiler;
|
||||
class CodeRunner;
|
||||
class BaseMapper;
|
||||
class ScriptHost;
|
||||
class DebugHud;
|
||||
|
||||
class Debugger
|
||||
{
|
||||
|
@ -43,13 +46,19 @@ private:
|
|||
shared_ptr<TraceLogger> _traceLogger;
|
||||
shared_ptr<Profiler> _profiler;
|
||||
unique_ptr<CodeRunner> _codeRunner;
|
||||
unique_ptr<DebugHud> _debugHud;
|
||||
|
||||
shared_ptr<Console> _console;
|
||||
shared_ptr<CPU> _cpu;
|
||||
shared_ptr<PPU> _ppu;
|
||||
shared_ptr<APU> _apu;
|
||||
shared_ptr<MemoryManager> _memoryManager;
|
||||
shared_ptr<BaseMapper> _mapper;
|
||||
|
||||
bool _hasScript;
|
||||
int _nextScriptId;
|
||||
vector<shared_ptr<ScriptHost>> _scripts;
|
||||
|
||||
bool _bpUpdateNeeded;
|
||||
SimpleLock _bpUpdateLock;
|
||||
|
||||
|
@ -125,7 +134,7 @@ private:
|
|||
void RemoveExcessCallstackEntries();
|
||||
|
||||
public:
|
||||
Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<PPU> ppu, shared_ptr<MemoryManager> memoryManager, shared_ptr<BaseMapper> mapper);
|
||||
Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<PPU> ppu, shared_ptr<APU> apu, shared_ptr<MemoryManager> memoryManager, shared_ptr<BaseMapper> mapper);
|
||||
~Debugger();
|
||||
|
||||
void SetFlags(uint32_t flags);
|
||||
|
@ -210,4 +219,11 @@ public:
|
|||
static bool HasInputOverride(uint8_t port);
|
||||
static uint32_t GetInputOverride(uint8_t port);
|
||||
void SetInputOverride(uint8_t port, uint32_t state);
|
||||
|
||||
int32_t LoadScript(string content, int32_t scriptId);
|
||||
void RemoveScript(int32_t scriptId);
|
||||
const char* GetScriptLog(int32_t scriptId);
|
||||
void ProcessCpuOperation(uint16_t addr, uint8_t value, MemoryOperationType type);
|
||||
void ProcessPpuOperation(uint16_t addr, uint8_t value, MemoryOperationType type);
|
||||
void ProcessEvent(EventType type);
|
||||
};
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "Types.h"
|
||||
#include "EmulationSettings.h"
|
||||
|
||||
enum class DebuggerFlags
|
||||
{
|
||||
|
@ -66,6 +67,8 @@ struct DebugState
|
|||
State CPU;
|
||||
PPUDebugState PPU;
|
||||
CartridgeState Cartridge;
|
||||
ApuState APU;
|
||||
NesModel Model;
|
||||
};
|
||||
|
||||
struct OperationInfo
|
||||
|
@ -74,3 +77,14 @@ struct OperationInfo
|
|||
int16_t Value;
|
||||
MemoryOperationType OperationType;
|
||||
};
|
||||
|
||||
enum class EventType
|
||||
{
|
||||
Power = 0,
|
||||
Reset = 1,
|
||||
Nmi = 2,
|
||||
Irq = 3,
|
||||
StartFrame = 4,
|
||||
EndFrame = 5,
|
||||
CodeBreak = 6
|
||||
};
|
|
@ -5,6 +5,7 @@
|
|||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include "PPU.h"
|
||||
#include "DebugHud.h"
|
||||
|
||||
DefaultVideoFilter::DefaultVideoFilter()
|
||||
{
|
||||
|
@ -54,21 +55,26 @@ void DefaultVideoFilter::OnBeforeApplyFilter()
|
|||
|
||||
void DefaultVideoFilter::DecodePpuBuffer(uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, bool displayScanlines)
|
||||
{
|
||||
uint32_t* out = outputBuffer;
|
||||
OverscanDimensions overscan = GetOverscan();
|
||||
double scanlineIntensity = 1.0 - EmulationSettings::GetPictureSettings().ScanlineIntensity;
|
||||
for(uint32_t i = overscan.Top, iMax = 240 - overscan.Bottom; i < iMax; i++) {
|
||||
if(displayScanlines && (i + overscan.Top) % 2 == 0) {
|
||||
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
|
||||
*outputBuffer = ProcessIntensifyBits(ppuOutputBuffer[i * 256 + j], scanlineIntensity);
|
||||
outputBuffer++;
|
||||
*out = ProcessIntensifyBits(ppuOutputBuffer[i * 256 + j], scanlineIntensity);
|
||||
out++;
|
||||
}
|
||||
} else {
|
||||
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
|
||||
*outputBuffer = ProcessIntensifyBits(ppuOutputBuffer[i * 256 + j]);
|
||||
outputBuffer++;
|
||||
*out = ProcessIntensifyBits(ppuOutputBuffer[i * 256 + j]);
|
||||
out++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(DebugHud::GetInstance()) {
|
||||
DebugHud::GetInstance()->Draw(outputBuffer, overscan);
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
|
||||
|
|
|
@ -211,3 +211,17 @@ void DeltaModulationChannel::SetReadBuffer()
|
|||
{
|
||||
Instance->FillReadBuffer();
|
||||
}
|
||||
|
||||
ApuDmcState DeltaModulationChannel::GetState()
|
||||
{
|
||||
ApuDmcState state;
|
||||
state.BytesRemaining = _bytesRemaining;
|
||||
state.Frequency = (uint32_t)(CPU::GetClockRate(GetNesModel()) / 32.0 / (_period + 1));
|
||||
state.IrqEnabled = _irqEnabled;
|
||||
state.Loop = _loopFlag;
|
||||
state.OutputVolume = _lastOutput;
|
||||
state.Period = _period;
|
||||
state.SampleAddr = _sampleAddr;
|
||||
state.SampleLength = _sampleLength;
|
||||
return state;
|
||||
}
|
|
@ -52,4 +52,6 @@ public:
|
|||
void SetEnabled(bool enabled);
|
||||
void StartDmcTransfer();
|
||||
static void SetReadBuffer();
|
||||
|
||||
ApuDmcState GetState();
|
||||
};
|
59
Core/DrawCommand.h
Normal file
59
Core/DrawCommand.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "EmulationSettings.h"
|
||||
|
||||
class DrawCommand
|
||||
{
|
||||
private:
|
||||
int _frameCount;
|
||||
uint32_t* _argbBuffer;
|
||||
OverscanDimensions _overscan;
|
||||
|
||||
protected:
|
||||
virtual void InternalDraw() = 0;
|
||||
__forceinline void DrawPixel(uint32_t x, uint32_t y, int color)
|
||||
{
|
||||
if(x < _overscan.Left || x >= _overscan.Left + _overscan.GetScreenWidth() ||
|
||||
y < _overscan.Top || y >= _overscan.Top + _overscan.GetScreenHeight()) {
|
||||
//In overscan (out of bounds), skip drawing
|
||||
return;
|
||||
}
|
||||
|
||||
if((color & 0xFF000000) != 0xFF000000) {
|
||||
BlendColors((uint8_t*)&_argbBuffer[(y - _overscan.Top)*_overscan.GetScreenWidth() + (x - _overscan.Left)], (uint8_t*)&color);
|
||||
} else {
|
||||
_argbBuffer[(y - _overscan.Top)*_overscan.GetScreenWidth() + (x - _overscan.Left)] = color;
|
||||
}
|
||||
}
|
||||
|
||||
__forceinline void BlendColors(uint8_t output[4], uint8_t input[4])
|
||||
{
|
||||
uint8_t alpha = input[3] + 1;
|
||||
uint8_t invertedAlpha = 256 - input[3];
|
||||
output[0] = (uint8_t)((alpha * input[0] + invertedAlpha * output[0]) >> 8);
|
||||
output[1] = (uint8_t)((alpha * input[1] + invertedAlpha * output[1]) >> 8);
|
||||
output[2] = (uint8_t)((alpha * input[2] + invertedAlpha * output[2]) >> 8);
|
||||
output[3] = 0xFF;
|
||||
}
|
||||
|
||||
public:
|
||||
DrawCommand(int frameCount)
|
||||
{
|
||||
_frameCount = frameCount > 0 ? frameCount : -1;
|
||||
}
|
||||
|
||||
void Draw(uint32_t* argbBuffer, OverscanDimensions &overscan)
|
||||
{
|
||||
_argbBuffer = argbBuffer;
|
||||
_overscan = overscan;
|
||||
|
||||
InternalDraw();
|
||||
|
||||
_frameCount--;
|
||||
}
|
||||
|
||||
bool Expired()
|
||||
{
|
||||
return _frameCount == 0;
|
||||
}
|
||||
};
|
42
Core/DrawLineCommand.h
Normal file
42
Core/DrawLineCommand.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
class DrawLineCommand : public DrawCommand
|
||||
{
|
||||
private:
|
||||
int _x, _y, _x2, _y2, _color;
|
||||
|
||||
protected:
|
||||
void InternalDraw()
|
||||
{
|
||||
int xDiff = _x2 - _x;
|
||||
int yDiff = _y2 - _y;
|
||||
if(xDiff == 0) {
|
||||
for(int i = _y; i <= _y2; i++) {
|
||||
DrawPixel(_x, i, _color);
|
||||
}
|
||||
} else {
|
||||
double deltaErr = abs((double)yDiff / (double)xDiff);
|
||||
double error = deltaErr - 0.5;
|
||||
int y = _y;
|
||||
for(int x = _x; x <= _x2; x++) {
|
||||
DrawPixel(x, y, _color);
|
||||
error += deltaErr;
|
||||
if(error >= 0.5) {
|
||||
y++;
|
||||
error -= 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DrawLineCommand(int x, int y, int x2, int y2, int color, int frameCount) :
|
||||
_x(x), _y(y), _x2(x2), _y2(y2), _color(color), DrawCommand(frameCount)
|
||||
{
|
||||
if(!(_color & 0xFF000000)) {
|
||||
_color |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
};
|
24
Core/DrawPixelCommand.h
Normal file
24
Core/DrawPixelCommand.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
class DrawPixelCommand : public DrawCommand
|
||||
{
|
||||
private:
|
||||
int _x, _y, _color;
|
||||
|
||||
protected:
|
||||
void InternalDraw()
|
||||
{
|
||||
DrawPixel(_x, _y, _color);
|
||||
}
|
||||
|
||||
public:
|
||||
DrawPixelCommand(int x, int y, int color, int frameCount) :
|
||||
_x(x), _y(y), _color(color), DrawCommand(frameCount)
|
||||
{
|
||||
if(!(_color & 0xFF000000)) {
|
||||
_color |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
};
|
40
Core/DrawRectangleCommand.h
Normal file
40
Core/DrawRectangleCommand.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
class DrawRectangleCommand : public DrawCommand
|
||||
{
|
||||
private:
|
||||
int _x, _y, _width, _height, _color;
|
||||
bool _fill;
|
||||
|
||||
protected:
|
||||
void InternalDraw()
|
||||
{
|
||||
if(_fill) {
|
||||
for(int j = 0; j < _height; j++) {
|
||||
for(int i = 0; i < _width; i++) {
|
||||
DrawPixel(_x + i, _y + j, _color);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < _width; i++) {
|
||||
DrawPixel(_x + i, _y, _color);
|
||||
DrawPixel(_x + i, _y + _height - 1, _color);
|
||||
}
|
||||
for(int i = 0; i < _height; i++) {
|
||||
DrawPixel(_x, _y + i, _color);
|
||||
DrawPixel(_x + _width - 1, _y + i, _color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DrawRectangleCommand(int x, int y, int width, int height, int color, bool fill, int frameCount) :
|
||||
_x(x), _y(y), _width(width), _height(height), _color(color), _fill(fill), DrawCommand(frameCount)
|
||||
{
|
||||
if(!(_color & 0xFF000000)) {
|
||||
_color |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
};
|
163
Core/DrawStringCommand.h
Normal file
163
Core/DrawStringCommand.h
Normal file
|
@ -0,0 +1,163 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
class DrawStringCommand : public DrawCommand
|
||||
{
|
||||
private:
|
||||
int _x, _y, _color, _backColor;
|
||||
string _text;
|
||||
|
||||
//Taken from FCEUX's LUA code
|
||||
const int _tabSpace = 4;
|
||||
const uint8_t _font[792] = {
|
||||
6, 0, 0, 0, 0, 0, 0, 0, // 0x20 - Spacebar
|
||||
3, 64, 64, 64, 64, 64, 0, 64,
|
||||
5, 80, 80, 80, 0, 0, 0, 0,
|
||||
6, 80, 80,248, 80,248, 80, 80,
|
||||
6, 32,120,160,112, 40,240, 32,
|
||||
6, 64,168, 80, 32, 80,168, 16,
|
||||
6, 96,144,160, 64,168,144,104,
|
||||
3, 64, 64, 0, 0, 0, 0, 0,
|
||||
4, 32, 64, 64, 64, 64, 64, 32,
|
||||
4, 64, 32, 32, 32, 32, 32, 64,
|
||||
6, 0, 80, 32,248, 32, 80, 0,
|
||||
6, 0, 32, 32,248, 32, 32, 0,
|
||||
3, 0, 0, 0, 0, 0, 64,128,
|
||||
5, 0, 0, 0,240, 0, 0, 0,
|
||||
3, 0, 0, 0, 0, 0, 0, 64,
|
||||
5, 16, 16, 32, 32, 32, 64, 64,
|
||||
6,112,136,136,136,136,136,112, // 0x30 - 0
|
||||
6, 32, 96, 32, 32, 32, 32, 32,
|
||||
6,112,136, 8, 48, 64,128,248,
|
||||
6,112,136, 8, 48, 8,136,112,
|
||||
6, 16, 48, 80,144,248, 16, 16,
|
||||
6,248,128,128,240, 8, 8,240,
|
||||
6, 48, 64,128,240,136,136,112,
|
||||
6,248, 8, 16, 16, 32, 32, 32,
|
||||
6,112,136,136,112,136,136,112,
|
||||
6,112,136,136,120, 8, 16, 96,
|
||||
3, 0, 0, 64, 0, 0, 64, 0,
|
||||
3, 0, 0, 64, 0, 0, 64,128,
|
||||
4, 0, 32, 64,128, 64, 32, 0,
|
||||
5, 0, 0,240, 0,240, 0, 0,
|
||||
4, 0,128, 64, 32, 64,128, 0,
|
||||
6,112,136, 8, 16, 32, 0, 32, // 0x3F - ?
|
||||
6,112,136,136,184,176,128,112, // 0x40 - @
|
||||
6,112,136,136,248,136,136,136, // 0x41 - A
|
||||
6,240,136,136,240,136,136,240,
|
||||
6,112,136,128,128,128,136,112,
|
||||
6,224,144,136,136,136,144,224,
|
||||
6,248,128,128,240,128,128,248,
|
||||
6,248,128,128,240,128,128,128,
|
||||
6,112,136,128,184,136,136,120,
|
||||
6,136,136,136,248,136,136,136,
|
||||
4,224, 64, 64, 64, 64, 64,224,
|
||||
6, 8, 8, 8, 8, 8,136,112,
|
||||
6,136,144,160,192,160,144,136,
|
||||
6,128,128,128,128,128,128,248,
|
||||
6,136,216,168,168,136,136,136,
|
||||
6,136,136,200,168,152,136,136,
|
||||
7, 48, 72,132,132,132, 72, 48,
|
||||
6,240,136,136,240,128,128,128,
|
||||
6,112,136,136,136,168,144,104,
|
||||
6,240,136,136,240,144,136,136,
|
||||
6,112,136,128,112, 8,136,112,
|
||||
6,248, 32, 32, 32, 32, 32, 32,
|
||||
6,136,136,136,136,136,136,112,
|
||||
6,136,136,136, 80, 80, 32, 32,
|
||||
6,136,136,136,136,168,168, 80,
|
||||
6,136,136, 80, 32, 80,136,136,
|
||||
6,136,136, 80, 32, 32, 32, 32,
|
||||
6,248, 8, 16, 32, 64,128,248,
|
||||
3,192,128,128,128,128,128,192,
|
||||
5, 64, 64, 32, 32, 32, 16, 16,
|
||||
3,192, 64, 64, 64, 64, 64,192,
|
||||
4, 64,160, 0, 0, 0, 0, 0,
|
||||
6, 0, 0, 0, 0, 0, 0,248,
|
||||
3,128, 64, 0, 0, 0, 0, 0,
|
||||
5, 0, 0, 96, 16,112,144,112, // 0x61 - a
|
||||
5,128,128,224,144,144,144,224,
|
||||
5, 0, 0,112,128,128,128,112,
|
||||
5, 16, 16,112,144,144,144,112,
|
||||
5, 0, 0, 96,144,240,128,112,
|
||||
5, 48, 64,224, 64, 64, 64, 64,
|
||||
5, 0,112,144,144,112, 16,224,
|
||||
5,128,128,224,144,144,144,144,
|
||||
2,128, 0,128,128,128,128,128,
|
||||
4, 32, 0, 32, 32, 32, 32,192,
|
||||
5,128,128,144,160,192,160,144,
|
||||
2,128,128,128,128,128,128,128,
|
||||
6, 0, 0,208,168,168,168,168,
|
||||
5, 0, 0,224,144,144,144,144,
|
||||
5, 0, 0, 96,144,144,144, 96,
|
||||
5, 0,224,144,144,224,128,128,
|
||||
5, 0,112,144,144,112, 16, 16,
|
||||
5, 0, 0,176,192,128,128,128,
|
||||
5, 0, 0,112,128, 96, 16,224,
|
||||
4, 64, 64,224, 64, 64, 64, 32,
|
||||
5, 0, 0,144,144,144,144,112,
|
||||
5, 0, 0,144,144,144,160,192,
|
||||
6, 0, 0,136,136,168,168, 80,
|
||||
5, 0, 0,144,144, 96,144,144,
|
||||
5, 0,144,144,144,112, 16, 96,
|
||||
5, 0, 0,240, 32, 64,128,240,
|
||||
4, 32, 64, 64,128, 64, 64, 32,
|
||||
3, 64, 64, 64, 64, 64, 64, 64,
|
||||
4,128, 64, 64, 32, 64, 64,128,
|
||||
6, 0,104,176, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
int GetCharNumber(char ch)
|
||||
{
|
||||
ch -= 32;
|
||||
return (ch < 0 || ch > 98) ? 0 : ch;
|
||||
}
|
||||
|
||||
int GetCharWidth(char ch)
|
||||
{
|
||||
return _font[GetCharNumber(ch) * 8];
|
||||
}
|
||||
|
||||
protected:
|
||||
void InternalDraw()
|
||||
{
|
||||
int x = _x;
|
||||
int y = _y;
|
||||
for(char c : _text) {
|
||||
if(c == '\n') {
|
||||
x = _x;
|
||||
y += 9;
|
||||
} else if(c == '\t') {
|
||||
x += (_tabSpace - (((x - _x) / 8) % _tabSpace)) * 8;
|
||||
} else {
|
||||
int ch = GetCharNumber(c);
|
||||
int width = GetCharWidth(c);
|
||||
int rowOffset = (c == 'y' || c == 'g' || c == 'p' || c == 'q') ? 1 : 0;
|
||||
for(int j = 0; j < 8; j++) {
|
||||
uint8_t rowData = (j == 7 && rowOffset == 0 || j == 0 && rowOffset == 1) ? 0 : _font[ch * 8 + 1 + j - rowOffset];
|
||||
for(int i = 0; i < width; i++) {
|
||||
int drawFg = (rowData >> (7 - i)) & 0x01;
|
||||
DrawPixel(x + i, y + j, drawFg ? _color : _backColor);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < width; i++) {
|
||||
DrawPixel(x + i, y - 1, _backColor);
|
||||
}
|
||||
x += width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DrawStringCommand(int x, int y, string text, int color, int backColor, int frameCount) :
|
||||
_x(x), _y(y), _text(text), _color(color), _backColor(backColor), DrawCommand(frameCount)
|
||||
{
|
||||
if(!(_color & 0xFF000000)) {
|
||||
_color |= 0xFF000000;
|
||||
}
|
||||
if(!(_backColor & 0xFF000000)) {
|
||||
_backColor |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -359,7 +359,7 @@ int32_t ExpressionEvaluator::Evaluate(vector<int> &rpnList, DebugState &state, E
|
|||
case EvalOperators::BinaryNot: token = ~right; break;
|
||||
case EvalOperators::LogicalNot: token = !right; break;
|
||||
case EvalOperators::Bracket: token = _debugger->GetMemoryDumper()->GetMemoryValue(DebugMemoryType::CpuMemory, right); break;
|
||||
case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValue(DebugMemoryType::CpuMemory, right) | (_debugger->GetMemoryDumper()->GetMemoryValue(DebugMemoryType::CpuMemory, right+1) << 8); break;
|
||||
case EvalOperators::Braces: token = _debugger->GetMemoryDumper()->GetMemoryValueWord(DebugMemoryType::CpuMemory, right); break;
|
||||
default: throw std::runtime_error("Invalid operator");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ void HdAudioDevice::ProcessControlFlags(uint8_t flags)
|
|||
|
||||
void HdAudioDevice::GetMemoryRanges(MemoryRanges & ranges)
|
||||
{
|
||||
bool useAlternateRegisters = (_hdData->OptionFlags & (int)HdPackOptions::AlternateRegisterRange);
|
||||
bool useAlternateRegisters = (_hdData->OptionFlags & (int)HdPackOptions::AlternateRegisterRange) == (int)HdPackOptions::AlternateRegisterRange;
|
||||
ranges.SetAllowOverride();
|
||||
|
||||
if(useAlternateRegisters) {
|
||||
|
|
825
Core/LuaApi.cpp
Normal file
825
Core/LuaApi.cpp
Normal file
|
@ -0,0 +1,825 @@
|
|||
#include "stdafx.h"
|
||||
#include "LuaApi.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
#include "../Lua/lua.hpp"
|
||||
#include "LuaCallHelper.h"
|
||||
#include "Debugger.h"
|
||||
#include "MemoryDumper.h"
|
||||
#include "MessageManager.h"
|
||||
#include "ScriptingContext.h"
|
||||
#include "DebugHud.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "RewindManager.h"
|
||||
#include "SaveStateManager.h"
|
||||
#include "Console.h"
|
||||
#include "IKeyManager.h"
|
||||
#include "ControlManager.h"
|
||||
#include "StandardController.h"
|
||||
#include "PPU.h"
|
||||
#include "CheatManager.h"
|
||||
|
||||
#define lua_pushintvalue(name, value) lua_pushliteral(lua, #name); lua_pushinteger(lua, (int)value); lua_settable(lua, -3);
|
||||
#define lua_pushboolvalue(name, value) lua_pushliteral(lua, #name); lua_pushboolean(lua, (int)value); lua_settable(lua, -3);
|
||||
#define lua_starttable(name) lua_pushliteral(lua, name); lua_newtable(lua);
|
||||
#define lua_endtable() lua_settable(lua, -3);
|
||||
#define lua_readint(name, dest) lua_getfield(lua, -1, #name); dest = l.ReadInteger();
|
||||
#define lua_readbool(name, dest) lua_getfield(lua, -1, #name); dest = l.ReadBool();
|
||||
#define error(text) luaL_error(lua, text); return 0;
|
||||
#define errorCond(cond, text) if(cond) { luaL_error(lua, text); return 0; }
|
||||
#define checkparams() if(!l.CheckParamCount()) { return 0; }
|
||||
#define checkminparams(x) if(!l.CheckParamCount(x)) { return 0; }
|
||||
#define checkstartframe() if(!_context->CheckInStartFrameEvent()) { error("This function cannot be called outside StartFrame event callback"); return 0; }
|
||||
|
||||
enum class ExecuteCountType
|
||||
{
|
||||
CpuCycles = 0,
|
||||
PpuCycles = 1,
|
||||
CpuInstructions = 2
|
||||
};
|
||||
|
||||
Debugger* LuaApi::_debugger = nullptr;
|
||||
MemoryDumper* LuaApi::_memoryDumper = nullptr;
|
||||
ScriptingContext* LuaApi::_context = nullptr;
|
||||
|
||||
void LuaApi::SetContext(ScriptingContext * context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
void LuaApi::RegisterDebugger(Debugger * debugger)
|
||||
{
|
||||
_debugger = debugger;
|
||||
_memoryDumper = debugger->GetMemoryDumper().get();
|
||||
}
|
||||
|
||||
int LuaApi::GetLibrary(lua_State *lua)
|
||||
{
|
||||
static const luaL_Reg apilib[] = {
|
||||
{ "read", LuaApi::ReadMemory },
|
||||
{ "write", LuaApi::WriteMemory },
|
||||
{ "debugRead", LuaApi::DebugReadMemory },
|
||||
{ "debugWrite", LuaApi::DebugWriteMemory },
|
||||
{ "readWord", LuaApi::ReadMemoryWord },
|
||||
{ "writeWord", LuaApi::WriteMemoryWord },
|
||||
{ "debugReadWord", LuaApi::DebugReadMemoryWord },
|
||||
{ "debugWriteWord", LuaApi::DebugWriteMemoryWord },
|
||||
{ "revertPrgChrChanges", LuaApi::RevertPrgChrChanges },
|
||||
{ "addMemoryCallback", LuaApi::RegisterMemoryCallback },
|
||||
{ "removeMemoryCallback", LuaApi::UnregisterMemoryCallback },
|
||||
{ "addEventCallback", LuaApi::RegisterEventCallback },
|
||||
{ "removeEventCallback", LuaApi::UnregisterEventCallback },
|
||||
{ "drawString", LuaApi::DrawString },
|
||||
{ "drawPixel", LuaApi::DrawPixel },
|
||||
{ "drawLine", LuaApi::DrawLine },
|
||||
{ "drawRectangle", LuaApi::DrawRectangle },
|
||||
{ "clearScreen", LuaApi::ClearScreen },
|
||||
{ "getPixel", LuaApi::GetPixel },
|
||||
{ "getMouseState", LuaApi::GetMouseState },
|
||||
{ "log", LuaApi::Log },
|
||||
{ "displayMessage", LuaApi::DisplayMessage },
|
||||
{ "reset", LuaApi::Reset },
|
||||
{ "breakExecution", LuaApi::Break },
|
||||
{ "resume", LuaApi::Resume },
|
||||
{ "execute", LuaApi::Execute },
|
||||
{ "rewind", LuaApi::Rewind },
|
||||
{ "takeScreenshot", LuaApi::TakeScreenshot },
|
||||
{ "saveSavestate", LuaApi::SaveSavestate },
|
||||
{ "loadSavestate", LuaApi::LoadSavestate },
|
||||
{ "getInput", LuaApi::GetInput },
|
||||
{ "setInput", LuaApi::SetInput },
|
||||
{ "addCheat", LuaApi::AddCheat },
|
||||
{ "clearCheats", LuaApi::ClearCheats },
|
||||
{ "setState", LuaApi::SetState },
|
||||
{ "getState", LuaApi::GetState },
|
||||
{ NULL,NULL }
|
||||
};
|
||||
|
||||
luaL_newlib(lua, apilib);
|
||||
|
||||
//Expose DebugMemoryType enum as "memory.type"
|
||||
lua_pushliteral(lua, "memType");
|
||||
lua_newtable(lua);
|
||||
lua_pushintvalue(cpu, DebugMemoryType::CpuMemory);
|
||||
lua_pushintvalue(ppu, DebugMemoryType::PpuMemory);
|
||||
lua_pushintvalue(palette, DebugMemoryType::PaletteMemory);
|
||||
lua_pushintvalue(oam, DebugMemoryType::SpriteMemory);
|
||||
lua_pushintvalue(secondaryOam, DebugMemoryType::SecondarySpriteMemory);
|
||||
lua_pushintvalue(prgRom, DebugMemoryType::PrgRom);
|
||||
lua_pushintvalue(chrRom, DebugMemoryType::ChrRom);
|
||||
lua_pushintvalue(chrRam, DebugMemoryType::ChrRam);
|
||||
lua_pushintvalue(workRam, DebugMemoryType::WorkRam);
|
||||
lua_pushintvalue(saveRam, DebugMemoryType::SaveRam);
|
||||
lua_settable(lua, -3);
|
||||
|
||||
lua_pushliteral(lua, "memCallbackType");
|
||||
lua_newtable(lua);
|
||||
lua_pushintvalue(cpuRead, CallbackType::CpuRead);
|
||||
lua_pushintvalue(cpuWrite, CallbackType::CpuWrite);
|
||||
lua_pushintvalue(cpuExec, CallbackType::CpuExec);
|
||||
lua_pushintvalue(ppuRead, CallbackType::PpuRead);
|
||||
lua_pushintvalue(ppuWrite, CallbackType::PpuWrite);
|
||||
lua_settable(lua, -3);
|
||||
|
||||
lua_pushliteral(lua, "eventCallbackType");
|
||||
lua_newtable(lua);
|
||||
lua_pushintvalue(power, EventType::Power);
|
||||
lua_pushintvalue(reset, EventType::Reset);
|
||||
lua_pushintvalue(nmi, EventType::Nmi);
|
||||
lua_pushintvalue(irq, EventType::Irq);
|
||||
lua_pushintvalue(startFrame, EventType::StartFrame);
|
||||
lua_pushintvalue(endFrame, EventType::EndFrame);
|
||||
lua_pushintvalue(codeBreak, EventType::CodeBreak);
|
||||
lua_settable(lua, -3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaApi::ReadMemory(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
DebugMemoryType type = (DebugMemoryType)l.ReadInteger();
|
||||
int address = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(address < 0, "address must be >= 0");
|
||||
l.Return(_memoryDumper->GetMemoryValue(type, address, false));
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::WriteMemory(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
DebugMemoryType type = (DebugMemoryType)l.ReadInteger();
|
||||
int value = l.ReadInteger();
|
||||
int address = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(value > 255 || value < -128, "value out of range");
|
||||
errorCond(address < 0, "address must be >= 0");
|
||||
_memoryDumper->SetMemoryValue(type, address, value, false);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::DebugReadMemory(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
DebugMemoryType type = (DebugMemoryType)l.ReadInteger();
|
||||
int address = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(address < 0, "address must be >= 0");
|
||||
l.Return(_memoryDumper->GetMemoryValue(type, address));
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::DebugWriteMemory(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
DebugMemoryType type = (DebugMemoryType)l.ReadInteger();
|
||||
int value = l.ReadInteger();
|
||||
int address = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(value > 255 || value < -128, "value out of range");
|
||||
errorCond(address < 0, "address must be >= 0");
|
||||
_memoryDumper->SetMemoryValue(type, address, value);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::ReadMemoryWord(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
DebugMemoryType type = (DebugMemoryType)l.ReadInteger();
|
||||
int address = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(address < 0, "address must be >= 0");
|
||||
l.Return(_memoryDumper->GetMemoryValueWord(type, address, false));
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::WriteMemoryWord(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
DebugMemoryType type = (DebugMemoryType)l.ReadInteger();
|
||||
int value = l.ReadInteger();
|
||||
int address = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(value > 65535 || value < -32768, "value out of range");
|
||||
errorCond(address < 0, "address must be >= 0");
|
||||
_memoryDumper->SetMemoryValueWord(type, address, value, false);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::DebugReadMemoryWord(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
DebugMemoryType type = (DebugMemoryType)l.ReadInteger();
|
||||
int address = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(address < 0, "address must be >= 0");
|
||||
l.Return(_memoryDumper->GetMemoryValueWord(type, address));
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::DebugWriteMemoryWord(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
DebugMemoryType type = (DebugMemoryType)l.ReadInteger();
|
||||
int value = l.ReadInteger();
|
||||
int address = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(value > 65535 || value < -32768, "value out of range");
|
||||
errorCond(address < 0, "address must be >= 0");
|
||||
_memoryDumper->SetMemoryValueWord(type, address, value);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::RevertPrgChrChanges(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
checkparams();
|
||||
_debugger->RevertPrgChrChanges();
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::RegisterMemoryCallback(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
int endAddr = l.ReadInteger();
|
||||
int startAddr = l.ReadInteger();
|
||||
CallbackType type = (CallbackType)l.ReadInteger();
|
||||
int reference = l.GetReference();
|
||||
checkparams();
|
||||
errorCond(startAddr > endAddr, "start address must be <= end address");
|
||||
errorCond(type < CallbackType::CpuRead || type > CallbackType::PpuWrite, "the specified type is invalid");
|
||||
errorCond(reference == LUA_NOREF, "the specified function could not be found");
|
||||
_context->RegisterMemoryCallback(type, startAddr, endAddr, reference);
|
||||
_context->Log("Registered memory callback from $" + HexUtilities::ToHex((uint32_t)startAddr) + " to $" + HexUtilities::ToHex((uint32_t)endAddr));
|
||||
l.Return(reference);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::UnregisterMemoryCallback(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
int endAddr = l.ReadInteger();
|
||||
int startAddr = l.ReadInteger();
|
||||
CallbackType type = (CallbackType)l.ReadInteger();
|
||||
int reference = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(startAddr > endAddr, "start address must be <= end address");
|
||||
errorCond(type < CallbackType::CpuRead || type > CallbackType::PpuWrite, "the specified type is invalid");
|
||||
errorCond(reference == LUA_NOREF, "function reference is invalid");
|
||||
_context->UnregisterMemoryCallback(type, startAddr, endAddr, reference);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::RegisterEventCallback(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
EventType type = (EventType)l.ReadInteger();
|
||||
int reference = l.GetReference();
|
||||
checkparams();
|
||||
errorCond(type < EventType::Power || type > EventType::CodeBreak, "the specified type is invalid");
|
||||
errorCond(reference == LUA_NOREF, "the specified function could not be found");
|
||||
_context->RegisterEventCallback(type, reference);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::UnregisterEventCallback(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
EventType type = (EventType)l.ReadInteger();
|
||||
int reference = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(type < EventType::Power || type > EventType::CodeBreak, "the specified type is invalid");
|
||||
errorCond(reference == LUA_NOREF, "function reference is invalid");
|
||||
_context->UnregisterEventCallback(type, reference);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::DrawString(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
l.ForceParamCount(6);
|
||||
int frameCount = l.ReadInteger(1);
|
||||
int backColor = l.ReadInteger(0);
|
||||
int color = l.ReadInteger(0xFFFFFFFF);
|
||||
string text = l.ReadString();
|
||||
int y = l.ReadInteger();
|
||||
int x = l.ReadInteger();
|
||||
checkminparams(3);
|
||||
|
||||
DebugHud::GetInstance()->DrawString(x, y, text, color, backColor, frameCount);
|
||||
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::DrawLine(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
int frameCount = l.ReadInteger(1);
|
||||
int color = l.ReadInteger(0xFFFFFFFF);
|
||||
int y2 = l.ReadInteger();
|
||||
int x2 = l.ReadInteger();
|
||||
int y = l.ReadInteger();
|
||||
int x = l.ReadInteger();
|
||||
checkminparams(4);
|
||||
|
||||
DebugHud::GetInstance()->DrawLine(x, y, x2, y2, color, frameCount);
|
||||
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::DrawPixel(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
int frameCount = l.ReadInteger(1);
|
||||
int color = l.ReadInteger();
|
||||
int y = l.ReadInteger();
|
||||
int x = l.ReadInteger();
|
||||
checkminparams(3);
|
||||
|
||||
DebugHud::GetInstance()->DrawPixel(x, y, color, frameCount);
|
||||
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::DrawRectangle(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
int frameCount = l.ReadInteger(1);
|
||||
bool fill = l.ReadBool(false);
|
||||
int color = l.ReadInteger(0xFFFFFFFF);
|
||||
int height = l.ReadInteger();
|
||||
int width = l.ReadInteger();
|
||||
int y = l.ReadInteger();
|
||||
int x = l.ReadInteger();
|
||||
checkminparams(4);
|
||||
errorCond(height <= 0, "height must be >= 1");
|
||||
errorCond(width <= 0, "width must be >= 1");
|
||||
|
||||
DebugHud::GetInstance()->DrawRectangle(x, y, width, height, color, fill, frameCount);
|
||||
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::ClearScreen(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
checkparams();
|
||||
DebugHud::GetInstance()->ClearScreen();
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::GetPixel(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
int y = l.ReadInteger();
|
||||
int x = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(x < 0 || x > 255 || y < 0 || y > 239, "invalid x,y coordinates (must be between 0-255, 0-239)");
|
||||
|
||||
//Ignores intensify & grayscale bits
|
||||
l.Return(EmulationSettings::GetRgbPalette()[PPU::GetPixel(x, y) & 0x3F]);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::GetMouseState(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
MousePosition pos = ControlManager::GetMousePosition();
|
||||
checkparams();
|
||||
lua_newtable(lua);
|
||||
lua_pushintvalue(x, pos.X);
|
||||
lua_pushintvalue(y, pos.Y);
|
||||
lua_pushboolvalue(left, ControlManager::IsMouseButtonPressed(MouseButton::LeftButton));
|
||||
lua_pushboolvalue(middle, ControlManager::IsMouseButtonPressed(MouseButton::MiddleButton));
|
||||
lua_pushboolvalue(right, ControlManager::IsMouseButtonPressed(MouseButton::RightButton));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaApi::Log(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
string text = l.ReadString();
|
||||
checkparams();
|
||||
_context->Log(text);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::DisplayMessage(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
string text = l.ReadString();
|
||||
string category = l.ReadString();
|
||||
checkparams();
|
||||
MessageManager::DisplayMessage(category, text);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::Reset(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
checkparams();
|
||||
Console::RequestReset();
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::Break(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
checkparams();
|
||||
_debugger->Step(1);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::Resume(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
checkparams();
|
||||
_debugger->Run();
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::Execute(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
ExecuteCountType type = (ExecuteCountType)l.ReadInteger();
|
||||
int count = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(count <= 0, "count must be >= 1");
|
||||
errorCond(type < ExecuteCountType::CpuCycles || type > ExecuteCountType::CpuInstructions, "type is invalid");
|
||||
|
||||
switch(type) {
|
||||
case ExecuteCountType::CpuCycles: _debugger->StepCycles(count); break;
|
||||
case ExecuteCountType::PpuCycles: _debugger->PpuStep(count); break;
|
||||
case ExecuteCountType::CpuInstructions: _debugger->Step(count); break;
|
||||
}
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::Rewind(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
int seconds = l.ReadInteger();
|
||||
checkparams();
|
||||
checkstartframe();
|
||||
errorCond(seconds <= 0, "seconds must be >= 1");
|
||||
RewindManager::RewindSeconds(seconds);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::TakeScreenshot(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
checkparams();
|
||||
stringstream ss;
|
||||
VideoDecoder::GetInstance()->TakeScreenshot(ss);
|
||||
l.Return(ss.str());
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::SaveSavestate(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
checkstartframe();
|
||||
stringstream ss;
|
||||
SaveStateManager::SaveState(ss);
|
||||
l.Return(ss.str());
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::LoadSavestate(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
string savestate = l.ReadString();
|
||||
checkparams();
|
||||
checkstartframe();
|
||||
stringstream ss;
|
||||
ss << savestate;
|
||||
l.Return(SaveStateManager::LoadState(ss));
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::GetInput(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
int port = l.ReadInteger();
|
||||
checkparams();
|
||||
errorCond(port < 0 || port > 3, "Invalid port number - must be between 0 to 3");
|
||||
|
||||
shared_ptr<StandardController> controller = std::dynamic_pointer_cast<StandardController>(ControlManager::GetControlDevice(port));
|
||||
errorCond(controller == nullptr, "Input port must be connected to a standard controller");
|
||||
|
||||
ButtonState state = controller->GetButtonState();
|
||||
lua_newtable(lua);
|
||||
lua_pushboolvalue(a, state.A);
|
||||
lua_pushboolvalue(b, state.B);
|
||||
lua_pushboolvalue(start, state.Start);
|
||||
lua_pushboolvalue(select, state.Select);
|
||||
lua_pushboolvalue(up, state.Up);
|
||||
lua_pushboolvalue(down, state.Down);
|
||||
lua_pushboolvalue(left, state.Left);
|
||||
lua_pushboolvalue(right, state.Right);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaApi::SetInput(lua_State *lua)
|
||||
{
|
||||
lua_settop(lua, 2);
|
||||
luaL_checktype(lua, 2, LUA_TTABLE);
|
||||
lua_getfield(lua, 2, "a");
|
||||
lua_getfield(lua, 2, "b");
|
||||
lua_getfield(lua, 2, "start");
|
||||
lua_getfield(lua, 2, "select");
|
||||
lua_getfield(lua, 2, "up");
|
||||
lua_getfield(lua, 2, "down");
|
||||
lua_getfield(lua, 2, "left");
|
||||
lua_getfield(lua, 2, "right");
|
||||
|
||||
LuaCallHelper l(lua);
|
||||
ButtonState buttonState;
|
||||
buttonState.Right = l.ReadBool();
|
||||
buttonState.Left = l.ReadBool();
|
||||
buttonState.Down = l.ReadBool();
|
||||
buttonState.Up = l.ReadBool();
|
||||
buttonState.Select = l.ReadBool();
|
||||
buttonState.Start = l.ReadBool();
|
||||
buttonState.B = l.ReadBool();
|
||||
buttonState.A = l.ReadBool();
|
||||
lua_pop(lua, 1);
|
||||
int port = l.ReadInteger();
|
||||
|
||||
_debugger->SetInputOverride(port, buttonState.ToByte());
|
||||
errorCond(port < 0 || port > 3, "Invalid port number - must be between 0 to 3");
|
||||
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::AddCheat(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
string gamegenieCode = l.ReadString();
|
||||
checkparams();
|
||||
errorCond(gamegenieCode.length() != 6 && gamegenieCode.length() != 8, "Game genie code must be 6 or 8 characters long");
|
||||
errorCond(gamegenieCode.find_first_not_of("APZLGITYEOXUKSVN", 0) != string::npos, "Game genie code may only contain these characters: AEGIKLNOPSTUVXYZ");
|
||||
CheatManager::GetInstance()->AddGameGenieCode(gamegenieCode);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::ClearCheats(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
checkparams();
|
||||
CheatManager::GetInstance()->ClearCodes();
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::SetState(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
lua_settop(lua, 1);
|
||||
luaL_checktype(lua, -1, LUA_TTABLE);
|
||||
|
||||
DebugState state;
|
||||
|
||||
lua_getfield(lua, -1, "cpu");
|
||||
luaL_checktype(lua, -1, LUA_TTABLE);
|
||||
lua_readint(a, state.CPU.A);
|
||||
lua_readint(cycleCount, state.CPU.CycleCount);
|
||||
lua_readint(irqFlag, state.CPU.IRQFlag);
|
||||
lua_readbool(nmiFlag, state.CPU.NMIFlag);
|
||||
lua_readint(pc, state.CPU.PC);
|
||||
lua_readint(ps, state.CPU.PS);
|
||||
lua_readint(sp, state.CPU.SP);
|
||||
lua_readint(x, state.CPU.X);
|
||||
lua_readint(y, state.CPU.Y);
|
||||
lua_pop(lua, 1);
|
||||
|
||||
lua_getfield(lua, -1, "ppu");
|
||||
luaL_checktype(lua, -1, LUA_TTABLE);
|
||||
lua_readint(cycle, state.PPU.Cycle);
|
||||
lua_readint(frameCount, state.PPU.FrameCount);
|
||||
lua_readint(scanline, state.PPU.Scanline);
|
||||
|
||||
lua_getfield(lua, -1, "control");
|
||||
luaL_checktype(lua, -1, LUA_TTABLE);
|
||||
lua_readbool(backgroundEnabled, state.PPU.ControlFlags.BackgroundEnabled);
|
||||
lua_readbool(backgroundMask, state.PPU.ControlFlags.BackgroundMask);
|
||||
lua_readint(backgroundPatternAddr, state.PPU.ControlFlags.BackgroundPatternAddr);
|
||||
lua_readbool(grayscale, state.PPU.ControlFlags.Grayscale);
|
||||
lua_readbool(intensifyBlue, state.PPU.ControlFlags.IntensifyBlue);
|
||||
lua_readbool(intensifyGreen, state.PPU.ControlFlags.IntensifyGreen);
|
||||
lua_readbool(intensifyRed, state.PPU.ControlFlags.IntensifyRed);
|
||||
lua_readbool(largeSprites, state.PPU.ControlFlags.LargeSprites);
|
||||
lua_readbool(spriteMask, state.PPU.ControlFlags.SpriteMask);
|
||||
lua_readint(spritePatternAddr, state.PPU.ControlFlags.SpritePatternAddr);
|
||||
lua_readbool(spritesEnabled, state.PPU.ControlFlags.SpritesEnabled);
|
||||
lua_readbool(nmiOnVBlank, state.PPU.ControlFlags.VBlank);
|
||||
lua_readbool(verticalWrite, state.PPU.ControlFlags.VerticalWrite);
|
||||
lua_pop(lua, 1);
|
||||
|
||||
lua_getfield(lua, -1, "status");
|
||||
luaL_checktype(lua, -1, LUA_TTABLE);
|
||||
lua_readbool(sprite0Hit, state.PPU.StatusFlags.Sprite0Hit);
|
||||
lua_readbool(spriteOverflow, state.PPU.StatusFlags.SpriteOverflow);
|
||||
lua_readbool(verticalBlank, state.PPU.StatusFlags.VerticalBlank);
|
||||
lua_pop(lua, 1);
|
||||
|
||||
lua_getfield(lua, -1, "state");
|
||||
luaL_checktype(lua, -1, LUA_TTABLE);
|
||||
lua_readint(control, state.PPU.State.Control);
|
||||
lua_readint(highBitShift, state.PPU.State.HighBitShift);
|
||||
lua_readint(lowBitShift, state.PPU.State.LowBitShift);
|
||||
lua_readint(mask, state.PPU.State.Mask);
|
||||
lua_readint(spriteRamAddr, state.PPU.State.SpriteRamAddr);
|
||||
lua_readint(status, state.PPU.State.Status);
|
||||
lua_readint(tmpVideoRamAddr, state.PPU.State.TmpVideoRamAddr);
|
||||
lua_readint(videoRamAddr, state.PPU.State.VideoRamAddr);
|
||||
lua_readbool(writeToggle, state.PPU.State.WriteToggle);
|
||||
lua_readint(xScroll, state.PPU.State.XScroll);
|
||||
lua_pop(lua, 1);
|
||||
|
||||
lua_pop(lua, 1);
|
||||
|
||||
_debugger->SetState(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LuaApi::GetState(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
checkparams();
|
||||
DebugState state;
|
||||
_debugger->GetState(&state, true);
|
||||
|
||||
lua_newtable(lua);
|
||||
lua_pushintvalue(region, state.Model);
|
||||
|
||||
lua_starttable("cpu");
|
||||
lua_pushintvalue(a, state.CPU.A);
|
||||
lua_pushintvalue(cycleCount, state.CPU.CycleCount);
|
||||
lua_pushintvalue(irqFlag, state.CPU.IRQFlag);
|
||||
lua_pushboolvalue(nmiFlag, state.CPU.NMIFlag);
|
||||
lua_pushintvalue(pc, state.CPU.PC);
|
||||
lua_pushintvalue(status, state.CPU.PS);
|
||||
lua_pushintvalue(sp, state.CPU.SP);
|
||||
lua_pushintvalue(x, state.CPU.X);
|
||||
lua_pushintvalue(y, state.CPU.Y);
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("ppu");
|
||||
lua_pushintvalue(cycle, state.PPU.Cycle);
|
||||
lua_pushintvalue(frameCount, state.PPU.FrameCount);
|
||||
lua_pushintvalue(scanline, state.PPU.Scanline);
|
||||
|
||||
lua_starttable("control");
|
||||
lua_pushboolvalue(backgroundEnabled, state.PPU.ControlFlags.BackgroundEnabled);
|
||||
lua_pushboolvalue(backgroundMask, state.PPU.ControlFlags.BackgroundMask);
|
||||
lua_pushintvalue(backgroundPatternAddr, state.PPU.ControlFlags.BackgroundPatternAddr);
|
||||
lua_pushboolvalue(grayscale, state.PPU.ControlFlags.Grayscale);
|
||||
lua_pushboolvalue(intensifyBlue, state.PPU.ControlFlags.IntensifyBlue);
|
||||
lua_pushboolvalue(intensifyGreen, state.PPU.ControlFlags.IntensifyGreen);
|
||||
lua_pushboolvalue(intensifyRed, state.PPU.ControlFlags.IntensifyRed);
|
||||
lua_pushboolvalue(largeSprites, state.PPU.ControlFlags.LargeSprites);
|
||||
lua_pushboolvalue(spriteMask, state.PPU.ControlFlags.SpriteMask);
|
||||
lua_pushintvalue(spritePatternAddr, state.PPU.ControlFlags.SpritePatternAddr);
|
||||
lua_pushboolvalue(spritesEnabled, state.PPU.ControlFlags.SpritesEnabled);
|
||||
lua_pushboolvalue(nmiOnVBlank, state.PPU.ControlFlags.VBlank);
|
||||
lua_pushboolvalue(verticalWrite, state.PPU.ControlFlags.VerticalWrite);
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("status");
|
||||
lua_pushboolvalue(sprite0Hit, state.PPU.StatusFlags.Sprite0Hit);
|
||||
lua_pushboolvalue(spriteOverflow, state.PPU.StatusFlags.SpriteOverflow);
|
||||
lua_pushboolvalue(verticalBlank, state.PPU.StatusFlags.VerticalBlank);
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("state");
|
||||
lua_pushintvalue(control, state.PPU.State.Control);
|
||||
lua_pushintvalue(highBitShift, state.PPU.State.HighBitShift);
|
||||
lua_pushintvalue(lowBitShift, state.PPU.State.LowBitShift);
|
||||
lua_pushintvalue(mask, state.PPU.State.Mask);
|
||||
lua_pushintvalue(spriteRamAddr, state.PPU.State.SpriteRamAddr);
|
||||
lua_pushintvalue(status, state.PPU.State.Status);
|
||||
lua_pushintvalue(tmpVideoRamAddr, state.PPU.State.TmpVideoRamAddr);
|
||||
lua_pushintvalue(videoRamAddr, state.PPU.State.VideoRamAddr);
|
||||
lua_pushboolvalue(writeToggle, state.PPU.State.WriteToggle);
|
||||
lua_pushintvalue(xScroll, state.PPU.State.XScroll);
|
||||
lua_endtable();
|
||||
|
||||
lua_endtable(); //end ppu
|
||||
|
||||
lua_starttable("cart");
|
||||
lua_pushintvalue(chrPageCount, state.Cartridge.ChrPageCount);
|
||||
lua_pushintvalue(chrPageSize, state.Cartridge.ChrPageSize);
|
||||
lua_pushintvalue(chrRamSize, state.Cartridge.ChrRamSize);
|
||||
lua_pushintvalue(chrRomSize, state.Cartridge.ChrRomSize);
|
||||
lua_pushintvalue(prgPageCount, state.Cartridge.PrgPageCount);
|
||||
lua_pushintvalue(prgPageSize, state.Cartridge.PrgPageSize);
|
||||
lua_pushintvalue(prgRomSize, state.Cartridge.PrgRomSize);
|
||||
|
||||
lua_starttable("selectedPrgPages");
|
||||
for(int i = 0, max = 0x8000 / state.Cartridge.PrgPageSize; i < max; i++) {
|
||||
lua_pushinteger(lua, i + 1);
|
||||
lua_pushinteger(lua, (int32_t)state.Cartridge.PrgSelectedPages[i]);
|
||||
lua_settable(lua, -3);
|
||||
}
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("selectedChrPages");
|
||||
for(int i = 0, max = 0x2000 / state.Cartridge.ChrPageSize; i < max; i++) {
|
||||
lua_pushinteger(lua, i + 1);
|
||||
lua_pushinteger(lua, (int32_t)state.Cartridge.ChrSelectedPages[i]);
|
||||
lua_settable(lua, -3);
|
||||
}
|
||||
lua_endtable();
|
||||
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("apu");
|
||||
|
||||
lua_starttable("square1");
|
||||
PushSquareState(lua, state.APU.Square1);
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("square2");
|
||||
PushSquareState(lua, state.APU.Square2);
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("triangle");
|
||||
lua_pushboolvalue(enabled, state.APU.Triangle.Enabled);
|
||||
lua_pushintvalue(frequency, state.APU.Triangle.Frequency);
|
||||
PushLengthCounterState(lua, state.APU.Triangle.LengthCounter);
|
||||
lua_pushintvalue(outputVolume, state.APU.Triangle.OutputVolume);
|
||||
lua_pushintvalue(period, state.APU.Triangle.Period);
|
||||
lua_pushintvalue(sequencePosition, state.APU.Triangle.SequencePosition);
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("noise");
|
||||
lua_pushboolvalue(enabled, state.APU.Noise.Enabled);
|
||||
lua_pushintvalue(frequency, state.APU.Noise.Frequency);
|
||||
PushEnvelopeState(lua, state.APU.Noise.Envelope);
|
||||
PushLengthCounterState(lua, state.APU.Noise.LengthCounter);
|
||||
lua_pushboolvalue(modeFlag, state.APU.Noise.ModeFlag);
|
||||
lua_pushintvalue(outputVolume, state.APU.Noise.OutputVolume);
|
||||
lua_pushintvalue(period, state.APU.Noise.Period);
|
||||
lua_pushintvalue(shiftRegister, state.APU.Noise.ShiftRegister);
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("dmc");
|
||||
lua_pushintvalue(bytesRemaining, state.APU.Dmc.BytesRemaining);
|
||||
lua_pushintvalue(frequency, state.APU.Dmc.Frequency);
|
||||
lua_pushboolvalue(irqEnabled, state.APU.Dmc.IrqEnabled);
|
||||
lua_pushboolvalue(loop, state.APU.Dmc.Loop);
|
||||
lua_pushintvalue(outputVolume, state.APU.Dmc.OutputVolume);
|
||||
lua_pushintvalue(period, state.APU.Dmc.Period);
|
||||
lua_pushintvalue(sampleAddr, state.APU.Dmc.SampleAddr);
|
||||
lua_pushintvalue(sampleLength, state.APU.Dmc.SampleLength);
|
||||
lua_endtable();
|
||||
|
||||
lua_starttable("frameCounter");
|
||||
lua_pushintvalue(fiveStepMode, state.APU.FrameCounter.FiveStepMode);
|
||||
lua_pushboolvalue(irqEnabled, state.APU.FrameCounter.IrqEnabled);
|
||||
lua_pushintvalue(sequencePosition, state.APU.FrameCounter.SequencePosition);
|
||||
lua_endtable();
|
||||
|
||||
lua_endtable(); //end apu
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LuaApi::PushSquareState(lua_State *lua, ApuSquareState & state)
|
||||
{
|
||||
lua_pushintvalue(duty, state.Duty);
|
||||
lua_pushintvalue(dutyPosition, state.DutyPosition);
|
||||
lua_pushintvalue(frequency, state.Frequency);
|
||||
lua_pushintvalue(period, state.Period);
|
||||
lua_pushboolvalue(sweepEnabled, state.SweepEnabled);
|
||||
lua_pushboolvalue(sweepNegate, state.SweepNegate);
|
||||
lua_pushintvalue(sweepPeriod, state.SweepPeriod);
|
||||
lua_pushintvalue(sweepShift, state.SweepShift);
|
||||
lua_pushboolvalue(enabled, state.Enabled);
|
||||
lua_pushintvalue(outputVolume, state.OutputVolume);
|
||||
PushEnvelopeState(lua, state.Envelope);
|
||||
PushLengthCounterState(lua, state.LengthCounter);
|
||||
}
|
||||
|
||||
void LuaApi::PushEnvelopeState(lua_State *lua, ApuEnvelopeState & state)
|
||||
{
|
||||
lua_starttable("envelope");
|
||||
lua_pushboolvalue(startFlag, state.StartFlag);
|
||||
lua_pushboolvalue(loop, state.Loop);
|
||||
lua_pushboolvalue(constantVolume, state.ConstantVolume);
|
||||
lua_pushintvalue(divider, state.Divider);
|
||||
lua_pushintvalue(counter, state.Counter);
|
||||
lua_pushintvalue(volume, state.Volume);
|
||||
lua_endtable();
|
||||
}
|
||||
|
||||
void LuaApi::PushLengthCounterState(lua_State *lua, ApuLengthCounterState & state)
|
||||
{
|
||||
lua_starttable("lengthCounter");
|
||||
lua_pushboolvalue(halt, state.Halt);
|
||||
lua_pushintvalue(counter, state.Counter);
|
||||
lua_pushintvalue(reloadValue, state.ReloadValue);
|
||||
lua_endtable();
|
||||
}
|
72
Core/LuaApi.h
Normal file
72
Core/LuaApi.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
struct lua_State;
|
||||
class ScriptingContext;
|
||||
class Debugger;
|
||||
class MemoryDumper;
|
||||
struct ApuSquareState;
|
||||
struct ApuEnvelopeState;
|
||||
struct ApuLengthCounterState;
|
||||
|
||||
class LuaApi
|
||||
{
|
||||
public:
|
||||
static void SetContext(ScriptingContext *context);
|
||||
static void RegisterDebugger(Debugger* debugger);
|
||||
static int GetLibrary(lua_State *lua);
|
||||
|
||||
static int ReadMemory(lua_State *lua);
|
||||
static int WriteMemory(lua_State *lua);
|
||||
static int DebugReadMemory(lua_State *lua);
|
||||
static int DebugWriteMemory(lua_State *lua);
|
||||
static int ReadMemoryWord(lua_State *lua);
|
||||
static int WriteMemoryWord(lua_State *lua);
|
||||
static int DebugReadMemoryWord(lua_State *lua);
|
||||
static int DebugWriteMemoryWord(lua_State *lua);
|
||||
static int RevertPrgChrChanges(lua_State *lua);
|
||||
|
||||
static int RegisterMemoryCallback(lua_State *lua);
|
||||
static int UnregisterMemoryCallback(lua_State *lua);
|
||||
static int RegisterEventCallback(lua_State *lua);
|
||||
static int UnregisterEventCallback(lua_State *lua);
|
||||
|
||||
static int DrawString(lua_State *lua);
|
||||
static int DrawLine(lua_State *lua);
|
||||
static int DrawPixel(lua_State *lua);
|
||||
static int DrawRectangle(lua_State *lua);
|
||||
static int ClearScreen(lua_State *lua);
|
||||
static int GetPixel(lua_State *lua);
|
||||
static int GetMouseState(lua_State *lua);
|
||||
|
||||
static int Log(lua_State *lua);
|
||||
static int DisplayMessage(lua_State *lua);
|
||||
|
||||
static int Reset(lua_State *lua);
|
||||
static int Break(lua_State *lua);
|
||||
static int Resume(lua_State *lua);
|
||||
static int Execute(lua_State *lua);
|
||||
static int Rewind(lua_State *lua);
|
||||
|
||||
static int TakeScreenshot(lua_State *lua);
|
||||
static int SaveSavestate(lua_State *lua);
|
||||
static int LoadSavestate(lua_State *lua);
|
||||
|
||||
static int GetInput(lua_State *lua);
|
||||
static int SetInput(lua_State *lua);
|
||||
|
||||
static int AddCheat(lua_State *lua);
|
||||
static int ClearCheats(lua_State *lua);
|
||||
|
||||
static int SetState(lua_State *lua);
|
||||
static int GetState(lua_State *lua);
|
||||
|
||||
private:
|
||||
static Debugger* _debugger;
|
||||
static MemoryDumper* _memoryDumper;
|
||||
static ScriptingContext* _context;
|
||||
|
||||
static void PushSquareState(lua_State* lua, ApuSquareState &state);
|
||||
static void PushEnvelopeState(lua_State* lua, ApuEnvelopeState &state);
|
||||
static void PushLengthCounterState(lua_State* lua, ApuLengthCounterState &state);
|
||||
};
|
117
Core/LuaCallHelper.cpp
Normal file
117
Core/LuaCallHelper.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include "stdafx.h"
|
||||
#include "LuaCallHelper.h"
|
||||
|
||||
LuaCallHelper::LuaCallHelper(lua_State *lua) : _lua(lua)
|
||||
{
|
||||
_stackSize = lua_gettop(lua);
|
||||
}
|
||||
|
||||
void LuaCallHelper::ForceParamCount(int paramCount)
|
||||
{
|
||||
while(lua_gettop(_lua) < paramCount) {
|
||||
lua_pushnil(_lua);
|
||||
}
|
||||
}
|
||||
|
||||
bool LuaCallHelper::CheckParamCount(int minParamCount)
|
||||
{
|
||||
if(minParamCount >= 0 && _stackSize < _paramCount && _stackSize >= minParamCount) {
|
||||
return true;
|
||||
}
|
||||
if(_stackSize != _paramCount) {
|
||||
string message = string("too ") + (_stackSize < _paramCount ? "little" : "many") + " parameters. expected " + std::to_string(_paramCount) + " got " + std::to_string(_stackSize);
|
||||
luaL_error(_lua, message.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
double LuaCallHelper::ReadDouble()
|
||||
{
|
||||
_paramCount++;
|
||||
double value = 0;
|
||||
if(lua_isnumber(_lua, -1)) {
|
||||
value = lua_tonumber(_lua, -1);
|
||||
}
|
||||
lua_pop(_lua, 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool LuaCallHelper::ReadBool(bool defaultValue)
|
||||
{
|
||||
_paramCount++;
|
||||
bool value = defaultValue;
|
||||
if(lua_isboolean(_lua, -1)) {
|
||||
value = lua_toboolean(_lua, -1) != 0;
|
||||
} else if(lua_isnumber(_lua, -1)) {
|
||||
value = lua_tonumber(_lua, -1) != 0;
|
||||
}
|
||||
lua_pop(_lua, 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t LuaCallHelper::ReadInteger(uint32_t defaultValue)
|
||||
{
|
||||
_paramCount++;
|
||||
uint32_t value = defaultValue;
|
||||
if(lua_isinteger(_lua, -1)) {
|
||||
value = (uint32_t)lua_tointeger(_lua, -1);
|
||||
} else if(lua_isnumber(_lua, -1)) {
|
||||
value = (uint32_t)lua_tonumber(_lua, -1);
|
||||
}
|
||||
lua_pop(_lua, 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
string LuaCallHelper::ReadString()
|
||||
{
|
||||
_paramCount++;
|
||||
size_t len;
|
||||
string str;
|
||||
if(lua_isstring(_lua, -1)) {
|
||||
const char* cstr = lua_tolstring(_lua, -1, &len);
|
||||
str = string(cstr, len);
|
||||
}
|
||||
lua_pop(_lua, 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
int LuaCallHelper::GetReference()
|
||||
{
|
||||
_paramCount++;
|
||||
if(lua_isfunction(_lua, -1)) {
|
||||
return luaL_ref(_lua, LUA_REGISTRYINDEX);
|
||||
} else {
|
||||
lua_pop(_lua, 1);
|
||||
return LUA_NOREF;
|
||||
}
|
||||
}
|
||||
|
||||
void LuaCallHelper::Return(bool value)
|
||||
{
|
||||
lua_pushboolean(_lua, value);
|
||||
_returnCount++;
|
||||
}
|
||||
|
||||
void LuaCallHelper::Return(int value)
|
||||
{
|
||||
lua_pushinteger(_lua, value);
|
||||
_returnCount++;
|
||||
}
|
||||
|
||||
void LuaCallHelper::Return(uint32_t value)
|
||||
{
|
||||
lua_pushinteger(_lua, value);
|
||||
_returnCount++;
|
||||
}
|
||||
|
||||
void LuaCallHelper::Return(string value)
|
||||
{
|
||||
lua_pushlstring(_lua, value.c_str(), value.size());
|
||||
_returnCount++;
|
||||
}
|
||||
|
||||
int LuaCallHelper::ReturnCount()
|
||||
{
|
||||
return _returnCount;
|
||||
}
|
31
Core/LuaCallHelper.h
Normal file
31
Core/LuaCallHelper.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "../Lua/lua.hpp"
|
||||
|
||||
class LuaCallHelper
|
||||
{
|
||||
private:
|
||||
int _stackSize = 0;
|
||||
int _paramCount = 0;
|
||||
int _returnCount = 0;
|
||||
lua_State* _lua;
|
||||
|
||||
public:
|
||||
LuaCallHelper(lua_State* lua);
|
||||
|
||||
void ForceParamCount(int paramCount);
|
||||
bool CheckParamCount(int minParamCount = -1);
|
||||
|
||||
double ReadDouble();
|
||||
bool ReadBool(bool defaultValue = false);
|
||||
uint32_t ReadInteger(uint32_t defaultValue = 0);
|
||||
string ReadString();
|
||||
int GetReference();
|
||||
|
||||
void Return(bool value);
|
||||
void Return(int value);
|
||||
void Return(uint32_t value);
|
||||
void Return(string value);
|
||||
|
||||
int ReturnCount();
|
||||
};
|
67
Core/LuaScriptingContext.cpp
Normal file
67
Core/LuaScriptingContext.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "stdafx.h"
|
||||
#include "../Lua/lua.hpp"
|
||||
#include "LuaScriptingContext.h"
|
||||
#include "LuaApi.h"
|
||||
#include "LuaCallHelper.h"
|
||||
#include "DebuggerTypes.h"
|
||||
#include "Debugger.h"
|
||||
|
||||
LuaScriptingContext::LuaScriptingContext() { }
|
||||
|
||||
LuaScriptingContext::~LuaScriptingContext()
|
||||
{
|
||||
if(_lua) {
|
||||
lua_close(_lua);
|
||||
_lua = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool LuaScriptingContext::LoadScript(string scriptContent, Debugger* debugger)
|
||||
{
|
||||
int iErr = 0;
|
||||
_lua = luaL_newstate();
|
||||
LuaApi::RegisterDebugger(debugger);
|
||||
LuaApi::SetContext(this);
|
||||
|
||||
luaL_openlibs(_lua);
|
||||
luaL_requiref(_lua, "emu", LuaApi::GetLibrary, 1);
|
||||
Log("Loading script...");
|
||||
if((iErr = luaL_loadstring(_lua, scriptContent.c_str())) == 0) {
|
||||
if((iErr = lua_pcall(_lua, 0, LUA_MULTRET, 0)) == 0) {
|
||||
//Script loaded properly
|
||||
Log("Script loaded successfully.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(lua_isstring(_lua, -1)) {
|
||||
Log(lua_tostring(_lua, -1));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LuaScriptingContext::CallMemoryCallback(int addr, int value, CallbackType type)
|
||||
{
|
||||
LuaApi::SetContext(this);
|
||||
for(int &ref : _callbacks[(int)type][addr]) {
|
||||
lua_rawgeti(_lua, LUA_REGISTRYINDEX, ref);
|
||||
lua_pushinteger(_lua, addr);
|
||||
lua_pushinteger(_lua, value);
|
||||
if(lua_pcall(_lua, 2, 0, 0) != 0) {
|
||||
Log(lua_tostring(_lua, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int LuaScriptingContext::InternalCallEventCallback(EventType type)
|
||||
{
|
||||
LuaApi::SetContext(this);
|
||||
LuaCallHelper l(_lua);
|
||||
for(int &ref : _eventCallbacks[(int)type]) {
|
||||
lua_rawgeti(_lua, LUA_REGISTRYINDEX, ref);
|
||||
if(lua_pcall(_lua, 0, 0, 0) != 0) {
|
||||
Log(lua_tostring(_lua, -1));
|
||||
}
|
||||
}
|
||||
return l.ReturnCount();
|
||||
}
|
20
Core/LuaScriptingContext.h
Normal file
20
Core/LuaScriptingContext.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "ScriptingContext.h"
|
||||
|
||||
struct lua_State;
|
||||
class Debugger;
|
||||
|
||||
class LuaScriptingContext : public ScriptingContext
|
||||
{
|
||||
private:
|
||||
lua_State* _lua = nullptr;
|
||||
|
||||
public:
|
||||
LuaScriptingContext();
|
||||
~LuaScriptingContext();
|
||||
|
||||
bool LoadScript(string scriptContent, Debugger* debugger);
|
||||
void CallMemoryCallback(int addr, int value, CallbackType type);
|
||||
int InternalCallEventCallback(EventType type);
|
||||
};
|
|
@ -126,7 +126,7 @@ void MemoryDumper::SetMemoryValues(DebugMemoryType memoryType, uint32_t address,
|
|||
}
|
||||
}
|
||||
|
||||
void MemoryDumper::SetMemoryValue(DebugMemoryType memoryType, uint32_t address, uint8_t value, bool preventRebuildCache)
|
||||
void MemoryDumper::SetMemoryValue(DebugMemoryType memoryType, uint32_t address, uint8_t value, bool preventRebuildCache, bool disableSideEffects)
|
||||
{
|
||||
switch(memoryType) {
|
||||
case DebugMemoryType::CpuMemory:
|
||||
|
@ -134,15 +134,15 @@ void MemoryDumper::SetMemoryValue(DebugMemoryType memoryType, uint32_t address,
|
|||
_debugger->GetAbsoluteAddressAndType(address, &info);
|
||||
if(info.Address >= 0) {
|
||||
switch(info.Type) {
|
||||
case AddressType::InternalRam: SetMemoryValue(DebugMemoryType::InternalRam, info.Address, value, preventRebuildCache); break;
|
||||
case AddressType::PrgRom: SetMemoryValue(DebugMemoryType::PrgRom, info.Address, value, preventRebuildCache); break;
|
||||
case AddressType::WorkRam: SetMemoryValue(DebugMemoryType::WorkRam, info.Address, value, preventRebuildCache); break;
|
||||
case AddressType::SaveRam: SetMemoryValue(DebugMemoryType::SaveRam, info.Address, value, preventRebuildCache); break;
|
||||
case AddressType::InternalRam: SetMemoryValue(DebugMemoryType::InternalRam, info.Address, value, preventRebuildCache, disableSideEffects); break;
|
||||
case AddressType::PrgRom: SetMemoryValue(DebugMemoryType::PrgRom, info.Address, value, preventRebuildCache, disableSideEffects); break;
|
||||
case AddressType::WorkRam: SetMemoryValue(DebugMemoryType::WorkRam, info.Address, value, preventRebuildCache, disableSideEffects); break;
|
||||
case AddressType::SaveRam: SetMemoryValue(DebugMemoryType::SaveRam, info.Address, value, preventRebuildCache, disableSideEffects); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DebugMemoryType::InternalRam: _memoryManager->DebugWrite(address, value); break;
|
||||
case DebugMemoryType::InternalRam: _memoryManager->DebugWrite(address, value, disableSideEffects); break;
|
||||
|
||||
case DebugMemoryType::PaletteMemory: _ppu->WritePaletteRAM(address, value); break;
|
||||
case DebugMemoryType::SpriteMemory: _ppu->GetSpriteRam()[address] = value; break;
|
||||
|
@ -166,7 +166,18 @@ void MemoryDumper::SetMemoryValue(DebugMemoryType memoryType, uint32_t address,
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t MemoryDumper::GetMemoryValue(DebugMemoryType memoryType, uint32_t address)
|
||||
uint16_t MemoryDumper::GetMemoryValueWord(DebugMemoryType memoryType, uint32_t address, bool disableSideEffects)
|
||||
{
|
||||
return GetMemoryValue(memoryType, address, disableSideEffects) | (GetMemoryValue(memoryType, address + 1, disableSideEffects) << 8);
|
||||
}
|
||||
|
||||
void MemoryDumper::SetMemoryValueWord(DebugMemoryType memoryType, uint32_t address, uint16_t value, bool preventRebuildCache, bool disableSideEffects)
|
||||
{
|
||||
SetMemoryValue(memoryType, address, (uint8_t)value, preventRebuildCache, disableSideEffects);
|
||||
SetMemoryValue(memoryType, address + 1, (uint8_t)(value >> 8), preventRebuildCache, disableSideEffects);
|
||||
}
|
||||
|
||||
uint8_t MemoryDumper::GetMemoryValue(DebugMemoryType memoryType, uint32_t address, bool disableSideEffects)
|
||||
{
|
||||
switch(memoryType) {
|
||||
case DebugMemoryType::CpuMemory:
|
||||
|
@ -174,15 +185,15 @@ uint8_t MemoryDumper::GetMemoryValue(DebugMemoryType memoryType, uint32_t addres
|
|||
_debugger->GetAbsoluteAddressAndType(address, &info);
|
||||
if(info.Address >= 0) {
|
||||
switch(info.Type) {
|
||||
case AddressType::InternalRam: return GetMemoryValue(DebugMemoryType::InternalRam, info.Address);
|
||||
case AddressType::PrgRom: return GetMemoryValue(DebugMemoryType::PrgRom, info.Address);
|
||||
case AddressType::WorkRam: return GetMemoryValue(DebugMemoryType::WorkRam, info.Address);
|
||||
case AddressType::SaveRam: return GetMemoryValue(DebugMemoryType::SaveRam, info.Address);
|
||||
case AddressType::InternalRam: return GetMemoryValue(DebugMemoryType::InternalRam, info.Address, disableSideEffects);
|
||||
case AddressType::PrgRom: return GetMemoryValue(DebugMemoryType::PrgRom, info.Address, disableSideEffects);
|
||||
case AddressType::WorkRam: return GetMemoryValue(DebugMemoryType::WorkRam, info.Address, disableSideEffects);
|
||||
case AddressType::SaveRam: return GetMemoryValue(DebugMemoryType::SaveRam, info.Address, disableSideEffects);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DebugMemoryType::InternalRam: return _memoryManager->DebugRead(address);
|
||||
case DebugMemoryType::InternalRam: return _memoryManager->DebugRead(address, disableSideEffects);
|
||||
|
||||
case DebugMemoryType::PaletteMemory: return _ppu->ReadPaletteRAM(address);
|
||||
case DebugMemoryType::SpriteMemory: return _ppu->GetSpriteRam()[address];
|
||||
|
|
|
@ -29,8 +29,10 @@ public:
|
|||
void GetSprites(uint32_t* frameBuffer);
|
||||
void GetPalette(uint32_t* frameBuffer);
|
||||
|
||||
uint8_t GetMemoryValue(DebugMemoryType memoryType, uint32_t address);
|
||||
uint8_t GetMemoryValue(DebugMemoryType memoryType, uint32_t address, bool disableSideEffects = true);
|
||||
uint16_t GetMemoryValueWord(DebugMemoryType memoryType, uint32_t address, bool disableSideEffects = true);
|
||||
void SetMemoryValue(DebugMemoryType memoryType, uint32_t address, uint8_t value, bool preventRebuildCache = false, bool disableSideEffects = true);
|
||||
void SetMemoryValueWord(DebugMemoryType memoryType, uint32_t address, uint16_t value, bool preventRebuildCache = false, bool disableSideEffects = true);
|
||||
void SetMemoryValues(DebugMemoryType memoryType, uint32_t address, uint8_t* data, int32_t length);
|
||||
void SetMemoryValue(DebugMemoryType memoryType, uint32_t address, uint8_t value, bool preventRebuildCache = false);
|
||||
void SetMemoryState(DebugMemoryType type, uint8_t *buffer);
|
||||
};
|
|
@ -101,13 +101,22 @@ uint8_t* MemoryManager::GetInternalRAM()
|
|||
return _internalRAM;
|
||||
}
|
||||
|
||||
uint8_t MemoryManager::DebugRead(uint16_t addr, bool disableRegisterReads)
|
||||
uint8_t MemoryManager::DebugRead(uint16_t addr, bool disableSideEffects)
|
||||
{
|
||||
uint8_t value = 0x00;
|
||||
if(addr <= 0x1FFF) {
|
||||
value = _internalRAM[addr & 0x07FF];
|
||||
} else if(!disableRegisterReads || addr > 0x4017) {
|
||||
value = ReadRegister(addr);
|
||||
} else {
|
||||
IMemoryHandler* handler = _ramReadHandlers[addr];
|
||||
if(handler) {
|
||||
if(handler == _mapper.get() && disableSideEffects) {
|
||||
value = ((BaseMapper*)handler)->DebugReadRAM(addr);
|
||||
} else {
|
||||
value = handler->ReadRAM(addr);
|
||||
}
|
||||
} else {
|
||||
value = GetOpenBus();
|
||||
}
|
||||
}
|
||||
|
||||
CheatManager::ApplyRamCodes(addr, value);
|
||||
|
@ -154,12 +163,19 @@ void MemoryManager::Write(uint16_t addr, uint8_t value)
|
|||
}
|
||||
}
|
||||
|
||||
void MemoryManager::DebugWrite(uint16_t addr, uint8_t value)
|
||||
void MemoryManager::DebugWrite(uint16_t addr, uint8_t value, bool disableSideEffects)
|
||||
{
|
||||
if(addr <= 0x1FFF) {
|
||||
_internalRAM[addr & 0x07FF] = value;
|
||||
} else {
|
||||
WriteRegister(addr, value);
|
||||
IMemoryHandler* handler = _ramReadHandlers[addr];
|
||||
if(handler) {
|
||||
if(handler == _mapper.get() && disableSideEffects) {
|
||||
((BaseMapper*)handler)->DebugWriteRAM(addr, value);
|
||||
} else {
|
||||
handler->WriteRAM(addr, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ class MemoryManager: public Snapshotable
|
|||
void RegisterIODevice(IMemoryHandler *handler);
|
||||
void UnregisterIODevice(IMemoryHandler *handler);
|
||||
|
||||
uint8_t DebugRead(uint16_t addr, bool disableRegisterReads = true);
|
||||
uint8_t DebugRead(uint16_t addr, bool disableSideEffects = true);
|
||||
uint16_t DebugReadWord(uint16_t addr);
|
||||
void DebugWrite(uint16_t addr, uint8_t value);
|
||||
void DebugWrite(uint16_t addr, uint8_t value, bool disableSideEffects = true);
|
||||
|
||||
uint8_t* GetInternalRAM();
|
||||
|
||||
|
|
|
@ -85,4 +85,18 @@ public:
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ApuNoiseState GetState()
|
||||
{
|
||||
ApuNoiseState state;
|
||||
state.Enabled = _enabled;
|
||||
state.Envelope = ApuEnvelope::GetState();
|
||||
state.Frequency = (uint32_t)((CPU::GetClockRate(GetNesModel()) / (_period + 1)) / (_modeFlag ? 93 : 1));
|
||||
state.LengthCounter = ApuLengthCounter::GetState();
|
||||
state.ModeFlag = _modeFlag;
|
||||
state.OutputVolume = _lastOutput;
|
||||
state.Period = _period;
|
||||
state.ShiftRegister = _shiftRegister;
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -90,7 +90,7 @@ bool OggReader::LoadSamples()
|
|||
|
||||
void OggReader::ApplySamples(int16_t * buffer, size_t sampleCount, uint8_t volume)
|
||||
{
|
||||
while(blip_samples_avail(_blipLeft) < sampleCount) {
|
||||
while(blip_samples_avail(_blipLeft) < (int)sampleCount) {
|
||||
if(!LoadSamples()) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -232,4 +232,9 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
uint32_t argbColor = EmulationSettings::GetRgbPalette()[pixelData & 0x3F];
|
||||
return (argbColor & 0xFF) + ((argbColor >> 8) & 0xFF) + ((argbColor >> 16) & 0xFF);
|
||||
}
|
||||
|
||||
static uint16_t GetPixel(uint8_t x, uint8_t y)
|
||||
{
|
||||
return PPU::Instance->_currentOutputBuffer[y << 8 | x];
|
||||
}
|
||||
};
|
||||
|
|
60
Core/ScriptHost.cpp
Normal file
60
Core/ScriptHost.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "stdafx.h"
|
||||
#include "ScriptHost.h"
|
||||
#include "ScriptingContext.h"
|
||||
#include "LuaScriptingContext.h"
|
||||
|
||||
ScriptHost::ScriptHost(int scriptId)
|
||||
{
|
||||
_scriptId = scriptId;
|
||||
}
|
||||
|
||||
int ScriptHost::GetScriptId()
|
||||
{
|
||||
return _scriptId;
|
||||
}
|
||||
|
||||
const char* ScriptHost::GetLog()
|
||||
{
|
||||
return _context ? _context->GetLog() : "";
|
||||
}
|
||||
|
||||
bool ScriptHost::LoadScript(string scriptContent, Debugger* debugger)
|
||||
{
|
||||
_context.reset();
|
||||
if(scriptContent.size() > 0) {
|
||||
_context.reset(new LuaScriptingContext());
|
||||
|
||||
if(!_context->LoadScript(scriptContent, debugger)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptHost::ProcessCpuOperation(uint16_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
if(_context) {
|
||||
switch(type) {
|
||||
case MemoryOperationType::Read: _context->CallMemoryCallback(addr, value, CallbackType::CpuRead); break;
|
||||
case MemoryOperationType::Write: _context->CallMemoryCallback(addr, value, CallbackType::CpuWrite); break;
|
||||
case MemoryOperationType::ExecOpCode: _context->CallMemoryCallback(addr, value, CallbackType::CpuExec); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptHost::ProcessPpuOperation(uint16_t addr, uint8_t value, MemoryOperationType type)
|
||||
{
|
||||
if(_context) {
|
||||
switch(type) {
|
||||
case MemoryOperationType::Read: _context->CallMemoryCallback(addr, value, CallbackType::PpuRead); break;
|
||||
case MemoryOperationType::Write: _context->CallMemoryCallback(addr, value, CallbackType::PpuWrite); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptHost::ProcessEvent(EventType eventType)
|
||||
{
|
||||
if(_context) {
|
||||
_context->CallEventCallback(eventType);
|
||||
}
|
||||
}
|
25
Core/ScriptHost.h
Normal file
25
Core/ScriptHost.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DebuggerTypes.h"
|
||||
|
||||
class ScriptingContext;
|
||||
class Debugger;
|
||||
|
||||
class ScriptHost
|
||||
{
|
||||
private:
|
||||
shared_ptr<ScriptingContext> _context;
|
||||
int _scriptId;
|
||||
|
||||
public:
|
||||
ScriptHost(int scriptId);
|
||||
|
||||
int GetScriptId();
|
||||
const char* GetLog();
|
||||
|
||||
bool LoadScript(string scriptContent, Debugger* debugger);
|
||||
|
||||
void ProcessCpuOperation(uint16_t addr, uint8_t value, MemoryOperationType type);
|
||||
void ProcessPpuOperation(uint16_t addr, uint8_t value, MemoryOperationType type);
|
||||
void ProcessEvent(EventType eventType);
|
||||
};
|
87
Core/ScriptingContext.cpp
Normal file
87
Core/ScriptingContext.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include "stdafx.h"
|
||||
#include "ScriptingContext.h"
|
||||
#include "DebuggerTypes.h"
|
||||
|
||||
void ScriptingContext::Log(string message)
|
||||
{
|
||||
auto lock = _logLock.AcquireSafe();
|
||||
_logRows.push_back(message);
|
||||
if(_logRows.size() > 500) {
|
||||
_logRows.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
const char* ScriptingContext::GetLog()
|
||||
{
|
||||
auto lock = _logLock.AcquireSafe();
|
||||
stringstream ss;
|
||||
for(string &msg : _logRows) {
|
||||
ss << msg << "\n";
|
||||
}
|
||||
_log = ss.str();
|
||||
return _log.c_str();
|
||||
}
|
||||
|
||||
int ScriptingContext::CallEventCallback(EventType type)
|
||||
{
|
||||
_inStartFrameEvent = type == EventType::StartFrame;
|
||||
int returnValue = InternalCallEventCallback(type);
|
||||
_inStartFrameEvent = false;
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool ScriptingContext::CheckInStartFrameEvent()
|
||||
{
|
||||
return _inStartFrameEvent;
|
||||
}
|
||||
|
||||
void ScriptingContext::RegisterMemoryCallback(CallbackType type, int startAddr, int endAddr, int reference)
|
||||
{
|
||||
if(endAddr < startAddr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(startAddr == 0 && endAddr == 0) {
|
||||
if(type <= CallbackType::CpuExec) {
|
||||
endAddr = 0xFFFF;
|
||||
} else {
|
||||
endAddr = 0x3FFF;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = startAddr; i < endAddr; i++) {
|
||||
_callbacks[(int)type][i].push_back(reference);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingContext::UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, int reference)
|
||||
{
|
||||
if(endAddr < startAddr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(startAddr == 0 && endAddr == 0) {
|
||||
if(type <= CallbackType::CpuExec) {
|
||||
endAddr = 0xFFFF;
|
||||
} else {
|
||||
endAddr = 0x3FFF;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = startAddr; startAddr < endAddr; i++) {
|
||||
vector<int> &refs = _callbacks[(int)type][i];
|
||||
refs.erase(std::remove(refs.begin(), refs.end(), reference), refs.end());
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingContext::RegisterEventCallback(EventType type, int reference)
|
||||
{
|
||||
_eventCallbacks[(int)type].push_back(reference);
|
||||
}
|
||||
|
||||
void ScriptingContext::UnregisterEventCallback(EventType type, int reference)
|
||||
{
|
||||
vector<int> &callbacks = _eventCallbacks[(int)type];
|
||||
callbacks.erase(std::remove(callbacks.begin(), callbacks.end(), reference), callbacks.end());
|
||||
}
|
46
Core/ScriptingContext.h
Normal file
46
Core/ScriptingContext.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <deque>
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "DebuggerTypes.h"
|
||||
|
||||
class Debugger;
|
||||
|
||||
enum class CallbackType
|
||||
{
|
||||
CpuRead = 0,
|
||||
CpuWrite = 1,
|
||||
CpuExec = 2,
|
||||
PpuRead = 3,
|
||||
PpuWrite = 4
|
||||
};
|
||||
|
||||
class ScriptingContext
|
||||
{
|
||||
private:
|
||||
std::deque<string> _logRows;
|
||||
string _log;
|
||||
SimpleLock _logLock;
|
||||
bool _inStartFrameEvent = false;
|
||||
|
||||
protected:
|
||||
vector<int> _callbacks[5][0x10000];
|
||||
vector<int> _eventCallbacks[7];
|
||||
|
||||
public:
|
||||
virtual bool LoadScript(string scriptContent, Debugger* debugger) = 0;
|
||||
|
||||
void Log(string message);
|
||||
const char* GetLog();
|
||||
|
||||
virtual void CallMemoryCallback(int addr, int value, CallbackType type) = 0;
|
||||
virtual int InternalCallEventCallback(EventType type) = 0;
|
||||
|
||||
int CallEventCallback(EventType type);
|
||||
bool CheckInStartFrameEvent();
|
||||
|
||||
void RegisterMemoryCallback(CallbackType type, int startAddr, int endAddr, int reference);
|
||||
void UnregisterMemoryCallback(CallbackType type, int startAddr, int endAddr, int reference);
|
||||
void RegisterEventCallback(EventType type, int reference);
|
||||
void UnregisterEventCallback(EventType type, int reference);
|
||||
};
|
|
@ -183,4 +183,22 @@ public:
|
|||
_reloadSweep = false;
|
||||
}
|
||||
}
|
||||
|
||||
ApuSquareState GetState()
|
||||
{
|
||||
ApuSquareState state;
|
||||
state.Duty = _duty;
|
||||
state.DutyPosition = _dutyPos;
|
||||
state.Enabled = _enabled;
|
||||
state.Envelope = ApuEnvelope::GetState();
|
||||
state.Frequency = (uint32_t)(CPU::GetClockRate(GetNesModel()) / 16.0 / (_realPeriod + 1));
|
||||
state.LengthCounter = ApuLengthCounter::GetState();
|
||||
state.OutputVolume = _lastOutput;
|
||||
state.Period = _realPeriod;
|
||||
state.SweepEnabled = _sweepEnabled;
|
||||
state.SweepNegate = _sweepNegate;
|
||||
state.SweepPeriod = _sweepPeriod;
|
||||
state.SweepShift = _sweepShift;
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -32,7 +32,7 @@ bool StandardController::IsMicrophoneActive()
|
|||
return false;
|
||||
}
|
||||
|
||||
uint8_t StandardController::GetButtonState()
|
||||
ButtonState StandardController::GetButtonState()
|
||||
{
|
||||
ButtonState state;
|
||||
|
||||
|
@ -70,12 +70,12 @@ uint8_t StandardController::GetButtonState()
|
|||
}
|
||||
}
|
||||
|
||||
return state.ToByte();
|
||||
return state;
|
||||
}
|
||||
|
||||
uint32_t StandardController::GetNetPlayState()
|
||||
{
|
||||
return GetButtonState();
|
||||
return GetButtonState().ToByte();
|
||||
}
|
||||
|
||||
uint8_t StandardController::GetPortOutput()
|
||||
|
@ -132,7 +132,7 @@ void StandardController::RefreshStateBuffer()
|
|||
|
||||
uint8_t StandardController::RefreshState()
|
||||
{
|
||||
return GetButtonState();
|
||||
return GetButtonState().ToByte();
|
||||
}
|
||||
|
||||
void StandardController::AddAdditionalController(shared_ptr<BaseControlDevice> controller)
|
||||
|
|
|
@ -12,7 +12,6 @@ private:
|
|||
uint8_t _lastButtonState = 0;
|
||||
|
||||
shared_ptr<BaseControlDevice> _additionalController;
|
||||
uint8_t GetButtonState();
|
||||
|
||||
protected:
|
||||
uint8_t RefreshState() override;
|
||||
|
@ -21,6 +20,7 @@ protected:
|
|||
public:
|
||||
StandardController(uint8_t port, bool emptyPort = false);
|
||||
|
||||
ButtonState GetButtonState();
|
||||
uint32_t GetNetPlayState() override;
|
||||
|
||||
uint8_t GetPortOutput() override;
|
||||
|
|
|
@ -23,7 +23,6 @@ protected:
|
|||
if(_lengthCounter > 0 && _linearCounter > 0) {
|
||||
_sequencePosition = (_sequencePosition + 1) & 0x1F;
|
||||
|
||||
|
||||
if(_period >= 2 || !EmulationSettings::CheckFlag(EmulationFlags::SilenceTriangleHighFreq)) {
|
||||
//Disabling the triangle channel when period is < 2 removes "pops" in the audio that are caused by the ultrasonic frequencies
|
||||
//This is less "accurate" in terms of emulation, so this is an option (disabled by default)
|
||||
|
@ -101,4 +100,16 @@ public:
|
|||
_linearReloadFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
ApuTriangleState GetState()
|
||||
{
|
||||
ApuTriangleState state;
|
||||
state.Enabled = _enabled;
|
||||
state.Frequency = (uint32_t)(CPU::GetClockRate(GetNesModel()) / 32.0 / (_period + 1));
|
||||
state.LengthCounter = ApuLengthCounter::GetState();
|
||||
state.OutputVolume = _lastOutput;
|
||||
state.Period = _period;
|
||||
state.SequencePosition = _sequencePosition;
|
||||
return state;
|
||||
}
|
||||
};
|
94
Core/Types.h
94
Core/Types.h
|
@ -78,7 +78,6 @@ struct CartridgeState
|
|||
uint32_t Nametables[8];
|
||||
};
|
||||
|
||||
|
||||
struct PPUControlFlags
|
||||
{
|
||||
bool VerticalWrite;
|
||||
|
@ -138,3 +137,96 @@ struct SpriteInfo : TileInfo
|
|||
|
||||
bool VerticalMirror; //used by HD ppu
|
||||
};
|
||||
|
||||
struct ApuLengthCounterState
|
||||
{
|
||||
bool Halt;
|
||||
uint8_t Counter;
|
||||
uint8_t ReloadValue;
|
||||
};
|
||||
|
||||
struct ApuEnvelopeState
|
||||
{
|
||||
bool StartFlag;
|
||||
bool Loop;
|
||||
bool ConstantVolume;
|
||||
uint8_t Divider;
|
||||
uint8_t Counter;
|
||||
uint8_t Volume;
|
||||
};
|
||||
|
||||
struct ApuSquareState
|
||||
{
|
||||
uint8_t Duty;
|
||||
uint8_t DutyPosition;
|
||||
uint16_t Period;
|
||||
|
||||
bool SweepEnabled;
|
||||
bool SweepNegate;
|
||||
uint8_t SweepPeriod;
|
||||
uint8_t SweepShift;
|
||||
|
||||
bool Enabled;
|
||||
uint8_t OutputVolume;
|
||||
uint32_t Frequency;
|
||||
|
||||
ApuLengthCounterState LengthCounter;
|
||||
ApuEnvelopeState Envelope;
|
||||
};
|
||||
|
||||
struct ApuTriangleState
|
||||
{
|
||||
uint16_t Period;
|
||||
uint8_t SequencePosition;
|
||||
|
||||
bool Enabled;
|
||||
uint32_t Frequency;
|
||||
uint8_t OutputVolume;
|
||||
|
||||
ApuLengthCounterState LengthCounter;
|
||||
};
|
||||
|
||||
struct ApuNoiseState
|
||||
{
|
||||
uint16_t Period;
|
||||
uint16_t ShiftRegister;
|
||||
bool ModeFlag;
|
||||
|
||||
bool Enabled;
|
||||
uint32_t Frequency;
|
||||
uint8_t OutputVolume;
|
||||
|
||||
ApuLengthCounterState LengthCounter;
|
||||
ApuEnvelopeState Envelope;
|
||||
};
|
||||
|
||||
struct ApuDmcState
|
||||
{
|
||||
uint16_t SampleAddr;
|
||||
uint16_t SampleLength;
|
||||
|
||||
bool Loop;
|
||||
bool IrqEnabled;
|
||||
uint16_t Period;
|
||||
uint16_t BytesRemaining;
|
||||
|
||||
uint32_t Frequency;
|
||||
uint8_t OutputVolume;
|
||||
};
|
||||
|
||||
struct ApuFrameCounterState
|
||||
{
|
||||
bool FiveStepMode;
|
||||
uint8_t SequencePosition;
|
||||
bool IrqEnabled;
|
||||
};
|
||||
|
||||
struct ApuState
|
||||
{
|
||||
ApuSquareState Square1;
|
||||
ApuSquareState Square2;
|
||||
ApuTriangleState Triangle;
|
||||
ApuNoiseState Noise;
|
||||
ApuDmcState Dmc;
|
||||
ApuFrameCounterState FrameCounter;
|
||||
};
|
|
@ -90,6 +90,8 @@ namespace Mesen.GUI.Config
|
|||
|
||||
public class DebugInfo
|
||||
{
|
||||
private const int MaxRecentScripts = 10;
|
||||
|
||||
public DebugViewInfo LeftView;
|
||||
public DebugViewInfo RightView;
|
||||
|
||||
|
@ -161,6 +163,13 @@ namespace Mesen.GUI.Config
|
|||
public bool TraceIndentCode = false;
|
||||
public Size TraceLoggerSize = new Size(0, 0);
|
||||
|
||||
public Size ScriptWindowSize = new Size(0, 0);
|
||||
public int ScriptCodeWindowHeight = 0;
|
||||
public List<string> RecentScripts = new List<string>();
|
||||
public bool SaveScriptBeforeRun = true;
|
||||
public bool AutoReloadScript = false;
|
||||
public int ScriptZoom = 100;
|
||||
|
||||
public DebugInfo()
|
||||
{
|
||||
LeftView = new DebugViewInfo();
|
||||
|
@ -178,5 +187,19 @@ namespace Mesen.GUI.Config
|
|||
StatusFormat = StatusFlagFormat.Hexadecimal
|
||||
};
|
||||
}
|
||||
|
||||
public void AddRecentScript(string scriptFile)
|
||||
{
|
||||
string existingItem = RecentScripts.Where((file) => file == scriptFile).FirstOrDefault();
|
||||
if(existingItem != null) {
|
||||
RecentScripts.Remove(existingItem);
|
||||
}
|
||||
|
||||
RecentScripts.Insert(0, scriptFile);
|
||||
if(RecentScripts.Count > DebugInfo.MaxRecentScripts) {
|
||||
RecentScripts.RemoveAt(DebugInfo.MaxRecentScripts);
|
||||
}
|
||||
ConfigManager.ApplyChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace Mesen.GUI.Controls
|
|||
} else if(this.FixedPanel == FixedPanel.Panel2) {
|
||||
_originalDistance = this.SplitterDistance;
|
||||
_originalMinSize = this.Panel2MinSize;
|
||||
this.Panel2MinSize = 4;
|
||||
this.Panel2MinSize = 2;
|
||||
this.SplitterDistance = this.Orientation == Orientation.Horizontal ? this.Height : this.Width;
|
||||
|
||||
this.PanelCollapsed?.Invoke(this, EventArgs.Empty);
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Mesen.GUI.Debugger
|
|||
case DebugWindow.MemoryViewer: frm = new frmMemoryViewer(); break;
|
||||
case DebugWindow.Assembler: frm = new frmAssembler(); break;
|
||||
case DebugWindow.Debugger: frm = new frmDebugger(); break;
|
||||
case DebugWindow.ScriptWindow: frm = new frmScript(); break;
|
||||
}
|
||||
_openedWindows.Add(frm);
|
||||
frm.FormClosed += Debugger_FormClosed;
|
||||
|
@ -97,6 +98,7 @@ namespace Mesen.GUI.Debugger
|
|||
MemoryViewer,
|
||||
TraceLogger,
|
||||
Assembler,
|
||||
Debugger
|
||||
Debugger,
|
||||
ScriptWindow,
|
||||
}
|
||||
}
|
||||
|
|
266
GUI.NET/Debugger/FastColoredTextBox/AutocompleteItem.cs
Normal file
266
GUI.NET/Debugger/FastColoredTextBox/AutocompleteItem.cs
Normal file
|
@ -0,0 +1,266 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Printing;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Item of autocomplete menu
|
||||
/// </summary>
|
||||
public class AutocompleteItem
|
||||
{
|
||||
public string Text;
|
||||
public int ImageIndex = -1;
|
||||
public object Tag;
|
||||
string toolTipTitle;
|
||||
string toolTipText;
|
||||
string menuText;
|
||||
public AutocompleteMenu Parent { get; internal set; }
|
||||
|
||||
|
||||
public AutocompleteItem()
|
||||
{
|
||||
}
|
||||
|
||||
public AutocompleteItem(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
|
||||
public AutocompleteItem(string text, int imageIndex)
|
||||
: this(text)
|
||||
{
|
||||
this.ImageIndex = imageIndex;
|
||||
}
|
||||
|
||||
public AutocompleteItem(string text, int imageIndex, string menuText)
|
||||
: this(text, imageIndex)
|
||||
{
|
||||
this.menuText = menuText;
|
||||
}
|
||||
|
||||
public AutocompleteItem(string text, int imageIndex, string menuText, string toolTipTitle, string toolTipText)
|
||||
: this(text, imageIndex, menuText)
|
||||
{
|
||||
this.toolTipTitle = toolTipTitle;
|
||||
this.toolTipText = toolTipText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns text for inserting into Textbox
|
||||
/// </summary>
|
||||
public virtual string GetTextForReplace()
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares fragment text with this item
|
||||
/// </summary>
|
||||
public virtual CompareResult Compare(string fragmentText)
|
||||
{
|
||||
if (Text.StartsWith(fragmentText, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
Text != fragmentText)
|
||||
return CompareResult.VisibleAndSelected;
|
||||
|
||||
return CompareResult.Hidden;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns text for display into popup menu
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return menuText ?? Text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is called after item inserted into text
|
||||
/// </summary>
|
||||
public virtual void OnSelected(AutocompleteMenu popupMenu, SelectedEventArgs e)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Title for tooltip.
|
||||
/// </summary>
|
||||
/// <remarks>Return null for disable tooltip for this item</remarks>
|
||||
public virtual string ToolTipTitle
|
||||
{
|
||||
get { return toolTipTitle; }
|
||||
set { toolTipTitle = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tooltip text.
|
||||
/// </summary>
|
||||
/// <remarks>For display tooltip text, ToolTipTitle must be not null</remarks>
|
||||
public virtual string ToolTipText
|
||||
{
|
||||
get{ return toolTipText; }
|
||||
set { toolTipText = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Menu text. This text is displayed in the drop-down menu.
|
||||
/// </summary>
|
||||
public virtual string MenuText
|
||||
{
|
||||
get { return menuText; }
|
||||
set { menuText = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fore color of text of item
|
||||
/// </summary>
|
||||
public virtual Color ForeColor
|
||||
{
|
||||
get { return Color.Transparent; }
|
||||
set { throw new NotImplementedException("Override this property to change color"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Back color of item
|
||||
/// </summary>
|
||||
public virtual Color BackColor
|
||||
{
|
||||
get { return Color.Transparent; }
|
||||
set { throw new NotImplementedException("Override this property to change color"); }
|
||||
}
|
||||
}
|
||||
|
||||
public enum CompareResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Item do not appears
|
||||
/// </summary>
|
||||
Hidden,
|
||||
/// <summary>
|
||||
/// Item appears
|
||||
/// </summary>
|
||||
Visible,
|
||||
/// <summary>
|
||||
/// Item appears and will selected
|
||||
/// </summary>
|
||||
VisibleAndSelected
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Autocomplete item for code snippets
|
||||
/// </summary>
|
||||
/// <remarks>Snippet can contain special char ^ for caret position.</remarks>
|
||||
public class SnippetAutocompleteItem : AutocompleteItem
|
||||
{
|
||||
public SnippetAutocompleteItem(string snippet)
|
||||
{
|
||||
Text = snippet.Replace("\r", "");
|
||||
ToolTipTitle = "Code snippet:";
|
||||
ToolTipText = Text;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return MenuText ?? Text.Replace("\n", " ").Replace("^", "");
|
||||
}
|
||||
|
||||
public override string GetTextForReplace()
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
|
||||
public override void OnSelected(AutocompleteMenu popupMenu, SelectedEventArgs e)
|
||||
{
|
||||
e.Tb.BeginUpdate();
|
||||
e.Tb.Selection.BeginUpdate();
|
||||
//remember places
|
||||
var p1 = popupMenu.Fragment.Start;
|
||||
var p2 = e.Tb.Selection.Start;
|
||||
//do auto indent
|
||||
if (e.Tb.AutoIndent)
|
||||
{
|
||||
for (int iLine = p1.iLine + 1; iLine <= p2.iLine; iLine++)
|
||||
{
|
||||
e.Tb.Selection.Start = new Place(0, iLine);
|
||||
e.Tb.DoAutoIndent(iLine);
|
||||
}
|
||||
}
|
||||
e.Tb.Selection.Start = p1;
|
||||
//move caret position right and find char ^
|
||||
while (e.Tb.Selection.CharBeforeStart != '^')
|
||||
if (!e.Tb.Selection.GoRightThroughFolded())
|
||||
break;
|
||||
//remove char ^
|
||||
e.Tb.Selection.GoLeft(true);
|
||||
e.Tb.InsertText("");
|
||||
//
|
||||
e.Tb.Selection.EndUpdate();
|
||||
e.Tb.EndUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares fragment text with this item
|
||||
/// </summary>
|
||||
public override CompareResult Compare(string fragmentText)
|
||||
{
|
||||
if (Text.StartsWith(fragmentText, StringComparison.InvariantCultureIgnoreCase) &&
|
||||
Text != fragmentText)
|
||||
return CompareResult.Visible;
|
||||
|
||||
return CompareResult.Hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This autocomplete item appears after dot
|
||||
/// </summary>
|
||||
public class MethodAutocompleteItem : AutocompleteItem
|
||||
{
|
||||
string firstPart;
|
||||
string lowercaseText;
|
||||
|
||||
public MethodAutocompleteItem(string text)
|
||||
: base(text)
|
||||
{
|
||||
lowercaseText = Text.ToLower();
|
||||
}
|
||||
|
||||
public override CompareResult Compare(string fragmentText)
|
||||
{
|
||||
int i = fragmentText.LastIndexOf('.');
|
||||
if (i < 0)
|
||||
return CompareResult.Hidden;
|
||||
string lastPart = fragmentText.Substring(i + 1);
|
||||
firstPart = fragmentText.Substring(0, i);
|
||||
|
||||
if(lastPart=="") return CompareResult.Visible;
|
||||
if(Text.StartsWith(lastPart, StringComparison.InvariantCultureIgnoreCase))
|
||||
return CompareResult.VisibleAndSelected;
|
||||
if(lowercaseText.Contains(lastPart.ToLower()))
|
||||
return CompareResult.Visible;
|
||||
|
||||
return CompareResult.Hidden;
|
||||
}
|
||||
|
||||
public override string GetTextForReplace()
|
||||
{
|
||||
return firstPart + "." + Text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Item does not check correspondence to current text fragment.
|
||||
/// SuggestItem is intended for dynamic menus.
|
||||
/// </summary>
|
||||
public class SuggestItem : AutocompleteItem
|
||||
{
|
||||
public SuggestItem(string text, int imageIndex):base(text, imageIndex)
|
||||
{
|
||||
}
|
||||
|
||||
public override CompareResult Compare(string fragmentText)
|
||||
{
|
||||
return CompareResult.Visible;
|
||||
}
|
||||
}
|
||||
}
|
750
GUI.NET/Debugger/FastColoredTextBox/AutocompleteMenu.cs
Normal file
750
GUI.NET/Debugger/FastColoredTextBox/AutocompleteMenu.cs
Normal file
|
@ -0,0 +1,750 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Popup menu for autocomplete
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public class AutocompleteMenu : UserControl
|
||||
{
|
||||
AutocompleteListView listView;
|
||||
public Range Fragment { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Regex pattern for serach fragment around caret
|
||||
/// </summary>
|
||||
public string SearchPattern { get; set; }
|
||||
/// <summary>
|
||||
/// Minimum fragment length for popup
|
||||
/// </summary>
|
||||
public int MinFragmentLength { get; set; }
|
||||
/// <summary>
|
||||
/// User selects item
|
||||
/// </summary>
|
||||
public event EventHandler<SelectingEventArgs> Selecting;
|
||||
/// <summary>
|
||||
/// It fires after item inserting
|
||||
/// </summary>
|
||||
public event EventHandler<SelectedEventArgs> Selected;
|
||||
/// <summary>
|
||||
/// Occurs when popup menu is opening
|
||||
/// </summary>
|
||||
public event EventHandler<CancelEventArgs> Opening;
|
||||
/// <summary>
|
||||
/// Allow TAB for select menu item
|
||||
/// </summary>
|
||||
public bool AllowTabKey { get { return listView.AllowTabKey; } set { listView.AllowTabKey = value; } }
|
||||
/// <summary>
|
||||
/// Interval of menu appear (ms)
|
||||
/// </summary>
|
||||
public int AppearInterval { get { return listView.AppearInterval; } set { listView.AppearInterval = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Back color of selected item
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "Orange")]
|
||||
public Color SelectedColor
|
||||
{
|
||||
get { return listView.SelectedColor; }
|
||||
set { listView.SelectedColor = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Border color of hovered item
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "Red")]
|
||||
public Color HoveredColor
|
||||
{
|
||||
get { return listView.HoveredColor; }
|
||||
set { listView.HoveredColor = value; }
|
||||
}
|
||||
|
||||
public AutocompleteMenu(FastColoredTextBox tb, Form parentForm)
|
||||
{
|
||||
// create a new popup and add the list view to it
|
||||
Visible = false;
|
||||
BorderStyle = BorderStyle.FixedSingle;
|
||||
AutoSize = false;
|
||||
Margin = Padding.Empty;
|
||||
Padding = Padding.Empty;
|
||||
BackColor = Color.White;
|
||||
listView = new AutocompleteListView(this, tb, parentForm);
|
||||
CalcSize();
|
||||
this.Controls.Add(listView);
|
||||
SearchPattern = @"[\w\.]";
|
||||
MinFragmentLength = 2;
|
||||
}
|
||||
|
||||
public new Font Font
|
||||
{
|
||||
get { return listView.Font; }
|
||||
set { listView.Font = value; }
|
||||
}
|
||||
|
||||
internal void OnOpening(CancelEventArgs args)
|
||||
{
|
||||
if (Opening != null)
|
||||
Opening(this, args);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
listView.toolTip.Hide(listView);
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
internal void CalcSize()
|
||||
{
|
||||
Size = new System.Drawing.Size(listView.Size.Width + 2, listView.Size.Height + 2);
|
||||
}
|
||||
|
||||
public virtual void OnSelecting()
|
||||
{
|
||||
listView.OnSelecting();
|
||||
}
|
||||
|
||||
public void SelectNext(int shift)
|
||||
{
|
||||
listView.SelectNext(shift);
|
||||
}
|
||||
|
||||
internal void OnSelecting(SelectingEventArgs args)
|
||||
{
|
||||
if (Selecting != null)
|
||||
Selecting(this, args);
|
||||
}
|
||||
|
||||
public void OnSelected(SelectedEventArgs args)
|
||||
{
|
||||
if (Selected != null)
|
||||
Selected(this, args);
|
||||
}
|
||||
|
||||
public AutocompleteListView Items
|
||||
{
|
||||
get { return listView; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows popup menu immediately
|
||||
/// </summary>
|
||||
/// <param name="forced">If True - MinFragmentLength will be ignored</param>
|
||||
public void Show(bool forced)
|
||||
{
|
||||
Items.DoAutocomplete(forced);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Minimal size of menu
|
||||
/// </summary>
|
||||
public new Size MinimumSize
|
||||
{
|
||||
get { return Items.MinimumSize; }
|
||||
set { Items.MinimumSize = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Image list of menu
|
||||
/// </summary>
|
||||
public ImageList ImageList
|
||||
{
|
||||
get { return Items.ImageList; }
|
||||
set { Items.ImageList = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tooltip duration (ms)
|
||||
/// </summary>
|
||||
public int ToolTipDuration
|
||||
{
|
||||
get { return Items.ToolTipDuration; }
|
||||
set { Items.ToolTipDuration = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tooltip
|
||||
/// </summary>
|
||||
public ToolTip ToolTip
|
||||
{
|
||||
get { return Items.toolTip; }
|
||||
set { Items.toolTip = value; }
|
||||
}
|
||||
}
|
||||
|
||||
[System.ComponentModel.ToolboxItem(false)]
|
||||
public class AutocompleteListView : UserControl
|
||||
{
|
||||
public event EventHandler FocussedItemIndexChanged;
|
||||
|
||||
internal List<AutocompleteItem> visibleItems;
|
||||
IEnumerable<AutocompleteItem> sourceItems = new List<AutocompleteItem>();
|
||||
int focussedItemIndex = 0;
|
||||
int hoveredItemIndex = -1;
|
||||
|
||||
private int ItemHeight
|
||||
{
|
||||
get { return Font.Height + 2; }
|
||||
}
|
||||
|
||||
private AutocompleteMenu Menu { get; set; }
|
||||
int oldItemCount = 0;
|
||||
FastColoredTextBox tb;
|
||||
internal ToolTip toolTip = new ToolTip();
|
||||
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
|
||||
|
||||
internal bool AllowTabKey { get; set; }
|
||||
public ImageList ImageList { get; set; }
|
||||
internal int AppearInterval { get { return timer.Interval; } set { timer.Interval = value; } }
|
||||
internal int ToolTipDuration { get; set; }
|
||||
|
||||
public override Size GetPreferredSize(Size proposedSize)
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
public Color SelectedColor { get; set; }
|
||||
public Color HoveredColor { get; set; }
|
||||
public int FocussedItemIndex
|
||||
{
|
||||
get { return focussedItemIndex; }
|
||||
set
|
||||
{
|
||||
if (focussedItemIndex != value)
|
||||
{
|
||||
focussedItemIndex = value;
|
||||
if (FocussedItemIndexChanged != null)
|
||||
FocussedItemIndexChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AutocompleteItem FocussedItem
|
||||
{
|
||||
get
|
||||
{
|
||||
if (FocussedItemIndex >= 0 && focussedItemIndex < visibleItems.Count)
|
||||
return visibleItems[focussedItemIndex];
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
FocussedItemIndex = visibleItems.IndexOf(value);
|
||||
}
|
||||
}
|
||||
|
||||
public Form AutocompleteParent { get; set; }
|
||||
|
||||
internal AutocompleteListView(AutocompleteMenu menu, FastColoredTextBox tb, Form parent)
|
||||
{
|
||||
Menu = menu;
|
||||
AutocompleteParent = parent;
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
|
||||
base.Font = new Font(FontFamily.GenericSansSerif, 9);
|
||||
visibleItems = new List<AutocompleteItem>();
|
||||
VerticalScroll.SmallChange = ItemHeight;
|
||||
MaximumSize = new Size(Size.Width, 180);
|
||||
toolTip.ShowAlways = false;
|
||||
AppearInterval = 200;
|
||||
timer.Tick += new EventHandler(timer_Tick);
|
||||
SelectedColor = Color.Orange;
|
||||
HoveredColor = Color.Red;
|
||||
ToolTipDuration = 30000;
|
||||
|
||||
this.tb = tb;
|
||||
|
||||
tb.KeyDown += new KeyEventHandler(tb_KeyDown);
|
||||
tb.SelectionChanged += new EventHandler(tb_SelectionChanged);
|
||||
tb.KeyPressed += new KeyPressEventHandler(tb_KeyPressed);
|
||||
|
||||
Form form = tb.FindForm();
|
||||
if (form != null)
|
||||
{
|
||||
form.LocationChanged += (o, e) => Menu.Close();
|
||||
form.ResizeBegin += (o, e) => Menu.Close();
|
||||
form.FormClosing += (o, e) => Menu.Close();
|
||||
form.LostFocus += (o, e) => Menu.Close();
|
||||
}
|
||||
|
||||
tb.LostFocus += (o, e) =>
|
||||
{
|
||||
if (!Menu.Focused) Menu.Close();
|
||||
};
|
||||
|
||||
tb.Scroll += (o, e) => Menu.Close();
|
||||
|
||||
this.VisibleChanged += (o, e) =>
|
||||
{
|
||||
if (this.Visible)
|
||||
DoSelectedVisible();
|
||||
};
|
||||
}
|
||||
|
||||
void tb_KeyPressed(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
bool backspaceORdel = e.KeyChar == '\b' || e.KeyChar == 0xff;
|
||||
|
||||
/*
|
||||
if (backspaceORdel)
|
||||
prevSelection = tb.Selection.Start;*/
|
||||
|
||||
if (Menu.Visible && !backspaceORdel)
|
||||
DoAutocomplete(false);
|
||||
else
|
||||
ResetTimer(timer);
|
||||
}
|
||||
|
||||
void timer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
timer.Stop();
|
||||
DoAutocomplete(false);
|
||||
}
|
||||
|
||||
void ResetTimer(System.Windows.Forms.Timer timer)
|
||||
{
|
||||
timer.Stop();
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
internal void DoAutocomplete()
|
||||
{
|
||||
DoAutocomplete(false);
|
||||
}
|
||||
|
||||
internal void DoAutocomplete(bool forced)
|
||||
{
|
||||
if (!Menu.Enabled)
|
||||
{
|
||||
Menu.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
visibleItems.Clear();
|
||||
FocussedItemIndex = 0;
|
||||
VerticalScroll.Value = 0;
|
||||
//some magic for update scrolls
|
||||
AutoScrollMinSize += new Size(1, 0);
|
||||
AutoScrollMinSize -= new Size(1, 0);
|
||||
//get fragment around caret
|
||||
Range fragment = tb.Selection.GetFragment(Menu.SearchPattern);
|
||||
string text = fragment.Text;
|
||||
//calc screen point for popup menu
|
||||
Point point = tb.PlaceToPoint(fragment.End);
|
||||
Point offset = tb.PointToScreen(point);
|
||||
point = AutocompleteParent.PointToClient(offset);
|
||||
point.Offset(2, tb.CharHeight);
|
||||
//
|
||||
if (forced || (text.Length >= Menu.MinFragmentLength
|
||||
&& tb.Selection.IsEmpty /*pops up only if selected range is empty*/
|
||||
&& (tb.Selection.Start > fragment.Start || text.Length == 0/*pops up only if caret is after first letter*/)))
|
||||
{
|
||||
Menu.Fragment = fragment;
|
||||
bool foundSelected = false;
|
||||
//build popup menu
|
||||
foreach (var item in sourceItems)
|
||||
{
|
||||
item.Parent = Menu;
|
||||
CompareResult res = item.Compare(text);
|
||||
if(res != CompareResult.Hidden)
|
||||
visibleItems.Add(item);
|
||||
if (res == CompareResult.VisibleAndSelected && !foundSelected)
|
||||
{
|
||||
foundSelected = true;
|
||||
FocussedItemIndex = visibleItems.Count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundSelected)
|
||||
{
|
||||
AdjustScroll();
|
||||
DoSelectedVisible();
|
||||
}
|
||||
}
|
||||
|
||||
//show popup menu
|
||||
if (Count > 0)
|
||||
{
|
||||
if (!Menu.Visible)
|
||||
{
|
||||
CancelEventArgs args = new CancelEventArgs();
|
||||
Menu.OnOpening(args);
|
||||
if (!args.Cancel)
|
||||
{
|
||||
Menu.Location = point;
|
||||
Menu.Parent = AutocompleteParent;
|
||||
Menu.Show();
|
||||
Menu.BringToFront();
|
||||
}
|
||||
}
|
||||
else
|
||||
Invalidate();
|
||||
}
|
||||
else
|
||||
Menu.Close();
|
||||
}
|
||||
|
||||
void tb_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
/*
|
||||
FastColoredTextBox tb = sender as FastColoredTextBox;
|
||||
|
||||
if (Math.Abs(prevSelection.iChar - tb.Selection.Start.iChar) > 1 ||
|
||||
prevSelection.iLine != tb.Selection.Start.iLine)
|
||||
Menu.Close();
|
||||
prevSelection = tb.Selection.Start;*/
|
||||
if (Menu.Visible)
|
||||
{
|
||||
bool needClose = false;
|
||||
|
||||
if (!tb.Selection.IsEmpty)
|
||||
needClose = true;
|
||||
else
|
||||
if (!Menu.Fragment.Contains(tb.Selection.Start))
|
||||
{
|
||||
if (tb.Selection.Start.iLine == Menu.Fragment.End.iLine && tb.Selection.Start.iChar == Menu.Fragment.End.iChar + 1)
|
||||
{
|
||||
//user press key at end of fragment
|
||||
char c = tb.Selection.CharBeforeStart;
|
||||
if (!Regex.IsMatch(c.ToString(), Menu.SearchPattern))//check char
|
||||
needClose = true;
|
||||
}
|
||||
else
|
||||
needClose = true;
|
||||
}
|
||||
|
||||
if (needClose)
|
||||
Menu.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void tb_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
var tb = sender as FastColoredTextBox;
|
||||
|
||||
if (Menu.Visible)
|
||||
if (ProcessKey(e.KeyCode, e.Modifiers))
|
||||
e.Handled = true;
|
||||
|
||||
if (!Menu.Visible)
|
||||
{
|
||||
if (tb.HotkeysMapping.ContainsKey(e.KeyData) && tb.HotkeysMapping[e.KeyData] == FCTBAction.AutocompleteMenu)
|
||||
{
|
||||
DoAutocomplete();
|
||||
e.Handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.KeyCode == Keys.Escape && timer.Enabled)
|
||||
timer.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdjustScroll()
|
||||
{
|
||||
Range fragment = tb.Selection.GetFragment(Menu.SearchPattern);
|
||||
string text = fragment.Text;
|
||||
//calc screen point for popup menu
|
||||
Point point = tb.PlaceToPoint(fragment.End);
|
||||
Point offset = tb.PointToScreen(point);
|
||||
point = AutocompleteParent.PointToClient(offset);
|
||||
point.Offset(2, tb.CharHeight);
|
||||
if(Menu.Width + point.X > AutocompleteParent.ClientSize.Width - 10) {
|
||||
point.X -= Menu.Width;
|
||||
}
|
||||
if(Menu.Height + point.Y > AutocompleteParent.ClientSize.Height - 10) {
|
||||
point.Y -= Menu.Height + 15;
|
||||
}
|
||||
Menu.Location = point;
|
||||
|
||||
if (oldItemCount == visibleItems.Count)
|
||||
return;
|
||||
|
||||
int needHeight = ItemHeight * visibleItems.Count + 1;
|
||||
Height = Math.Min(needHeight, MaximumSize.Height);
|
||||
Menu.CalcSize();
|
||||
|
||||
AutoScrollMinSize = new Size(0, needHeight);
|
||||
oldItemCount = visibleItems.Count;
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
AdjustScroll();
|
||||
|
||||
var itemHeight = ItemHeight;
|
||||
int startI = VerticalScroll.Value / itemHeight - 1;
|
||||
int finishI = (VerticalScroll.Value + ClientSize.Height) / itemHeight + 1;
|
||||
startI = Math.Max(startI, 0);
|
||||
finishI = Math.Min(finishI, visibleItems.Count);
|
||||
int y = 0;
|
||||
int leftPadding = 18;
|
||||
for (int i = startI; i < finishI; i++)
|
||||
{
|
||||
y = i * itemHeight - VerticalScroll.Value;
|
||||
|
||||
var item = visibleItems[i];
|
||||
|
||||
if(item.BackColor != Color.Transparent)
|
||||
using (var brush = new SolidBrush(item.BackColor))
|
||||
e.Graphics.FillRectangle(brush, 1, y, ClientSize.Width, itemHeight);
|
||||
|
||||
if (ImageList != null && visibleItems[i].ImageIndex >= 0)
|
||||
e.Graphics.DrawImage(ImageList.Images[item.ImageIndex], 1, y);
|
||||
|
||||
if (i == FocussedItemIndex)
|
||||
using (var selectedBrush = new LinearGradientBrush(new Point(0, y - 3), new Point(0, y + itemHeight), Color.Transparent, SelectedColor))
|
||||
using (var pen = new Pen(SelectedColor))
|
||||
{
|
||||
e.Graphics.FillRectangle(selectedBrush, leftPadding, y, ClientSize.Width - 1 - leftPadding, itemHeight);
|
||||
e.Graphics.DrawRectangle(pen, leftPadding, y, ClientSize.Width - 1 - leftPadding, itemHeight);
|
||||
}
|
||||
|
||||
if (i == hoveredItemIndex)
|
||||
using(var pen = new Pen(HoveredColor))
|
||||
e.Graphics.DrawRectangle(pen, leftPadding, y, ClientSize.Width - leftPadding, itemHeight);
|
||||
|
||||
using (var brush = new SolidBrush(item.ForeColor != Color.Transparent ? item.ForeColor : ForeColor))
|
||||
e.Graphics.DrawString(item.ToString(), Font, brush, leftPadding, y);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnScroll(ScrollEventArgs se)
|
||||
{
|
||||
base.OnScroll(se);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnMouseClick(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseClick(e);
|
||||
|
||||
if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
||||
{
|
||||
FocussedItemIndex = PointToItemIndex(e.Location);
|
||||
DoSelectedVisible();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseDoubleClick(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseDoubleClick(e);
|
||||
FocussedItemIndex = PointToItemIndex(e.Location);
|
||||
Invalidate();
|
||||
OnSelecting();
|
||||
}
|
||||
|
||||
internal virtual void OnSelecting()
|
||||
{
|
||||
if (FocussedItemIndex < 0 || FocussedItemIndex >= visibleItems.Count)
|
||||
return;
|
||||
tb.TextSource.Manager.BeginAutoUndoCommands();
|
||||
try
|
||||
{
|
||||
AutocompleteItem item = FocussedItem;
|
||||
SelectingEventArgs args = new SelectingEventArgs()
|
||||
{
|
||||
Item = item,
|
||||
SelectedIndex = FocussedItemIndex
|
||||
};
|
||||
|
||||
Menu.OnSelecting(args);
|
||||
|
||||
if (args.Cancel)
|
||||
{
|
||||
FocussedItemIndex = args.SelectedIndex;
|
||||
Invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.Handled)
|
||||
{
|
||||
var fragment = Menu.Fragment;
|
||||
DoAutocomplete(item, fragment);
|
||||
}
|
||||
|
||||
Menu.Close();
|
||||
//
|
||||
SelectedEventArgs args2 = new SelectedEventArgs()
|
||||
{
|
||||
Item = item,
|
||||
Tb = Menu.Fragment.tb
|
||||
};
|
||||
item.OnSelected(Menu, args2);
|
||||
Menu.OnSelected(args2);
|
||||
}
|
||||
finally
|
||||
{
|
||||
tb.TextSource.Manager.EndAutoUndoCommands();
|
||||
}
|
||||
}
|
||||
|
||||
private void DoAutocomplete(AutocompleteItem item, Range fragment)
|
||||
{
|
||||
string newText = item.GetTextForReplace();
|
||||
|
||||
//replace text of fragment
|
||||
var tb = fragment.tb;
|
||||
|
||||
tb.BeginAutoUndo();
|
||||
tb.TextSource.Manager.ExecuteCommand(new SelectCommand(tb.TextSource));
|
||||
if (tb.Selection.ColumnSelectionMode)
|
||||
{
|
||||
var start = tb.Selection.Start;
|
||||
var end = tb.Selection.End;
|
||||
start.iChar = fragment.Start.iChar;
|
||||
end.iChar = fragment.End.iChar;
|
||||
tb.Selection.Start = start;
|
||||
tb.Selection.End = end;
|
||||
}
|
||||
else
|
||||
{
|
||||
tb.Selection.Start = fragment.Start;
|
||||
tb.Selection.End = fragment.End;
|
||||
}
|
||||
tb.InsertText(newText);
|
||||
tb.TextSource.Manager.ExecuteCommand(new SelectCommand(tb.TextSource));
|
||||
tb.EndAutoUndo();
|
||||
tb.Focus();
|
||||
}
|
||||
|
||||
int PointToItemIndex(Point p)
|
||||
{
|
||||
return (p.Y + VerticalScroll.Value) / ItemHeight;
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
ProcessKey(keyData, Keys.None);
|
||||
|
||||
return base.ProcessCmdKey(ref msg, keyData);
|
||||
}
|
||||
|
||||
private bool ProcessKey(Keys keyData, Keys keyModifiers)
|
||||
{
|
||||
if (keyModifiers == Keys.None)
|
||||
switch (keyData)
|
||||
{
|
||||
case Keys.Down:
|
||||
SelectNext(+1);
|
||||
return true;
|
||||
case Keys.PageDown:
|
||||
SelectNext(+10);
|
||||
return true;
|
||||
case Keys.Up:
|
||||
SelectNext(-1);
|
||||
return true;
|
||||
case Keys.PageUp:
|
||||
SelectNext(-10);
|
||||
return true;
|
||||
case Keys.Enter:
|
||||
OnSelecting();
|
||||
return true;
|
||||
case Keys.Tab:
|
||||
if (!AllowTabKey)
|
||||
break;
|
||||
OnSelecting();
|
||||
return true;
|
||||
case Keys.Escape:
|
||||
Menu.Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SelectNext(int shift)
|
||||
{
|
||||
FocussedItemIndex = Math.Max(0, Math.Min(FocussedItemIndex + shift, visibleItems.Count - 1));
|
||||
DoSelectedVisible();
|
||||
//
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
private void DoSelectedVisible()
|
||||
{
|
||||
if (FocussedItem != null)
|
||||
SetToolTip(FocussedItem);
|
||||
|
||||
var y = FocussedItemIndex * ItemHeight - VerticalScroll.Value;
|
||||
if (y < 0)
|
||||
VerticalScroll.Value = FocussedItemIndex * ItemHeight;
|
||||
if (y > ClientSize.Height - ItemHeight)
|
||||
VerticalScroll.Value = Math.Min(VerticalScroll.Maximum, FocussedItemIndex * ItemHeight - ClientSize.Height + ItemHeight);
|
||||
//some magic for update scrolls
|
||||
AutoScrollMinSize -= new Size(1, 0);
|
||||
AutoScrollMinSize += new Size(1, 0);
|
||||
}
|
||||
|
||||
private void SetToolTip(AutocompleteItem autocompleteItem)
|
||||
{
|
||||
var title = autocompleteItem.ToolTipTitle;
|
||||
var text = autocompleteItem.ToolTipText;
|
||||
|
||||
Control window = tb;
|
||||
if (string.IsNullOrEmpty(title))
|
||||
{
|
||||
toolTip.Hide(window);
|
||||
return;
|
||||
}
|
||||
|
||||
var location = new Point(Right + 3 + Menu.Left, Menu.Top);
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
toolTip.ToolTipTitle = null;
|
||||
if (ToolTipDuration == 0)
|
||||
toolTip.Show(title, window, location);
|
||||
else
|
||||
toolTip.Show(title, window, location, ToolTipDuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
toolTip.ToolTipTitle = title;
|
||||
if (ToolTipDuration == 0)
|
||||
toolTip.Show(text, window, location);
|
||||
else
|
||||
toolTip.Show(text, window, location, ToolTipDuration);
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return visibleItems.Count; }
|
||||
}
|
||||
|
||||
public void SetAutocompleteItems(ICollection<string> items)
|
||||
{
|
||||
List<AutocompleteItem> list = new List<AutocompleteItem>(items.Count);
|
||||
foreach (var item in items)
|
||||
list.Add(new AutocompleteItem(item));
|
||||
SetAutocompleteItems(list);
|
||||
}
|
||||
|
||||
public void SetAutocompleteItems(IEnumerable<AutocompleteItem> items)
|
||||
{
|
||||
sourceItems = items;
|
||||
}
|
||||
}
|
||||
|
||||
public class SelectingEventArgs : EventArgs
|
||||
{
|
||||
public AutocompleteItem Item { get; internal set; }
|
||||
public bool Cancel {get;set;}
|
||||
public int SelectedIndex{get;set;}
|
||||
public bool Handled { get; set; }
|
||||
}
|
||||
|
||||
public class SelectedEventArgs : EventArgs
|
||||
{
|
||||
public AutocompleteItem Item { get; internal set; }
|
||||
public FastColoredTextBox Tb { get; set; }
|
||||
}
|
||||
}
|
256
GUI.NET/Debugger/FastColoredTextBox/Bookmarks.cs
Normal file
256
GUI.NET/Debugger/FastColoredTextBox/Bookmarks.cs
Normal file
|
@ -0,0 +1,256 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for bookmark collection
|
||||
/// </summary>
|
||||
public abstract class BaseBookmarks : ICollection<Bookmark>, IDisposable
|
||||
{
|
||||
#region ICollection
|
||||
public abstract void Add(Bookmark item);
|
||||
public abstract void Clear();
|
||||
public abstract bool Contains(Bookmark item);
|
||||
public abstract void CopyTo(Bookmark[] array, int arrayIndex);
|
||||
public abstract int Count { get; }
|
||||
public abstract bool IsReadOnly { get; }
|
||||
public abstract bool Remove(Bookmark item);
|
||||
public abstract IEnumerator<Bookmark> GetEnumerator();
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
public abstract void Dispose();
|
||||
#endregion
|
||||
|
||||
#region Additional properties
|
||||
|
||||
public abstract void Add(int lineIndex, string bookmarkName);
|
||||
public abstract void Add(int lineIndex);
|
||||
public abstract bool Contains(int lineIndex);
|
||||
public abstract bool Remove(int lineIndex);
|
||||
public abstract Bookmark GetBookmark(int i);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection of bookmarks
|
||||
/// </summary>
|
||||
public class Bookmarks : BaseBookmarks
|
||||
{
|
||||
protected FastColoredTextBox tb;
|
||||
protected List<Bookmark> items = new List<Bookmark>();
|
||||
protected int counter;
|
||||
|
||||
public Bookmarks(FastColoredTextBox tb)
|
||||
{
|
||||
this.tb = tb;
|
||||
tb.LineInserted += tb_LineInserted;
|
||||
tb.LineRemoved += tb_LineRemoved;
|
||||
}
|
||||
|
||||
protected virtual void tb_LineRemoved(object sender, LineRemovedEventArgs e)
|
||||
{
|
||||
for(int i=0; i<Count; i++)
|
||||
if (items[i].LineIndex >= e.Index)
|
||||
{
|
||||
if (items[i].LineIndex >= e.Index + e.Count)
|
||||
{
|
||||
items[i].LineIndex = items[i].LineIndex - e.Count;
|
||||
continue;
|
||||
}
|
||||
|
||||
var was = e.Index <= 0;
|
||||
foreach (var b in items)
|
||||
if (b.LineIndex == e.Index - 1)
|
||||
was = true;
|
||||
|
||||
if(was)
|
||||
{
|
||||
items.RemoveAt(i);
|
||||
i--;
|
||||
}else
|
||||
items[i].LineIndex = e.Index - 1;
|
||||
|
||||
//if (items[i].LineIndex == e.Index + e.Count - 1)
|
||||
//{
|
||||
// items[i].LineIndex = items[i].LineIndex - e.Count;
|
||||
// continue;
|
||||
//}
|
||||
//
|
||||
//items.RemoveAt(i);
|
||||
//i--;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void tb_LineInserted(object sender, LineInsertedEventArgs e)
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (items[i].LineIndex >= e.Index)
|
||||
{
|
||||
items[i].LineIndex = items[i].LineIndex + e.Count;
|
||||
}else
|
||||
if (items[i].LineIndex == e.Index - 1 && e.Count == 1)
|
||||
{
|
||||
if(tb[e.Index - 1].StartSpacesCount == tb[e.Index - 1].Count)
|
||||
items[i].LineIndex = items[i].LineIndex + e.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
tb.LineInserted -= tb_LineInserted;
|
||||
tb.LineRemoved -= tb_LineRemoved;
|
||||
}
|
||||
|
||||
public override IEnumerator<Bookmark> GetEnumerator()
|
||||
{
|
||||
foreach (var item in items)
|
||||
yield return item;
|
||||
}
|
||||
|
||||
public override void Add(int lineIndex, string bookmarkName)
|
||||
{
|
||||
Add(new Bookmark(tb, bookmarkName ?? "Bookmark " + counter, lineIndex));
|
||||
}
|
||||
|
||||
public override void Add(int lineIndex)
|
||||
{
|
||||
Add(new Bookmark(tb, "Bookmark " + counter, lineIndex));
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
items.Clear();
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
public override void Add(Bookmark bookmark)
|
||||
{
|
||||
foreach (var bm in items)
|
||||
if (bm.LineIndex == bookmark.LineIndex)
|
||||
return;
|
||||
|
||||
items.Add(bookmark);
|
||||
counter++;
|
||||
tb.Invalidate();
|
||||
}
|
||||
|
||||
public override bool Contains(Bookmark item)
|
||||
{
|
||||
return items.Contains(item);
|
||||
}
|
||||
|
||||
public override bool Contains(int lineIndex)
|
||||
{
|
||||
foreach (var item in items)
|
||||
if (item.LineIndex == lineIndex)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void CopyTo(Bookmark[] array, int arrayIndex)
|
||||
{
|
||||
items.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public override int Count
|
||||
{
|
||||
get { return items.Count; }
|
||||
}
|
||||
|
||||
public override bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool Remove(Bookmark item)
|
||||
{
|
||||
tb.Invalidate();
|
||||
return items.Remove(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes bookmark by line index
|
||||
/// </summary>
|
||||
public override bool Remove(int lineIndex)
|
||||
{
|
||||
bool was = false;
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (items[i].LineIndex == lineIndex)
|
||||
{
|
||||
items.RemoveAt(i);
|
||||
i--;
|
||||
was = true;
|
||||
}
|
||||
tb.Invalidate();
|
||||
|
||||
return was;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns Bookmark by index.
|
||||
/// </summary>
|
||||
public override Bookmark GetBookmark(int i)
|
||||
{
|
||||
return items[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bookmark of FastColoredTextbox
|
||||
/// </summary>
|
||||
public class Bookmark
|
||||
{
|
||||
public FastColoredTextBox TB { get; private set; }
|
||||
/// <summary>
|
||||
/// Name of bookmark
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// Line index
|
||||
/// </summary>
|
||||
public int LineIndex {get; set; }
|
||||
/// <summary>
|
||||
/// Color of bookmark sign
|
||||
/// </summary>
|
||||
public Color Color { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scroll textbox to the bookmark
|
||||
/// </summary>
|
||||
public virtual void DoVisible()
|
||||
{
|
||||
TB.Selection.Start = new Place(0, LineIndex);
|
||||
TB.DoRangeVisible(TB.Selection, true);
|
||||
TB.Invalidate();
|
||||
}
|
||||
|
||||
public Bookmark(FastColoredTextBox tb, string name, int lineIndex)
|
||||
{
|
||||
this.TB = tb;
|
||||
this.Name = name;
|
||||
this.LineIndex = lineIndex;
|
||||
Color = tb.BookmarkColor;
|
||||
}
|
||||
|
||||
public virtual void Paint(Graphics gr, Rectangle lineRect)
|
||||
{
|
||||
var size = TB.CharHeight - 1;
|
||||
using (var brush = new LinearGradientBrush(new Rectangle(0, lineRect.Top, size, size), Color.White, Color, 45))
|
||||
gr.FillEllipse(brush, 0, lineRect.Top, size, size);
|
||||
using (var pen = new Pen(Color))
|
||||
gr.DrawEllipse(pen, 0, lineRect.Top, size, size);
|
||||
}
|
||||
}
|
||||
}
|
26
GUI.NET/Debugger/FastColoredTextBox/Char.cs
Normal file
26
GUI.NET/Debugger/FastColoredTextBox/Char.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Char and style
|
||||
/// </summary>
|
||||
public struct Char
|
||||
{
|
||||
/// <summary>
|
||||
/// Unicode character
|
||||
/// </summary>
|
||||
public char c;
|
||||
/// <summary>
|
||||
/// Style bit mask
|
||||
/// </summary>
|
||||
/// <remarks>Bit 1 in position n means that this char will rendering by FastColoredTextBox.Styles[n]</remarks>
|
||||
public StyleIndex style;
|
||||
|
||||
public Char(char c)
|
||||
{
|
||||
this.c = c;
|
||||
style = StyleIndex.None;
|
||||
}
|
||||
}
|
||||
}
|
239
GUI.NET/Debugger/FastColoredTextBox/CommandManager.cs
Normal file
239
GUI.NET/Debugger/FastColoredTextBox/CommandManager.cs
Normal file
|
@ -0,0 +1,239 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public class CommandManager
|
||||
{
|
||||
readonly int maxHistoryLength = 200;
|
||||
LimitedStack<UndoableCommand> history;
|
||||
Stack<UndoableCommand> redoStack = new Stack<UndoableCommand>();
|
||||
public TextSource TextSource{ get; private set; }
|
||||
public bool UndoRedoStackIsEnabled { get; set; }
|
||||
|
||||
public CommandManager(TextSource ts)
|
||||
{
|
||||
history = new LimitedStack<UndoableCommand>(maxHistoryLength);
|
||||
TextSource = ts;
|
||||
UndoRedoStackIsEnabled = true;
|
||||
}
|
||||
|
||||
public virtual void ExecuteCommand(Command cmd)
|
||||
{
|
||||
if (disabledCommands > 0)
|
||||
return;
|
||||
|
||||
//multirange ?
|
||||
if (cmd.ts.CurrentTB.Selection.ColumnSelectionMode)
|
||||
if (cmd is UndoableCommand)
|
||||
//make wrapper
|
||||
cmd = new MultiRangeCommand((UndoableCommand)cmd);
|
||||
|
||||
|
||||
if (cmd is UndoableCommand)
|
||||
{
|
||||
//if range is ColumnRange, then create wrapper
|
||||
(cmd as UndoableCommand).autoUndo = autoUndoCommands > 0;
|
||||
history.Push(cmd as UndoableCommand);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
cmd.Execute();
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
//OnTextChanging cancels enter of the text
|
||||
if (cmd is UndoableCommand)
|
||||
history.Pop();
|
||||
}
|
||||
//
|
||||
if (!UndoRedoStackIsEnabled)
|
||||
ClearHistory();
|
||||
//
|
||||
redoStack.Clear();
|
||||
//
|
||||
TextSource.CurrentTB.OnUndoRedoStateChanged();
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
if (history.Count > 0)
|
||||
{
|
||||
var cmd = history.Pop();
|
||||
//
|
||||
BeginDisableCommands();//prevent text changing into handlers
|
||||
try
|
||||
{
|
||||
cmd.Undo();
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndDisableCommands();
|
||||
}
|
||||
//
|
||||
redoStack.Push(cmd);
|
||||
}
|
||||
|
||||
//undo next autoUndo command
|
||||
if (history.Count > 0)
|
||||
{
|
||||
if (history.Peek().autoUndo)
|
||||
Undo();
|
||||
}
|
||||
|
||||
TextSource.CurrentTB.OnUndoRedoStateChanged();
|
||||
}
|
||||
|
||||
protected int disabledCommands = 0;
|
||||
|
||||
private void EndDisableCommands()
|
||||
{
|
||||
disabledCommands--;
|
||||
}
|
||||
|
||||
private void BeginDisableCommands()
|
||||
{
|
||||
disabledCommands++;
|
||||
}
|
||||
|
||||
int autoUndoCommands = 0;
|
||||
|
||||
public void EndAutoUndoCommands()
|
||||
{
|
||||
autoUndoCommands--;
|
||||
if (autoUndoCommands == 0)
|
||||
if (history.Count > 0)
|
||||
history.Peek().autoUndo = false;
|
||||
}
|
||||
|
||||
public void BeginAutoUndoCommands()
|
||||
{
|
||||
autoUndoCommands++;
|
||||
}
|
||||
|
||||
internal void ClearHistory()
|
||||
{
|
||||
history.Clear();
|
||||
redoStack.Clear();
|
||||
TextSource.CurrentTB.OnUndoRedoStateChanged();
|
||||
}
|
||||
|
||||
internal void Redo()
|
||||
{
|
||||
if (redoStack.Count == 0)
|
||||
return;
|
||||
UndoableCommand cmd;
|
||||
BeginDisableCommands();//prevent text changing into handlers
|
||||
try
|
||||
{
|
||||
cmd = redoStack.Pop();
|
||||
if (TextSource.CurrentTB.Selection.ColumnSelectionMode)
|
||||
TextSource.CurrentTB.Selection.ColumnSelectionMode = false;
|
||||
TextSource.CurrentTB.Selection.Start = cmd.sel.Start;
|
||||
TextSource.CurrentTB.Selection.End = cmd.sel.End;
|
||||
cmd.Execute();
|
||||
history.Push(cmd);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndDisableCommands();
|
||||
}
|
||||
|
||||
//redo command after autoUndoable command
|
||||
if (cmd.autoUndo)
|
||||
Redo();
|
||||
|
||||
TextSource.CurrentTB.OnUndoRedoStateChanged();
|
||||
}
|
||||
|
||||
public bool UndoEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return history.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool RedoEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return redoStack.Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Command
|
||||
{
|
||||
public TextSource ts;
|
||||
public abstract void Execute();
|
||||
}
|
||||
|
||||
internal class RangeInfo
|
||||
{
|
||||
public Place Start { get; set; }
|
||||
public Place End { get; set; }
|
||||
|
||||
public RangeInfo(Range r)
|
||||
{
|
||||
Start = r.Start;
|
||||
End = r.End;
|
||||
}
|
||||
|
||||
internal int FromX
|
||||
{
|
||||
get
|
||||
{
|
||||
if (End.iLine < Start.iLine) return End.iChar;
|
||||
if (End.iLine > Start.iLine) return Start.iChar;
|
||||
return Math.Min(End.iChar, Start.iChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class UndoableCommand : Command
|
||||
{
|
||||
internal RangeInfo sel;
|
||||
internal RangeInfo lastSel;
|
||||
internal bool autoUndo;
|
||||
|
||||
public UndoableCommand(TextSource ts)
|
||||
{
|
||||
this.ts = ts;
|
||||
sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
public virtual void Undo()
|
||||
{
|
||||
OnTextChanged(true);
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
lastSel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
OnTextChanged(false);
|
||||
}
|
||||
|
||||
protected virtual void OnTextChanged(bool invert)
|
||||
{
|
||||
bool b = sel.Start.iLine < lastSel.Start.iLine;
|
||||
if (invert)
|
||||
{
|
||||
if (b)
|
||||
ts.OnTextChanged(sel.Start.iLine, sel.Start.iLine);
|
||||
else
|
||||
ts.OnTextChanged(sel.Start.iLine, lastSel.Start.iLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b)
|
||||
ts.OnTextChanged(sel.Start.iLine, lastSel.Start.iLine);
|
||||
else
|
||||
ts.OnTextChanged(lastSel.Start.iLine, lastSel.Start.iLine);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract UndoableCommand Clone();
|
||||
}
|
||||
}
|
809
GUI.NET/Debugger/FastColoredTextBox/Commands.cs
Normal file
809
GUI.NET/Debugger/FastColoredTextBox/Commands.cs
Normal file
|
@ -0,0 +1,809 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Insert single char
|
||||
/// </summary>
|
||||
/// <remarks>This operation includes also insertion of new line and removing char by backspace</remarks>
|
||||
public class InsertCharCommand : UndoableCommand
|
||||
{
|
||||
public char c;
|
||||
char deletedChar = '\x0';
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="c">Inserting char</param>
|
||||
public InsertCharCommand(TextSource ts, char c): base(ts)
|
||||
{
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
ts.OnTextChanging();
|
||||
switch (c)
|
||||
{
|
||||
case '\n': MergeLines(sel.Start.iLine, ts); break;
|
||||
case '\r': break;
|
||||
case '\b':
|
||||
ts.CurrentTB.Selection.Start = lastSel.Start;
|
||||
char cc = '\x0';
|
||||
if (deletedChar != '\x0')
|
||||
{
|
||||
ts.CurrentTB.ExpandBlock(ts.CurrentTB.Selection.Start.iLine);
|
||||
InsertChar(deletedChar, ref cc, ts);
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
ts.CurrentTB.ExpandBlock(sel.Start.iLine);
|
||||
for (int i = sel.FromX; i < lastSel.FromX; i++)
|
||||
ts[sel.Start.iLine].RemoveAt(sel.Start.iChar);
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
break;
|
||||
default:
|
||||
ts.CurrentTB.ExpandBlock(sel.Start.iLine);
|
||||
ts[sel.Start.iLine].RemoveAt(sel.Start.iChar);
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
break;
|
||||
}
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(sel.Start.iLine, sel.Start.iLine));
|
||||
|
||||
base.Undo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
ts.CurrentTB.ExpandBlock(ts.CurrentTB.Selection.Start.iLine);
|
||||
string s = c.ToString();
|
||||
ts.OnTextChanging(ref s);
|
||||
if (s.Length == 1)
|
||||
c = s[0];
|
||||
|
||||
if (String.IsNullOrEmpty(s))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
|
||||
if (ts.Count == 0)
|
||||
InsertLine(ts);
|
||||
InsertChar(c, ref deletedChar, ts);
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(ts.CurrentTB.Selection.Start.iLine, ts.CurrentTB.Selection.Start.iLine));
|
||||
base.Execute();
|
||||
}
|
||||
|
||||
internal static void InsertChar(char c, ref char deletedChar, TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
if (!ts.CurrentTB.AllowInsertRemoveLines)
|
||||
throw new ArgumentOutOfRangeException("Cant insert this char in ColumnRange mode");
|
||||
if (ts.Count == 0)
|
||||
InsertLine(ts);
|
||||
InsertLine(ts);
|
||||
break;
|
||||
case '\r': break;
|
||||
case '\b'://backspace
|
||||
if (tb.Selection.Start.iChar == 0 && tb.Selection.Start.iLine == 0)
|
||||
return;
|
||||
if (tb.Selection.Start.iChar == 0)
|
||||
{
|
||||
if (!ts.CurrentTB.AllowInsertRemoveLines)
|
||||
throw new ArgumentOutOfRangeException("Cant insert this char in ColumnRange mode");
|
||||
if (tb.LineInfos[tb.Selection.Start.iLine - 1].VisibleState != VisibleState.Visible)
|
||||
tb.ExpandBlock(tb.Selection.Start.iLine - 1);
|
||||
deletedChar = '\n';
|
||||
MergeLines(tb.Selection.Start.iLine - 1, ts);
|
||||
}
|
||||
else
|
||||
{
|
||||
deletedChar = ts[tb.Selection.Start.iLine][tb.Selection.Start.iChar - 1].c;
|
||||
ts[tb.Selection.Start.iLine].RemoveAt(tb.Selection.Start.iChar - 1);
|
||||
tb.Selection.Start = new Place(tb.Selection.Start.iChar - 1, tb.Selection.Start.iLine);
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
int spaceCountNextTabStop = tb.TabLength - (tb.Selection.Start.iChar % tb.TabLength);
|
||||
if (spaceCountNextTabStop == 0)
|
||||
spaceCountNextTabStop = tb.TabLength;
|
||||
|
||||
for (int i = 0; i < spaceCountNextTabStop; i++)
|
||||
ts[tb.Selection.Start.iLine].Insert(tb.Selection.Start.iChar, new Char(' '));
|
||||
|
||||
tb.Selection.Start = new Place(tb.Selection.Start.iChar + spaceCountNextTabStop, tb.Selection.Start.iLine);
|
||||
break;
|
||||
default:
|
||||
ts[tb.Selection.Start.iLine].Insert(tb.Selection.Start.iChar, new Char(c));
|
||||
tb.Selection.Start = new Place(tb.Selection.Start.iChar + 1, tb.Selection.Start.iLine);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InsertLine(TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
if (!tb.Multiline && tb.LinesCount > 0)
|
||||
return;
|
||||
|
||||
if (ts.Count == 0)
|
||||
ts.InsertLine(0, ts.CreateLine());
|
||||
else
|
||||
BreakLines(tb.Selection.Start.iLine, tb.Selection.Start.iChar, ts);
|
||||
|
||||
tb.Selection.Start = new Place(0, tb.Selection.Start.iLine + 1);
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merge lines i and i+1
|
||||
/// </summary>
|
||||
internal static void MergeLines(int i, TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
if (i + 1 >= ts.Count)
|
||||
return;
|
||||
tb.ExpandBlock(i);
|
||||
tb.ExpandBlock(i + 1);
|
||||
int pos = ts[i].Count;
|
||||
//
|
||||
/*
|
||||
if(ts[i].Count == 0)
|
||||
ts.RemoveLine(i);
|
||||
else*/
|
||||
if (ts[i + 1].Count == 0)
|
||||
ts.RemoveLine(i + 1);
|
||||
else
|
||||
{
|
||||
ts[i].AddRange(ts[i + 1]);
|
||||
ts.RemoveLine(i + 1);
|
||||
}
|
||||
tb.Selection.Start = new Place(pos, i);
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
internal static void BreakLines(int iLine, int pos, TextSource ts)
|
||||
{
|
||||
Line newLine = ts.CreateLine();
|
||||
for(int i=pos;i<ts[iLine].Count;i++)
|
||||
newLine.Add(ts[iLine][i]);
|
||||
ts[iLine].RemoveRange(pos, ts[iLine].Count - pos);
|
||||
//
|
||||
ts.InsertLine(iLine+1, newLine);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new InsertCharCommand(ts, c);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert text
|
||||
/// </summary>
|
||||
public class InsertTextCommand : UndoableCommand
|
||||
{
|
||||
public string InsertedText;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="insertedText">Text for inserting</param>
|
||||
public InsertTextCommand(TextSource ts, string insertedText): base(ts)
|
||||
{
|
||||
this.InsertedText = insertedText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
ts.CurrentTB.Selection.End = lastSel.Start;
|
||||
ts.OnTextChanging();
|
||||
ClearSelectedCommand.ClearSelected(ts);
|
||||
base.Undo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
ts.OnTextChanging(ref InsertedText);
|
||||
InsertText(InsertedText, ts);
|
||||
base.Execute();
|
||||
}
|
||||
|
||||
internal static void InsertText(string insertedText, TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
try
|
||||
{
|
||||
tb.Selection.BeginUpdate();
|
||||
char cc = '\x0';
|
||||
|
||||
if (ts.Count == 0)
|
||||
{
|
||||
InsertCharCommand.InsertLine(ts);
|
||||
tb.Selection.Start = Place.Empty;
|
||||
}
|
||||
tb.ExpandBlock(tb.Selection.Start.iLine);
|
||||
var len = insertedText.Length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
var c = insertedText[i];
|
||||
if(c == '\r' && (i >= len - 1 || insertedText[i + 1] != '\n'))
|
||||
InsertCharCommand.InsertChar('\n', ref cc, ts);
|
||||
else
|
||||
InsertCharCommand.InsertChar(c, ref cc, ts);
|
||||
}
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
finally {
|
||||
tb.Selection.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new InsertTextCommand(ts, InsertedText);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert text into given ranges
|
||||
/// </summary>
|
||||
public class ReplaceTextCommand : UndoableCommand
|
||||
{
|
||||
string insertedText;
|
||||
List<Range> ranges;
|
||||
List<string> prevText = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="ranges">List of ranges for replace</param>
|
||||
/// <param name="insertedText">Text for inserting</param>
|
||||
public ReplaceTextCommand(TextSource ts, List<Range> ranges, string insertedText)
|
||||
: base(ts)
|
||||
{
|
||||
//sort ranges by place
|
||||
ranges.Sort((r1, r2)=>
|
||||
{
|
||||
if (r1.Start.iLine == r2.Start.iLine)
|
||||
return r1.Start.iChar.CompareTo(r2.Start.iChar);
|
||||
return r1.Start.iLine.CompareTo(r2.Start.iLine);
|
||||
});
|
||||
//
|
||||
this.ranges = ranges;
|
||||
this.insertedText = insertedText;
|
||||
lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
ts.OnTextChanging();
|
||||
tb.BeginUpdate();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for (int i = 0; i<ranges.Count; i++)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].Start;
|
||||
for (int j = 0; j < insertedText.Length; j++)
|
||||
tb.Selection.GoRight(true);
|
||||
ClearSelected(ts);
|
||||
InsertTextCommand.InsertText(prevText[prevText.Count - i - 1], ts);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
tb.EndUpdate();
|
||||
|
||||
if (ranges.Count > 0)
|
||||
ts.OnTextChanged(ranges[0].Start.iLine, ranges[ranges.Count - 1].End.iLine);
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
prevText.Clear();
|
||||
|
||||
ts.OnTextChanging(ref insertedText);
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
tb.BeginUpdate();
|
||||
for (int i = ranges.Count - 1; i >= 0; i--)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].Start;
|
||||
tb.Selection.End = ranges[i].End;
|
||||
prevText.Add(tb.Selection.Text);
|
||||
ClearSelected(ts);
|
||||
if (insertedText != "")
|
||||
InsertTextCommand.InsertText(insertedText, ts);
|
||||
}
|
||||
if(ranges.Count > 0)
|
||||
ts.OnTextChanged(ranges[0].Start.iLine, ranges[ranges.Count - 1].End.iLine);
|
||||
tb.EndUpdate();
|
||||
tb.Selection.EndUpdate();
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new ReplaceTextCommand(ts, new List<Range>(ranges), insertedText);
|
||||
}
|
||||
|
||||
internal static void ClearSelected(TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
tb.Selection.Normalize();
|
||||
|
||||
Place start = tb.Selection.Start;
|
||||
Place end = tb.Selection.End;
|
||||
int fromLine = Math.Min(end.iLine, start.iLine);
|
||||
int toLine = Math.Max(end.iLine, start.iLine);
|
||||
int fromChar = tb.Selection.FromX;
|
||||
int toChar = tb.Selection.ToX;
|
||||
if (fromLine < 0) return;
|
||||
//
|
||||
if (fromLine == toLine)
|
||||
ts[fromLine].RemoveRange(fromChar, toChar - fromChar);
|
||||
else
|
||||
{
|
||||
ts[fromLine].RemoveRange(fromChar, ts[fromLine].Count - fromChar);
|
||||
ts[toLine].RemoveRange(0, toChar);
|
||||
ts.RemoveLine(fromLine + 1, toLine - fromLine - 1);
|
||||
InsertCharCommand.MergeLines(fromLine, ts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear selected text
|
||||
/// </summary>
|
||||
public class ClearSelectedCommand : UndoableCommand
|
||||
{
|
||||
string deletedText;
|
||||
|
||||
/// <summary>
|
||||
/// Construstor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
public ClearSelectedCommand(TextSource ts): base(ts)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
ts.CurrentTB.Selection.Start = new Place(sel.FromX, Math.Min(sel.Start.iLine, sel.End.iLine));
|
||||
ts.OnTextChanging();
|
||||
InsertTextCommand.InsertText(deletedText, ts);
|
||||
ts.OnTextChanged(sel.Start.iLine, sel.End.iLine);
|
||||
ts.CurrentTB.Selection.Start = sel.Start;
|
||||
ts.CurrentTB.Selection.End = sel.End;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
string temp = null;
|
||||
ts.OnTextChanging(ref temp);
|
||||
if (temp == "")
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
deletedText = tb.Selection.Text;
|
||||
ClearSelected(ts);
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
ts.OnTextChanged(lastSel.Start.iLine, lastSel.Start.iLine);
|
||||
}
|
||||
|
||||
internal static void ClearSelected(TextSource ts)
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
Place start = tb.Selection.Start;
|
||||
Place end = tb.Selection.End;
|
||||
int fromLine = Math.Min(end.iLine, start.iLine);
|
||||
int toLine = Math.Max(end.iLine, start.iLine);
|
||||
int fromChar = tb.Selection.FromX;
|
||||
int toChar = tb.Selection.ToX;
|
||||
if (fromLine < 0) return;
|
||||
//
|
||||
if (fromLine == toLine)
|
||||
ts[fromLine].RemoveRange(fromChar, toChar - fromChar);
|
||||
else
|
||||
{
|
||||
ts[fromLine].RemoveRange(fromChar, ts[fromLine].Count - fromChar);
|
||||
ts[toLine].RemoveRange(0, toChar);
|
||||
ts.RemoveLine(fromLine + 1, toLine - fromLine - 1);
|
||||
InsertCharCommand.MergeLines(fromLine, ts);
|
||||
}
|
||||
//
|
||||
tb.Selection.Start = new Place(fromChar, fromLine);
|
||||
//
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(fromLine, toLine));
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new ClearSelectedCommand(ts);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces text
|
||||
/// </summary>
|
||||
public class ReplaceMultipleTextCommand : UndoableCommand
|
||||
{
|
||||
List<ReplaceRange> ranges;
|
||||
List<string> prevText = new List<string>();
|
||||
|
||||
public class ReplaceRange
|
||||
{
|
||||
public Range ReplacedRange { get; set; }
|
||||
public String ReplaceText { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="ts">Underlaying textsource</param>
|
||||
/// <param name="ranges">List of ranges for replace</param>
|
||||
public ReplaceMultipleTextCommand(TextSource ts, List<ReplaceRange> ranges)
|
||||
: base(ts)
|
||||
{
|
||||
//sort ranges by place
|
||||
ranges.Sort((r1, r2) =>
|
||||
{
|
||||
if (r1.ReplacedRange.Start.iLine == r2.ReplacedRange.Start.iLine)
|
||||
return r1.ReplacedRange.Start.iChar.CompareTo(r2.ReplacedRange.Start.iChar);
|
||||
return r1.ReplacedRange.Start.iLine.CompareTo(r2.ReplacedRange.Start.iLine);
|
||||
});
|
||||
//
|
||||
this.ranges = ranges;
|
||||
lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for (int i = 0; i < ranges.Count; i++)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].ReplacedRange.Start;
|
||||
for (int j = 0; j < ranges[i].ReplaceText.Length; j++)
|
||||
tb.Selection.GoRight(true);
|
||||
ClearSelectedCommand.ClearSelected(ts);
|
||||
var prevTextIndex = ranges.Count - 1 - i;
|
||||
InsertTextCommand.InsertText(prevText[prevTextIndex], ts);
|
||||
ts.OnTextChanged(ranges[i].ReplacedRange.Start.iLine, ranges[i].ReplacedRange.Start.iLine);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
prevText.Clear();
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for (int i = ranges.Count - 1; i >= 0; i--)
|
||||
{
|
||||
tb.Selection.Start = ranges[i].ReplacedRange.Start;
|
||||
tb.Selection.End = ranges[i].ReplacedRange.End;
|
||||
prevText.Add(tb.Selection.Text);
|
||||
ClearSelectedCommand.ClearSelected(ts);
|
||||
InsertTextCommand.InsertText(ranges[i].ReplaceText, ts);
|
||||
ts.OnTextChanged(ranges[i].ReplacedRange.Start.iLine, ranges[i].ReplacedRange.End.iLine);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new ReplaceMultipleTextCommand(ts, new List<ReplaceRange>(ranges));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes lines
|
||||
/// </summary>
|
||||
public class RemoveLinesCommand : UndoableCommand
|
||||
{
|
||||
List<int> iLines;
|
||||
List<string> prevText = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="tb">Underlaying textbox</param>
|
||||
/// <param name="ranges">List of ranges for replace</param>
|
||||
/// <param name="insertedText">Text for inserting</param>
|
||||
public RemoveLinesCommand(TextSource ts, List<int> iLines)
|
||||
: base(ts)
|
||||
{
|
||||
//sort iLines
|
||||
iLines.Sort();
|
||||
//
|
||||
this.iLines = iLines;
|
||||
lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undo operation
|
||||
/// </summary>
|
||||
public override void Undo()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
//tb.BeginUpdate();
|
||||
for (int i = 0; i < iLines.Count; i++)
|
||||
{
|
||||
var iLine = iLines[i];
|
||||
|
||||
if(iLine < ts.Count)
|
||||
tb.Selection.Start = new Place(0, iLine);
|
||||
else
|
||||
tb.Selection.Start = new Place(ts[ts.Count - 1].Count, ts.Count - 1);
|
||||
|
||||
InsertCharCommand.InsertLine(ts);
|
||||
tb.Selection.Start = new Place(0, iLine);
|
||||
var text = prevText[prevText.Count - i - 1];
|
||||
InsertTextCommand.InsertText(text, ts);
|
||||
ts[iLine].IsChanged = true;
|
||||
if (iLine < ts.Count - 1)
|
||||
ts[iLine + 1].IsChanged = true;
|
||||
else
|
||||
ts[iLine - 1].IsChanged = true;
|
||||
if(text.Trim() != string.Empty)
|
||||
ts.OnTextChanged(iLine, iLine);
|
||||
}
|
||||
//tb.EndUpdate();
|
||||
tb.Selection.EndUpdate();
|
||||
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute operation
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
var tb = ts.CurrentTB;
|
||||
prevText.Clear();
|
||||
|
||||
ts.OnTextChanging();
|
||||
|
||||
tb.Selection.BeginUpdate();
|
||||
for(int i = iLines.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var iLine = iLines[i];
|
||||
|
||||
prevText.Add(ts[iLine].Text);//backward
|
||||
ts.RemoveLine(iLine);
|
||||
//ts.OnTextChanged(ranges[i].Start.iLine, ranges[i].End.iLine);
|
||||
}
|
||||
tb.Selection.Start = new Place(0, 0);
|
||||
tb.Selection.EndUpdate();
|
||||
ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));
|
||||
|
||||
lastSel = new RangeInfo(tb.Selection);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
return new RemoveLinesCommand(ts, new List<int>(iLines));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for multirange commands
|
||||
/// </summary>
|
||||
public class MultiRangeCommand : UndoableCommand
|
||||
{
|
||||
private UndoableCommand cmd;
|
||||
private Range range;
|
||||
private List<UndoableCommand> commandsByRanges = new List<UndoableCommand>();
|
||||
|
||||
public MultiRangeCommand(UndoableCommand command):base(command.ts)
|
||||
{
|
||||
this.cmd = command;
|
||||
range = ts.CurrentTB.Selection.Clone();
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
commandsByRanges.Clear();
|
||||
var prevSelection = range.Clone();
|
||||
var iChar = -1;
|
||||
var iStartLine = prevSelection.Start.iLine;
|
||||
var iEndLine = prevSelection.End.iLine;
|
||||
ts.CurrentTB.Selection.ColumnSelectionMode = false;
|
||||
ts.CurrentTB.Selection.BeginUpdate();
|
||||
ts.CurrentTB.BeginUpdate();
|
||||
ts.CurrentTB.AllowInsertRemoveLines = false;
|
||||
try
|
||||
{
|
||||
if (cmd is InsertTextCommand)
|
||||
ExecuteInsertTextCommand(ref iChar, (cmd as InsertTextCommand).InsertedText);
|
||||
else
|
||||
if (cmd is InsertCharCommand && (cmd as InsertCharCommand).c != '\x0' && (cmd as InsertCharCommand).c != '\b')//if not DEL or BACKSPACE
|
||||
ExecuteInsertTextCommand(ref iChar, (cmd as InsertCharCommand).c.ToString());
|
||||
else
|
||||
ExecuteCommand(ref iChar);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
ts.CurrentTB.AllowInsertRemoveLines = true;
|
||||
ts.CurrentTB.EndUpdate();
|
||||
|
||||
ts.CurrentTB.Selection = range;
|
||||
if (iChar >= 0)
|
||||
{
|
||||
ts.CurrentTB.Selection.Start = new Place(iChar, iStartLine);
|
||||
ts.CurrentTB.Selection.End = new Place(iChar, iEndLine);
|
||||
}
|
||||
ts.CurrentTB.Selection.ColumnSelectionMode = true;
|
||||
ts.CurrentTB.Selection.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteInsertTextCommand(ref int iChar, string text)
|
||||
{
|
||||
var lines = text.Split('\n');
|
||||
var iLine = 0;
|
||||
foreach (var r in range.GetSubRanges(true))
|
||||
{
|
||||
var line = ts.CurrentTB[r.Start.iLine];
|
||||
var lineIsEmpty = r.End < r.Start && line.StartSpacesCount == line.Count;
|
||||
if (!lineIsEmpty)
|
||||
{
|
||||
var insertedText = lines[iLine%lines.Length];
|
||||
if (r.End < r.Start && insertedText!="")
|
||||
{
|
||||
//add forwarding spaces
|
||||
insertedText = new string(' ', r.Start.iChar - r.End.iChar) + insertedText;
|
||||
r.Start = r.End;
|
||||
}
|
||||
ts.CurrentTB.Selection = r;
|
||||
var c = new InsertTextCommand(ts, insertedText);
|
||||
c.Execute();
|
||||
if (ts.CurrentTB.Selection.End.iChar > iChar)
|
||||
iChar = ts.CurrentTB.Selection.End.iChar;
|
||||
commandsByRanges.Add(c);
|
||||
}
|
||||
iLine++;
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteCommand(ref int iChar)
|
||||
{
|
||||
foreach (var r in range.GetSubRanges(false))
|
||||
{
|
||||
ts.CurrentTB.Selection = r;
|
||||
var c = cmd.Clone();
|
||||
c.Execute();
|
||||
if (ts.CurrentTB.Selection.End.iChar > iChar)
|
||||
iChar = ts.CurrentTB.Selection.End.iChar;
|
||||
commandsByRanges.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
ts.CurrentTB.BeginUpdate();
|
||||
ts.CurrentTB.Selection.BeginUpdate();
|
||||
try
|
||||
{
|
||||
for (int i = commandsByRanges.Count - 1; i >= 0; i--)
|
||||
commandsByRanges[i].Undo();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ts.CurrentTB.Selection.EndUpdate();
|
||||
ts.CurrentTB.EndUpdate();
|
||||
}
|
||||
ts.CurrentTB.Selection = range.Clone();
|
||||
ts.CurrentTB.OnTextChanged(range);
|
||||
ts.CurrentTB.OnSelectionChanged();
|
||||
ts.CurrentTB.Selection.ColumnSelectionMode = true;
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remembers current selection and restore it after Undo
|
||||
/// </summary>
|
||||
public class SelectCommand : UndoableCommand
|
||||
{
|
||||
public SelectCommand(TextSource ts):base(ts)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
//remember selection
|
||||
lastSel = new RangeInfo(ts.CurrentTB.Selection);
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(bool invert)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Undo()
|
||||
{
|
||||
//restore selection
|
||||
ts.CurrentTB.Selection = new Range(ts.CurrentTB, lastSel.Start, lastSel.End);
|
||||
}
|
||||
|
||||
public override UndoableCommand Clone()
|
||||
{
|
||||
var result = new SelectCommand(ts);
|
||||
if(lastSel!=null)
|
||||
result.lastSel = new RangeInfo(new Range(ts.CurrentTB, lastSel.Start, lastSel.End));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
250
GUI.NET/Debugger/FastColoredTextBox/DocumentMap.cs
Normal file
250
GUI.NET/Debugger/FastColoredTextBox/DocumentMap.cs
Normal file
|
@ -0,0 +1,250 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows document map of FCTB
|
||||
/// </summary>
|
||||
public class DocumentMap : Control
|
||||
{
|
||||
public EventHandler TargetChanged;
|
||||
|
||||
FastColoredTextBox target;
|
||||
private float scale = 0.3f;
|
||||
private bool needRepaint = true;
|
||||
private Place startPlace = Place.Empty;
|
||||
private bool scrollbarVisible = true;
|
||||
|
||||
[Description("Target FastColoredTextBox")]
|
||||
public FastColoredTextBox Target
|
||||
{
|
||||
get { return target; }
|
||||
set
|
||||
{
|
||||
if (target != null)
|
||||
UnSubscribe(target);
|
||||
|
||||
target = value;
|
||||
if (value != null)
|
||||
{
|
||||
Subscribe(target);
|
||||
}
|
||||
OnTargetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scale
|
||||
/// </summary>
|
||||
[Description("Scale")]
|
||||
[DefaultValue(0.3f)]
|
||||
public new float Scale
|
||||
{
|
||||
get { return scale; }
|
||||
set
|
||||
{
|
||||
scale = value;
|
||||
NeedRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrollbar visibility
|
||||
/// </summary>
|
||||
[Description("Scrollbar visibility")]
|
||||
[DefaultValue(true)]
|
||||
public bool ScrollbarVisible
|
||||
{
|
||||
get { return scrollbarVisible; }
|
||||
set
|
||||
{
|
||||
scrollbarVisible = value;
|
||||
NeedRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
public DocumentMap()
|
||||
{
|
||||
ForeColor = Color.Maroon;
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.ResizeRedraw, true);
|
||||
Application.Idle += Application_Idle;
|
||||
}
|
||||
|
||||
void Application_Idle(object sender, EventArgs e)
|
||||
{
|
||||
if(needRepaint)
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected virtual void OnTargetChanged()
|
||||
{
|
||||
NeedRepaint();
|
||||
|
||||
if (TargetChanged != null)
|
||||
TargetChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void UnSubscribe(FastColoredTextBox target)
|
||||
{
|
||||
target.Scroll -= new ScrollEventHandler(Target_Scroll);
|
||||
target.SelectionChangedDelayed -= new EventHandler(Target_SelectionChanged);
|
||||
target.VisibleRangeChanged -= new EventHandler(Target_VisibleRangeChanged);
|
||||
}
|
||||
|
||||
protected virtual void Subscribe(FastColoredTextBox target)
|
||||
{
|
||||
target.Scroll += new ScrollEventHandler(Target_Scroll);
|
||||
target.SelectionChangedDelayed += new EventHandler(Target_SelectionChanged);
|
||||
target.VisibleRangeChanged += new EventHandler(Target_VisibleRangeChanged);
|
||||
}
|
||||
|
||||
protected virtual void Target_VisibleRangeChanged(object sender, EventArgs e)
|
||||
{
|
||||
NeedRepaint();
|
||||
}
|
||||
|
||||
protected virtual void Target_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
NeedRepaint();
|
||||
}
|
||||
|
||||
protected virtual void Target_Scroll(object sender, ScrollEventArgs e)
|
||||
{
|
||||
NeedRepaint();
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
NeedRepaint();
|
||||
}
|
||||
|
||||
public void NeedRepaint()
|
||||
{
|
||||
needRepaint = true;
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
var zoom = this.Scale * 100 / target.Zoom;
|
||||
|
||||
if (zoom <= float.Epsilon)
|
||||
return;
|
||||
|
||||
//calc startPlace
|
||||
var r = target.VisibleRange;
|
||||
if (startPlace.iLine > r.Start.iLine)
|
||||
startPlace.iLine = r.Start.iLine;
|
||||
else
|
||||
{
|
||||
var endP = target.PlaceToPoint(r.End);
|
||||
endP.Offset(0, -(int)(ClientSize.Height / zoom) + target.CharHeight);
|
||||
var pp = target.PointToPlace(endP);
|
||||
if (pp.iLine > startPlace.iLine)
|
||||
startPlace.iLine = pp.iLine;
|
||||
}
|
||||
startPlace.iChar = 0;
|
||||
//calc scroll pos
|
||||
var linesCount = target.Lines.Count;
|
||||
var sp1 = (float)r.Start.iLine / linesCount;
|
||||
var sp2 = (float)r.End.iLine / linesCount;
|
||||
|
||||
//scale graphics
|
||||
e.Graphics.ScaleTransform(zoom, zoom);
|
||||
//draw text
|
||||
var size = new SizeF(ClientSize.Width / zoom, ClientSize.Height / zoom);
|
||||
target.DrawText(e.Graphics, startPlace, size.ToSize());
|
||||
|
||||
//draw visible rect
|
||||
var p0 = target.PlaceToPoint(startPlace);
|
||||
var p1 = target.PlaceToPoint(r.Start);
|
||||
var p2 = target.PlaceToPoint(r.End);
|
||||
var y1 = p1.Y - p0.Y;
|
||||
var y2 = p2.Y + target.CharHeight - p0.Y;
|
||||
|
||||
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
using (var brush = new SolidBrush(Color.FromArgb(50, ForeColor)))
|
||||
using (var pen = new Pen(brush, 1 / zoom))
|
||||
{
|
||||
var rect = new Rectangle(0, y1, (int)((ClientSize.Width - 1) / zoom), y2 - y1);
|
||||
e.Graphics.FillRectangle(brush, rect);
|
||||
e.Graphics.DrawRectangle(pen, rect);
|
||||
}
|
||||
|
||||
//draw scrollbar
|
||||
if (scrollbarVisible)
|
||||
{
|
||||
e.Graphics.ResetTransform();
|
||||
e.Graphics.SmoothingMode = SmoothingMode.None;
|
||||
|
||||
using (var brush = new SolidBrush(Color.FromArgb(200, ForeColor)))
|
||||
{
|
||||
var rect = new RectangleF(ClientSize.Width - 3, ClientSize.Height*sp1, 2,
|
||||
ClientSize.Height*(sp2 - sp1));
|
||||
e.Graphics.FillRectangle(brush, rect);
|
||||
}
|
||||
}
|
||||
|
||||
needRepaint = false;
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
||||
Scroll(e.Location);
|
||||
base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
||||
Scroll(e.Location);
|
||||
base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
private void Scroll(Point point)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
var zoom = this.Scale*100/target.Zoom;
|
||||
|
||||
if (zoom <= float.Epsilon)
|
||||
return;
|
||||
|
||||
var p0 = target.PlaceToPoint(startPlace);
|
||||
p0 = new Point(0, p0.Y + (int) (point.Y/zoom));
|
||||
var pp = target.PointToPlace(p0);
|
||||
target.DoRangeVisible(new Range(target, pp, pp), true);
|
||||
BeginInvoke((MethodInvoker)OnScroll);
|
||||
}
|
||||
|
||||
private void OnScroll()
|
||||
{
|
||||
Refresh();
|
||||
target.Refresh();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Application.Idle -= Application_Idle;
|
||||
if (target != null)
|
||||
UnSubscribe(target);
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
363
GUI.NET/Debugger/FastColoredTextBox/EncodingDetector.cs
Normal file
363
GUI.NET/Debugger/FastColoredTextBox/EncodingDetector.cs
Normal file
|
@ -0,0 +1,363 @@
|
|||
// Copyright Tao Klerks, 2010-2012, tao@klerks.biz
|
||||
// Licensed under the modified BSD license.
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public static class EncodingDetector
|
||||
{
|
||||
const long _defaultHeuristicSampleSize = 0x10000; //completely arbitrary - inappropriate for high numbers of files / high speed requirements
|
||||
|
||||
public static Encoding DetectTextFileEncoding(string InputFilename)
|
||||
{
|
||||
using (FileStream textfileStream = File.OpenRead(InputFilename))
|
||||
{
|
||||
return DetectTextFileEncoding(textfileStream, _defaultHeuristicSampleSize);
|
||||
}
|
||||
}
|
||||
|
||||
public static Encoding DetectTextFileEncoding(FileStream InputFileStream, long HeuristicSampleSize)
|
||||
{
|
||||
bool uselessBool = false;
|
||||
return DetectTextFileEncoding(InputFileStream, _defaultHeuristicSampleSize, out uselessBool);
|
||||
}
|
||||
|
||||
public static Encoding DetectTextFileEncoding(FileStream InputFileStream, long HeuristicSampleSize, out bool HasBOM)
|
||||
{
|
||||
Encoding encodingFound = null;
|
||||
|
||||
long originalPos = InputFileStream.Position;
|
||||
|
||||
InputFileStream.Position = 0;
|
||||
|
||||
|
||||
//First read only what we need for BOM detection
|
||||
byte[] bomBytes = new byte[InputFileStream.Length > 4 ? 4 : InputFileStream.Length];
|
||||
InputFileStream.Read(bomBytes, 0, bomBytes.Length);
|
||||
|
||||
encodingFound = DetectBOMBytes(bomBytes);
|
||||
|
||||
if (encodingFound != null)
|
||||
{
|
||||
InputFileStream.Position = originalPos;
|
||||
HasBOM = true;
|
||||
return encodingFound;
|
||||
}
|
||||
|
||||
|
||||
//BOM Detection failed, going for heuristics now.
|
||||
// create sample byte array and populate it
|
||||
byte[] sampleBytes = new byte[HeuristicSampleSize > InputFileStream.Length ? InputFileStream.Length : HeuristicSampleSize];
|
||||
Array.Copy(bomBytes, sampleBytes, bomBytes.Length);
|
||||
if (InputFileStream.Length > bomBytes.Length)
|
||||
InputFileStream.Read(sampleBytes, bomBytes.Length, sampleBytes.Length - bomBytes.Length);
|
||||
InputFileStream.Position = originalPos;
|
||||
|
||||
//test byte array content
|
||||
encodingFound = DetectUnicodeInByteSampleByHeuristics(sampleBytes);
|
||||
|
||||
HasBOM = false;
|
||||
return encodingFound;
|
||||
}
|
||||
|
||||
public static Encoding DetectBOMBytes(byte[] BOMBytes)
|
||||
{
|
||||
if (BOMBytes.Length < 2)
|
||||
return null;
|
||||
|
||||
if (BOMBytes[0] == 0xff
|
||||
&& BOMBytes[1] == 0xfe
|
||||
&& (BOMBytes.Length < 4
|
||||
|| BOMBytes[2] != 0
|
||||
|| BOMBytes[3] != 0
|
||||
)
|
||||
)
|
||||
return Encoding.Unicode;
|
||||
|
||||
if (BOMBytes[0] == 0xfe
|
||||
&& BOMBytes[1] == 0xff
|
||||
)
|
||||
return Encoding.BigEndianUnicode;
|
||||
|
||||
if (BOMBytes.Length < 3)
|
||||
return null;
|
||||
|
||||
if (BOMBytes[0] == 0xef && BOMBytes[1] == 0xbb && BOMBytes[2] == 0xbf)
|
||||
return Encoding.UTF8;
|
||||
|
||||
if (BOMBytes[0] == 0x2b && BOMBytes[1] == 0x2f && BOMBytes[2] == 0x76)
|
||||
return Encoding.UTF7;
|
||||
|
||||
if (BOMBytes.Length < 4)
|
||||
return null;
|
||||
|
||||
if (BOMBytes[0] == 0xff && BOMBytes[1] == 0xfe && BOMBytes[2] == 0 && BOMBytes[3] == 0)
|
||||
return Encoding.UTF32;
|
||||
|
||||
if (BOMBytes[0] == 0 && BOMBytes[1] == 0 && BOMBytes[2] == 0xfe && BOMBytes[3] == 0xff)
|
||||
return Encoding.GetEncoding(12001);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Encoding DetectUnicodeInByteSampleByHeuristics(byte[] SampleBytes)
|
||||
{
|
||||
long oddBinaryNullsInSample = 0;
|
||||
long evenBinaryNullsInSample = 0;
|
||||
long suspiciousUTF8SequenceCount = 0;
|
||||
long suspiciousUTF8BytesTotal = 0;
|
||||
long likelyUSASCIIBytesInSample = 0;
|
||||
|
||||
//Cycle through, keeping count of binary null positions, possible UTF-8
|
||||
// sequences from upper ranges of Windows-1252, and probable US-ASCII
|
||||
// character counts.
|
||||
|
||||
long currentPos = 0;
|
||||
int skipUTF8Bytes = 0;
|
||||
|
||||
while (currentPos < SampleBytes.Length)
|
||||
{
|
||||
//binary null distribution
|
||||
if (SampleBytes[currentPos] == 0)
|
||||
{
|
||||
if (currentPos % 2 == 0)
|
||||
evenBinaryNullsInSample++;
|
||||
else
|
||||
oddBinaryNullsInSample++;
|
||||
}
|
||||
|
||||
//likely US-ASCII characters
|
||||
if (IsCommonUSASCIIByte(SampleBytes[currentPos]))
|
||||
likelyUSASCIIBytesInSample++;
|
||||
|
||||
//suspicious sequences (look like UTF-8)
|
||||
if (skipUTF8Bytes == 0)
|
||||
{
|
||||
int lengthFound = DetectSuspiciousUTF8SequenceLength(SampleBytes, currentPos);
|
||||
|
||||
if (lengthFound > 0)
|
||||
{
|
||||
suspiciousUTF8SequenceCount++;
|
||||
suspiciousUTF8BytesTotal += lengthFound;
|
||||
skipUTF8Bytes = lengthFound - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
skipUTF8Bytes--;
|
||||
}
|
||||
|
||||
currentPos++;
|
||||
}
|
||||
|
||||
//1: UTF-16 LE - in english / european environments, this is usually characterized by a
|
||||
// high proportion of odd binary nulls (starting at 0), with (as this is text) a low
|
||||
// proportion of even binary nulls.
|
||||
// The thresholds here used (less than 20% nulls where you expect non-nulls, and more than
|
||||
// 60% nulls where you do expect nulls) are completely arbitrary.
|
||||
|
||||
if (((evenBinaryNullsInSample * 2.0) / SampleBytes.Length) < 0.2
|
||||
&& ((oddBinaryNullsInSample * 2.0) / SampleBytes.Length) > 0.6
|
||||
)
|
||||
return Encoding.Unicode;
|
||||
|
||||
|
||||
//2: UTF-16 BE - in english / european environments, this is usually characterized by a
|
||||
// high proportion of even binary nulls (starting at 0), with (as this is text) a low
|
||||
// proportion of odd binary nulls.
|
||||
// The thresholds here used (less than 20% nulls where you expect non-nulls, and more than
|
||||
// 60% nulls where you do expect nulls) are completely arbitrary.
|
||||
|
||||
if (((oddBinaryNullsInSample * 2.0) / SampleBytes.Length) < 0.2
|
||||
&& ((evenBinaryNullsInSample * 2.0) / SampleBytes.Length) > 0.6
|
||||
)
|
||||
return Encoding.BigEndianUnicode;
|
||||
|
||||
|
||||
//3: UTF-8 - Martin Dürst outlines a method for detecting whether something CAN be UTF-8 content
|
||||
// using regexp, in his w3c.org unicode FAQ entry:
|
||||
// http://www.w3.org/International/questions/qa-forms-utf-8
|
||||
// adapted here for C#.
|
||||
string potentiallyMangledString = Encoding.ASCII.GetString(SampleBytes);
|
||||
Regex UTF8Validator = new Regex(@"\A("
|
||||
+ @"[\x09\x0A\x0D\x20-\x7E]"
|
||||
+ @"|[\xC2-\xDF][\x80-\xBF]"
|
||||
+ @"|\xE0[\xA0-\xBF][\x80-\xBF]"
|
||||
+ @"|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}"
|
||||
+ @"|\xED[\x80-\x9F][\x80-\xBF]"
|
||||
+ @"|\xF0[\x90-\xBF][\x80-\xBF]{2}"
|
||||
+ @"|[\xF1-\xF3][\x80-\xBF]{3}"
|
||||
+ @"|\xF4[\x80-\x8F][\x80-\xBF]{2}"
|
||||
+ @")*\z");
|
||||
if (UTF8Validator.IsMatch(potentiallyMangledString))
|
||||
{
|
||||
//Unfortunately, just the fact that it CAN be UTF-8 doesn't tell you much about probabilities.
|
||||
//If all the characters are in the 0-127 range, no harm done, most western charsets are same as UTF-8 in these ranges.
|
||||
//If some of the characters were in the upper range (western accented characters), however, they would likely be mangled to 2-byte by the UTF-8 encoding process.
|
||||
// So, we need to play stats.
|
||||
|
||||
// The "Random" likelihood of any pair of randomly generated characters being one
|
||||
// of these "suspicious" character sequences is:
|
||||
// 128 / (256 * 256) = 0.2%.
|
||||
//
|
||||
// In western text data, that is SIGNIFICANTLY reduced - most text data stays in the <127
|
||||
// character range, so we assume that more than 1 in 500,000 of these character
|
||||
// sequences indicates UTF-8. The number 500,000 is completely arbitrary - so sue me.
|
||||
//
|
||||
// We can only assume these character sequences will be rare if we ALSO assume that this
|
||||
// IS in fact western text - in which case the bulk of the UTF-8 encoded data (that is
|
||||
// not already suspicious sequences) should be plain US-ASCII bytes. This, I
|
||||
// arbitrarily decided, should be 80% (a random distribution, eg binary data, would yield
|
||||
// approx 40%, so the chances of hitting this threshold by accident in random data are
|
||||
// VERY low).
|
||||
|
||||
if ((suspiciousUTF8SequenceCount * 500000.0 / SampleBytes.Length >= 1) //suspicious sequences
|
||||
&& (
|
||||
//all suspicious, so cannot evaluate proportion of US-Ascii
|
||||
SampleBytes.Length - suspiciousUTF8BytesTotal == 0
|
||||
||
|
||||
likelyUSASCIIBytesInSample * 1.0 / (SampleBytes.Length - suspiciousUTF8BytesTotal) >= 0.8
|
||||
)
|
||||
)
|
||||
return Encoding.UTF8;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsCommonUSASCIIByte(byte testByte)
|
||||
{
|
||||
if (testByte == 0x0A //lf
|
||||
|| testByte == 0x0D //cr
|
||||
|| testByte == 0x09 //tab
|
||||
|| (testByte >= 0x20 && testByte <= 0x2F) //common punctuation
|
||||
|| (testByte >= 0x30 && testByte <= 0x39) //digits
|
||||
|| (testByte >= 0x3A && testByte <= 0x40) //common punctuation
|
||||
|| (testByte >= 0x41 && testByte <= 0x5A) //capital letters
|
||||
|| (testByte >= 0x5B && testByte <= 0x60) //common punctuation
|
||||
|| (testByte >= 0x61 && testByte <= 0x7A) //lowercase letters
|
||||
|| (testByte >= 0x7B && testByte <= 0x7E) //common punctuation
|
||||
)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int DetectSuspiciousUTF8SequenceLength(byte[] SampleBytes, long currentPos)
|
||||
{
|
||||
int lengthFound = 0;
|
||||
|
||||
if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xC2
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x81
|
||||
|| SampleBytes[currentPos + 1] == 0x8D
|
||||
|| SampleBytes[currentPos + 1] == 0x8F
|
||||
)
|
||||
lengthFound = 2;
|
||||
else if (SampleBytes[currentPos + 1] == 0x90
|
||||
|| SampleBytes[currentPos + 1] == 0x9D
|
||||
)
|
||||
lengthFound = 2;
|
||||
else if (SampleBytes[currentPos + 1] >= 0xA0
|
||||
&& SampleBytes[currentPos + 1] <= 0xBF
|
||||
)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xC3
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] >= 0x80
|
||||
&& SampleBytes[currentPos + 1] <= 0xBF
|
||||
)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xC5
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x92
|
||||
|| SampleBytes[currentPos + 1] == 0x93
|
||||
)
|
||||
lengthFound = 2;
|
||||
else if (SampleBytes[currentPos + 1] == 0xA0
|
||||
|| SampleBytes[currentPos + 1] == 0xA1
|
||||
)
|
||||
lengthFound = 2;
|
||||
else if (SampleBytes[currentPos + 1] == 0xB8
|
||||
|| SampleBytes[currentPos + 1] == 0xBD
|
||||
|| SampleBytes[currentPos + 1] == 0xBE
|
||||
)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xC6
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x92)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 1
|
||||
&& SampleBytes[currentPos] == 0xCB
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x86
|
||||
|| SampleBytes[currentPos + 1] == 0x9C
|
||||
)
|
||||
lengthFound = 2;
|
||||
}
|
||||
else if (SampleBytes.Length >= currentPos + 2
|
||||
&& SampleBytes[currentPos] == 0xE2
|
||||
)
|
||||
{
|
||||
if (SampleBytes[currentPos + 1] == 0x80)
|
||||
{
|
||||
if (SampleBytes[currentPos + 2] == 0x93
|
||||
|| SampleBytes[currentPos + 2] == 0x94
|
||||
)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0x98
|
||||
|| SampleBytes[currentPos + 2] == 0x99
|
||||
|| SampleBytes[currentPos + 2] == 0x9A
|
||||
)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0x9C
|
||||
|| SampleBytes[currentPos + 2] == 0x9D
|
||||
|| SampleBytes[currentPos + 2] == 0x9E
|
||||
)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0xA0
|
||||
|| SampleBytes[currentPos + 2] == 0xA1
|
||||
|| SampleBytes[currentPos + 2] == 0xA2
|
||||
)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0xA6)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0xB0)
|
||||
lengthFound = 3;
|
||||
if (SampleBytes[currentPos + 2] == 0xB9
|
||||
|| SampleBytes[currentPos + 2] == 0xBA
|
||||
)
|
||||
lengthFound = 3;
|
||||
}
|
||||
else if (SampleBytes[currentPos + 1] == 0x82
|
||||
&& SampleBytes[currentPos + 2] == 0xAC
|
||||
)
|
||||
lengthFound = 3;
|
||||
else if (SampleBytes[currentPos + 1] == 0x84
|
||||
&& SampleBytes[currentPos + 2] == 0xA2
|
||||
)
|
||||
lengthFound = 3;
|
||||
}
|
||||
|
||||
return lengthFound;
|
||||
}
|
||||
}
|
||||
}
|
222
GUI.NET/Debugger/FastColoredTextBox/ExportToHTML.cs
Normal file
222
GUI.NET/Debugger/FastColoredTextBox/ExportToHTML.cs
Normal file
|
@ -0,0 +1,222 @@
|
|||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Exports colored text as HTML
|
||||
/// </summary>
|
||||
/// <remarks>At this time only TextStyle renderer is supported. Other styles is not exported.</remarks>
|
||||
public class ExportToHTML
|
||||
{
|
||||
public string LineNumbersCSS = "<style type=\"text/css\"> .lineNumber{font-family : monospace; font-size : small; font-style : normal; font-weight : normal; color : Teal; background-color : ThreedFace;} </style>";
|
||||
|
||||
/// <summary>
|
||||
/// Use nbsp; instead space
|
||||
/// </summary>
|
||||
public bool UseNbsp { get; set; }
|
||||
/// <summary>
|
||||
/// Use nbsp; instead space in beginning of line
|
||||
/// </summary>
|
||||
public bool UseForwardNbsp { get; set; }
|
||||
/// <summary>
|
||||
/// Use original font
|
||||
/// </summary>
|
||||
public bool UseOriginalFont { get; set; }
|
||||
/// <summary>
|
||||
/// Use style tag instead style attribute
|
||||
/// </summary>
|
||||
public bool UseStyleTag { get; set; }
|
||||
/// <summary>
|
||||
/// Use 'br' tag instead of '\n'
|
||||
/// </summary>
|
||||
public bool UseBr { get; set; }
|
||||
/// <summary>
|
||||
/// Includes line numbers
|
||||
/// </summary>
|
||||
public bool IncludeLineNumbers { get; set; }
|
||||
|
||||
FastColoredTextBox tb;
|
||||
|
||||
public ExportToHTML()
|
||||
{
|
||||
UseNbsp = true;
|
||||
UseOriginalFont = true;
|
||||
UseStyleTag = true;
|
||||
UseBr = true;
|
||||
}
|
||||
|
||||
public string GetHtml(FastColoredTextBox tb)
|
||||
{
|
||||
this.tb = tb;
|
||||
Range sel = new Range(tb);
|
||||
sel.SelectAll();
|
||||
return GetHtml(sel);
|
||||
}
|
||||
|
||||
public string GetHtml(Range r)
|
||||
{
|
||||
this.tb = r.tb;
|
||||
Dictionary<StyleIndex, object> styles = new Dictionary<StyleIndex, object>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder tempSB = new StringBuilder();
|
||||
StyleIndex currentStyleId = StyleIndex.None;
|
||||
r.Normalize();
|
||||
int currentLine = r.Start.iLine;
|
||||
styles[currentStyleId] = null;
|
||||
//
|
||||
if (UseOriginalFont)
|
||||
sb.AppendFormat("<font style=\"font-family: {0}, monospace; font-size: {1}pt; line-height: {2}px;\">",
|
||||
r.tb.Font.Name, r.tb.Font.SizeInPoints, r.tb.CharHeight);
|
||||
|
||||
//
|
||||
if (IncludeLineNumbers)
|
||||
tempSB.AppendFormat("<span class=lineNumber>{0}</span> ", currentLine + 1);
|
||||
//
|
||||
bool hasNonSpace = false;
|
||||
foreach (Place p in r)
|
||||
{
|
||||
Char c = r.tb[p.iLine][p.iChar];
|
||||
if (c.style != currentStyleId)
|
||||
{
|
||||
Flush(sb, tempSB, currentStyleId);
|
||||
currentStyleId = c.style;
|
||||
styles[currentStyleId] = null;
|
||||
}
|
||||
|
||||
if (p.iLine != currentLine)
|
||||
{
|
||||
for (int i = currentLine; i < p.iLine; i++)
|
||||
{
|
||||
tempSB.Append(UseBr ? "<br>" : "\r\n");
|
||||
if (IncludeLineNumbers)
|
||||
tempSB.AppendFormat("<span class=lineNumber>{0}</span> ", i + 2);
|
||||
}
|
||||
currentLine = p.iLine;
|
||||
hasNonSpace = false;
|
||||
}
|
||||
switch (c.c)
|
||||
{
|
||||
case ' ':
|
||||
if ((hasNonSpace || !UseForwardNbsp) && !UseNbsp)
|
||||
goto default;
|
||||
|
||||
tempSB.Append(" ");
|
||||
break;
|
||||
case '<':
|
||||
tempSB.Append("<");
|
||||
break;
|
||||
case '>':
|
||||
tempSB.Append(">");
|
||||
break;
|
||||
case '&':
|
||||
tempSB.Append("&");
|
||||
break;
|
||||
default:
|
||||
hasNonSpace = true;
|
||||
tempSB.Append(c.c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Flush(sb, tempSB, currentStyleId);
|
||||
|
||||
if (UseOriginalFont)
|
||||
sb.Append("</font>");
|
||||
|
||||
//build styles
|
||||
if (UseStyleTag)
|
||||
{
|
||||
tempSB.Length = 0;
|
||||
tempSB.Append("<style type=\"text/css\">");
|
||||
foreach (var styleId in styles.Keys)
|
||||
tempSB.AppendFormat(".fctb{0}{{ {1} }}\r\n", GetStyleName(styleId), GetCss(styleId));
|
||||
tempSB.Append("</style>");
|
||||
|
||||
sb.Insert(0, tempSB.ToString());
|
||||
}
|
||||
|
||||
if (IncludeLineNumbers)
|
||||
sb.Insert(0, LineNumbersCSS);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private string GetCss(StyleIndex styleIndex)
|
||||
{
|
||||
List<Style> styles = new List<Style>();
|
||||
//find text renderer
|
||||
TextStyle textStyle = null;
|
||||
int mask = 1;
|
||||
bool hasTextStyle = false;
|
||||
for (int i = 0; i < tb.Styles.Length; i++)
|
||||
{
|
||||
if (tb.Styles[i] != null && ((int)styleIndex & mask) != 0)
|
||||
if (tb.Styles[i].IsExportable)
|
||||
{
|
||||
var style = tb.Styles[i];
|
||||
styles.Add(style);
|
||||
|
||||
bool isTextStyle = style is TextStyle;
|
||||
if (isTextStyle)
|
||||
if (!hasTextStyle || tb.AllowSeveralTextStyleDrawing)
|
||||
{
|
||||
hasTextStyle = true;
|
||||
textStyle = style as TextStyle;
|
||||
}
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
//add TextStyle css
|
||||
string result = "";
|
||||
|
||||
if (!hasTextStyle)
|
||||
{
|
||||
//draw by default renderer
|
||||
result = tb.DefaultStyle.GetCSS();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = textStyle.GetCSS();
|
||||
}
|
||||
//add no TextStyle css
|
||||
foreach(var style in styles)
|
||||
// if (style != textStyle)
|
||||
if(!(style is TextStyle))
|
||||
result += style.GetCSS();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GetColorAsString(Color color)
|
||||
{
|
||||
if(color==Color.Transparent)
|
||||
return "";
|
||||
return string.Format("#{0:x2}{1:x2}{2:x2}", color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
string GetStyleName(StyleIndex styleIndex)
|
||||
{
|
||||
return styleIndex.ToString().Replace(" ", "").Replace(",", "");
|
||||
}
|
||||
|
||||
private void Flush(StringBuilder sb, StringBuilder tempSB, StyleIndex currentStyle)
|
||||
{
|
||||
//find textRenderer
|
||||
if (tempSB.Length == 0)
|
||||
return;
|
||||
if (UseStyleTag)
|
||||
sb.AppendFormat("<font class=fctb{0}>{1}</font>", GetStyleName(currentStyle), tempSB.ToString());
|
||||
else
|
||||
{
|
||||
string css = GetCss(currentStyle);
|
||||
if(css!="")
|
||||
sb.AppendFormat("<font style=\"{0}\">", css);
|
||||
sb.Append(tempSB.ToString());
|
||||
if (css != "")
|
||||
sb.Append("</font>");
|
||||
}
|
||||
tempSB.Length = 0;
|
||||
}
|
||||
}
|
||||
}
|
217
GUI.NET/Debugger/FastColoredTextBox/ExportToRTF.cs
Normal file
217
GUI.NET/Debugger/FastColoredTextBox/ExportToRTF.cs
Normal file
|
@ -0,0 +1,217 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Exports colored text as RTF
|
||||
/// </summary>
|
||||
/// <remarks>At this time only TextStyle renderer is supported. Other styles is not exported.</remarks>
|
||||
public class ExportToRTF
|
||||
{
|
||||
/// <summary>
|
||||
/// Includes line numbers
|
||||
/// </summary>
|
||||
public bool IncludeLineNumbers { get; set; }
|
||||
/// <summary>
|
||||
/// Use original font
|
||||
/// </summary>
|
||||
public bool UseOriginalFont { get; set; }
|
||||
|
||||
FastColoredTextBox tb;
|
||||
Dictionary<Color, int> colorTable = new Dictionary<Color, int>();
|
||||
|
||||
public ExportToRTF()
|
||||
{
|
||||
UseOriginalFont = true;
|
||||
}
|
||||
|
||||
public string GetRtf(FastColoredTextBox tb)
|
||||
{
|
||||
this.tb = tb;
|
||||
Range sel = new Range(tb);
|
||||
sel.SelectAll();
|
||||
return GetRtf(sel);
|
||||
}
|
||||
|
||||
public string GetRtf(Range r)
|
||||
{
|
||||
this.tb = r.tb;
|
||||
var styles = new Dictionary<StyleIndex, object>();
|
||||
var sb = new StringBuilder();
|
||||
var tempSB = new StringBuilder();
|
||||
var currentStyleId = StyleIndex.None;
|
||||
r.Normalize();
|
||||
int currentLine = r.Start.iLine;
|
||||
styles[currentStyleId] = null;
|
||||
colorTable.Clear();
|
||||
//
|
||||
var lineNumberColor = GetColorTableNumber(r.tb.LineNumberColor);
|
||||
|
||||
if (IncludeLineNumbers)
|
||||
tempSB.AppendFormat(@"{{\cf{1} {0}}}\tab", currentLine + 1, lineNumberColor);
|
||||
//
|
||||
foreach (Place p in r)
|
||||
{
|
||||
Char c = r.tb[p.iLine][p.iChar];
|
||||
if (c.style != currentStyleId)
|
||||
{
|
||||
Flush(sb, tempSB, currentStyleId);
|
||||
currentStyleId = c.style;
|
||||
styles[currentStyleId] = null;
|
||||
}
|
||||
|
||||
if (p.iLine != currentLine)
|
||||
{
|
||||
for (int i = currentLine; i < p.iLine; i++)
|
||||
{
|
||||
tempSB.AppendLine(@"\line");
|
||||
if (IncludeLineNumbers)
|
||||
tempSB.AppendFormat(@"{{\cf{1} {0}}}\tab", i + 2, lineNumberColor);
|
||||
}
|
||||
currentLine = p.iLine;
|
||||
}
|
||||
switch (c.c)
|
||||
{
|
||||
case '\\':
|
||||
tempSB.Append(@"\\");
|
||||
break;
|
||||
case '{':
|
||||
tempSB.Append(@"\{");
|
||||
break;
|
||||
case '}':
|
||||
tempSB.Append(@"\}");
|
||||
break;
|
||||
default:
|
||||
var ch = c.c;
|
||||
var code = (int)ch;
|
||||
if(code < 128)
|
||||
tempSB.Append(c.c);
|
||||
else
|
||||
tempSB.AppendFormat(@"{{\u{0}}}", code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Flush(sb, tempSB, currentStyleId);
|
||||
|
||||
//build color table
|
||||
var list = new SortedList<int, Color>();
|
||||
foreach (var pair in colorTable)
|
||||
list.Add(pair.Value, pair.Key);
|
||||
|
||||
tempSB.Length = 0;
|
||||
tempSB.AppendFormat(@"{{\colortbl;");
|
||||
|
||||
foreach (var pair in list)
|
||||
tempSB.Append(GetColorAsString(pair.Value)+";");
|
||||
tempSB.AppendLine("}");
|
||||
|
||||
//
|
||||
if (UseOriginalFont)
|
||||
{
|
||||
sb.Insert(0, string.Format(@"{{\fonttbl{{\f0\fmodern {0};}}}}{{\fs{1} ",
|
||||
tb.Font.Name, (int)(2 * tb.Font.SizeInPoints), tb.CharHeight));
|
||||
sb.AppendLine(@"}");
|
||||
}
|
||||
|
||||
sb.Insert(0, tempSB.ToString());
|
||||
|
||||
sb.Insert(0, @"{\rtf1\ud\deff0");
|
||||
sb.AppendLine(@"}");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private RTFStyleDescriptor GetRtfDescriptor(StyleIndex styleIndex)
|
||||
{
|
||||
List<Style> styles = new List<Style>();
|
||||
//find text renderer
|
||||
TextStyle textStyle = null;
|
||||
int mask = 1;
|
||||
bool hasTextStyle = false;
|
||||
for (int i = 0; i < tb.Styles.Length; i++)
|
||||
{
|
||||
if (tb.Styles[i] != null && ((int)styleIndex & mask) != 0)
|
||||
if (tb.Styles[i].IsExportable)
|
||||
{
|
||||
var style = tb.Styles[i];
|
||||
styles.Add(style);
|
||||
|
||||
bool isTextStyle = style is TextStyle;
|
||||
if (isTextStyle)
|
||||
if (!hasTextStyle || tb.AllowSeveralTextStyleDrawing)
|
||||
{
|
||||
hasTextStyle = true;
|
||||
textStyle = style as TextStyle;
|
||||
}
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
//add TextStyle css
|
||||
RTFStyleDescriptor result = null;
|
||||
|
||||
if (!hasTextStyle)
|
||||
{
|
||||
//draw by default renderer
|
||||
result = tb.DefaultStyle.GetRTF();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = textStyle.GetRTF();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GetColorAsString(Color color)
|
||||
{
|
||||
if (color == Color.Transparent)
|
||||
return "";
|
||||
return string.Format(@"\red{0}\green{1}\blue{2}", color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
private void Flush(StringBuilder sb, StringBuilder tempSB, StyleIndex currentStyle)
|
||||
{
|
||||
//find textRenderer
|
||||
if (tempSB.Length == 0)
|
||||
return;
|
||||
|
||||
var desc = GetRtfDescriptor(currentStyle);
|
||||
var cf = GetColorTableNumber(desc.ForeColor);
|
||||
var cb = GetColorTableNumber(desc.BackColor);
|
||||
var tags = new StringBuilder();
|
||||
if (cf >= 0)
|
||||
tags.AppendFormat(@"\cf{0}", cf);
|
||||
if (cb >= 0)
|
||||
tags.AppendFormat(@"\highlight{0}", cb);
|
||||
if(!string.IsNullOrEmpty(desc.AdditionalTags))
|
||||
tags.Append(desc.AdditionalTags.Trim());
|
||||
|
||||
if(tags.Length > 0)
|
||||
sb.AppendFormat(@"{{{0} {1}}}", tags, tempSB.ToString());
|
||||
else
|
||||
sb.Append(tempSB.ToString());
|
||||
tempSB.Length = 0;
|
||||
}
|
||||
|
||||
private int GetColorTableNumber(Color color)
|
||||
{
|
||||
if (color.A == 0)
|
||||
return -1;
|
||||
|
||||
if (!colorTable.ContainsKey(color))
|
||||
colorTable[color] = colorTable.Count + 1;
|
||||
|
||||
return colorTable[color];
|
||||
}
|
||||
}
|
||||
|
||||
public class RTFStyleDescriptor
|
||||
{
|
||||
public Color ForeColor { get; set; }
|
||||
public Color BackColor { get; set; }
|
||||
public string AdditionalTags { get; set; }
|
||||
}
|
||||
}
|
8466
GUI.NET/Debugger/FastColoredTextBox/FastColoredTextBox.cs
Normal file
8466
GUI.NET/Debugger/FastColoredTextBox/FastColoredTextBox.cs
Normal file
File diff suppressed because it is too large
Load diff
120
GUI.NET/Debugger/FastColoredTextBox/FastColoredTextBox.resx
Normal file
120
GUI.NET/Debugger/FastColoredTextBox/FastColoredTextBox.resx
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
453
GUI.NET/Debugger/FastColoredTextBox/FileTextSource.cs
Normal file
453
GUI.NET/Debugger/FastColoredTextBox/FileTextSource.cs
Normal file
|
@ -0,0 +1,453 @@
|
|||
//#define debug
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// This class contains the source text (chars and styles).
|
||||
/// It stores a text lines, the manager of commands, undo/redo stack, styles.
|
||||
/// </summary>
|
||||
public class FileTextSource : TextSource, IDisposable
|
||||
{
|
||||
List<int> sourceFileLinePositions = new List<int>();
|
||||
FileStream fs;
|
||||
Encoding fileEncoding;
|
||||
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when need to display line in the textbox
|
||||
/// </summary>
|
||||
public event EventHandler<LineNeededEventArgs> LineNeeded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when need to save line in the file
|
||||
/// </summary>
|
||||
public event EventHandler<LinePushedEventArgs> LinePushed;
|
||||
|
||||
public FileTextSource(FastColoredTextBox currentTB)
|
||||
: base(currentTB)
|
||||
{
|
||||
timer.Interval = 10000;
|
||||
timer.Tick += new EventHandler(timer_Tick);
|
||||
timer.Enabled = true;
|
||||
|
||||
SaveEOL = Environment.NewLine;
|
||||
}
|
||||
|
||||
void timer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
timer.Enabled = false;
|
||||
try
|
||||
{
|
||||
UnloadUnusedLines();
|
||||
}
|
||||
finally
|
||||
{
|
||||
timer.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UnloadUnusedLines()
|
||||
{
|
||||
const int margin = 2000;
|
||||
var iStartVisibleLine = CurrentTB.VisibleRange.Start.iLine;
|
||||
var iFinishVisibleLine = CurrentTB.VisibleRange.End.iLine;
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (base.lines[i] != null && !base.lines[i].IsChanged && Math.Abs(i - iFinishVisibleLine) > margin)
|
||||
{
|
||||
base.lines[i] = null;
|
||||
count++;
|
||||
}
|
||||
#if debug
|
||||
Console.WriteLine("UnloadUnusedLines: " + count);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OpenFile(string fileName, Encoding enc)
|
||||
{
|
||||
Clear();
|
||||
|
||||
if (fs != null)
|
||||
fs.Dispose();
|
||||
|
||||
SaveEOL = Environment.NewLine;
|
||||
|
||||
//read lines of file
|
||||
fs = new FileStream(fileName, FileMode.Open);
|
||||
var length = fs.Length;
|
||||
//read signature
|
||||
enc = DefineEncoding(enc, fs);
|
||||
int shift = DefineShift(enc);
|
||||
//first line
|
||||
sourceFileLinePositions.Add((int)fs.Position);
|
||||
base.lines.Add(null);
|
||||
//other lines
|
||||
sourceFileLinePositions.Capacity = (int)(length/7 + 1000);
|
||||
int prev = 0;
|
||||
while(fs.Position < length)
|
||||
{
|
||||
var b = fs.ReadByte();
|
||||
|
||||
if (b == 10)// \n
|
||||
{
|
||||
sourceFileLinePositions.Add((int)(fs.Position) + shift);
|
||||
base.lines.Add(null);
|
||||
}else
|
||||
if (prev == 13)// \r (Mac format)
|
||||
{
|
||||
sourceFileLinePositions.Add((int)(fs.Position - 1) + shift);
|
||||
base.lines.Add(null);
|
||||
SaveEOL = "\r";
|
||||
}
|
||||
|
||||
prev = b;
|
||||
}
|
||||
|
||||
if (prev == 13)
|
||||
{
|
||||
sourceFileLinePositions.Add((int)(fs.Position) + shift);
|
||||
base.lines.Add(null);
|
||||
}
|
||||
|
||||
if(length > 2000000)
|
||||
GC.Collect();
|
||||
|
||||
Line[] temp = new Line[100];
|
||||
|
||||
var c = base.lines.Count;
|
||||
base.lines.AddRange(temp);
|
||||
base.lines.TrimExcess();
|
||||
base.lines.RemoveRange(c, temp.Length);
|
||||
|
||||
|
||||
int[] temp2 = new int[100];
|
||||
c = base.lines.Count;
|
||||
sourceFileLinePositions.AddRange(temp2);
|
||||
sourceFileLinePositions.TrimExcess();
|
||||
sourceFileLinePositions.RemoveRange(c, temp.Length);
|
||||
|
||||
|
||||
fileEncoding = enc;
|
||||
|
||||
OnLineInserted(0, Count);
|
||||
//load first lines for calc width of the text
|
||||
var linesCount = Math.Min(lines.Count, CurrentTB.ClientRectangle.Height/CurrentTB.CharHeight);
|
||||
for (int i = 0; i < linesCount; i++)
|
||||
LoadLineFromSourceFile(i);
|
||||
//
|
||||
NeedRecalc(new TextChangedEventArgs(0, linesCount - 1));
|
||||
if (CurrentTB.WordWrap)
|
||||
OnRecalcWordWrap(new TextChangedEventArgs(0, linesCount - 1));
|
||||
}
|
||||
|
||||
private int DefineShift(Encoding enc)
|
||||
{
|
||||
if (enc.IsSingleByte)
|
||||
return 0;
|
||||
|
||||
if (enc.HeaderName == "unicodeFFFE")
|
||||
return 0;//UTF16 BE
|
||||
|
||||
if (enc.HeaderName == "utf-16")
|
||||
return 1;//UTF16 LE
|
||||
|
||||
if (enc.HeaderName == "utf-32BE")
|
||||
return 0;//UTF32 BE
|
||||
|
||||
if (enc.HeaderName == "utf-32")
|
||||
return 3;//UTF32 LE
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static Encoding DefineEncoding(Encoding enc, FileStream fs)
|
||||
{
|
||||
int bytesPerSignature = 0;
|
||||
byte[] signature = new byte[4];
|
||||
int c = fs.Read(signature, 0, 4);
|
||||
if (signature[0] == 0xFF && signature[1] == 0xFE && signature[2] == 0x00 && signature[3] == 0x00 && c >= 4)
|
||||
{
|
||||
enc = Encoding.UTF32;//UTF32 LE
|
||||
bytesPerSignature = 4;
|
||||
}
|
||||
else
|
||||
if (signature[0] == 0x00 && signature[1] == 0x00 && signature[2] == 0xFE && signature[3] == 0xFF)
|
||||
{
|
||||
enc = new UTF32Encoding(true, true);//UTF32 BE
|
||||
bytesPerSignature = 4;
|
||||
}
|
||||
else
|
||||
if (signature[0] == 0xEF && signature[1] == 0xBB && signature[2] == 0xBF)
|
||||
{
|
||||
enc = Encoding.UTF8;//UTF8
|
||||
bytesPerSignature = 3;
|
||||
}
|
||||
else
|
||||
if (signature[0] == 0xFE && signature[1] == 0xFF)
|
||||
{
|
||||
enc = Encoding.BigEndianUnicode;//UTF16 BE
|
||||
bytesPerSignature = 2;
|
||||
}
|
||||
else
|
||||
if (signature[0] == 0xFF && signature[1] == 0xFE)
|
||||
{
|
||||
enc = Encoding.Unicode;//UTF16 LE
|
||||
bytesPerSignature = 2;
|
||||
}
|
||||
|
||||
fs.Seek(bytesPerSignature, SeekOrigin.Begin);
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
public void CloseFile()
|
||||
{
|
||||
if(fs!=null)
|
||||
try
|
||||
{
|
||||
fs.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
;
|
||||
}
|
||||
fs = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End Of Line characters used for saving
|
||||
/// </summary>
|
||||
public string SaveEOL { get; set; }
|
||||
|
||||
public override void SaveToFile(string fileName, Encoding enc)
|
||||
{
|
||||
//
|
||||
var newLinePos = new List<int>(Count);
|
||||
//create temp file
|
||||
var dir = Path.GetDirectoryName(fileName);
|
||||
var tempFileName = Path.Combine(dir, Path.GetFileNameWithoutExtension(fileName) + ".tmp");
|
||||
|
||||
StreamReader sr = new StreamReader(fs, fileEncoding);
|
||||
using (FileStream tempFs = new FileStream(tempFileName, FileMode.Create))
|
||||
using (StreamWriter sw = new StreamWriter(tempFs, enc))
|
||||
{
|
||||
sw.Flush();
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
newLinePos.Add((int)tempFs.Length);
|
||||
|
||||
var sourceLine = ReadLine(sr, i);//read line from source file
|
||||
string line;
|
||||
|
||||
bool lineIsChanged = lines[i] != null && lines[i].IsChanged;
|
||||
|
||||
if (lineIsChanged)
|
||||
line = lines[i].Text;
|
||||
else
|
||||
line = sourceLine;
|
||||
|
||||
//call event handler
|
||||
if (LinePushed != null)
|
||||
{
|
||||
var args = new LinePushedEventArgs(sourceLine, i, lineIsChanged ? line : null);
|
||||
LinePushed(this, args);
|
||||
|
||||
if(args.SavedText != null)
|
||||
line = args.SavedText;
|
||||
}
|
||||
|
||||
//save line to file
|
||||
sw.Write(line);
|
||||
|
||||
if (i < Count - 1)
|
||||
sw.Write(SaveEOL);
|
||||
|
||||
sw.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
//clear lines buffer
|
||||
for (int i = 0; i < Count; i++)
|
||||
lines[i] = null;
|
||||
//deattach from source file
|
||||
sr.Dispose();
|
||||
fs.Dispose();
|
||||
//delete target file
|
||||
if (File.Exists(fileName))
|
||||
File.Delete(fileName);
|
||||
//rename temp file
|
||||
File.Move(tempFileName, fileName);
|
||||
|
||||
//binding to new file
|
||||
sourceFileLinePositions = newLinePos;
|
||||
fs = new FileStream(fileName, FileMode.Open);
|
||||
this.fileEncoding = enc;
|
||||
}
|
||||
|
||||
private string ReadLine(StreamReader sr, int i)
|
||||
{
|
||||
string line;
|
||||
var filePos = sourceFileLinePositions[i];
|
||||
if (filePos < 0)
|
||||
return "";
|
||||
fs.Seek(filePos, SeekOrigin.Begin);
|
||||
sr.DiscardBufferedData();
|
||||
line = sr.ReadLine();
|
||||
return line;
|
||||
}
|
||||
|
||||
public override void ClearIsChanged()
|
||||
{
|
||||
foreach (var line in lines)
|
||||
if(line!=null)
|
||||
line.IsChanged = false;
|
||||
}
|
||||
|
||||
public override Line this[int i]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (base.lines[i] != null)
|
||||
return lines[i];
|
||||
else
|
||||
LoadLineFromSourceFile(i);
|
||||
|
||||
return lines[i];
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadLineFromSourceFile(int i)
|
||||
{
|
||||
var line = CreateLine();
|
||||
fs.Seek(sourceFileLinePositions[i], SeekOrigin.Begin);
|
||||
StreamReader sr = new StreamReader(fs, fileEncoding);
|
||||
|
||||
var s = sr.ReadLine();
|
||||
if (s == null)
|
||||
s = "";
|
||||
|
||||
//call event handler
|
||||
if(LineNeeded!=null)
|
||||
{
|
||||
var args = new LineNeededEventArgs(s, i);
|
||||
LineNeeded(this, args);
|
||||
s = args.DisplayedLineText;
|
||||
if (s == null)
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var c in s)
|
||||
line.Add(new Char(c));
|
||||
base.lines[i] = line;
|
||||
|
||||
if (CurrentTB.WordWrap)
|
||||
OnRecalcWordWrap(new TextChangedEventArgs(i, i));
|
||||
}
|
||||
|
||||
public override void InsertLine(int index, Line line)
|
||||
{
|
||||
sourceFileLinePositions.Insert(index, -1);
|
||||
base.InsertLine(index, line);
|
||||
}
|
||||
|
||||
public override void RemoveLine(int index, int count)
|
||||
{
|
||||
sourceFileLinePositions.RemoveRange(index, count);
|
||||
base.RemoveLine(index, count);
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
base.Clear();
|
||||
}
|
||||
|
||||
public override int GetLineLength(int i)
|
||||
{
|
||||
if (base.lines[i] == null)
|
||||
return 0;
|
||||
else
|
||||
return base.lines[i].Count;
|
||||
}
|
||||
|
||||
public override bool LineHasFoldingStartMarker(int iLine)
|
||||
{
|
||||
if (lines[iLine] == null)
|
||||
return false;
|
||||
else
|
||||
return !string.IsNullOrEmpty(lines[iLine].FoldingStartMarker);
|
||||
}
|
||||
|
||||
public override bool LineHasFoldingEndMarker(int iLine)
|
||||
{
|
||||
if (lines[iLine] == null)
|
||||
return false;
|
||||
else
|
||||
return !string.IsNullOrEmpty(lines[iLine].FoldingEndMarker);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (fs != null)
|
||||
fs.Dispose();
|
||||
|
||||
timer.Dispose();
|
||||
}
|
||||
|
||||
internal void UnloadLine(int iLine)
|
||||
{
|
||||
if (lines[iLine] != null && !lines[iLine].IsChanged)
|
||||
lines[iLine] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public class LineNeededEventArgs : EventArgs
|
||||
{
|
||||
public string SourceLineText { get; private set; }
|
||||
public int DisplayedLineIndex { get; private set; }
|
||||
/// <summary>
|
||||
/// This text will be displayed in textbox
|
||||
/// </summary>
|
||||
public string DisplayedLineText { get; set; }
|
||||
|
||||
public LineNeededEventArgs(string sourceLineText, int displayedLineIndex)
|
||||
{
|
||||
this.SourceLineText = sourceLineText;
|
||||
this.DisplayedLineIndex = displayedLineIndex;
|
||||
this.DisplayedLineText = sourceLineText;
|
||||
}
|
||||
}
|
||||
|
||||
public class LinePushedEventArgs : EventArgs
|
||||
{
|
||||
public string SourceLineText { get; private set; }
|
||||
public int DisplayedLineIndex { get; private set; }
|
||||
/// <summary>
|
||||
/// This property contains only changed text.
|
||||
/// If text of line is not changed, this property contains null.
|
||||
/// </summary>
|
||||
public string DisplayedLineText { get; private set; }
|
||||
/// <summary>
|
||||
/// This text will be saved in the file
|
||||
/// </summary>
|
||||
public string SavedText { get; set; }
|
||||
|
||||
public LinePushedEventArgs(string sourceLineText, int displayedLineIndex, string displayedLineText)
|
||||
{
|
||||
this.SourceLineText = sourceLineText;
|
||||
this.DisplayedLineIndex = displayedLineIndex;
|
||||
this.DisplayedLineText = displayedLineText;
|
||||
this.SavedText = displayedLineText;
|
||||
}
|
||||
}
|
||||
}
|
129
GUI.NET/Debugger/FastColoredTextBox/FindForm.cs
Normal file
129
GUI.NET/Debugger/FastColoredTextBox/FindForm.cs
Normal file
|
@ -0,0 +1,129 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class FindForm : Form
|
||||
{
|
||||
bool firstSearch = true;
|
||||
Place startPlace;
|
||||
FastColoredTextBox tb;
|
||||
|
||||
public FindForm(FastColoredTextBox tb)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.tb = tb;
|
||||
}
|
||||
|
||||
private void btClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void btFindNext_Click(object sender, EventArgs e)
|
||||
{
|
||||
FindNext(tbFind.Text);
|
||||
}
|
||||
|
||||
public virtual void FindNext(string pattern)
|
||||
{
|
||||
try
|
||||
{
|
||||
RegexOptions opt = cbMatchCase.Checked ? RegexOptions.None : RegexOptions.IgnoreCase;
|
||||
if (!cbRegex.Checked)
|
||||
pattern = Regex.Escape(pattern);
|
||||
if (cbWholeWord.Checked)
|
||||
pattern = "\\b" + pattern + "\\b";
|
||||
//
|
||||
Range range = tb.Selection.Clone();
|
||||
range.Normalize();
|
||||
//
|
||||
if (firstSearch)
|
||||
{
|
||||
startPlace = range.Start;
|
||||
firstSearch = false;
|
||||
}
|
||||
//
|
||||
range.Start = range.End;
|
||||
if (range.Start >= startPlace)
|
||||
range.End = new Place(tb.GetLineLength(tb.LinesCount - 1), tb.LinesCount - 1);
|
||||
else
|
||||
range.End = startPlace;
|
||||
//
|
||||
foreach (var r in range.GetRangesByLines(pattern, opt))
|
||||
{
|
||||
tb.Selection = r;
|
||||
tb.DoSelectionVisible();
|
||||
tb.Invalidate();
|
||||
return;
|
||||
}
|
||||
//
|
||||
if (range.Start >= startPlace && startPlace > Place.Empty)
|
||||
{
|
||||
tb.Selection.Start = new Place(0, 0);
|
||||
FindNext(pattern);
|
||||
return;
|
||||
}
|
||||
MessageBox.Show("Not found");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void tbFind_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == '\r')
|
||||
{
|
||||
btFindNext.PerformClick();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
if (e.KeyChar == '\x1b')
|
||||
{
|
||||
Hide();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void FindForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (e.CloseReason == CloseReason.UserClosing)
|
||||
{
|
||||
e.Cancel = true;
|
||||
Hide();
|
||||
}
|
||||
this.tb.Focus();
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
if (keyData == Keys.Escape)
|
||||
{
|
||||
this.Close();
|
||||
return true;
|
||||
}
|
||||
return base.ProcessCmdKey(ref msg, keyData);
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e)
|
||||
{
|
||||
tbFind.Focus();
|
||||
ResetSerach();
|
||||
}
|
||||
|
||||
void ResetSerach()
|
||||
{
|
||||
firstSearch = true;
|
||||
}
|
||||
|
||||
private void cbMatchCase_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
ResetSerach();
|
||||
}
|
||||
}
|
||||
}
|
146
GUI.NET/Debugger/FastColoredTextBox/FindForm.designer.cs
generated
Normal file
146
GUI.NET/Debugger/FastColoredTextBox/FindForm.designer.cs
generated
Normal file
|
@ -0,0 +1,146 @@
|
|||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class FindForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btClose = new System.Windows.Forms.Button();
|
||||
this.btFindNext = new System.Windows.Forms.Button();
|
||||
this.tbFind = new System.Windows.Forms.TextBox();
|
||||
this.cbRegex = new System.Windows.Forms.CheckBox();
|
||||
this.cbMatchCase = new System.Windows.Forms.CheckBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.cbWholeWord = new System.Windows.Forms.CheckBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btClose
|
||||
//
|
||||
this.btClose.Location = new System.Drawing.Point(273, 73);
|
||||
this.btClose.Name = "btClose";
|
||||
this.btClose.Size = new System.Drawing.Size(75, 23);
|
||||
this.btClose.TabIndex = 5;
|
||||
this.btClose.Text = "Close";
|
||||
this.btClose.UseVisualStyleBackColor = true;
|
||||
this.btClose.Click += new System.EventHandler(this.btClose_Click);
|
||||
//
|
||||
// btFindNext
|
||||
//
|
||||
this.btFindNext.Location = new System.Drawing.Point(192, 73);
|
||||
this.btFindNext.Name = "btFindNext";
|
||||
this.btFindNext.Size = new System.Drawing.Size(75, 23);
|
||||
this.btFindNext.TabIndex = 4;
|
||||
this.btFindNext.Text = "Find next";
|
||||
this.btFindNext.UseVisualStyleBackColor = true;
|
||||
this.btFindNext.Click += new System.EventHandler(this.btFindNext_Click);
|
||||
//
|
||||
// tbFind
|
||||
//
|
||||
this.tbFind.Location = new System.Drawing.Point(42, 12);
|
||||
this.tbFind.Name = "tbFind";
|
||||
this.tbFind.Size = new System.Drawing.Size(306, 20);
|
||||
this.tbFind.TabIndex = 0;
|
||||
this.tbFind.TextChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
this.tbFind.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbFind_KeyPress);
|
||||
//
|
||||
// cbRegex
|
||||
//
|
||||
this.cbRegex.AutoSize = true;
|
||||
this.cbRegex.Location = new System.Drawing.Point(249, 38);
|
||||
this.cbRegex.Name = "cbRegex";
|
||||
this.cbRegex.Size = new System.Drawing.Size(57, 17);
|
||||
this.cbRegex.TabIndex = 3;
|
||||
this.cbRegex.Text = "Regex";
|
||||
this.cbRegex.UseVisualStyleBackColor = true;
|
||||
this.cbRegex.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// cbMatchCase
|
||||
//
|
||||
this.cbMatchCase.AutoSize = true;
|
||||
this.cbMatchCase.Location = new System.Drawing.Point(42, 38);
|
||||
this.cbMatchCase.Name = "cbMatchCase";
|
||||
this.cbMatchCase.Size = new System.Drawing.Size(82, 17);
|
||||
this.cbMatchCase.TabIndex = 1;
|
||||
this.cbMatchCase.Text = "Match case";
|
||||
this.cbMatchCase.UseVisualStyleBackColor = true;
|
||||
this.cbMatchCase.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(6, 15);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(33, 13);
|
||||
this.label1.TabIndex = 5;
|
||||
this.label1.Text = "Find: ";
|
||||
//
|
||||
// cbWholeWord
|
||||
//
|
||||
this.cbWholeWord.AutoSize = true;
|
||||
this.cbWholeWord.Location = new System.Drawing.Point(130, 38);
|
||||
this.cbWholeWord.Name = "cbWholeWord";
|
||||
this.cbWholeWord.Size = new System.Drawing.Size(113, 17);
|
||||
this.cbWholeWord.TabIndex = 2;
|
||||
this.cbWholeWord.Text = "Match whole word";
|
||||
this.cbWholeWord.UseVisualStyleBackColor = true;
|
||||
this.cbWholeWord.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// FindForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(360, 108);
|
||||
this.Controls.Add(this.cbWholeWord);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.cbMatchCase);
|
||||
this.Controls.Add(this.cbRegex);
|
||||
this.Controls.Add(this.tbFind);
|
||||
this.Controls.Add(this.btFindNext);
|
||||
this.Controls.Add(this.btClose);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.Name = "FindForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Find";
|
||||
this.TopMost = true;
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FindForm_FormClosing);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btClose;
|
||||
private System.Windows.Forms.Button btFindNext;
|
||||
private System.Windows.Forms.CheckBox cbRegex;
|
||||
private System.Windows.Forms.CheckBox cbMatchCase;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.CheckBox cbWholeWord;
|
||||
public System.Windows.Forms.TextBox tbFind;
|
||||
}
|
||||
}
|
120
GUI.NET/Debugger/FastColoredTextBox/FindForm.resx
Normal file
120
GUI.NET/Debugger/FastColoredTextBox/FindForm.resx
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
53
GUI.NET/Debugger/FastColoredTextBox/GoToForm.cs
Normal file
53
GUI.NET/Debugger/FastColoredTextBox/GoToForm.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class GoToForm : Form
|
||||
{
|
||||
public int SelectedLineNumber { get; set; }
|
||||
public int TotalLineCount { get; set; }
|
||||
|
||||
public GoToForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
this.tbLineNumber.Text = this.SelectedLineNumber.ToString();
|
||||
|
||||
this.label.Text = String.Format("Line number (1 - {0}):", this.TotalLineCount);
|
||||
}
|
||||
|
||||
protected override void OnShown(EventArgs e)
|
||||
{
|
||||
base.OnShown(e);
|
||||
|
||||
this.tbLineNumber.Focus();
|
||||
}
|
||||
|
||||
private void btnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
int enteredLine;
|
||||
if (int.TryParse(this.tbLineNumber.Text, out enteredLine))
|
||||
{
|
||||
enteredLine = Math.Min(enteredLine, this.TotalLineCount);
|
||||
enteredLine = Math.Max(1, enteredLine);
|
||||
|
||||
this.SelectedLineNumber = enteredLine;
|
||||
}
|
||||
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
}
|
110
GUI.NET/Debugger/FastColoredTextBox/GoToForm.designer.cs
generated
Normal file
110
GUI.NET/Debugger/FastColoredTextBox/GoToForm.designer.cs
generated
Normal file
|
@ -0,0 +1,110 @@
|
|||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class GoToForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.label = new System.Windows.Forms.Label();
|
||||
this.tbLineNumber = new System.Windows.Forms.TextBox();
|
||||
this.btnOk = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// label
|
||||
//
|
||||
this.label.AutoSize = true;
|
||||
this.label.Location = new System.Drawing.Point(12, 9);
|
||||
this.label.Name = "label";
|
||||
this.label.Size = new System.Drawing.Size(96, 13);
|
||||
this.label.TabIndex = 0;
|
||||
this.label.Text = "Line Number (1/1):";
|
||||
//
|
||||
// tbLineNumber
|
||||
//
|
||||
this.tbLineNumber.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.tbLineNumber.Location = new System.Drawing.Point(12, 29);
|
||||
this.tbLineNumber.Name = "tbLineNumber";
|
||||
this.tbLineNumber.Size = new System.Drawing.Size(296, 20);
|
||||
this.tbLineNumber.TabIndex = 1;
|
||||
//
|
||||
// btnOk
|
||||
//
|
||||
this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.btnOk.Location = new System.Drawing.Point(152, 71);
|
||||
this.btnOk.Name = "btnOk";
|
||||
this.btnOk.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOk.TabIndex = 2;
|
||||
this.btnOk.Text = "OK";
|
||||
this.btnOk.UseVisualStyleBackColor = true;
|
||||
this.btnOk.Click += new System.EventHandler(this.btnOk_Click);
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(233, 71);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.TabIndex = 3;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||
//
|
||||
// GoToForm
|
||||
//
|
||||
this.AcceptButton = this.btnOk;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btnCancel;
|
||||
this.ClientSize = new System.Drawing.Size(320, 106);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
this.Controls.Add(this.btnOk);
|
||||
this.Controls.Add(this.tbLineNumber);
|
||||
this.Controls.Add(this.label);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "GoToForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Go To Line";
|
||||
this.TopMost = true;
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label label;
|
||||
private System.Windows.Forms.TextBox tbLineNumber;
|
||||
private System.Windows.Forms.Button btnOk;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
}
|
||||
}
|
120
GUI.NET/Debugger/FastColoredTextBox/GoToForm.resx
Normal file
120
GUI.NET/Debugger/FastColoredTextBox/GoToForm.resx
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
364
GUI.NET/Debugger/FastColoredTextBox/Hints.cs
Normal file
364
GUI.NET/Debugger/FastColoredTextBox/Hints.cs
Normal file
|
@ -0,0 +1,364 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection of Hints.
|
||||
/// This is temporary buffer for currently displayed hints.
|
||||
/// </summary>
|
||||
public class Hints : ICollection<Hint>, IDisposable
|
||||
{
|
||||
FastColoredTextBox tb;
|
||||
List<Hint> items = new List<Hint>();
|
||||
|
||||
public Hints(FastColoredTextBox tb)
|
||||
{
|
||||
this.tb = tb;
|
||||
tb.TextChanged += OnTextBoxTextChanged;
|
||||
tb.KeyDown += OnTextBoxKeyDown;
|
||||
tb.VisibleRangeChanged += OnTextBoxVisibleRangeChanged;
|
||||
}
|
||||
|
||||
protected virtual void OnTextBoxKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == System.Windows.Forms.Keys.Escape && e.Modifiers == System.Windows.Forms.Keys.None)
|
||||
Clear();
|
||||
}
|
||||
|
||||
protected virtual void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
tb.TextChanged -= OnTextBoxTextChanged;
|
||||
tb.KeyDown -= OnTextBoxKeyDown;
|
||||
tb.VisibleRangeChanged -= OnTextBoxVisibleRangeChanged;
|
||||
}
|
||||
|
||||
void OnTextBoxVisibleRangeChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (items.Count == 0)
|
||||
return;
|
||||
|
||||
tb.NeedRecalc(true);
|
||||
foreach (var item in items)
|
||||
{
|
||||
LayoutHint(item);
|
||||
item.HostPanel.Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void LayoutHint(Hint hint)
|
||||
{
|
||||
if (hint.Inline || hint.Range.Start.iLine >= tb.LinesCount - 1)
|
||||
{
|
||||
if (hint.Range.Start.iLine < tb.LineInfos.Count - 1)
|
||||
hint.HostPanel.Top = tb.LineInfos[hint.Range.Start.iLine + 1].startY - hint.TopPadding - hint.HostPanel.Height - tb.VerticalScroll.Value;
|
||||
else
|
||||
hint.HostPanel.Top = tb.TextHeight + tb.Paddings.Top - hint.HostPanel.Height - tb.VerticalScroll.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
hint.HostPanel.Top = tb.LineInfos[hint.Range.Start.iLine + 1].startY - tb.VerticalScroll.Value;
|
||||
}
|
||||
|
||||
if (hint.Dock == DockStyle.Fill)
|
||||
{
|
||||
hint.Width = tb.ClientSize.Width - tb.LeftIndent - 2;
|
||||
hint.HostPanel.Left = tb.LeftIndent;
|
||||
}
|
||||
else
|
||||
{
|
||||
var p1 = tb.PlaceToPoint(hint.Range.Start);
|
||||
var p2 = tb.PlaceToPoint(hint.Range.End);
|
||||
var cx = (p1.X + p2.X) / 2;
|
||||
hint.HostPanel.Left = Math.Max( tb.LeftIndent, cx - hint.HostPanel.Width / 2);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<Hint> GetEnumerator()
|
||||
{
|
||||
foreach (var item in items)
|
||||
yield return item;
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all displayed hints
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
items.Clear();
|
||||
if (tb.Controls.Count != 0)
|
||||
{
|
||||
var toDelete = new List<Control>();
|
||||
foreach (Control item in tb.Controls)
|
||||
if (item is UnfocusablePanel)
|
||||
toDelete.Add(item);
|
||||
|
||||
foreach (var item in toDelete)
|
||||
tb.Controls.Remove(item);
|
||||
|
||||
for (int i = 0; i < tb.LineInfos.Count; i++)
|
||||
{
|
||||
var li = tb.LineInfos[i];
|
||||
li.bottomPadding = 0;
|
||||
tb.LineInfos[i] = li;
|
||||
}
|
||||
tb.NeedRecalc();
|
||||
tb.Invalidate();
|
||||
tb.Select();
|
||||
tb.ActiveControl = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add and shows the hint
|
||||
/// </summary>
|
||||
/// <param name="hint"></param>
|
||||
public void Add(Hint hint)
|
||||
{
|
||||
items.Add(hint);
|
||||
|
||||
if (hint.Inline || hint.Range.Start.iLine >= tb.LinesCount - 1)
|
||||
{
|
||||
var li = tb.LineInfos[hint.Range.Start.iLine];
|
||||
hint.TopPadding = li.bottomPadding;
|
||||
li.bottomPadding += hint.HostPanel.Height;
|
||||
tb.LineInfos[hint.Range.Start.iLine] = li;
|
||||
tb.NeedRecalc(true);
|
||||
}
|
||||
|
||||
LayoutHint(hint);
|
||||
|
||||
tb.OnVisibleRangeChanged();
|
||||
|
||||
hint.HostPanel.Parent = tb;
|
||||
|
||||
tb.Select();
|
||||
tb.ActiveControl = null;
|
||||
tb.Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is collection contains the hint?
|
||||
/// </summary>
|
||||
public bool Contains(Hint item)
|
||||
{
|
||||
return items.Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(Hint[] array, int arrayIndex)
|
||||
{
|
||||
items.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count of hints
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return items.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public bool Remove(Hint item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hint of FastColoredTextbox
|
||||
/// </summary>
|
||||
public class Hint
|
||||
{
|
||||
/// <summary>
|
||||
/// Text of simple hint
|
||||
/// </summary>
|
||||
public string Text { get { return HostPanel.Text; } set { HostPanel.Text = value; } }
|
||||
/// <summary>
|
||||
/// Linked range
|
||||
/// </summary>
|
||||
public Range Range { get; set; }
|
||||
/// <summary>
|
||||
/// Backcolor
|
||||
/// </summary>
|
||||
public Color BackColor { get { return HostPanel.BackColor; } set { HostPanel.BackColor = value; } }
|
||||
/// <summary>
|
||||
/// Second backcolor
|
||||
/// </summary>
|
||||
public Color BackColor2 { get { return HostPanel.BackColor2; } set { HostPanel.BackColor2 = value; } }
|
||||
/// <summary>
|
||||
/// Border color
|
||||
/// </summary>
|
||||
public Color BorderColor { get { return HostPanel.BorderColor; } set { HostPanel.BorderColor = value; } }
|
||||
/// <summary>
|
||||
/// Fore color
|
||||
/// </summary>
|
||||
public Color ForeColor { get { return HostPanel.ForeColor; } set { HostPanel.ForeColor = value; } }
|
||||
/// <summary>
|
||||
/// Text alignment
|
||||
/// </summary>
|
||||
public StringAlignment TextAlignment { get { return HostPanel.TextAlignment; } set { HostPanel.TextAlignment = value; } }
|
||||
/// <summary>
|
||||
/// Font
|
||||
/// </summary>
|
||||
public Font Font { get { return HostPanel.Font; } set { HostPanel.Font = value; } }
|
||||
/// <summary>
|
||||
/// Occurs when user click on simple hint
|
||||
/// </summary>
|
||||
public event EventHandler Click
|
||||
{
|
||||
add { HostPanel.Click += value; }
|
||||
remove { HostPanel.Click -= value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Inner control
|
||||
/// </summary>
|
||||
public Control InnerControl { get; set; }
|
||||
/// <summary>
|
||||
/// Docking (allows None and Fill only)
|
||||
/// </summary>
|
||||
public DockStyle Dock { get; set; }
|
||||
/// <summary>
|
||||
/// Width of hint (if Dock is None)
|
||||
/// </summary>
|
||||
public int Width { get { return HostPanel.Width; } set { HostPanel.Width = value; } }
|
||||
/// <summary>
|
||||
/// Height of hint
|
||||
/// </summary>
|
||||
public int Height { get { return HostPanel.Height; } set { HostPanel.Height = value; } }
|
||||
/// <summary>
|
||||
/// Host panel
|
||||
/// </summary>
|
||||
public UnfocusablePanel HostPanel { get; private set; }
|
||||
|
||||
internal int TopPadding { get; set; }
|
||||
/// <summary>
|
||||
/// Tag
|
||||
/// </summary>
|
||||
public object Tag { get; set; }
|
||||
/// <summary>
|
||||
/// Cursor
|
||||
/// </summary>
|
||||
public Cursor Cursor { get { return HostPanel.Cursor; } set { HostPanel.Cursor = value; } }
|
||||
/// <summary>
|
||||
/// Inlining. If True then hint will moves apart text.
|
||||
/// </summary>
|
||||
public bool Inline{get; set;}
|
||||
|
||||
/// <summary>
|
||||
/// Scroll textbox to the hint
|
||||
/// </summary>
|
||||
public virtual void DoVisible()
|
||||
{
|
||||
Range.tb.DoRangeVisible(Range, true);
|
||||
Range.tb.Invalidate();
|
||||
}
|
||||
|
||||
private Hint(Range range, Control innerControl, string text, bool inline, bool dock)
|
||||
{
|
||||
this.Range = range;
|
||||
this.Inline = inline;
|
||||
this.InnerControl = innerControl;
|
||||
|
||||
Init();
|
||||
|
||||
Dock = dock ? DockStyle.Fill : DockStyle.None;
|
||||
Text = text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates Hint
|
||||
/// </summary>
|
||||
/// <param name="range">Linked range</param>
|
||||
/// <param name="text">Text for simple hint</param>
|
||||
/// <param name="inline">Inlining. If True then hint will moves apart text</param>
|
||||
/// <param name="dock">Docking. If True then hint will fill whole line</param>
|
||||
public Hint(Range range, string text, bool inline, bool dock)
|
||||
: this(range, null, text, inline, dock)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates Hint
|
||||
/// </summary>
|
||||
/// <param name="range">Linked range</param>
|
||||
/// <param name="text">Text for simple hint</param>
|
||||
public Hint(Range range, string text)
|
||||
: this(range, null, text, true, true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates Hint
|
||||
/// </summary>
|
||||
/// <param name="range">Linked range</param>
|
||||
/// <param name="innerControl">Inner control</param>
|
||||
/// <param name="inline">Inlining. If True then hint will moves apart text</param>
|
||||
/// <param name="dock">Docking. If True then hint will fill whole line</param>
|
||||
public Hint(Range range, Control innerControl, bool inline, bool dock)
|
||||
: this(range, innerControl, null, inline, dock)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates Hint
|
||||
/// </summary>
|
||||
/// <param name="range">Linked range</param>
|
||||
/// <param name="innerControl">Inner control</param>
|
||||
public Hint(Range range, Control innerControl)
|
||||
: this(range, innerControl, null, true, true)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void Init()
|
||||
{
|
||||
HostPanel = new UnfocusablePanel();
|
||||
HostPanel.Click += OnClick;
|
||||
|
||||
if (InnerControl != null)
|
||||
{
|
||||
HostPanel.Controls.Add(InnerControl);
|
||||
HostPanel.Width = InnerControl.Width + 2;
|
||||
HostPanel.Height = InnerControl.Height + 2;
|
||||
InnerControl.Dock = DockStyle.Fill;
|
||||
InnerControl.Visible = true;
|
||||
BackColor = SystemColors.Control;
|
||||
}
|
||||
else
|
||||
{
|
||||
HostPanel.Height = Range.tb.CharHeight + 5;
|
||||
}
|
||||
|
||||
Cursor = Cursors.Default;
|
||||
BorderColor = Color.Silver;
|
||||
BackColor2 = Color.White;
|
||||
BackColor = InnerControl == null ? Color.Silver : SystemColors.Control;
|
||||
ForeColor = Color.Black;
|
||||
TextAlignment = StringAlignment.Near;
|
||||
Font = Range.tb.Parent == null ? Range.tb.Font : Range.tb.Parent.Font;
|
||||
}
|
||||
|
||||
protected virtual void OnClick(object sender, EventArgs e)
|
||||
{
|
||||
Range.tb.OnHintClick(this);
|
||||
}
|
||||
}
|
||||
}
|
251
GUI.NET/Debugger/FastColoredTextBox/Hotkeys.cs
Normal file
251
GUI.NET/Debugger/FastColoredTextBox/Hotkeys.cs
Normal file
|
@ -0,0 +1,251 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Design;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.Design;
|
||||
using KEYS = System.Windows.Forms.Keys;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Dictionary of shortcuts for FCTB
|
||||
/// </summary>
|
||||
public class HotkeysMapping : SortedDictionary<Keys, FCTBAction>
|
||||
{
|
||||
public virtual void InitDefault()
|
||||
{
|
||||
this[KEYS.Control | KEYS.G] = FCTBAction.GoToDialog;
|
||||
this[KEYS.Control | KEYS.F] = FCTBAction.FindDialog;
|
||||
this[KEYS.Control | KEYS.Alt | KEYS.F] = FCTBAction.FindChar;
|
||||
this[KEYS.F3] = FCTBAction.FindNext;
|
||||
this[KEYS.Control | KEYS.H] = FCTBAction.ReplaceDialog;
|
||||
this[KEYS.Control | KEYS.C] = FCTBAction.Copy;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.C] = FCTBAction.CommentSelected;
|
||||
this[KEYS.Control | KEYS.X] = FCTBAction.Cut;
|
||||
this[KEYS.Control | KEYS.V] = FCTBAction.Paste;
|
||||
this[KEYS.Control | KEYS.A] = FCTBAction.SelectAll;
|
||||
this[KEYS.Control | KEYS.Z] = FCTBAction.Undo;
|
||||
this[KEYS.Control | KEYS.R] = FCTBAction.Redo;
|
||||
this[KEYS.Control | KEYS.U] = FCTBAction.UpperCase;
|
||||
this[KEYS.Shift | KEYS.Control | KEYS.U] = FCTBAction.LowerCase;
|
||||
this[KEYS.Control | KEYS.OemMinus] = FCTBAction.NavigateBackward;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.OemMinus] = FCTBAction.NavigateForward;
|
||||
this[KEYS.Control | KEYS.B] = FCTBAction.BookmarkLine;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.B] = FCTBAction.UnbookmarkLine;
|
||||
this[KEYS.Control | KEYS.N] = FCTBAction.GoNextBookmark;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.N] = FCTBAction.GoPrevBookmark;
|
||||
this[KEYS.Alt | KEYS.Back] = FCTBAction.Undo;
|
||||
this[KEYS.Control | KEYS.Back] = FCTBAction.ClearWordLeft;
|
||||
this[KEYS.Insert] = FCTBAction.ReplaceMode;
|
||||
this[KEYS.Control | KEYS.Insert] = FCTBAction.Copy;
|
||||
this[KEYS.Shift | KEYS.Insert] = FCTBAction.Paste;
|
||||
this[KEYS.Delete] = FCTBAction.DeleteCharRight;
|
||||
this[KEYS.Control | KEYS.Delete] = FCTBAction.ClearWordRight;
|
||||
this[KEYS.Shift | KEYS.Delete] = FCTBAction.Cut;
|
||||
this[KEYS.Left] = FCTBAction.GoLeft;
|
||||
this[KEYS.Shift | KEYS.Left] = FCTBAction.GoLeftWithSelection;
|
||||
this[KEYS.Control | KEYS.Left] = FCTBAction.GoWordLeft;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.Left] = FCTBAction.GoWordLeftWithSelection;
|
||||
this[KEYS.Alt | KEYS.Shift | KEYS.Left] = FCTBAction.GoLeft_ColumnSelectionMode;
|
||||
this[KEYS.Right] = FCTBAction.GoRight;
|
||||
this[KEYS.Shift | KEYS.Right] = FCTBAction.GoRightWithSelection;
|
||||
this[KEYS.Control | KEYS.Right] = FCTBAction.GoWordRight;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.Right] = FCTBAction.GoWordRightWithSelection;
|
||||
this[KEYS.Alt | KEYS.Shift | KEYS.Right] = FCTBAction.GoRight_ColumnSelectionMode;
|
||||
this[KEYS.Up] = FCTBAction.GoUp;
|
||||
this[KEYS.Shift | KEYS.Up] = FCTBAction.GoUpWithSelection;
|
||||
this[KEYS.Alt | KEYS.Shift | KEYS.Up] = FCTBAction.GoUp_ColumnSelectionMode;
|
||||
this[KEYS.Alt | KEYS.Up] = FCTBAction.MoveSelectedLinesUp;
|
||||
this[KEYS.Control | KEYS.Up] = FCTBAction.ScrollUp;
|
||||
this[KEYS.Down] = FCTBAction.GoDown;
|
||||
this[KEYS.Shift | KEYS.Down] = FCTBAction.GoDownWithSelection;
|
||||
this[KEYS.Alt | KEYS.Shift | KEYS.Down] = FCTBAction.GoDown_ColumnSelectionMode;
|
||||
this[KEYS.Alt | KEYS.Down] = FCTBAction.MoveSelectedLinesDown;
|
||||
this[KEYS.Control | KEYS.Down] = FCTBAction.ScrollDown;
|
||||
this[KEYS.PageUp] = FCTBAction.GoPageUp;
|
||||
this[KEYS.Shift | KEYS.PageUp] = FCTBAction.GoPageUpWithSelection;
|
||||
this[KEYS.PageDown] = FCTBAction.GoPageDown;
|
||||
this[KEYS.Shift | KEYS.PageDown] = FCTBAction.GoPageDownWithSelection;
|
||||
this[KEYS.Home] = FCTBAction.GoHome;
|
||||
this[KEYS.Shift | KEYS.Home] = FCTBAction.GoHomeWithSelection;
|
||||
this[KEYS.Control | KEYS.Home] = FCTBAction.GoFirstLine;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.Home] = FCTBAction.GoFirstLineWithSelection;
|
||||
this[KEYS.End] = FCTBAction.GoEnd;
|
||||
this[KEYS.Shift | KEYS.End] = FCTBAction.GoEndWithSelection;
|
||||
this[KEYS.Control | KEYS.End] = FCTBAction.GoLastLine;
|
||||
this[KEYS.Control | KEYS.Shift | KEYS.End] = FCTBAction.GoLastLineWithSelection;
|
||||
this[KEYS.Escape] = FCTBAction.ClearHints;
|
||||
this[KEYS.Control | KEYS.M] = FCTBAction.MacroRecord;
|
||||
this[KEYS.Control | KEYS.E] = FCTBAction.MacroExecute;
|
||||
this[KEYS.Control | KEYS.Space] = FCTBAction.AutocompleteMenu;
|
||||
this[KEYS.Tab] = FCTBAction.IndentIncrease;
|
||||
this[KEYS.Shift | KEYS.Tab] = FCTBAction.IndentDecrease;
|
||||
this[KEYS.Control | KEYS.Subtract] = FCTBAction.ZoomOut;
|
||||
this[KEYS.Control | KEYS.Add] = FCTBAction.ZoomIn;
|
||||
this[KEYS.Control | KEYS.D0] = FCTBAction.ZoomNormal;
|
||||
this[KEYS.Control | KEYS.I] = FCTBAction.AutoIndentChars;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var cult = Thread.CurrentThread.CurrentUICulture;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var kc = new KeysConverter();
|
||||
foreach (var pair in this)
|
||||
{
|
||||
sb.AppendFormat("{0}={1}, ", kc.ConvertToString(pair.Key), pair.Value);
|
||||
}
|
||||
|
||||
if (sb.Length > 1)
|
||||
sb.Remove(sb.Length - 2, 2);
|
||||
Thread.CurrentThread.CurrentUICulture = cult;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static HotkeysMapping Parse(string s)
|
||||
{
|
||||
var result = new HotkeysMapping();
|
||||
result.Clear();
|
||||
var cult = Thread.CurrentThread.CurrentUICulture;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
|
||||
var kc = new KeysConverter();
|
||||
|
||||
foreach (var p in s.Split(','))
|
||||
{
|
||||
var pp = p.Split('=');
|
||||
var k = (Keys)kc.ConvertFromString(pp[0].Trim());
|
||||
var a = (FCTBAction)Enum.Parse(typeof(FCTBAction), pp[1].Trim());
|
||||
result[k] = a;
|
||||
}
|
||||
|
||||
Thread.CurrentThread.CurrentUICulture = cult;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Actions for shortcuts
|
||||
/// </summary>
|
||||
public enum FCTBAction
|
||||
{
|
||||
None,
|
||||
AutocompleteMenu,
|
||||
AutoIndentChars,
|
||||
BookmarkLine,
|
||||
ClearHints,
|
||||
ClearWordLeft,
|
||||
ClearWordRight,
|
||||
CommentSelected,
|
||||
Copy,
|
||||
Cut,
|
||||
DeleteCharRight,
|
||||
FindChar,
|
||||
FindDialog,
|
||||
FindNext,
|
||||
GoDown,
|
||||
GoDownWithSelection,
|
||||
GoDown_ColumnSelectionMode,
|
||||
GoEnd,
|
||||
GoEndWithSelection,
|
||||
GoFirstLine,
|
||||
GoFirstLineWithSelection,
|
||||
GoHome,
|
||||
GoHomeWithSelection,
|
||||
GoLastLine,
|
||||
GoLastLineWithSelection,
|
||||
GoLeft,
|
||||
GoLeftWithSelection,
|
||||
GoLeft_ColumnSelectionMode,
|
||||
GoPageDown,
|
||||
GoPageDownWithSelection,
|
||||
GoPageUp,
|
||||
GoPageUpWithSelection,
|
||||
GoRight,
|
||||
GoRightWithSelection,
|
||||
GoRight_ColumnSelectionMode,
|
||||
GoToDialog,
|
||||
GoNextBookmark,
|
||||
GoPrevBookmark,
|
||||
GoUp,
|
||||
GoUpWithSelection,
|
||||
GoUp_ColumnSelectionMode,
|
||||
GoWordLeft,
|
||||
GoWordLeftWithSelection,
|
||||
GoWordRight,
|
||||
GoWordRightWithSelection,
|
||||
IndentIncrease,
|
||||
IndentDecrease,
|
||||
LowerCase,
|
||||
MacroExecute,
|
||||
MacroRecord,
|
||||
MoveSelectedLinesDown,
|
||||
MoveSelectedLinesUp,
|
||||
NavigateBackward,
|
||||
NavigateForward,
|
||||
Paste,
|
||||
Redo,
|
||||
ReplaceDialog,
|
||||
ReplaceMode,
|
||||
ScrollDown,
|
||||
ScrollUp,
|
||||
SelectAll,
|
||||
UnbookmarkLine,
|
||||
Undo,
|
||||
UpperCase,
|
||||
ZoomIn,
|
||||
ZoomNormal,
|
||||
ZoomOut,
|
||||
CustomAction1,
|
||||
CustomAction2,
|
||||
CustomAction3,
|
||||
CustomAction4,
|
||||
CustomAction5,
|
||||
CustomAction6,
|
||||
CustomAction7,
|
||||
CustomAction8,
|
||||
CustomAction9,
|
||||
CustomAction10,
|
||||
CustomAction11,
|
||||
CustomAction12,
|
||||
CustomAction13,
|
||||
CustomAction14,
|
||||
CustomAction15,
|
||||
CustomAction16,
|
||||
CustomAction17,
|
||||
CustomAction18,
|
||||
CustomAction19,
|
||||
CustomAction20
|
||||
}
|
||||
|
||||
internal class HotkeysEditor : UITypeEditor
|
||||
{
|
||||
public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
|
||||
{
|
||||
return UITypeEditorEditStyle.Modal;
|
||||
}
|
||||
|
||||
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
|
||||
{
|
||||
if ((provider != null) && (((IWindowsFormsEditorService) provider.GetService(typeof(IWindowsFormsEditorService))) != null))
|
||||
{
|
||||
var form = new HotkeysEditorForm(HotkeysMapping.Parse(value as string));
|
||||
|
||||
if (form.ShowDialog() == DialogResult.OK)
|
||||
value = form.GetHotkeys().ToString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
179
GUI.NET/Debugger/FastColoredTextBox/HotkeysEditorForm.cs
Normal file
179
GUI.NET/Debugger/FastColoredTextBox/HotkeysEditorForm.cs
Normal file
|
@ -0,0 +1,179 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class HotkeysEditorForm : Form
|
||||
{
|
||||
BindingList<HotkeyWrapper> wrappers = new BindingList<HotkeyWrapper>();
|
||||
|
||||
public HotkeysEditorForm(HotkeysMapping hotkeys)
|
||||
{
|
||||
InitializeComponent();
|
||||
BuildWrappers(hotkeys);
|
||||
dgv.DataSource = wrappers;
|
||||
}
|
||||
|
||||
int CompereKeys(Keys key1, Keys key2)
|
||||
{
|
||||
var res = ((int)key1 & 0xff).CompareTo((int)key2 & 0xff);
|
||||
if (res == 0)
|
||||
res = key1.CompareTo(key2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private void BuildWrappers(HotkeysMapping hotkeys)
|
||||
{
|
||||
var keys = new List<Keys>(hotkeys.Keys);
|
||||
keys.Sort(CompereKeys);
|
||||
|
||||
wrappers.Clear();
|
||||
foreach (var k in keys)
|
||||
wrappers.Add(new HotkeyWrapper(k, hotkeys[k]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns edited hotkey map
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public HotkeysMapping GetHotkeys()
|
||||
{
|
||||
var result = new HotkeysMapping();
|
||||
foreach (var w in wrappers)
|
||||
result[w.ToKeyData()] = w.Action;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void btAdd_Click(object sender, EventArgs e)
|
||||
{
|
||||
wrappers.Add(new HotkeyWrapper(Keys.None, FCTBAction.None));
|
||||
}
|
||||
|
||||
private void dgv_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
|
||||
{
|
||||
var cell = (dgv[0, e.RowIndex] as DataGridViewComboBoxCell);
|
||||
if(cell.Items.Count == 0)
|
||||
foreach(var item in new string[]{"", "Ctrl", "Ctrl + Shift", "Ctrl + Alt", "Shift", "Shift + Alt", "Alt", "Ctrl + Shift + Alt"})
|
||||
cell.Items.Add(item);
|
||||
|
||||
cell = (dgv[1, e.RowIndex] as DataGridViewComboBoxCell);
|
||||
if (cell.Items.Count == 0)
|
||||
foreach (var item in Enum.GetValues(typeof(Keys)))
|
||||
cell.Items.Add(item);
|
||||
|
||||
cell = (dgv[2, e.RowIndex] as DataGridViewComboBoxCell);
|
||||
if (cell.Items.Count == 0)
|
||||
foreach (var item in Enum.GetValues(typeof(FCTBAction)))
|
||||
cell.Items.Add(item);
|
||||
}
|
||||
|
||||
private void btResore_Click(object sender, EventArgs e)
|
||||
{
|
||||
HotkeysMapping h = new HotkeysMapping();
|
||||
h.InitDefault();
|
||||
BuildWrappers(h);
|
||||
}
|
||||
|
||||
private void btRemove_Click(object sender, EventArgs e)
|
||||
{
|
||||
for (int i = dgv.RowCount - 1; i >= 0; i--)
|
||||
if (dgv.Rows[i].Selected) dgv.Rows.RemoveAt(i);
|
||||
}
|
||||
|
||||
private void HotkeysEditorForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if(DialogResult == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
var actions = GetUnAssignedActions();
|
||||
if (!string.IsNullOrEmpty(actions))
|
||||
{
|
||||
if (MessageBox.Show("Some actions are not assigned!\r\nActions: " + actions + "\r\nPress Yes to save and exit, press No to continue editing", "Some actions is not assigned", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.No)
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetUnAssignedActions()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var dic = new Dictionary<FCTBAction, FCTBAction>();
|
||||
|
||||
foreach (var w in wrappers)
|
||||
dic[w.Action] = w.Action;
|
||||
|
||||
foreach (var item in Enum.GetValues(typeof(FCTBAction)))
|
||||
if ((FCTBAction)item != FCTBAction.None)
|
||||
if(!((FCTBAction)item).ToString().StartsWith("CustomAction"))
|
||||
{
|
||||
if(!dic.ContainsKey((FCTBAction)item))
|
||||
sb.Append(item+", ");
|
||||
}
|
||||
|
||||
return sb.ToString().TrimEnd(' ', ',');
|
||||
}
|
||||
}
|
||||
|
||||
internal class HotkeyWrapper
|
||||
{
|
||||
public HotkeyWrapper(Keys keyData, FCTBAction action)
|
||||
{
|
||||
KeyEventArgs a = new KeyEventArgs(keyData);
|
||||
Ctrl = a.Control;
|
||||
Shift = a.Shift;
|
||||
Alt = a.Alt;
|
||||
|
||||
Key = a.KeyCode;
|
||||
Action = action;
|
||||
}
|
||||
|
||||
public Keys ToKeyData()
|
||||
{
|
||||
var res = Key;
|
||||
if (Ctrl) res |= Keys.Control;
|
||||
if (Alt) res |= Keys.Alt;
|
||||
if (Shift) res |= Keys.Shift;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Ctrl;
|
||||
bool Shift;
|
||||
bool Alt;
|
||||
|
||||
public string Modifiers
|
||||
{
|
||||
get
|
||||
{
|
||||
var res = "";
|
||||
if (Ctrl) res += "Ctrl + ";
|
||||
if (Shift) res += "Shift + ";
|
||||
if (Alt) res += "Alt + ";
|
||||
|
||||
return res.Trim(' ', '+');
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Ctrl = Alt = Shift = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ctrl = value.Contains("Ctrl");
|
||||
Shift = value.Contains("Shift");
|
||||
Alt = value.Contains("Alt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Keys Key { get; set; }
|
||||
public FCTBAction Action { get; set; }
|
||||
}
|
||||
}
|
210
GUI.NET/Debugger/FastColoredTextBox/HotkeysEditorForm.designer.cs
generated
Normal file
210
GUI.NET/Debugger/FastColoredTextBox/HotkeysEditorForm.designer.cs
generated
Normal file
|
@ -0,0 +1,210 @@
|
|||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class HotkeysEditorForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
|
||||
this.dgv = new System.Windows.Forms.DataGridView();
|
||||
this.cbModifiers = new System.Windows.Forms.DataGridViewComboBoxColumn();
|
||||
this.cbKey = new System.Windows.Forms.DataGridViewComboBoxColumn();
|
||||
this.cbAction = new System.Windows.Forms.DataGridViewComboBoxColumn();
|
||||
this.btAdd = new System.Windows.Forms.Button();
|
||||
this.btRemove = new System.Windows.Forms.Button();
|
||||
this.btCancel = new System.Windows.Forms.Button();
|
||||
this.btOk = new System.Windows.Forms.Button();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.btResore = new System.Windows.Forms.Button();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// dgv
|
||||
//
|
||||
this.dgv.AllowUserToAddRows = false;
|
||||
this.dgv.AllowUserToDeleteRows = false;
|
||||
this.dgv.AllowUserToResizeColumns = false;
|
||||
this.dgv.AllowUserToResizeRows = false;
|
||||
this.dgv.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.dgv.BackgroundColor = System.Drawing.SystemColors.Control;
|
||||
this.dgv.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.dgv.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.cbModifiers,
|
||||
this.cbKey,
|
||||
this.cbAction});
|
||||
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
|
||||
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window;
|
||||
dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
|
||||
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;
|
||||
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.Color.LightSteelBlue;
|
||||
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
|
||||
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
|
||||
this.dgv.DefaultCellStyle = dataGridViewCellStyle1;
|
||||
this.dgv.GridColor = System.Drawing.SystemColors.Control;
|
||||
this.dgv.Location = new System.Drawing.Point(12, 28);
|
||||
this.dgv.Name = "dgv";
|
||||
this.dgv.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None;
|
||||
this.dgv.RowHeadersVisible = false;
|
||||
this.dgv.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
|
||||
this.dgv.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
|
||||
this.dgv.Size = new System.Drawing.Size(525, 278);
|
||||
this.dgv.TabIndex = 0;
|
||||
this.dgv.RowsAdded += new System.Windows.Forms.DataGridViewRowsAddedEventHandler(this.dgv_RowsAdded);
|
||||
//
|
||||
// cbModifiers
|
||||
//
|
||||
this.cbModifiers.DataPropertyName = "Modifiers";
|
||||
this.cbModifiers.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
|
||||
this.cbModifiers.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.cbModifiers.HeaderText = "Modifiers";
|
||||
this.cbModifiers.Name = "cbModifiers";
|
||||
//
|
||||
// cbKey
|
||||
//
|
||||
this.cbKey.DataPropertyName = "Key";
|
||||
this.cbKey.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
|
||||
this.cbKey.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.cbKey.HeaderText = "Key";
|
||||
this.cbKey.Name = "cbKey";
|
||||
this.cbKey.Resizable = System.Windows.Forms.DataGridViewTriState.True;
|
||||
this.cbKey.Width = 120;
|
||||
//
|
||||
// cbAction
|
||||
//
|
||||
this.cbAction.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
|
||||
this.cbAction.DataPropertyName = "Action";
|
||||
this.cbAction.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
|
||||
this.cbAction.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.cbAction.HeaderText = "Action";
|
||||
this.cbAction.Name = "cbAction";
|
||||
//
|
||||
// btAdd
|
||||
//
|
||||
this.btAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btAdd.Location = new System.Drawing.Point(13, 322);
|
||||
this.btAdd.Name = "btAdd";
|
||||
this.btAdd.Size = new System.Drawing.Size(75, 23);
|
||||
this.btAdd.TabIndex = 1;
|
||||
this.btAdd.Text = "Add";
|
||||
this.btAdd.UseVisualStyleBackColor = true;
|
||||
this.btAdd.Click += new System.EventHandler(this.btAdd_Click);
|
||||
//
|
||||
// btRemove
|
||||
//
|
||||
this.btRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btRemove.Location = new System.Drawing.Point(103, 322);
|
||||
this.btRemove.Name = "btRemove";
|
||||
this.btRemove.Size = new System.Drawing.Size(75, 23);
|
||||
this.btRemove.TabIndex = 2;
|
||||
this.btRemove.Text = "Remove";
|
||||
this.btRemove.UseVisualStyleBackColor = true;
|
||||
this.btRemove.Click += new System.EventHandler(this.btRemove_Click);
|
||||
//
|
||||
// btCancel
|
||||
//
|
||||
this.btCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btCancel.Location = new System.Drawing.Point(460, 322);
|
||||
this.btCancel.Name = "btCancel";
|
||||
this.btCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btCancel.TabIndex = 4;
|
||||
this.btCancel.Text = "Cancel";
|
||||
this.btCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btOk
|
||||
//
|
||||
this.btOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btOk.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.btOk.Location = new System.Drawing.Point(379, 322);
|
||||
this.btOk.Name = "btOk";
|
||||
this.btOk.Size = new System.Drawing.Size(75, 23);
|
||||
this.btOk.TabIndex = 3;
|
||||
this.btOk.Text = "OK";
|
||||
this.btOk.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
|
||||
this.label1.Location = new System.Drawing.Point(12, 9);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(114, 16);
|
||||
this.label1.TabIndex = 5;
|
||||
this.label1.Text = "Hotkeys mapping";
|
||||
//
|
||||
// btResore
|
||||
//
|
||||
this.btResore.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btResore.Location = new System.Drawing.Point(194, 322);
|
||||
this.btResore.Name = "btResore";
|
||||
this.btResore.Size = new System.Drawing.Size(105, 23);
|
||||
this.btResore.TabIndex = 6;
|
||||
this.btResore.Text = "Restore default";
|
||||
this.btResore.UseVisualStyleBackColor = true;
|
||||
this.btResore.Click += new System.EventHandler(this.btResore_Click);
|
||||
//
|
||||
// HotkeysEditorForm
|
||||
//
|
||||
this.AcceptButton = this.btOk;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.CancelButton = this.btCancel;
|
||||
this.ClientSize = new System.Drawing.Size(549, 357);
|
||||
this.Controls.Add(this.btResore);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.btCancel);
|
||||
this.Controls.Add(this.btOk);
|
||||
this.Controls.Add(this.btRemove);
|
||||
this.Controls.Add(this.btAdd);
|
||||
this.Controls.Add(this.dgv);
|
||||
this.MaximumSize = new System.Drawing.Size(565, 700);
|
||||
this.MinimumSize = new System.Drawing.Size(565, 395);
|
||||
this.Name = "HotkeysEditorForm";
|
||||
this.ShowIcon = false;
|
||||
this.Text = "Hotkeys Editor";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.HotkeysEditorForm_FormClosing);
|
||||
((System.ComponentModel.ISupportInitialize)(this.dgv)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.DataGridView dgv;
|
||||
private System.Windows.Forms.Button btAdd;
|
||||
private System.Windows.Forms.Button btRemove;
|
||||
private System.Windows.Forms.Button btCancel;
|
||||
private System.Windows.Forms.Button btOk;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Button btResore;
|
||||
private System.Windows.Forms.DataGridViewComboBoxColumn cbModifiers;
|
||||
private System.Windows.Forms.DataGridViewComboBoxColumn cbKey;
|
||||
private System.Windows.Forms.DataGridViewComboBoxColumn cbAction;
|
||||
}
|
||||
}
|
129
GUI.NET/Debugger/FastColoredTextBox/HotkeysEditorForm.resx
Normal file
129
GUI.NET/Debugger/FastColoredTextBox/HotkeysEditorForm.resx
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="cbModifiers.UserAddedColumn" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="cbKey.UserAddedColumn" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="cbAction.UserAddedColumn" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
</root>
|
105
GUI.NET/Debugger/FastColoredTextBox/LimitedStack.cs
Normal file
105
GUI.NET/Debugger/FastColoredTextBox/LimitedStack.cs
Normal file
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Limited stack
|
||||
/// </summary>
|
||||
public class LimitedStack<T>
|
||||
{
|
||||
T[] items;
|
||||
int count;
|
||||
int start;
|
||||
|
||||
/// <summary>
|
||||
/// Max stack length
|
||||
/// </summary>
|
||||
public int MaxItemCount
|
||||
{
|
||||
get { return items.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current length of stack
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="maxItemCount">Maximum length of stack</param>
|
||||
public LimitedStack(int maxItemCount)
|
||||
{
|
||||
items = new T[maxItemCount];
|
||||
count = 0;
|
||||
start = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pop item
|
||||
/// </summary>
|
||||
public T Pop()
|
||||
{
|
||||
if (count == 0)
|
||||
throw new Exception("Stack is empty");
|
||||
|
||||
int i = LastIndex;
|
||||
T item = items[i];
|
||||
items[i] = default(T);
|
||||
|
||||
count--;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
int LastIndex
|
||||
{
|
||||
get { return (start + count - 1) % items.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Peek item
|
||||
/// </summary>
|
||||
public T Peek()
|
||||
{
|
||||
if (count == 0)
|
||||
return default(T);
|
||||
|
||||
return items[LastIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Push item
|
||||
/// </summary>
|
||||
public void Push(T item)
|
||||
{
|
||||
if (count == items.Length)
|
||||
start = (start + 1) % items.Length;
|
||||
else
|
||||
count++;
|
||||
|
||||
items[LastIndex] = item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear stack
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
items = new T[items.Length];
|
||||
count = 0;
|
||||
start = 0;
|
||||
}
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] result = new T[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
result[i] = items[(start + i) % items.Length];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
289
GUI.NET/Debugger/FastColoredTextBox/Line.cs
Normal file
289
GUI.NET/Debugger/FastColoredTextBox/Line.cs
Normal file
|
@ -0,0 +1,289 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Line of text
|
||||
/// </summary>
|
||||
public class Line : IList<Char>
|
||||
{
|
||||
protected List<Char> chars;
|
||||
|
||||
public string FoldingStartMarker { get; set; }
|
||||
public string FoldingEndMarker { get; set; }
|
||||
/// <summary>
|
||||
/// Text of line was changed
|
||||
/// </summary>
|
||||
public bool IsChanged { get; set; }
|
||||
/// <summary>
|
||||
/// Time of last visit of caret in this line
|
||||
/// </summary>
|
||||
/// <remarks>This property can be used for forward/backward navigating</remarks>
|
||||
public DateTime LastVisit { get; set; }
|
||||
/// <summary>
|
||||
/// Background brush.
|
||||
/// </summary>
|
||||
public Brush BackgroundBrush { get; set;}
|
||||
/// <summary>
|
||||
/// Unique ID
|
||||
/// </summary>
|
||||
public int UniqueId { get; private set; }
|
||||
/// <summary>
|
||||
/// Count of needed start spaces for AutoIndent
|
||||
/// </summary>
|
||||
public int AutoIndentSpacesNeededCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal Line(int uid)
|
||||
{
|
||||
this.UniqueId = uid;
|
||||
chars = new List<Char>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears style of chars, delete folding markers
|
||||
/// </summary>
|
||||
public void ClearStyle(StyleIndex styleIndex)
|
||||
{
|
||||
FoldingStartMarker = null;
|
||||
FoldingEndMarker = null;
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
Char c = this[i];
|
||||
c.style &= ~styleIndex;
|
||||
this[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text of the line
|
||||
/// </summary>
|
||||
public virtual string Text
|
||||
{
|
||||
get{
|
||||
StringBuilder sb = new StringBuilder(Count);
|
||||
foreach(Char c in this)
|
||||
sb.Append(c.c);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears folding markers
|
||||
/// </summary>
|
||||
public void ClearFoldingMarkers()
|
||||
{
|
||||
FoldingStartMarker = null;
|
||||
FoldingEndMarker = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count of start spaces
|
||||
/// </summary>
|
||||
public int StartSpacesCount
|
||||
{
|
||||
get
|
||||
{
|
||||
int spacesCount = 0;
|
||||
for (int i = 0; i < Count; i++)
|
||||
if (this[i].c == ' ')
|
||||
spacesCount++;
|
||||
else
|
||||
break;
|
||||
return spacesCount;
|
||||
}
|
||||
}
|
||||
|
||||
public int IndexOf(Char item)
|
||||
{
|
||||
return chars.IndexOf(item);
|
||||
}
|
||||
|
||||
public void Insert(int index, Char item)
|
||||
{
|
||||
chars.Insert(index, item);
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
chars.RemoveAt(index);
|
||||
}
|
||||
|
||||
public Char this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return chars[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
chars[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(Char item)
|
||||
{
|
||||
chars.Add(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
chars.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(Char item)
|
||||
{
|
||||
return chars.Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(Char[] array, int arrayIndex)
|
||||
{
|
||||
chars.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chars count
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return chars.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public bool Remove(Char item)
|
||||
{
|
||||
return chars.Remove(item);
|
||||
}
|
||||
|
||||
public IEnumerator<Char> GetEnumerator()
|
||||
{
|
||||
return chars.GetEnumerator();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return chars.GetEnumerator() as System.Collections.IEnumerator;
|
||||
}
|
||||
|
||||
public virtual void RemoveRange(int index, int count)
|
||||
{
|
||||
if (index >= Count)
|
||||
return;
|
||||
chars.RemoveRange(index, Math.Min(Count - index, count));
|
||||
}
|
||||
|
||||
public virtual void TrimExcess()
|
||||
{
|
||||
chars.TrimExcess();
|
||||
}
|
||||
|
||||
public virtual void AddRange(IEnumerable<Char> collection)
|
||||
{
|
||||
chars.AddRange(collection);
|
||||
}
|
||||
}
|
||||
|
||||
public struct LineInfo
|
||||
{
|
||||
List<int> cutOffPositions;
|
||||
//Y coordinate of line on screen
|
||||
internal int startY;
|
||||
internal int bottomPadding;
|
||||
//indent of secondary wordwrap strings (in chars)
|
||||
internal int wordWrapIndent;
|
||||
/// <summary>
|
||||
/// Visible state
|
||||
/// </summary>
|
||||
public VisibleState VisibleState;
|
||||
|
||||
public LineInfo(int startY)
|
||||
{
|
||||
cutOffPositions = null;
|
||||
VisibleState = VisibleState.Visible;
|
||||
this.startY = startY;
|
||||
bottomPadding = 0;
|
||||
wordWrapIndent = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Positions for wordwrap cutoffs
|
||||
/// </summary>
|
||||
public List<int> CutOffPositions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cutOffPositions == null)
|
||||
cutOffPositions = new List<int>();
|
||||
return cutOffPositions;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count of wordwrap string count for this line
|
||||
/// </summary>
|
||||
public int WordWrapStringsCount
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (VisibleState)
|
||||
{
|
||||
case VisibleState.Visible:
|
||||
if (cutOffPositions == null)
|
||||
return 1;
|
||||
else
|
||||
return cutOffPositions.Count + 1;
|
||||
case VisibleState.Hidden: return 0;
|
||||
case VisibleState.StartOfHiddenBlock: return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetWordWrapStringStartPosition(int iWordWrapLine)
|
||||
{
|
||||
return iWordWrapLine == 0 ? 0 : CutOffPositions[iWordWrapLine - 1];
|
||||
}
|
||||
|
||||
internal int GetWordWrapStringFinishPosition(int iWordWrapLine, Line line)
|
||||
{
|
||||
if (WordWrapStringsCount <= 0)
|
||||
return 0;
|
||||
return iWordWrapLine == WordWrapStringsCount - 1 ? line.Count - 1 : CutOffPositions[iWordWrapLine] - 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets index of wordwrap string for given char position
|
||||
/// </summary>
|
||||
public int GetWordWrapStringIndex(int iChar)
|
||||
{
|
||||
if (cutOffPositions == null || cutOffPositions.Count == 0) return 0;
|
||||
for (int i = 0; i < cutOffPositions.Count; i++)
|
||||
if (cutOffPositions[i] >/*>=*/ iChar)
|
||||
return i;
|
||||
return cutOffPositions.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public enum VisibleState: byte
|
||||
{
|
||||
Visible, StartOfHiddenBlock, Hidden
|
||||
}
|
||||
|
||||
public enum IndentMarker
|
||||
{
|
||||
None,
|
||||
Increased,
|
||||
Decreased
|
||||
}
|
||||
}
|
98
GUI.NET/Debugger/FastColoredTextBox/LinesAccessor.cs
Normal file
98
GUI.NET/Debugger/FastColoredTextBox/LinesAccessor.cs
Normal file
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public class LinesAccessor : IList<string>
|
||||
{
|
||||
IList<Line> ts;
|
||||
|
||||
public LinesAccessor(IList<Line> ts)
|
||||
{
|
||||
this.ts = ts;
|
||||
}
|
||||
|
||||
public int IndexOf(string item)
|
||||
{
|
||||
for (int i = 0; i < ts.Count; i++)
|
||||
if (ts[i].Text == item)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Insert(int index, string item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return ts[index].Text;
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(string item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Contains(string item)
|
||||
{
|
||||
for (int i = 0; i < ts.Count; i++)
|
||||
if (ts[i].Text == item)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(string[] array, int arrayIndex)
|
||||
{
|
||||
for (int i = 0; i < ts.Count; i++)
|
||||
array[i + arrayIndex] = ts[i].Text;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return ts.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public bool Remove(string item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerator<string> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i < ts.Count; i++)
|
||||
yield return ts[i].Text;
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
183
GUI.NET/Debugger/FastColoredTextBox/MacrosManager.cs
Normal file
183
GUI.NET/Debugger/FastColoredTextBox/MacrosManager.cs
Normal file
|
@ -0,0 +1,183 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// This class records, stores and executes the macros.
|
||||
/// </summary>
|
||||
public class MacrosManager
|
||||
{
|
||||
private readonly List<object> macro = new List<object>();
|
||||
|
||||
internal MacrosManager(FastColoredTextBox ctrl)
|
||||
{
|
||||
UnderlayingControl = ctrl;
|
||||
AllowMacroRecordingByUser = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows to user to record macros
|
||||
/// </summary>
|
||||
public bool AllowMacroRecordingByUser { get;set; }
|
||||
|
||||
private bool isRecording;
|
||||
|
||||
/// <summary>
|
||||
/// Returns current recording state. Set to True/False to start/stop recording programmatically.
|
||||
/// </summary>
|
||||
public bool IsRecording
|
||||
{
|
||||
get { return isRecording; }
|
||||
set { isRecording = value; UnderlayingControl.Invalidate(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FCTB
|
||||
/// </summary>
|
||||
public FastColoredTextBox UnderlayingControl { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes recorded macro
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void ExecuteMacros()
|
||||
{
|
||||
IsRecording = false;
|
||||
UnderlayingControl.BeginUpdate();
|
||||
UnderlayingControl.Selection.BeginUpdate();
|
||||
UnderlayingControl.BeginAutoUndo();
|
||||
foreach (var item in macro)
|
||||
{
|
||||
if (item is Keys)
|
||||
{
|
||||
UnderlayingControl.ProcessKey((Keys)item);
|
||||
}
|
||||
if (item is KeyValuePair<char, Keys>)
|
||||
{
|
||||
var p = (KeyValuePair<char, Keys>)item;
|
||||
UnderlayingControl.ProcessKey(p.Key, p.Value);
|
||||
}
|
||||
|
||||
}
|
||||
UnderlayingControl.EndAutoUndo();
|
||||
UnderlayingControl.Selection.EndUpdate();
|
||||
UnderlayingControl.EndUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the char to current macro
|
||||
/// </summary>
|
||||
public void AddCharToMacros(char c, Keys modifiers)
|
||||
{
|
||||
macro.Add(new KeyValuePair<char, Keys>(c, modifiers));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds keyboard key to current macro
|
||||
/// </summary>
|
||||
public void AddKeyToMacros(Keys keyData)
|
||||
{
|
||||
macro.Add(keyData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears last recorded macro
|
||||
/// </summary>
|
||||
public void ClearMacros()
|
||||
{
|
||||
macro.Clear();
|
||||
}
|
||||
|
||||
|
||||
internal void ProcessKey(Keys keyData)
|
||||
{
|
||||
if (IsRecording)
|
||||
AddKeyToMacros(keyData);
|
||||
}
|
||||
|
||||
internal void ProcessKey(char c, Keys modifiers)
|
||||
{
|
||||
if (IsRecording)
|
||||
AddCharToMacros(c, modifiers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns True if last macro is empty
|
||||
/// </summary>
|
||||
public bool MacroIsEmpty { get { return macro.Count == 0; }}
|
||||
|
||||
/// <summary>
|
||||
/// Macros as string.
|
||||
/// </summary>
|
||||
public string Macros
|
||||
{
|
||||
get
|
||||
{
|
||||
var cult = Thread.CurrentThread.CurrentUICulture;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
var kc = new KeysConverter();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine("<macros>");
|
||||
foreach (var item in macro)
|
||||
{
|
||||
if (item is Keys)
|
||||
{
|
||||
sb.AppendFormat("<item key='{0}' />\r\n", kc.ConvertToString((Keys)item));
|
||||
}
|
||||
else if (item is KeyValuePair<char, Keys>)
|
||||
{
|
||||
var p = (KeyValuePair<char, Keys>)item;
|
||||
sb.AppendFormat("<item char='{0}' key='{1}' />\r\n", (int)p.Key, kc.ConvertToString(p.Value));
|
||||
}
|
||||
}
|
||||
sb.AppendLine("</macros>");
|
||||
|
||||
Thread.CurrentThread.CurrentUICulture = cult;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
isRecording = false;
|
||||
ClearMacros();
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return;
|
||||
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(value);
|
||||
var list = doc.SelectNodes("./macros/item");
|
||||
|
||||
var cult = Thread.CurrentThread.CurrentUICulture;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
var kc = new KeysConverter();
|
||||
|
||||
if(list != null)
|
||||
foreach (XmlElement node in list)
|
||||
{
|
||||
var ca = node.GetAttributeNode("char");
|
||||
var ka = node.GetAttributeNode("key");
|
||||
if (ca != null)
|
||||
{
|
||||
if(ka!=null)
|
||||
AddCharToMacros((char)int.Parse(ca.Value), (Keys)kc.ConvertFromString(ka.Value));
|
||||
else
|
||||
AddCharToMacros((char)int.Parse(ca.Value), Keys.None);
|
||||
}else
|
||||
if(ka!=null)
|
||||
AddKeyToMacros((Keys)kc.ConvertFromString(ka.Value));
|
||||
}
|
||||
|
||||
Thread.CurrentThread.CurrentUICulture = cult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
GUI.NET/Debugger/FastColoredTextBox/MonoUtility.cs
Normal file
21
GUI.NET/Debugger/FastColoredTextBox/MonoUtility.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
internal class MonoUtility
|
||||
{
|
||||
// .Net 1.0 and 1.1 didn't have the PlatformID value for Unix, so Mono used the value 128.
|
||||
private const PlatformID MonoUnix = (PlatformID)128;
|
||||
|
||||
public static bool IsLinux
|
||||
{
|
||||
get
|
||||
{
|
||||
PlatformID p = Environment.OSVersion.Platform;
|
||||
return (p == PlatformID.Unix) || (p == PlatformID.MacOSX) || (p == MonoUnix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
GUI.NET/Debugger/FastColoredTextBox/NativeMethods.cs
Normal file
62
GUI.NET/Debugger/FastColoredTextBox/NativeMethods.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
internal class NativeMethods
|
||||
{
|
||||
//[DllImport("user32.dll")]
|
||||
//internal static extern IntPtr GetOpenClipboardWindow(); // unused ?
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
protected static extern bool CloseClipboard(); // corrected intptr -> bool
|
||||
|
||||
[DllImport("Imm32.dll")]
|
||||
protected static extern IntPtr ImmGetContext(IntPtr hWnd);
|
||||
|
||||
[DllImport("Imm32.dll")]
|
||||
protected static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
protected static extern bool CreateCaret(IntPtr hWnd, int hBitmap, int nWidth, int nHeight);
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
protected static extern bool SetCaretPos(int x, int y);
|
||||
|
||||
//[DllImport("User32.dll")]
|
||||
//internal static extern bool DestroyCaret(); // unused ?
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
protected static extern bool ShowCaret(IntPtr hWnd);
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
protected static extern bool HideCaret(IntPtr hWnd);
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
protected static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); // change corrent
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
protected static extern void GetNativeSystemInfo(ref SYSTEM_INFO lpSystemInfo);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
protected static extern void GetSystemInfo(ref SYSTEM_INFO lpSystemInfo);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct SYSTEM_INFO
|
||||
{
|
||||
public ushort wProcessorArchitecture;
|
||||
public ushort wReserved;
|
||||
public uint dwPageSize;
|
||||
public IntPtr lpMinimumApplicationAddress;
|
||||
public IntPtr lpMaximumApplicationAddress;
|
||||
public UIntPtr dwActiveProcessorMask;
|
||||
public uint dwNumberOfProcessors;
|
||||
public uint dwProcessorType;
|
||||
public uint dwAllocationGranularity;
|
||||
public ushort wProcessorLevel;
|
||||
public ushort wProcessorRevision;
|
||||
};
|
||||
}
|
||||
}
|
129
GUI.NET/Debugger/FastColoredTextBox/NativeMethodsWrapper.cs
Normal file
129
GUI.NET/Debugger/FastColoredTextBox/NativeMethodsWrapper.cs
Normal file
|
@ -0,0 +1,129 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
internal class NativeMethodsWrapper : NativeMethods
|
||||
{
|
||||
internal new static bool CloseClipboard()
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
return true; // TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
return NativeMethods.CloseClipboard();
|
||||
}
|
||||
}
|
||||
|
||||
internal new static IntPtr ImmGetContext(IntPtr hWnd)
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NativeMethods.ImmGetContext(hWnd);
|
||||
}
|
||||
}
|
||||
|
||||
internal new static IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC)
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NativeMethods.ImmAssociateContext(hWnd, hIMC);
|
||||
}
|
||||
}
|
||||
|
||||
internal new static bool CreateCaret(IntPtr hWnd, int hBitmap, int nWidth, int nHeight)
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
return true; // TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
return NativeMethods.CreateCaret(hWnd, hBitmap, nWidth, nHeight);
|
||||
}
|
||||
}
|
||||
|
||||
internal new static bool SetCaretPos(int x, int y)
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
return true; // TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
return NativeMethods.SetCaretPos(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
internal new static bool ShowCaret(IntPtr hWnd)
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
return true; // TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
return NativeMethods.ShowCaret(hWnd);
|
||||
}
|
||||
}
|
||||
|
||||
internal new static bool HideCaret(IntPtr hWnd)
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
return true; // TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
return NativeMethods.HideCaret(hWnd);
|
||||
}
|
||||
}
|
||||
|
||||
internal new static IntPtr SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam)
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
return IntPtr.Zero; // TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
return NativeMethods.SendMessage(hWnd, wMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
internal new static void GetNativeSystemInfo(ref SYSTEM_INFO lpSystemInfo)
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
throw new ApplicationException("This method is not supported in mono");
|
||||
}
|
||||
else
|
||||
{
|
||||
NativeMethods.GetNativeSystemInfo(ref lpSystemInfo);
|
||||
}
|
||||
}
|
||||
|
||||
internal new static void GetSystemInfo(ref SYSTEM_INFO lpSystemInfo)
|
||||
{
|
||||
if (MonoUtility.IsLinux)
|
||||
{
|
||||
throw new ApplicationException("This method is not supported in mono");
|
||||
}
|
||||
else
|
||||
{
|
||||
NativeMethods.GetSystemInfo(ref lpSystemInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
99
GUI.NET/Debugger/FastColoredTextBox/Place.cs
Normal file
99
GUI.NET/Debugger/FastColoredTextBox/Place.cs
Normal file
|
@ -0,0 +1,99 @@
|
|||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Line index and char index
|
||||
/// </summary>
|
||||
public struct Place : IEquatable<Place>
|
||||
{
|
||||
public int iChar;
|
||||
public int iLine;
|
||||
|
||||
public Place(int iChar, int iLine)
|
||||
{
|
||||
this.iChar = iChar;
|
||||
this.iLine = iLine;
|
||||
}
|
||||
|
||||
public void Offset(int dx, int dy)
|
||||
{
|
||||
iChar += dx;
|
||||
iLine += dy;
|
||||
}
|
||||
|
||||
public bool Equals(Place other)
|
||||
{
|
||||
return iChar == other.iChar && iLine == other.iLine;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is Place) && Equals((Place)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return iChar.GetHashCode() ^ iLine.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator !=(Place p1, Place p2)
|
||||
{
|
||||
return !p1.Equals(p2);
|
||||
}
|
||||
|
||||
public static bool operator ==(Place p1, Place p2)
|
||||
{
|
||||
return p1.Equals(p2);
|
||||
}
|
||||
|
||||
public static bool operator <(Place p1, Place p2)
|
||||
{
|
||||
if (p1.iLine < p2.iLine) return true;
|
||||
if (p1.iLine > p2.iLine) return false;
|
||||
if (p1.iChar < p2.iChar) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator <=(Place p1, Place p2)
|
||||
{
|
||||
if (p1.Equals(p2)) return true;
|
||||
if (p1.iLine < p2.iLine) return true;
|
||||
if (p1.iLine > p2.iLine) return false;
|
||||
if (p1.iChar < p2.iChar) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator >(Place p1, Place p2)
|
||||
{
|
||||
if (p1.iLine > p2.iLine) return true;
|
||||
if (p1.iLine < p2.iLine) return false;
|
||||
if (p1.iChar > p2.iChar) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator >=(Place p1, Place p2)
|
||||
{
|
||||
if (p1.Equals(p2)) return true;
|
||||
if (p1.iLine > p2.iLine) return true;
|
||||
if (p1.iLine < p2.iLine) return false;
|
||||
if (p1.iChar > p2.iChar) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Place operator +(Place p1, Place p2)
|
||||
{
|
||||
return new Place(p1.iChar + p2.iChar, p1.iLine + p2.iLine);
|
||||
}
|
||||
|
||||
public static Place Empty
|
||||
{
|
||||
get { return new Place(); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "(" + iChar + "," + iLine + ")";
|
||||
}
|
||||
}
|
||||
}
|
60
GUI.NET/Debugger/FastColoredTextBox/PlatformType.cs
Normal file
60
GUI.NET/Debugger/FastColoredTextBox/PlatformType.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public static class PlatformType
|
||||
{
|
||||
const ushort PROCESSOR_ARCHITECTURE_INTEL = 0;
|
||||
const ushort PROCESSOR_ARCHITECTURE_IA64 = 6;
|
||||
const ushort PROCESSOR_ARCHITECTURE_AMD64 = 9;
|
||||
const ushort PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF;
|
||||
|
||||
public static Platform GetOperationSystemPlatform()
|
||||
{
|
||||
if(MonoUtility.IsLinux)
|
||||
{
|
||||
return Platform.Unknown;
|
||||
}
|
||||
else
|
||||
{
|
||||
var sysInfo = new NativeMethods.SYSTEM_INFO();
|
||||
|
||||
// WinXP and older - use GetNativeSystemInfo
|
||||
if (Environment.OSVersion.Version.Major > 5 ||
|
||||
(Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1))
|
||||
{
|
||||
NativeMethodsWrapper.GetNativeSystemInfo(ref sysInfo);
|
||||
}
|
||||
// else use GetSystemInfo
|
||||
else
|
||||
{
|
||||
NativeMethodsWrapper.GetSystemInfo(ref sysInfo);
|
||||
}
|
||||
|
||||
switch (sysInfo.wProcessorArchitecture)
|
||||
{
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
return Platform.X64;
|
||||
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
return Platform.X86;
|
||||
|
||||
default:
|
||||
return Platform.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Platform
|
||||
{
|
||||
X86,
|
||||
X64,
|
||||
Unknown
|
||||
}
|
||||
|
||||
}
|
1678
GUI.NET/Debugger/FastColoredTextBox/Range.cs
Normal file
1678
GUI.NET/Debugger/FastColoredTextBox/Range.cs
Normal file
File diff suppressed because it is too large
Load diff
187
GUI.NET/Debugger/FastColoredTextBox/ReplaceForm.cs
Normal file
187
GUI.NET/Debugger/FastColoredTextBox/ReplaceForm.cs
Normal file
|
@ -0,0 +1,187 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class ReplaceForm : Form
|
||||
{
|
||||
FastColoredTextBox tb;
|
||||
bool firstSearch = true;
|
||||
Place startPlace;
|
||||
|
||||
public ReplaceForm(FastColoredTextBox tb)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.tb = tb;
|
||||
}
|
||||
|
||||
private void btClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void btFindNext_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Find(tbFind.Text))
|
||||
MessageBox.Show("Not found");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Range> FindAll(string pattern)
|
||||
{
|
||||
var opt = cbMatchCase.Checked ? RegexOptions.None : RegexOptions.IgnoreCase;
|
||||
if (!cbRegex.Checked)
|
||||
pattern = Regex.Escape(pattern);
|
||||
if (cbWholeWord.Checked)
|
||||
pattern = "\\b" + pattern + "\\b";
|
||||
//
|
||||
var range = tb.Selection.IsEmpty? tb.Range.Clone() : tb.Selection.Clone();
|
||||
//
|
||||
var list = new List<Range>();
|
||||
foreach (var r in range.GetRangesByLines(pattern, opt))
|
||||
list.Add(r);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public bool Find(string pattern)
|
||||
{
|
||||
RegexOptions opt = cbMatchCase.Checked ? RegexOptions.None : RegexOptions.IgnoreCase;
|
||||
if (!cbRegex.Checked)
|
||||
pattern = Regex.Escape(pattern);
|
||||
if (cbWholeWord.Checked)
|
||||
pattern = "\\b" + pattern + "\\b";
|
||||
//
|
||||
Range range = tb.Selection.Clone();
|
||||
range.Normalize();
|
||||
//
|
||||
if (firstSearch)
|
||||
{
|
||||
startPlace = range.Start;
|
||||
firstSearch = false;
|
||||
}
|
||||
//
|
||||
range.Start = range.End;
|
||||
if (range.Start >= startPlace)
|
||||
range.End = new Place(tb.GetLineLength(tb.LinesCount - 1), tb.LinesCount - 1);
|
||||
else
|
||||
range.End = startPlace;
|
||||
//
|
||||
foreach (var r in range.GetRangesByLines(pattern, opt))
|
||||
{
|
||||
tb.Selection.Start = r.Start;
|
||||
tb.Selection.End = r.End;
|
||||
tb.DoSelectionVisible();
|
||||
tb.Invalidate();
|
||||
return true;
|
||||
}
|
||||
if (range.Start >= startPlace && startPlace > Place.Empty)
|
||||
{
|
||||
tb.Selection.Start = new Place(0, 0);
|
||||
return Find(pattern);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void tbFind_KeyPress(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == '\r')
|
||||
btFindNext_Click(sender, null);
|
||||
if (e.KeyChar == '\x1b')
|
||||
Hide();
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) // David
|
||||
{
|
||||
if (keyData == Keys.Escape)
|
||||
{
|
||||
this.Close();
|
||||
return true;
|
||||
}
|
||||
return base.ProcessCmdKey(ref msg, keyData);
|
||||
}
|
||||
|
||||
private void ReplaceForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (e.CloseReason == CloseReason.UserClosing)
|
||||
{
|
||||
e.Cancel = true;
|
||||
Hide();
|
||||
}
|
||||
this.tb.Focus();
|
||||
}
|
||||
|
||||
private void btReplace_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tb.SelectionLength != 0)
|
||||
if (!tb.Selection.ReadOnly)
|
||||
tb.InsertText(tbReplace.Text);
|
||||
btFindNext_Click(sender, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void btReplaceAll_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
tb.Selection.BeginUpdate();
|
||||
|
||||
//search
|
||||
var ranges = FindAll(tbFind.Text);
|
||||
//check readonly
|
||||
var ro = false;
|
||||
foreach (var r in ranges)
|
||||
if (r.ReadOnly)
|
||||
{
|
||||
ro = true;
|
||||
break;
|
||||
}
|
||||
//replace
|
||||
if (!ro)
|
||||
if (ranges.Count > 0)
|
||||
{
|
||||
tb.TextSource.Manager.ExecuteCommand(new ReplaceTextCommand(tb.TextSource, ranges, tbReplace.Text));
|
||||
tb.Selection.Start = new Place(0, 0);
|
||||
}
|
||||
//
|
||||
tb.Invalidate();
|
||||
MessageBox.Show(ranges.Count + " occurrence(s) replaced");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
tb.Selection.EndUpdate();
|
||||
}
|
||||
|
||||
protected override void OnActivated(EventArgs e)
|
||||
{
|
||||
tbFind.Focus();
|
||||
ResetSerach();
|
||||
}
|
||||
|
||||
void ResetSerach()
|
||||
{
|
||||
firstSearch = true;
|
||||
}
|
||||
|
||||
private void cbMatchCase_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
ResetSerach();
|
||||
}
|
||||
}
|
||||
}
|
196
GUI.NET/Debugger/FastColoredTextBox/ReplaceForm.designer.cs
generated
Normal file
196
GUI.NET/Debugger/FastColoredTextBox/ReplaceForm.designer.cs
generated
Normal file
|
@ -0,0 +1,196 @@
|
|||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class ReplaceForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btClose = new System.Windows.Forms.Button();
|
||||
this.btFindNext = new System.Windows.Forms.Button();
|
||||
this.tbFind = new System.Windows.Forms.TextBox();
|
||||
this.cbRegex = new System.Windows.Forms.CheckBox();
|
||||
this.cbMatchCase = new System.Windows.Forms.CheckBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.cbWholeWord = new System.Windows.Forms.CheckBox();
|
||||
this.btReplace = new System.Windows.Forms.Button();
|
||||
this.btReplaceAll = new System.Windows.Forms.Button();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.tbReplace = new System.Windows.Forms.TextBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btClose
|
||||
//
|
||||
this.btClose.Location = new System.Drawing.Point(273, 153);
|
||||
this.btClose.Name = "btClose";
|
||||
this.btClose.Size = new System.Drawing.Size(75, 23);
|
||||
this.btClose.TabIndex = 8;
|
||||
this.btClose.Text = "Close";
|
||||
this.btClose.UseVisualStyleBackColor = true;
|
||||
this.btClose.Click += new System.EventHandler(this.btClose_Click);
|
||||
//
|
||||
// btFindNext
|
||||
//
|
||||
this.btFindNext.Location = new System.Drawing.Point(111, 124);
|
||||
this.btFindNext.Name = "btFindNext";
|
||||
this.btFindNext.Size = new System.Drawing.Size(75, 23);
|
||||
this.btFindNext.TabIndex = 5;
|
||||
this.btFindNext.Text = "Find next";
|
||||
this.btFindNext.UseVisualStyleBackColor = true;
|
||||
this.btFindNext.Click += new System.EventHandler(this.btFindNext_Click);
|
||||
//
|
||||
// tbFind
|
||||
//
|
||||
this.tbFind.Location = new System.Drawing.Point(62, 12);
|
||||
this.tbFind.Name = "tbFind";
|
||||
this.tbFind.Size = new System.Drawing.Size(286, 20);
|
||||
this.tbFind.TabIndex = 0;
|
||||
this.tbFind.TextChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
this.tbFind.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbFind_KeyPress);
|
||||
//
|
||||
// cbRegex
|
||||
//
|
||||
this.cbRegex.AutoSize = true;
|
||||
this.cbRegex.Location = new System.Drawing.Point(273, 38);
|
||||
this.cbRegex.Name = "cbRegex";
|
||||
this.cbRegex.Size = new System.Drawing.Size(57, 17);
|
||||
this.cbRegex.TabIndex = 3;
|
||||
this.cbRegex.Text = "Regex";
|
||||
this.cbRegex.UseVisualStyleBackColor = true;
|
||||
this.cbRegex.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// cbMatchCase
|
||||
//
|
||||
this.cbMatchCase.AutoSize = true;
|
||||
this.cbMatchCase.Location = new System.Drawing.Point(66, 38);
|
||||
this.cbMatchCase.Name = "cbMatchCase";
|
||||
this.cbMatchCase.Size = new System.Drawing.Size(82, 17);
|
||||
this.cbMatchCase.TabIndex = 1;
|
||||
this.cbMatchCase.Text = "Match case";
|
||||
this.cbMatchCase.UseVisualStyleBackColor = true;
|
||||
this.cbMatchCase.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(23, 14);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(33, 13);
|
||||
this.label1.TabIndex = 5;
|
||||
this.label1.Text = "Find: ";
|
||||
//
|
||||
// cbWholeWord
|
||||
//
|
||||
this.cbWholeWord.AutoSize = true;
|
||||
this.cbWholeWord.Location = new System.Drawing.Point(154, 38);
|
||||
this.cbWholeWord.Name = "cbWholeWord";
|
||||
this.cbWholeWord.Size = new System.Drawing.Size(113, 17);
|
||||
this.cbWholeWord.TabIndex = 2;
|
||||
this.cbWholeWord.Text = "Match whole word";
|
||||
this.cbWholeWord.UseVisualStyleBackColor = true;
|
||||
this.cbWholeWord.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
//
|
||||
// btReplace
|
||||
//
|
||||
this.btReplace.Location = new System.Drawing.Point(192, 124);
|
||||
this.btReplace.Name = "btReplace";
|
||||
this.btReplace.Size = new System.Drawing.Size(75, 23);
|
||||
this.btReplace.TabIndex = 6;
|
||||
this.btReplace.Text = "Replace";
|
||||
this.btReplace.UseVisualStyleBackColor = true;
|
||||
this.btReplace.Click += new System.EventHandler(this.btReplace_Click);
|
||||
//
|
||||
// btReplaceAll
|
||||
//
|
||||
this.btReplaceAll.Location = new System.Drawing.Point(273, 124);
|
||||
this.btReplaceAll.Name = "btReplaceAll";
|
||||
this.btReplaceAll.Size = new System.Drawing.Size(75, 23);
|
||||
this.btReplaceAll.TabIndex = 7;
|
||||
this.btReplaceAll.Text = "Replace all";
|
||||
this.btReplaceAll.UseVisualStyleBackColor = true;
|
||||
this.btReplaceAll.Click += new System.EventHandler(this.btReplaceAll_Click);
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(6, 81);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(50, 13);
|
||||
this.label2.TabIndex = 9;
|
||||
this.label2.Text = "Replace:";
|
||||
//
|
||||
// tbReplace
|
||||
//
|
||||
this.tbReplace.Location = new System.Drawing.Point(62, 78);
|
||||
this.tbReplace.Name = "tbReplace";
|
||||
this.tbReplace.Size = new System.Drawing.Size(286, 20);
|
||||
this.tbReplace.TabIndex = 0;
|
||||
this.tbReplace.TextChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);
|
||||
this.tbReplace.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbFind_KeyPress);
|
||||
//
|
||||
// ReplaceForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(360, 191);
|
||||
this.Controls.Add(this.tbFind);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.tbReplace);
|
||||
this.Controls.Add(this.btReplaceAll);
|
||||
this.Controls.Add(this.btReplace);
|
||||
this.Controls.Add(this.cbWholeWord);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.cbMatchCase);
|
||||
this.Controls.Add(this.cbRegex);
|
||||
this.Controls.Add(this.btFindNext);
|
||||
this.Controls.Add(this.btClose);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.Name = "ReplaceForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Find and replace";
|
||||
this.TopMost = true;
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ReplaceForm_FormClosing);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btClose;
|
||||
private System.Windows.Forms.Button btFindNext;
|
||||
private System.Windows.Forms.CheckBox cbRegex;
|
||||
private System.Windows.Forms.CheckBox cbMatchCase;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.CheckBox cbWholeWord;
|
||||
private System.Windows.Forms.Button btReplace;
|
||||
private System.Windows.Forms.Button btReplaceAll;
|
||||
private System.Windows.Forms.Label label2;
|
||||
public System.Windows.Forms.TextBox tbFind;
|
||||
public System.Windows.Forms.TextBox tbReplace;
|
||||
}
|
||||
}
|
120
GUI.NET/Debugger/FastColoredTextBox/ReplaceForm.resx
Normal file
120
GUI.NET/Debugger/FastColoredTextBox/ReplaceForm.resx
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
138
GUI.NET/Debugger/FastColoredTextBox/Ruler.cs
Normal file
138
GUI.NET/Debugger/FastColoredTextBox/Ruler.cs
Normal file
|
@ -0,0 +1,138 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public partial class Ruler : UserControl
|
||||
{
|
||||
public EventHandler TargetChanged;
|
||||
|
||||
[DefaultValue(typeof(Color), "ControlLight")]
|
||||
public Color BackColor2 { get; set; }
|
||||
|
||||
[DefaultValue(typeof(Color), "DarkGray")]
|
||||
public Color TickColor { get; set; }
|
||||
|
||||
[DefaultValue(typeof(Color), "Black")]
|
||||
public Color CaretTickColor { get; set; }
|
||||
|
||||
FastColoredTextBox target;
|
||||
|
||||
[Description("Target FastColoredTextBox")]
|
||||
public FastColoredTextBox Target
|
||||
{
|
||||
get { return target; }
|
||||
set
|
||||
{
|
||||
if (target != null)
|
||||
UnSubscribe(target);
|
||||
target = value;
|
||||
Subscribe(target);
|
||||
OnTargetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public Ruler()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
|
||||
MinimumSize = new Size(0, 24);
|
||||
MaximumSize = new Size(int.MaxValue/2, 24);
|
||||
|
||||
BackColor2 = SystemColors.ControlLight;
|
||||
TickColor = Color.DarkGray;
|
||||
CaretTickColor = Color.Black;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void OnTargetChanged()
|
||||
{
|
||||
if (TargetChanged != null)
|
||||
TargetChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void UnSubscribe(FastColoredTextBox target)
|
||||
{
|
||||
target.Scroll -= new ScrollEventHandler(target_Scroll);
|
||||
target.SelectionChanged -= new EventHandler(target_SelectionChanged);
|
||||
target.VisibleRangeChanged -= new EventHandler(target_VisibleRangeChanged);
|
||||
}
|
||||
|
||||
protected virtual void Subscribe(FastColoredTextBox target)
|
||||
{
|
||||
target.Scroll += new ScrollEventHandler(target_Scroll);
|
||||
target.SelectionChanged += new EventHandler(target_SelectionChanged);
|
||||
target.VisibleRangeChanged += new EventHandler(target_VisibleRangeChanged);
|
||||
}
|
||||
|
||||
void target_VisibleRangeChanged(object sender, EventArgs e)
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void target_SelectionChanged(object sender, EventArgs e)
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected virtual void target_Scroll(object sender, ScrollEventArgs e)
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
Point car = PointToClient(target.PointToScreen(target.PlaceToPoint(target.Selection.Start)));
|
||||
|
||||
Size fontSize = TextRenderer.MeasureText("W", Font);
|
||||
|
||||
int column = 0;
|
||||
e.Graphics.FillRectangle(new LinearGradientBrush(new Rectangle(0, 0, Width, Height), BackColor, BackColor2, 270), new Rectangle(0, 0, Width, Height));
|
||||
|
||||
float columnWidth = target.CharWidth;
|
||||
var sf = new StringFormat();
|
||||
sf.Alignment = StringAlignment.Center;
|
||||
sf.LineAlignment = StringAlignment.Near;
|
||||
|
||||
var zeroPoint = target.PositionToPoint(0);
|
||||
zeroPoint = PointToClient(target.PointToScreen(zeroPoint));
|
||||
|
||||
using (var pen = new Pen(TickColor))
|
||||
using (var textBrush = new SolidBrush(ForeColor))
|
||||
for (float x = zeroPoint.X; x < Right; x += columnWidth, ++column)
|
||||
{
|
||||
if (column % 10 == 0)
|
||||
e.Graphics.DrawString(column.ToString(), Font, textBrush, x, 0f, sf);
|
||||
|
||||
e.Graphics.DrawLine(pen, (int)x, fontSize.Height + (column % 5 == 0 ? 1 : 3), (int)x, Height - 4);
|
||||
}
|
||||
|
||||
using (var pen = new Pen(TickColor))
|
||||
e.Graphics.DrawLine(pen, new Point(car.X - 3, Height - 3), new Point(car.X + 3, Height - 3));
|
||||
|
||||
using (var pen = new Pen(CaretTickColor))
|
||||
{
|
||||
e.Graphics.DrawLine(pen, new Point(car.X - 2, fontSize.Height + 3), new Point(car.X - 2, Height - 4));
|
||||
e.Graphics.DrawLine(pen, new Point(car.X, fontSize.Height + 1), new Point(car.X, Height - 4));
|
||||
e.Graphics.DrawLine(pen, new Point(car.X + 2, fontSize.Height + 3), new Point(car.X + 2, Height - 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
GUI.NET/Debugger/FastColoredTextBox/Ruler.designer.cs
generated
Normal file
37
GUI.NET/Debugger/FastColoredTextBox/Ruler.designer.cs
generated
Normal file
|
@ -0,0 +1,37 @@
|
|||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
partial class Ruler
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
430
GUI.NET/Debugger/FastColoredTextBox/Style.cs
Normal file
430
GUI.NET/Debugger/FastColoredTextBox/Style.cs
Normal file
|
@ -0,0 +1,430 @@
|
|||
using System.Drawing;
|
||||
using System;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// Style of chars
|
||||
/// </summary>
|
||||
/// <remarks>This is base class for all text and design renderers</remarks>
|
||||
public abstract class Style : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// This style is exported to outer formats (HTML for example)
|
||||
/// </summary>
|
||||
public virtual bool IsExportable { get; set; }
|
||||
/// <summary>
|
||||
/// Occurs when user click on StyleVisualMarker joined to this style
|
||||
/// </summary>
|
||||
public event EventHandler<VisualMarkerEventArgs> VisualMarkerClick;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public Style()
|
||||
{
|
||||
IsExportable = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders given range of text
|
||||
/// </summary>
|
||||
/// <param name="gr">Graphics object</param>
|
||||
/// <param name="position">Position of the range in absolute control coordinates</param>
|
||||
/// <param name="range">Rendering range of text</param>
|
||||
public abstract void Draw(Graphics gr, Point position, Range range);
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when user click on StyleVisualMarker joined to this style
|
||||
/// </summary>
|
||||
public virtual void OnVisualMarkerClick(FastColoredTextBox tb, VisualMarkerEventArgs args)
|
||||
{
|
||||
if (VisualMarkerClick != null)
|
||||
VisualMarkerClick(tb, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows VisualMarker
|
||||
/// Call this method in Draw method, when you need to show VisualMarker for your style
|
||||
/// </summary>
|
||||
protected virtual void AddVisualMarker(FastColoredTextBox tb, StyleVisualMarker marker)
|
||||
{
|
||||
tb.AddVisualMarker(marker);
|
||||
}
|
||||
|
||||
public static Size GetSizeOfRange(Range range)
|
||||
{
|
||||
return new Size((range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);
|
||||
}
|
||||
|
||||
public static GraphicsPath GetRoundedRectangle(Rectangle rect, int d)
|
||||
{
|
||||
GraphicsPath gp = new GraphicsPath();
|
||||
|
||||
gp.AddArc(rect.X, rect.Y, d, d, 180, 90);
|
||||
gp.AddArc(rect.X + rect.Width - d, rect.Y, d, d, 270, 90);
|
||||
gp.AddArc(rect.X + rect.Width - d, rect.Y + rect.Height - d, d, d, 0, 90);
|
||||
gp.AddArc(rect.X, rect.Y + rect.Height - d, d, d, 90, 90);
|
||||
gp.AddLine(rect.X, rect.Y + rect.Height - d, rect.X, rect.Y + d / 2);
|
||||
|
||||
return gp;
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns CSS for export to HTML
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual string GetCSS()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns RTF descriptor for export to RTF
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual RTFStyleDescriptor GetRTF()
|
||||
{
|
||||
return new RTFStyleDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Style for chars rendering
|
||||
/// This renderer can draws chars, with defined fore and back colors
|
||||
/// </summary>
|
||||
public class TextStyle : Style
|
||||
{
|
||||
public Brush ForeBrush { get; set; }
|
||||
public Brush BackgroundBrush { get; set; }
|
||||
public FontStyle FontStyle { get; set; }
|
||||
//public readonly Font Font;
|
||||
public StringFormat stringFormat;
|
||||
|
||||
public TextStyle(Brush foreBrush, Brush backgroundBrush, FontStyle fontStyle)
|
||||
{
|
||||
this.ForeBrush = foreBrush;
|
||||
this.BackgroundBrush = backgroundBrush;
|
||||
this.FontStyle = fontStyle;
|
||||
stringFormat = new StringFormat(StringFormatFlags.MeasureTrailingSpaces);
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//draw background
|
||||
if (BackgroundBrush != null)
|
||||
gr.FillRectangle(BackgroundBrush, position.X, position.Y, (range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);
|
||||
//draw chars
|
||||
using(var f = new Font(range.tb.Font, FontStyle))
|
||||
{
|
||||
Line line = range.tb[range.Start.iLine];
|
||||
float dx = range.tb.CharWidth;
|
||||
float y = position.Y + range.tb.LineInterval/2;
|
||||
float x = position.X - range.tb.CharWidth/3;
|
||||
|
||||
if (ForeBrush == null)
|
||||
ForeBrush = new SolidBrush(range.tb.ForeColor);
|
||||
|
||||
if (range.tb.ImeAllowed)
|
||||
{
|
||||
//IME mode
|
||||
for (int i = range.Start.iChar; i < range.End.iChar; i++)
|
||||
{
|
||||
SizeF size = FastColoredTextBox.GetCharSize(f, line[i].c);
|
||||
|
||||
var gs = gr.Save();
|
||||
float k = size.Width > range.tb.CharWidth + 1 ? range.tb.CharWidth/size.Width : 1;
|
||||
gr.TranslateTransform(x, y + (1 - k)*range.tb.CharHeight/2);
|
||||
gr.ScaleTransform(k, (float) Math.Sqrt(k));
|
||||
gr.DrawString(line[i].c.ToString(), f, ForeBrush, 0, 0, stringFormat);
|
||||
gr.Restore(gs);
|
||||
x += dx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//classic mode
|
||||
for (int i = range.Start.iChar; i < range.End.iChar; i++)
|
||||
{
|
||||
//draw char
|
||||
gr.DrawString(line[i].c.ToString(), f, ForeBrush, x, y, stringFormat);
|
||||
x += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetCSS()
|
||||
{
|
||||
string result = "";
|
||||
|
||||
if (BackgroundBrush is SolidBrush)
|
||||
{
|
||||
var s = ExportToHTML.GetColorAsString((BackgroundBrush as SolidBrush).Color);
|
||||
if (s != "")
|
||||
result += "background-color:" + s + ";";
|
||||
}
|
||||
if (ForeBrush is SolidBrush)
|
||||
{
|
||||
var s = ExportToHTML.GetColorAsString((ForeBrush as SolidBrush).Color);
|
||||
if (s != "")
|
||||
result += "color:" + s + ";";
|
||||
}
|
||||
if ((FontStyle & FontStyle.Bold) != 0)
|
||||
result += "font-weight:bold;";
|
||||
if ((FontStyle & FontStyle.Italic) != 0)
|
||||
result += "font-style:oblique;";
|
||||
if ((FontStyle & FontStyle.Strikeout) != 0)
|
||||
result += "text-decoration:line-through;";
|
||||
if ((FontStyle & FontStyle.Underline) != 0)
|
||||
result += "text-decoration:underline;";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override RTFStyleDescriptor GetRTF()
|
||||
{
|
||||
var result = new RTFStyleDescriptor();
|
||||
|
||||
if (BackgroundBrush is SolidBrush)
|
||||
result.BackColor = (BackgroundBrush as SolidBrush).Color;
|
||||
|
||||
if (ForeBrush is SolidBrush)
|
||||
result.ForeColor = (ForeBrush as SolidBrush).Color;
|
||||
|
||||
if ((FontStyle & FontStyle.Bold) != 0)
|
||||
result.AdditionalTags += @"\b";
|
||||
if ((FontStyle & FontStyle.Italic) != 0)
|
||||
result.AdditionalTags += @"\i";
|
||||
if ((FontStyle & FontStyle.Strikeout) != 0)
|
||||
result.AdditionalTags += @"\strike";
|
||||
if ((FontStyle & FontStyle.Underline) != 0)
|
||||
result.AdditionalTags += @"\ul";
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renderer for folded block
|
||||
/// </summary>
|
||||
public class FoldedBlockStyle : TextStyle
|
||||
{
|
||||
public FoldedBlockStyle(Brush foreBrush, Brush backgroundBrush, FontStyle fontStyle):
|
||||
base(foreBrush, backgroundBrush, fontStyle)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
if (range.End.iChar > range.Start.iChar)
|
||||
{
|
||||
base.Draw(gr, position, range);
|
||||
|
||||
int firstNonSpaceSymbolX = position.X;
|
||||
|
||||
//find first non space symbol
|
||||
for (int i = range.Start.iChar; i < range.End.iChar; i++)
|
||||
if (range.tb[range.Start.iLine][i].c != ' ')
|
||||
break;
|
||||
else
|
||||
firstNonSpaceSymbolX += range.tb.CharWidth;
|
||||
|
||||
//create marker
|
||||
range.tb.AddVisualMarker(new FoldedAreaMarker(range.Start.iLine, new Rectangle(firstNonSpaceSymbolX, position.Y, position.X + (range.End.iChar - range.Start.iChar) * range.tb.CharWidth - firstNonSpaceSymbolX, range.tb.CharHeight)));
|
||||
}
|
||||
else
|
||||
{
|
||||
//draw '...'
|
||||
using(Font f = new Font(range.tb.Font, FontStyle))
|
||||
gr.DrawString("...", f, ForeBrush, range.tb.LeftIndent, position.Y - 2);
|
||||
//create marker
|
||||
range.tb.AddVisualMarker(new FoldedAreaMarker(range.Start.iLine, new Rectangle(range.tb.LeftIndent + 2, position.Y, 2 * range.tb.CharHeight, range.tb.CharHeight)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renderer for selected area
|
||||
/// </summary>
|
||||
public class SelectionStyle : Style
|
||||
{
|
||||
public Brush BackgroundBrush{ get; set;}
|
||||
public Brush ForegroundBrush { get; private set; }
|
||||
|
||||
public override bool IsExportable
|
||||
{
|
||||
get{return false;} set{}
|
||||
}
|
||||
|
||||
public SelectionStyle(Brush backgroundBrush, Brush foregroundBrush = null)
|
||||
{
|
||||
this.BackgroundBrush = backgroundBrush;
|
||||
this.ForegroundBrush = foregroundBrush;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//draw background
|
||||
if (BackgroundBrush != null)
|
||||
{
|
||||
gr.SmoothingMode = SmoothingMode.None;
|
||||
var rect = new Rectangle(position.X, position.Y, (range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);
|
||||
if (rect.Width == 0)
|
||||
return;
|
||||
gr.FillRectangle(BackgroundBrush, rect);
|
||||
//
|
||||
if (ForegroundBrush != null)
|
||||
{
|
||||
//draw text
|
||||
gr.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
var r = new Range(range.tb, range.Start.iChar, range.Start.iLine,
|
||||
Math.Min(range.tb[range.End.iLine].Count, range.End.iChar), range.End.iLine);
|
||||
using (var style = new TextStyle(ForegroundBrush, null, FontStyle.Regular))
|
||||
style.Draw(gr, new Point(position.X, position.Y - 1), r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marker style
|
||||
/// Draws background color for text
|
||||
/// </summary>
|
||||
public class MarkerStyle : Style
|
||||
{
|
||||
public Brush BackgroundBrush{get;set;}
|
||||
|
||||
public MarkerStyle(Brush backgroundBrush)
|
||||
{
|
||||
this.BackgroundBrush = backgroundBrush;
|
||||
IsExportable = true;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//draw background
|
||||
if (BackgroundBrush != null)
|
||||
{
|
||||
Rectangle rect = new Rectangle(position.X, position.Y, (range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);
|
||||
if (rect.Width == 0)
|
||||
return;
|
||||
gr.FillRectangle(BackgroundBrush, rect);
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetCSS()
|
||||
{
|
||||
string result = "";
|
||||
|
||||
if (BackgroundBrush is SolidBrush)
|
||||
{
|
||||
var s = ExportToHTML.GetColorAsString((BackgroundBrush as SolidBrush).Color);
|
||||
if (s != "")
|
||||
result += "background-color:" + s + ";";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws small rectangle for popup menu
|
||||
/// </summary>
|
||||
public class ShortcutStyle : Style
|
||||
{
|
||||
public Pen borderPen;
|
||||
|
||||
public ShortcutStyle(Pen borderPen)
|
||||
{
|
||||
this.borderPen = borderPen;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//get last char coordinates
|
||||
Point p = range.tb.PlaceToPoint(range.End);
|
||||
//draw small square under char
|
||||
Rectangle rect = new Rectangle(p.X - 5, p.Y + range.tb.CharHeight - 2, 4, 3);
|
||||
gr.FillPath(Brushes.White, GetRoundedRectangle(rect, 1));
|
||||
gr.DrawPath(borderPen, GetRoundedRectangle(rect, 1));
|
||||
//add visual marker for handle mouse events
|
||||
AddVisualMarker(range.tb, new StyleVisualMarker(new Rectangle(p.X-range.tb.CharWidth, p.Y, range.tb.CharWidth, range.tb.CharHeight), this));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This style draws a wavy line below a given text range.
|
||||
/// </summary>
|
||||
/// <remarks>Thanks for Yallie</remarks>
|
||||
public class WavyLineStyle : Style
|
||||
{
|
||||
private Pen Pen { get; set; }
|
||||
|
||||
public WavyLineStyle(int alpha, Color color)
|
||||
{
|
||||
Pen = new Pen(Color.FromArgb(alpha, color));
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point pos, Range range)
|
||||
{
|
||||
var size = GetSizeOfRange(range);
|
||||
var start = new Point(pos.X, pos.Y + size.Height - 1);
|
||||
var end = new Point(pos.X + size.Width, pos.Y + size.Height - 1);
|
||||
DrawWavyLine(gr, start, end);
|
||||
}
|
||||
|
||||
private void DrawWavyLine(Graphics graphics, Point start, Point end)
|
||||
{
|
||||
if (end.X - start.X < 2)
|
||||
{
|
||||
graphics.DrawLine(Pen, start, end);
|
||||
return;
|
||||
}
|
||||
|
||||
var offset = -1;
|
||||
var points = new List<Point>();
|
||||
|
||||
for (int i = start.X; i <= end.X; i += 2)
|
||||
{
|
||||
points.Add(new Point(i, start.Y + offset));
|
||||
offset = -offset;
|
||||
}
|
||||
|
||||
graphics.DrawLines(Pen, points.ToArray());
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
if (Pen != null)
|
||||
Pen.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This style is used to mark range of text as ReadOnly block
|
||||
/// </summary>
|
||||
/// <remarks>You can inherite this style to add visual effects of readonly text</remarks>
|
||||
public class ReadOnlyStyle : Style
|
||||
{
|
||||
public ReadOnlyStyle()
|
||||
{
|
||||
IsExportable = false;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Point position, Range range)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
51
GUI.NET/Debugger/FastColoredTextBox/SyntaxDescriptor.cs
Normal file
51
GUI.NET/Debugger/FastColoredTextBox/SyntaxDescriptor.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public class SyntaxDescriptor: IDisposable
|
||||
{
|
||||
public char leftBracket = '(';
|
||||
public char rightBracket = ')';
|
||||
public char leftBracket2 = '{';
|
||||
public char rightBracket2 = '}';
|
||||
public BracketsHighlightStrategy bracketsHighlightStrategy = BracketsHighlightStrategy.Strategy2;
|
||||
public readonly List<Style> styles = new List<Style>();
|
||||
public readonly List<RuleDesc> rules = new List<RuleDesc>();
|
||||
public readonly List<FoldingDesc> foldings = new List<FoldingDesc>();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var style in styles)
|
||||
style.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public class RuleDesc
|
||||
{
|
||||
Regex regex;
|
||||
public string pattern;
|
||||
public RegexOptions options = RegexOptions.None;
|
||||
public Style style;
|
||||
|
||||
public Regex Regex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (regex == null)
|
||||
{
|
||||
regex = new Regex(pattern, SyntaxHighlighter.RegexCompiledOption | options);
|
||||
}
|
||||
return regex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FoldingDesc
|
||||
{
|
||||
public string startMarkerRegex;
|
||||
public string finishMarkerRegex;
|
||||
public RegexOptions options = RegexOptions.None;
|
||||
}
|
||||
}
|
1383
GUI.NET/Debugger/FastColoredTextBox/SyntaxHighlighter.cs
Normal file
1383
GUI.NET/Debugger/FastColoredTextBox/SyntaxHighlighter.cs
Normal file
File diff suppressed because it is too large
Load diff
338
GUI.NET/Debugger/FastColoredTextBox/TextSource.cs
Normal file
338
GUI.NET/Debugger/FastColoredTextBox/TextSource.cs
Normal file
|
@ -0,0 +1,338 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
/// <summary>
|
||||
/// This class contains the source text (chars and styles).
|
||||
/// It stores a text lines, the manager of commands, undo/redo stack, styles.
|
||||
/// </summary>
|
||||
public class TextSource: IList<Line>, IDisposable
|
||||
{
|
||||
readonly protected List<Line> lines = new List<Line>();
|
||||
protected LinesAccessor linesAccessor;
|
||||
int lastLineUniqueId;
|
||||
public CommandManager Manager { get; set; }
|
||||
FastColoredTextBox currentTB;
|
||||
/// <summary>
|
||||
/// Styles
|
||||
/// </summary>
|
||||
public readonly Style[] Styles;
|
||||
/// <summary>
|
||||
/// Occurs when line was inserted/added
|
||||
/// </summary>
|
||||
public event EventHandler<LineInsertedEventArgs> LineInserted;
|
||||
/// <summary>
|
||||
/// Occurs when line was removed
|
||||
/// </summary>
|
||||
public event EventHandler<LineRemovedEventArgs> LineRemoved;
|
||||
/// <summary>
|
||||
/// Occurs when text was changed
|
||||
/// </summary>
|
||||
public event EventHandler<TextChangedEventArgs> TextChanged;
|
||||
/// <summary>
|
||||
/// Occurs when recalc is needed
|
||||
/// </summary>
|
||||
public event EventHandler<TextChangedEventArgs> RecalcNeeded;
|
||||
/// <summary>
|
||||
/// Occurs when recalc wordwrap is needed
|
||||
/// </summary>
|
||||
public event EventHandler<TextChangedEventArgs> RecalcWordWrap;
|
||||
/// <summary>
|
||||
/// Occurs before text changing
|
||||
/// </summary>
|
||||
public event EventHandler<TextChangingEventArgs> TextChanging;
|
||||
/// <summary>
|
||||
/// Occurs after CurrentTB was changed
|
||||
/// </summary>
|
||||
public event EventHandler CurrentTBChanged;
|
||||
/// <summary>
|
||||
/// Current focused FastColoredTextBox
|
||||
/// </summary>
|
||||
public FastColoredTextBox CurrentTB {
|
||||
get { return currentTB; }
|
||||
set {
|
||||
if (currentTB == value)
|
||||
return;
|
||||
currentTB = value;
|
||||
OnCurrentTBChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ClearIsChanged()
|
||||
{
|
||||
foreach(var line in lines)
|
||||
line.IsChanged = false;
|
||||
}
|
||||
|
||||
public virtual Line CreateLine()
|
||||
{
|
||||
return new Line(GenerateUniqueLineId());
|
||||
}
|
||||
|
||||
private void OnCurrentTBChanged()
|
||||
{
|
||||
if (CurrentTBChanged != null)
|
||||
CurrentTBChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default text style
|
||||
/// This style is using when no one other TextStyle is not defined in Char.style
|
||||
/// </summary>
|
||||
public TextStyle DefaultStyle { get; set; }
|
||||
|
||||
public TextSource(FastColoredTextBox currentTB)
|
||||
{
|
||||
this.CurrentTB = currentTB;
|
||||
linesAccessor = new LinesAccessor(this);
|
||||
Manager = new CommandManager(this);
|
||||
|
||||
if (Enum.GetUnderlyingType(typeof(StyleIndex)) == typeof(UInt32))
|
||||
Styles = new Style[32];
|
||||
else
|
||||
Styles = new Style[16];
|
||||
|
||||
InitDefaultStyle();
|
||||
}
|
||||
|
||||
public virtual void InitDefaultStyle()
|
||||
{
|
||||
DefaultStyle = new TextStyle(null, null, FontStyle.Regular);
|
||||
}
|
||||
|
||||
public virtual Line this[int i]
|
||||
{
|
||||
get{
|
||||
return lines[i];
|
||||
}
|
||||
set {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool IsLineLoaded(int iLine)
|
||||
{
|
||||
return lines[iLine] != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text lines
|
||||
/// </summary>
|
||||
public virtual IList<string> GetLines()
|
||||
{
|
||||
return linesAccessor;
|
||||
}
|
||||
|
||||
public IEnumerator<Line> GetEnumerator()
|
||||
{
|
||||
return lines.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return (lines as IEnumerator);
|
||||
}
|
||||
|
||||
public virtual int BinarySearch(Line item, IComparer<Line> comparer)
|
||||
{
|
||||
return lines.BinarySearch(item, comparer);
|
||||
}
|
||||
|
||||
public virtual int GenerateUniqueLineId()
|
||||
{
|
||||
return lastLineUniqueId++;
|
||||
}
|
||||
|
||||
public virtual void InsertLine(int index, Line line)
|
||||
{
|
||||
lines.Insert(index, line);
|
||||
OnLineInserted(index);
|
||||
}
|
||||
|
||||
public virtual void OnLineInserted(int index)
|
||||
{
|
||||
OnLineInserted(index, 1);
|
||||
}
|
||||
|
||||
public virtual void OnLineInserted(int index, int count)
|
||||
{
|
||||
if (LineInserted != null)
|
||||
LineInserted(this, new LineInsertedEventArgs(index, count));
|
||||
}
|
||||
|
||||
public virtual void RemoveLine(int index)
|
||||
{
|
||||
RemoveLine(index, 1);
|
||||
}
|
||||
|
||||
public virtual bool IsNeedBuildRemovedLineIds
|
||||
{
|
||||
get { return LineRemoved != null; }
|
||||
}
|
||||
|
||||
public virtual void RemoveLine(int index, int count)
|
||||
{
|
||||
List<int> removedLineIds = new List<int>();
|
||||
//
|
||||
if (count > 0)
|
||||
if (IsNeedBuildRemovedLineIds)
|
||||
for (int i = 0; i < count; i++)
|
||||
removedLineIds.Add(this[index + i].UniqueId);
|
||||
//
|
||||
lines.RemoveRange(index, count);
|
||||
|
||||
OnLineRemoved(index, count, removedLineIds);
|
||||
}
|
||||
|
||||
public virtual void OnLineRemoved(int index, int count, List<int> removedLineIds)
|
||||
{
|
||||
if (count > 0)
|
||||
if (LineRemoved != null)
|
||||
LineRemoved(this, new LineRemovedEventArgs(index, count, removedLineIds));
|
||||
}
|
||||
|
||||
public virtual void OnTextChanged(int fromLine, int toLine)
|
||||
{
|
||||
if (TextChanged != null)
|
||||
TextChanged(this, new TextChangedEventArgs(Math.Min(fromLine, toLine), Math.Max(fromLine, toLine) ));
|
||||
}
|
||||
|
||||
public class TextChangedEventArgs : EventArgs
|
||||
{
|
||||
public int iFromLine;
|
||||
public int iToLine;
|
||||
|
||||
public TextChangedEventArgs(int iFromLine, int iToLine)
|
||||
{
|
||||
this.iFromLine = iFromLine;
|
||||
this.iToLine = iToLine;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int IndexOf(Line item)
|
||||
{
|
||||
return lines.IndexOf(item);
|
||||
}
|
||||
|
||||
public virtual void Insert(int index, Line item)
|
||||
{
|
||||
InsertLine(index, item);
|
||||
}
|
||||
|
||||
public virtual void RemoveAt(int index)
|
||||
{
|
||||
RemoveLine(index);
|
||||
}
|
||||
|
||||
public virtual void Add(Line item)
|
||||
{
|
||||
InsertLine(Count, item);
|
||||
}
|
||||
|
||||
public virtual void Clear()
|
||||
{
|
||||
RemoveLine(0, Count);
|
||||
}
|
||||
|
||||
public virtual bool Contains(Line item)
|
||||
{
|
||||
return lines.Contains(item);
|
||||
}
|
||||
|
||||
public virtual void CopyTo(Line[] array, int arrayIndex)
|
||||
{
|
||||
lines.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lines count
|
||||
/// </summary>
|
||||
public virtual int Count
|
||||
{
|
||||
get { return lines.Count; }
|
||||
}
|
||||
|
||||
public virtual bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public virtual bool Remove(Line item)
|
||||
{
|
||||
int i = IndexOf(item);
|
||||
if (i >= 0)
|
||||
{
|
||||
RemoveLine(i);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void NeedRecalc(TextChangedEventArgs args)
|
||||
{
|
||||
if (RecalcNeeded != null)
|
||||
RecalcNeeded(this, args);
|
||||
}
|
||||
|
||||
public virtual void OnRecalcWordWrap(TextChangedEventArgs args)
|
||||
{
|
||||
if (RecalcWordWrap != null)
|
||||
RecalcWordWrap(this, args);
|
||||
}
|
||||
|
||||
public virtual void OnTextChanging()
|
||||
{
|
||||
string temp = null;
|
||||
OnTextChanging(ref temp);
|
||||
}
|
||||
|
||||
public virtual void OnTextChanging(ref string text)
|
||||
{
|
||||
if (TextChanging != null)
|
||||
{
|
||||
var args = new TextChangingEventArgs() { InsertingText = text };
|
||||
TextChanging(this, args);
|
||||
text = args.InsertingText;
|
||||
if (args.Cancel)
|
||||
text = string.Empty;
|
||||
};
|
||||
}
|
||||
|
||||
public virtual int GetLineLength(int i)
|
||||
{
|
||||
return lines[i].Count;
|
||||
}
|
||||
|
||||
public virtual bool LineHasFoldingStartMarker(int iLine)
|
||||
{
|
||||
return !string.IsNullOrEmpty(lines[iLine].FoldingStartMarker);
|
||||
}
|
||||
|
||||
public virtual bool LineHasFoldingEndMarker(int iLine)
|
||||
{
|
||||
return !string.IsNullOrEmpty(lines[iLine].FoldingEndMarker);
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
public virtual void SaveToFile(string fileName, Encoding enc)
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(fileName, false, enc))
|
||||
{
|
||||
for (int i = 0; i < Count - 1;i++ )
|
||||
sw.WriteLine(lines[i].Text);
|
||||
|
||||
sw.Write(lines[Count-1].Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
96
GUI.NET/Debugger/FastColoredTextBox/TypeDescriptor.cs
Normal file
96
GUI.NET/Debugger/FastColoredTextBox/TypeDescriptor.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
///
|
||||
/// These classes are required for correct data binding to Text property of FastColoredTextbox
|
||||
///
|
||||
class FCTBDescriptionProvider : TypeDescriptionProvider
|
||||
{
|
||||
public FCTBDescriptionProvider(Type type)
|
||||
: base(GetDefaultTypeProvider(type))
|
||||
{
|
||||
}
|
||||
|
||||
private static TypeDescriptionProvider GetDefaultTypeProvider(Type type)
|
||||
{
|
||||
return TypeDescriptor.GetProvider(type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
|
||||
{
|
||||
ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
|
||||
return new FCTBTypeDescriptor(defaultDescriptor, instance);
|
||||
}
|
||||
}
|
||||
|
||||
class FCTBTypeDescriptor : CustomTypeDescriptor
|
||||
{
|
||||
ICustomTypeDescriptor parent;
|
||||
object instance;
|
||||
|
||||
public FCTBTypeDescriptor(ICustomTypeDescriptor parent, object instance)
|
||||
: base(parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public override string GetComponentName()
|
||||
{
|
||||
var ctrl = (instance as Control);
|
||||
return ctrl == null ? null : ctrl.Name;
|
||||
}
|
||||
|
||||
public override EventDescriptorCollection GetEvents()
|
||||
{
|
||||
var coll = base.GetEvents();
|
||||
var list = new EventDescriptor[coll.Count];
|
||||
|
||||
for (int i = 0; i < coll.Count; i++)
|
||||
if (coll[i].Name == "TextChanged")//instead of TextChanged slip BindingTextChanged for binding
|
||||
list[i] = new FooTextChangedDescriptor(coll[i]);
|
||||
else
|
||||
list[i] = coll[i];
|
||||
|
||||
return new EventDescriptorCollection(list);
|
||||
}
|
||||
}
|
||||
|
||||
class FooTextChangedDescriptor : EventDescriptor
|
||||
{
|
||||
public FooTextChangedDescriptor(MemberDescriptor desc)
|
||||
: base(desc)
|
||||
{
|
||||
}
|
||||
|
||||
public override void AddEventHandler(object component, Delegate value)
|
||||
{
|
||||
(component as FastColoredTextBox).BindingTextChanged += value as EventHandler;
|
||||
}
|
||||
|
||||
public override Type ComponentType
|
||||
{
|
||||
get { return typeof(FastColoredTextBox); }
|
||||
}
|
||||
|
||||
public override Type EventType
|
||||
{
|
||||
get { return typeof(EventHandler); }
|
||||
}
|
||||
|
||||
public override bool IsMulticast
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override void RemoveEventHandler(object component, Delegate value)
|
||||
{
|
||||
(component as FastColoredTextBox).BindingTextChanged -= value as EventHandler;
|
||||
}
|
||||
}
|
||||
}
|
41
GUI.NET/Debugger/FastColoredTextBox/UnfocusablePanel.cs
Normal file
41
GUI.NET/Debugger/FastColoredTextBox/UnfocusablePanel.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
[System.ComponentModel.ToolboxItem(false)]
|
||||
public class UnfocusablePanel : UserControl
|
||||
{
|
||||
public Color BackColor2 { get; set; }
|
||||
public Color BorderColor { get; set; }
|
||||
public new string Text { get; set; }
|
||||
public StringAlignment TextAlignment { get; set; }
|
||||
|
||||
public UnfocusablePanel()
|
||||
{
|
||||
SetStyle(ControlStyles.Selectable, false);
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
using (var brush = new LinearGradientBrush(ClientRectangle, BackColor2, BackColor, 90))
|
||||
e.Graphics.FillRectangle(brush, 0, 0, ClientSize.Width - 1, ClientSize.Height - 1);
|
||||
using(var pen = new Pen(BorderColor))
|
||||
e.Graphics.DrawRectangle(pen, 0, 0, ClientSize.Width - 1, ClientSize.Height - 1);
|
||||
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
StringFormat sf = new StringFormat();
|
||||
sf.Alignment = TextAlignment;
|
||||
sf.LineAlignment = StringAlignment.Center;
|
||||
using(var brush = new SolidBrush(ForeColor))
|
||||
e.Graphics.DrawString(Text, Font, brush, new RectangleF(1, 1, ClientSize.Width - 2, ClientSize.Height - 2), sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
GUI.NET/Debugger/FastColoredTextBox/VisualMarker.cs
Normal file
106
GUI.NET/Debugger/FastColoredTextBox/VisualMarker.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FastColoredTextBoxNS
|
||||
{
|
||||
public class VisualMarker
|
||||
{
|
||||
public readonly Rectangle rectangle;
|
||||
|
||||
public VisualMarker(Rectangle rectangle)
|
||||
{
|
||||
this.rectangle = rectangle;
|
||||
}
|
||||
|
||||
public virtual void Draw(Graphics gr, Pen pen)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual Cursor Cursor
|
||||
{
|
||||
get { return Cursors.Hand; }
|
||||
}
|
||||
}
|
||||
|
||||
public class CollapseFoldingMarker: VisualMarker
|
||||
{
|
||||
public readonly int iLine;
|
||||
|
||||
public CollapseFoldingMarker(int iLine, Rectangle rectangle)
|
||||
: base(rectangle)
|
||||
{
|
||||
this.iLine = iLine;
|
||||
}
|
||||
|
||||
public void Draw(Graphics gr, Pen pen, Brush backgroundBrush, Pen forePen)
|
||||
{
|
||||
//draw minus
|
||||
gr.FillRectangle(backgroundBrush, rectangle);
|
||||
gr.DrawRectangle(pen, rectangle);
|
||||
gr.DrawLine(forePen, rectangle.Left + 2, rectangle.Top + rectangle.Height / 2, rectangle.Right - 2, rectangle.Top + rectangle.Height / 2);
|
||||
}
|
||||
}
|
||||
|
||||
public class ExpandFoldingMarker : VisualMarker
|
||||
{
|
||||
public readonly int iLine;
|
||||
|
||||
public ExpandFoldingMarker(int iLine, Rectangle rectangle)
|
||||
: base(rectangle)
|
||||
{
|
||||
this.iLine = iLine;
|
||||
}
|
||||
|
||||
public void Draw(Graphics gr, Pen pen, Brush backgroundBrush, Pen forePen)
|
||||
{
|
||||
//draw plus
|
||||
gr.FillRectangle(backgroundBrush, rectangle);
|
||||
gr.DrawRectangle(pen, rectangle);
|
||||
gr.DrawLine(forePen, rectangle.Left + 2, rectangle.Top + rectangle.Height / 2, rectangle.Right - 2, rectangle.Top + rectangle.Height / 2);
|
||||
gr.DrawLine(forePen, rectangle.Left + rectangle.Width / 2, rectangle.Top + 2, rectangle.Left + rectangle.Width / 2, rectangle.Bottom - 2);
|
||||
}
|
||||
}
|
||||
|
||||
public class FoldedAreaMarker : VisualMarker
|
||||
{
|
||||
public readonly int iLine;
|
||||
|
||||
public FoldedAreaMarker(int iLine, Rectangle rectangle)
|
||||
: base(rectangle)
|
||||
{
|
||||
this.iLine = iLine;
|
||||
}
|
||||
|
||||
public override void Draw(Graphics gr, Pen pen)
|
||||
{
|
||||
gr.DrawRectangle(pen, rectangle);
|
||||
}
|
||||
}
|
||||
|
||||
public class StyleVisualMarker : VisualMarker
|
||||
{
|
||||
public Style Style{get;private set;}
|
||||
|
||||
public StyleVisualMarker(Rectangle rectangle, Style style)
|
||||
: base(rectangle)
|
||||
{
|
||||
this.Style = style;
|
||||
}
|
||||
}
|
||||
|
||||
public class VisualMarkerEventArgs : MouseEventArgs
|
||||
{
|
||||
public Style Style { get; private set; }
|
||||
public StyleVisualMarker Marker { get; private set; }
|
||||
|
||||
public VisualMarkerEventArgs(Style style, StyleVisualMarker marker, MouseEventArgs args)
|
||||
: base(args.Button, args.Clicks, args.X, args.Y, args.Delta)
|
||||
{
|
||||
this.Style = style;
|
||||
this.Marker = marker;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue