From 1048b06ce4574af08f3b15ed874f0d416f2d764b Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Fri, 16 Oct 2015 00:52:50 +0200 Subject: [PATCH] Console improvements --- Console/CMakeLists.txt | 3 +- Console/Console.cc | 98 +++++++++++++++++++++++++++------ Console/Console.h | 18 +++++- Console/ConsoleTest.cc | 13 ++++- Console/ConsoleWindow.cc | 116 +++++++++++++++++++++++++++++++++++++++ Console/ConsoleWindow.h | 38 +++++++++++++ Console/InitConsole.cc | 22 ++------ 7 files changed, 266 insertions(+), 42 deletions(-) create mode 100644 Console/ConsoleWindow.cc create mode 100644 Console/ConsoleWindow.h diff --git a/Console/CMakeLists.txt b/Console/CMakeLists.txt index 5cb28cffa4..d00754a988 100644 --- a/Console/CMakeLists.txt +++ b/Console/CMakeLists.txt @@ -21,6 +21,8 @@ set(CMAKE_CXX_FLAGS "-std=c++11") add_library(RetroConsole Console.cc Console.h + ConsoleWindow.cc + ConsoleWindow.h MacUtils.h InitConsole.cc ) @@ -31,4 +33,3 @@ add_application(ConsoleTest ConsoleTest.cc ) target_link_libraries(ConsoleTest RetroConsole) - diff --git a/Console/Console.cc b/Console/Console.cc index 915fbb9bb1..13f3fa9c6d 100644 --- a/Console/Console.cc +++ b/Console/Console.cc @@ -29,10 +29,17 @@ using namespace Retro; Console *Console::currentInstance = NULL; -Console::Console(GrafPtr port, Rect r) - : consolePort(port), bounds(r), dirtyRect(), +Console::Console() + : consolePort(NULL), dirtyRect(), blinkTicks(0), cursorDrawn(false), cursorVisible(true) { +} + +void Console::Init(GrafPtr port, Rect r) +{ + consolePort = port; + bounds = r; + if(currentInstance == NULL) currentInstance = (Console*) -1; PortSetter setport(consolePort); @@ -52,9 +59,16 @@ Console::Console(GrafPtr port, Rect r) onscreen = chars; cursorX = cursorY = 0; - currentInstance = this; } + +Console::Console(GrafPtr port, Rect r) + : consolePort(NULL), dirtyRect(), + blinkTicks(0), cursorDrawn(false), cursorVisible(true) +{ + Init(port, r); +} + Console::~Console() { } @@ -103,16 +117,25 @@ void Console::DrawCells(short x1, short x2, short y, bool erase) DrawText(&chars[y * cols + x1], 0, x2 - x1); } -void Console::Draw() +void Console::Draw(Rect r) { PortSetter setport(consolePort); - for(short row = 0; row < rows; ++row) + short minRow = std::max(0, (r.top - bounds.top) / cellSizeY); + short maxRow = std::min((int)rows, (r.bottom - bounds.top + cellSizeY - 1) / cellSizeY); + + short minCol = std::max(0, (r.left - bounds.left) / cellSizeX); + short maxCol = std::min((int)cols, (r.right - bounds.left + cellSizeX - 1) / cellSizeX); + + EraseRect(&r); + for(short row = minRow; row < maxRow; ++row) { - for(short col = 0; col < cols; ++col) - { - DrawCell(col, row); - } + DrawCells(minCol, maxCol, row, false); + } + if(cursorDrawn) + { + Rect cursor = CellRect(cursorX, cursorY); + InvertRect(&cursor); } onscreen = chars; } @@ -231,15 +254,8 @@ std::string Console::ReadLine() char c; do - { - do - { - Idle(); - while(!GetNextEvent(everyEvent, &event)) - Idle(); - } while(event.what != keyDown && event.what != autoKey); - - c = event.message & charCodeMask; + { + c = WaitNextChar(); if(c == '\r') c = '\n'; @@ -288,3 +304,49 @@ void Console::Idle() Update(); } } + +void Console::Reshape(Rect newBounds) +{ + InsetRect(&newBounds, 2,2); + + bounds = newBounds; + short newRows = (bounds.bottom - bounds.top) / cellSizeY; + short newCols = (bounds.right - bounds.left) / cellSizeX; + + short upshift = 0; + if(cursorY >= newRows) + { + upshift = cursorY - (newRows - 1); + + InvalidateCursor(); + cursorY = newRows - 1; + } + + std::vector newChars(newRows*newCols, ' '); + for(short row = 0; row < newRows && row + upshift < rows; row++) + { + char *src = &chars[(row+upshift) * cols]; + char *dst = &newChars[row * newCols]; + std::copy(src, src + std::min(cols, newCols), dst); + } + chars.swap(newChars); + /*newChars = std::vector(newRows*newCols, ' '); + for(short row = 0; row < newRows && row < rows; row++) + { + char *src = &chars[row * cols]; + char *dst = &newChars[row * newCols]; + std::copy(src, src + std::min(cols, newCols), dst); + } + onscreen.swap(newChars);*/ + onscreen = newChars; + + rows = newRows; + cols = newCols; + + if(upshift) + { + //dirtyRect = Rect { 0, 0, rows, cols }; + //Update(); + Draw(); + } +} diff --git a/Console/Console.h b/Console/Console.h index 22bcba79b9..49cf4ac226 100644 --- a/Console/Console.h +++ b/Console/Console.h @@ -16,6 +16,8 @@ You should have received a copy of the GNU General Public License along with Retro68. If not, see . */ +#ifndef RETRO68_CONSOLE_H_ +#define RETRO68_CONSOLE_H_ #include #include @@ -29,7 +31,8 @@ namespace Retro public: Console(GrafPtr port, Rect r); ~Console(); - void Draw(); + void Draw(Rect r); + void Draw() { Draw(bounds); } void putch(char c); void write(const char *s, int n); @@ -39,6 +42,8 @@ namespace Retro short GetRows() const { return rows; } short GetCols() const { return cols; } + + void Idle(); private: GrafPtr consolePort; Rect bounds; @@ -67,8 +72,17 @@ namespace Retro void ScrollUp(short n = 1); void InvalidateCursor(); - void Idle(); + + virtual char WaitNextChar() = 0; + + protected: + Console(); + void Init(GrafPtr port, Rect r); + + void Reshape(Rect newBounds); }; } + +#endif /* RETRO68_CONSOLE_H_ */ diff --git a/Console/ConsoleTest.cc b/Console/ConsoleTest.cc index 6bf0741000..66ab24959a 100644 --- a/Console/ConsoleTest.cc +++ b/Console/ConsoleTest.cc @@ -9,8 +9,15 @@ namespace Retro int main() { Retro::InitConsole(); - const char *s = "Hello, world.\n"; - Retro::Console::currentInstance->write(s, strlen(s)); - Retro::Console::currentInstance->ReadLine(); + std::string out = "Hello, world.\nEnter \"exit\" to quit.\n"; + Retro::Console::currentInstance->write(out.data(), out.size()); + + std::string in; + do + { + in = Retro::Console::currentInstance->ReadLine(); + out = "You Entered: " + in; + Retro::Console::currentInstance->write(out.data(), out.size()); + } while(in != "exit\n"); return 0; } diff --git a/Console/ConsoleWindow.cc b/Console/ConsoleWindow.cc new file mode 100644 index 0000000000..6d28d31b10 --- /dev/null +++ b/Console/ConsoleWindow.cc @@ -0,0 +1,116 @@ +/* + Copyright 2012 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#include "ConsoleWindow.h" +#include "Events.h" +#include + +using namespace Retro; + +namespace +{ + std::unordered_map windows; +} + +ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title) +{ + GrafPtr port; + + win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, false, 0); + +#if !TARGET_API_MAC_CARBON + port = win; + Rect portRect = port->portRect; +#else + port = GetWindowPort(win); + Rect portRect; + GetPortBounds(port, &portRect); +#endif + + SetPort(port); + EraseRect(&portRect); + + windows[win] = this; + + Init(port, portRect); +} + +ConsoleWindow::~ConsoleWindow() +{ + windows.erase(win); + DisposeWindow(win); +} + +char ConsoleWindow::WaitNextChar() +{ + EventRecord event; + WindowPtr eventWin; + ConsoleWindow *realConsole; +#if TARGET_API_MAC_CARBON + Rect *boundsPtr = NULL; +#else + Rect *boundsPtr = &qd.screenBits.bounds; +#endif + + do + { + #if TARGET_API_MAC_CARBON + #define SystemTask() + #endif + SystemTask(); + Idle(); + while(!GetNextEvent(everyEvent, &event)) + { + SystemTask(); + Idle(); + } + + switch(event.what) + { + case updateEvt: + eventWin = (WindowPtr)event.message; + realConsole = windows[(WindowPtr)event.message]; + if(realConsole) + { + BeginUpdate(eventWin); + realConsole->Draw((*qd.thePort->visRgn)->rgnBBox); + EndUpdate(eventWin); + } + break; + case mouseDown: + + switch(FindWindow(event.where, &eventWin)) + { + case inDrag: + DragWindow(eventWin, event.where, boundsPtr); + break; + case inGrow: + { + long growResult = GrowWindow(eventWin, event.where, boundsPtr); + SizeWindow(eventWin, growResult & 0xFFFF, growResult >> 16, true); + Reshape(Rect {0, 0, (short) (growResult >> 16), (short) (growResult & 0xFFFF) }); + } + break; + } + break; + } + } while(event.what != keyDown && event.what != autoKey); + + return event.message & charCodeMask; +} diff --git a/Console/ConsoleWindow.h b/Console/ConsoleWindow.h new file mode 100644 index 0000000000..d2eb81a319 --- /dev/null +++ b/Console/ConsoleWindow.h @@ -0,0 +1,38 @@ +/* + Copyright 2012 Wolfgang Thaller. + + This file is part of Retro68. + + Retro68 is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Retro68 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Retro68. If not, see . +*/ + +#include +#include +#include + +#include "Console.h" + +namespace Retro +{ + class ConsoleWindow : public Console + { + public: + ConsoleWindow(Rect r, ConstStr255Param title); + ~ConsoleWindow(); + private: + WindowPtr win; + + virtual char WaitNextChar(); + }; +} diff --git a/Console/InitConsole.cc b/Console/InitConsole.cc index a3ff5e015b..dfd1e74cfa 100644 --- a/Console/InitConsole.cc +++ b/Console/InitConsole.cc @@ -30,6 +30,7 @@ #include "MacUtils.h" #include "Console.h" +#include "ConsoleWindow.h" namespace Retro { @@ -42,9 +43,6 @@ void Retro::InitConsole() { if(Console::currentInstance) return; - - WindowPtr win; - GrafPtr port; #if !TARGET_API_MAC_CARBON InitGraf(&qd.thePort); @@ -59,21 +57,9 @@ void Retro::InitConsole() r.top += 40; InsetRect(&r, 5,5); - win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, false, 0); - -#if !TARGET_API_MAC_CARBON - port = win; - Rect portRect = port->portRect; -#else - port = GetWindowPort(win); - Rect portRect; - GetPortBounds(port, &portRect); -#endif - - SetPort(port); - EraseRect(&portRect); - - Console *console = new Console(port, portRect); + + new ConsoleWindow(r, "\pRetro68 Console"); + InitCursor(); } extern "C" ssize_t _consolewrite(int fd, const void *buf, size_t count)