--- nono/lib/textscreen.cpp 2026/04/29 17:04:28 1.1.1.1 +++ nono/lib/textscreen.cpp 2026/04/29 17:05:30 1.1.1.12 @@ -1,15 +1,15 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "header.h" -#include "textscreen.h" - // // テキストスクリーン // +#include "textscreen.h" + // コンストラクタ TextScreen::TextScreen() { @@ -24,19 +24,20 @@ TextScreen::TextScreen(int arg_col, int // デストラクタ TextScreen::~TextScreen() { - if (textbuf) { - delete[] textbuf; - } } // 初期化 void -TextScreen::Init(int arg_col, int arg_row) +TextScreen::Init(int arg_col, int arg_row, ModeKind mode) { + assert(arg_col > 0); + assert(arg_row > 0); + col = arg_col; row = arg_row; + Mode = mode; - textbuf = new uint16 [col * row]; + textbuf.resize(col * row); X = 0; Y = 0; @@ -50,44 +51,130 @@ TextScreen::Clear() for (int i = 0; i < col * row; i++) { textbuf[i] = 0x0020; } + + // ホームポジション + Locate(0, 0); +} + +// 文字出力後の右移動。 +void +TextScreen::Ascend() +{ + X++; + if (X >= col) { + switch (Mode) { + case Fixed: + OutOfScreen = true; + break; + case Console: + case Ring: + CRLF(); + break; + } + } +} + +// 改行。 +void +TextScreen::LF() +{ + Y++; + switch (Mode) { + case Fixed: + break; + case Console: + if (Y >= row) { + ScrollUp(); + Y = row - 1; + } + break; + case Ring: + if (Y >= row) { + Y = 0; + } + break; + } + + // どのモードであっても OutOfScreen を更新 + // (Y=-1 から CRLF したら表示可能になるべき) + OutOfScreen = (Y < 0 || Y >= row); +} + +// 1 行上スクロール +void +TextScreen::ScrollUp() +{ + memmove(&textbuf[0], &textbuf[col], + (row - 1) * col * sizeof(textbuf[0])); + for (int i = 0; i < col; i++) { + textbuf[(row - 1) * col + i] = 0x0020; + } } + // 現在のカーソル位置に1文字出力する。 -// カーソルは一つ移動する。 -// 右もしくは下にはみ出した場合は無視する。 -// XXX どっかで拾えてもいいような void TextScreen::Putc(uint16 ch) { - if (X >= col || Y >= row) { + if (ch == '\n') { + CRLF(); + return; + } + + if (OutOfScreen) { return; } textbuf[(Y * col) + X] = ch; - X++; + Ascend(); +} + +// 現在のカーソル位置の文字を取得。 +// カーソルは移動しない。 +// カーソルが範囲外だったときは 0 を返す。 +uint16 +TextScreen::Getc() +{ + if (OutOfScreen) { + return 0; + } + + return textbuf[(Y * col) + X]; } // テキストスクリーンに文字列を出力する。 -// 右もしくは下にはみ出した場合は無視する。 -// XXX どっかで拾えてもいいような void TextScreen::Puts(const char *str) { while (*str != '\0') { - Putc(*str++); + uint16 ch = (uint8)*str++; + Putc(ch); } } // テキストスクリーンに文字列を出力する。 -// 右もしくは下にはみ出した場合は無視する。 void -TextScreen::Puts(uint attr, const char *str) +TextScreen::Puts(TA attr, const char *str) { while (*str != '\0') { - Putc(attr | *str++); + Putc(((uint)attr) | *str++); } } +// テキストスクリーンの現在位置から書式付き文字列を出力する。 +void +TextScreen::Print(const char *fmt, ...) +{ + char buf[1024]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + Puts(buf); +} + // テキストスクリーンに座標を指定して書式付き文字列を出力する。 void TextScreen::Print(int x, int y, const char *fmt, ...) @@ -99,14 +186,13 @@ TextScreen::Print(int x, int y, const ch vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - X = x; - Y = y; + Locate(x, y); Puts(buf); } // テキストスクリーンに座標と属性を指定して、書式付き文字列を出力する。 void -TextScreen::Print(int x, int y, uint attr, const char *fmt, ...) +TextScreen::Print(int x, int y, TA attr, const char *fmt, ...) { char buf[1024]; va_list ap; @@ -115,7 +201,71 @@ TextScreen::Print(int x, int y, uint att vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - X = x; - Y = y; + Locate(x, y); Puts(attr, buf); } + +// 現在のカーソル位置に文字を出力。 +// カーソルは移動しない。ch がカーソル移動を伴う制御文字なら動作不定。 +void +TextScreen::Setc(uint16 ch) +{ + textbuf[(Y * col) + X] = ch; +} + +// 指定のカーソル位置に文字を出力。 +// カーソルは移動しない。ch がカーソル移動を伴う制御文字なら動作不定。 +void +TextScreen::Setc(int x, int y, uint16 ch) +{ + textbuf[(y * col) + x] = ch; +} + +// 現在位置の属性を取得 +// カーソルが画面外の場合は TA::Normal を返す。 +TA +TextScreen::GetAttr() const +{ + if (OutOfScreen) { + return TA::Normal; + } + + return TA(textbuf[(Y * col) + X] & 0xff00); +} + +// 現在位置の属性を attr に設定する。 +// カーソルは移動しない。 +void +TextScreen::SetAttr(TA attr) +{ + if (OutOfScreen) { + return; + } + + auto& ch = textbuf[(Y * col) + X]; + ch = (ch & 0xff) | (uint)attr; +} + +// src の src_y 行目から rows 行をこのスクリーンの dst_y 行目以降にコピーする。 +// 双方のカーソルは移動しない。 +// もし row がどちらかではみ出た場合はコピーをそこで終了する。 +// src と dst (この screen) の桁数が違うと assert する。 +void +TextScreen::CopyRowsFrom(int dst_y, int rows, const TextScreen& src, int src_y) +{ + assert(GetCol() == src.GetCol()); + + const auto& srcbuf = src.GetBuf(); + + // rows を小さいほうに揃える。 + if (rows > GetRow() - dst_y) { + rows = GetRow() - dst_y; + } + if (rows > src.GetRow() - src_y) { + rows = src.GetRow() - src_y; + } + + // 内部構造を知っているので一気にコピー。 + memcpy(&textbuf[dst_y * col], &srcbuf[src_y * col], + sizeof(textbuf[0]) * col * rows); +}