Turbo Vision 2.0 的現代化移植版,經典的文字使用者介面框架。現已支援跨平台與 Unicode。
我於 2018 年底開始此專案作為個人計畫。到 2020 年 5 月,我認為它已非常接近原始版本的完整功能,並決定將其開源。
此專案的原始目標是:
一度我認為我做得夠多了,任何試圖改寫函式庫並克服其原始限制的嘗試,都需要擴展 API 或破壞向後相容性,而且很可能需要進行重大重寫。
然而,在 2020 年 7 月至 8 月之間,我找到了將完整的 Unicode 支援整合到現有架構的方法,編寫了 Turbo 文字編輯器,並將新功能帶到了 Windows。因此,我確信 Turbo Vision 現在可以滿足許多現代使用者和程式設計師的期望。
此專案的原始位置是 https://github.com/magiblot/tvision 。
自從 Borland 在 90 年代初期創建 Turbo Vision 以來,已經發生了很多變化。如今許多 GUI 工具將外觀規格與行為規格分開,使用更安全或動態的語言(在錯誤發生時不會出現 segfault),並支援平行或非同步程式設計,或兩者皆支援。
Turbo Vision 在這些方面並不特別突出,但它確實克服了程式設計師在編寫終端機應用程式時至今仍面臨的許多問題:
忘掉終端機能力和直接終端機 I/O 吧。編寫 Turbo Vision 應用程式時,您只需要關心您的應用程式想要如何表現和看起來——無需在程式碼中添加因應措施。Turbo Vision 會盡力在所有環境中產生相同的結果。例如:要在 Linux 主控台中獲得明亮的背景顏色,必須設定閃爍屬性。Turbo Vision 會為您處理這些。
重複使用已完成的工作。Turbo Vision 提供了許多小工具類別(也稱為視圖),包括可調整大小、重疊的視窗、下拉式選單、對話方塊、按鈕、捲軸、輸入框、核取方塊和選項按鈕。您可以直接使用和擴展它們;即使您偏好創建自己的,Turbo Vision 也已處理了事件分派、全寬 Unicode 字元的顯示等:您無需浪費時間重寫任何這些內容。
您能想像編寫一個同時在 Linux 和 Windows 上運行的文字介面(因此是跨平台的),開箱即用,無需 #ifdef 嗎?Turbo Vision 使這成為可能。首先:Turbo Vision 繼續使用字元陣列,而不是依賴於實作定義且平台相關的 wchar_t 或 TCHAR。其次:由於 Microsoft RTL 近期版本在 setlocale 中支援 UTF-8,像以下程式碼將按預期工作:
您可以從 Turbo Vision For C++ 使用者指南開始,並查看範例應用程式 hello、tvdemo 和 tvedit。一旦您掌握了基礎知識,我建議您查看 Turbo Vision 2.0 程式設計指南,我認為它更直觀且易於理解,儘管它使用 Pascal 編寫。屆時您可能會對調色盤範例感興趣,其中包含對調色盤如何使用的詳細描述。
別忘了也檢查功能和 API 變更部分。
此專案目前沒有穩定版本。如果您是開發者,請盡量堅持使用最新提交,並在升級時回報任何發現的問題。
如果您只想測試範例應用程式:
Turbo Vision 可以使用 CMake 和 GCC/Clang 建置為靜態函式庫。
版本早於 3.13 的 CMake 可能不支援 -B 選項。您可以嘗試以下方法代替:
上述命令將產生以下檔案:
函式庫和可執行檔位於 ./build 。
如果您的發行版提供獨立的開發套件(例如 Debian 相關發行版的 libncurses-dev、libgpm-dev),也請安裝它們。
從此專案根目錄建置 Turbo Vision 應用程式(例如 hello.cpp 與 GCC)所需的最小命令列是:
-Iinclude/tvision 如果您的應用程式使用 Turbo Vision 1.x 包含檔(#include <tv.h> 而非 #include <tvision/tv.h>)。
-Iinclude/tvision/compat/borland 如果您的應用程式包含 Borland 標頭檔(dir.h、iostream.h 等)。
在 Gentoo(以及可能的其他發行版)上:如果您的系統同時提供 libtinfo.so 和 libtinfow.so,則使用 -ltinfow。否則,您在運行 Turbo Vision 應用程式時可能會遇到段錯誤(#11)。請注意,tinfo 已包含在 ncurses 中。
-lgpm 僅在 Turbo Vision 使用 libgpm 支援建置時才需要。
include/tvision/compat/borland 中的向後相容標頭檔模擬了 Borland C++ RTL。Turbo Vision 的原始程式碼仍然依賴它們,並且在移植舊應用程式時可能很有用。這也意味著包含 tvision/tv.h 會將幾個 std 命名空間名稱引入全域命名空間。
使用 MSVC 的建置過程稍微複雜一些,因為有更多選項可供選擇。請注意,您需要為不同的目標架構使用不同的建置目錄。例如,要產生最佳化二進位檔:
在上述範例中,tvision.lib 和範例應用程式將位於 ./build/Release 。
如果您希望將 Turbo Vision 靜態連結到 Microsoft 的執行階段函式庫(使用 /MT 而非 /MD),請啟用 TV_USE_STATIC_RTL 選項(呼叫 cmake 時使用 -DTV_USE_STATIC_RTL=ON)。
如果您希望將應用程式連結到 Turbo Vision,請注意 MSVC 不允許您混合使用 /MT 和 /MD 或偵錯與非偵錯二進位檔。所有元件都必須以相同的方式連結到 RTL。
如果您自行開發 Turbo Vision 應用程式,請確保啟用以下編譯器旗標,否則在包含 <tvision/tv.h> 時會出現編譯錯誤:
如果您將 Turbo Vision 作為 CMake 子模組使用,這些旗標將自動啟用。
注意:Turbo Vision 使用 setlocale 將 RTL 函式設定為 UTF-8 模式。如果您使用舊版 RTL,這將無效。
當 RTL 靜態連結並在 setlocale 中支援 UTF-8 時,Turbo Vision 應用程式在 Windows Vista 及更高版本上是可移植的,並且預設情況下可以正常工作。如果您使用正確的 MSVC 版本和設定,它們也可以在 Windows XP 上工作。
正確設定您的 MinGW 環境後,建置方式與 Linux 類似:
在上述範例中,如果 TV_BUILD_EXAMPLES 選項為 ON(預設值),則 libtvision.a 和所有範例都位於 ./build 中。
如果您希望將應用程式連結到 Turbo Vision,只需將 -L./build/lib -ltvision 添加到您的連結器,並將 -I./include 添加到您的編譯器。
Turbo Vision 應用程式可以在 Windows XP 或更新版本上運行,前提是您的編譯器支援。
使用 Borland C++,Turbo Vision 仍然可以建置為 DOS 或 Windows 函式庫。顯然,這裡沒有 Unicode 支援。
我可以確認建置過程與以下版本一起工作:
您可能會根據您的建置環境遇到不同的問題。例如,Turbo Assembler 需要一個補丁才能在 Windows 95 下運行。在 Windows XP 上一切似乎都正常工作。在 Windows 10 上,MAKE 可能會發出錯誤 Fatal: Command arguments too long,這可以通過將 MAKE 升級到 Borland C++ 5.x 隨附的版本來解決。
是的,這在 64 位元 Windows 10 上有效。無法工作的是 Borland C++ 安裝程式,它是一個 16 位元應用程式。您必須在其他環境中運行它,或嘗試使用 winevdm。
專案目錄中可以找到 Borland Makefile。建置可以通過以下方式完成:
這將把函式庫編譯到專案旁邊的 LIB 目錄中,並為各自範例/* 目錄中的範例應用程式編譯可執行檔。
我抱歉,根目錄的 makefile 假設它是從專案目錄執行的。如果您想使用不同的設定,仍然可以直接運行原始的 makefiles(在 source/tvision 和 examples/* 中)。
Turbo Vision 可以使用 vcpkg 依賴管理器進行建置和安裝:
vcpkg 中的 tvision 埠由 Microsoft 團隊成員和社群貢獻者維護。如果您發現它已過時,請在 vcpkg 儲存庫中建立一個 issue 或 pull request。
如果您選擇 CMake 建置系統作為您的應用程式,有兩種主要方法可以連結到 Turbo Vision:
安裝 Turbo Vision 並使用 find_package 匯入。安裝取決於產生器類型:
首先,決定一個安裝前綴。預設的前綴將開箱即用,但通常需要管理員權限。在 Unix 系統上,您可以使用 $HOME/.local 代替。在 Windows 上,您可以使用任何自訂路徑,但您必須在建置應用程式時將其添加到 CMAKE_PREFIX_PATH 環境變數。
對於單一配置產生器(Unix Makefiles、Ninja...),您只需建置和安裝一次:
對於多重配置產生器(Visual Studio、Ninja Multi-Config...),您應該建置和安裝所有配置:
然後,在您的應用程式的 CMakeLists.txt 中,您可以這樣匯入它:
將 Turbo Vision 作為子模組放在您的儲存庫中,並使用 add_subdirectory 匯入:
無論哪種情況,編譯時您的應用程式的包含路徑中都會有 <tvision/tv.h>,並且您的應用程式將自動連結到必要的函式庫(Ncurses、GPM...)。
有幾個環境變數會影響所有 Turbo Vision 應用程式的行為:
以下環境變數也會被考慮在內:
TERM:Ncurses 使用它來確定終端機能力。它由終端機模擬器自動設定。
COLORTERM:當設定為 truecolor 或 24bit 時,Turbo Vision 會假設終端機模擬器支援 24 位元顏色。它由支援它的終端機模擬器自動設定。
ESCDELAY:按下 ESC 鍵後等待的毫秒數,預設為 10。如果在該延遲期間按下另一個鍵,它將被解釋為 Alt+Key 組合鍵。使用較大的值對於不支援 Alt 鍵的終端機很有用。
TVISION_USE_STDIO:當不為空時,終端機 I/O 通過 stdin/stdout 執行,以便可以從 shell 重定向。預設情況下,Turbo Vision 通過 /dev/tty 執行終端機 I/O,允許使用者為其需求重定向 stdin、stdout 和 stderr,而不影響應用程式的穩定性。
例如,以下命令將使 out.txt 為空:
而以下命令將把應用程式列印的所有轉義序列和文字傾印到 out.txt:
使用 Borland C++ 編譯時,以下功能不可用:
注意:Turbo Vision 直接將 UTF-8 文字寫入 Windows 主控台。如果主控台設定為舊版模式並正在使用點陣字體,Unicode 字元將無法正確顯示(照片)。為避免此情況,Turbo Vision 會偵測到此情況並嘗試將主控台字體變更為 Consolas 或 Lucida Console。
以下是 Borland 的 Turbo Vision 版本或先前開源移植版(Sigala、SET)中沒有的新功能:
螢幕寫入是緩衝的,通常在每次活動事件迴圈的迭代中發送到終端機(另請參閱 TVISION_MAX_FPS)。如果您需要在繁忙迴圈期間更新螢幕,可以使用 TScreen::flushScreen()。
TDrawBuffer 不再是固定長度的陣列,其方法可防止超出陣列末端的存取。因此,舊程式碼中與 sizeof(TDrawBuffer)/sizeof(ushort) 的比較不再有效;應移除此類檢查。
TApplication 現在提供 dosShell()、cascade() 和 tile(),並預設處理 cmDosShell、cmCascade 和 cmTile。可以通過覆寫 getTileRect() 和 writeShellMsg() 來客製化這些函式。這與 Pascal 版本中的行為相同。
滑鼠滾輪支援:新的滑鼠事件 evMouseWheel。滾輪方向在新的欄位 event.mouse.wheel 中指定,其可能值為 mwUp、mwDown、mwLeft 或 mwRight。
中間滑鼠按鈕支援:新的滑鼠按鈕旗標 mbMiddleButton。
evMouseUp 事件中的 buttons 欄位不再為空。它現在指示哪個按鈕被釋放。
三擊支援:新的滑鼠事件旗標 meTripleClick。
TRect 方法 move、grow、intersect 和 Union 現在返回 TRect& 而不是 void,以便可以鏈式呼叫。
TOutlineViewer 現在允許根節點有兄弟節點。
新的方法 THelpTopic::longestLineWidth,用於測量說明主題中最長行的寬度,並考慮換行。
新的函式 ushort popupMenu(TPoint where, TMenuItem &aMenu, TGroup *receiver = 0),它會在桌面上生成一個 TMenuPopup。請參閱 source/tvision/popupmnu.cpp。
新的虛擬方法 TMenuItem& TEditor::initContextMenu(TPoint p),它決定了 TEditor 中右鍵上下文選單的項目。
fexpand 現在可以接受第二個參數 relativeTo。
新的類別 TStringView,受 std::string_view 啟發。
新的類別 TSpan<T>,受 std::span 啟發。
新的類別 TDrawSurface 和 TSurfaceView,請參閱 <tvision/surface.h>。
Turbo Vision 的子系統(THardwareInfo、TScreen、TEventQueue...)現在在第一次建構 TApplication 時初始化,而不是在 main 之前。它們在 main 結束時仍然被銷毀。
新的方法 TVMemMgr::reallocateDiscardable(),可用於 allocateDiscardable 和 freeDiscardable。
新的方法 TView::textEvent(),允許以有效的方式接收文字,請參閱 Clipboard interaction。
新的類別 TClipboard,請參閱 Clipboard interaction。
True Color 支援,請參閱 extended colors。
新的方法 static void TEventQueue::waitForEvents(int timeoutMs),它可能會阻塞最多 timeoutMs 毫秒以等待輸入事件。負數的 timeoutMs 可用於無限期等待。如果阻塞,它會刷新螢幕更新(通過 TScreen::flushScreen())作為副作用。TProgram::getEvent() 使用靜態整數 TProgram::eventTimeoutMs(預設值為 20)作為參數來呼叫它,這樣事件迴圈就不會變成消耗 100% CPU 的忙碌迴圈。
新的方法 static void TEventQueue::wakeUp(),它會導致事件迴圈在 TEventQueue::waitForEvents() 阻塞時恢復執行。此方法是執行緒安全的,因為它的目的是從次要執行緒中解除事件迴圈的阻塞。
新的方法 void TView::getEvent(TEvent &, int timeoutMs),它允許使用使用者提供的超時時間(而不是 TProgram::eventTimeoutMs)等待事件。
現在可以在 TInputLine 中指定最大文字寬度或最大字元數。這是通過 TInputLine 建構子中的一個新參數 ushort limitMode 完成的,該參數控制第二個建構子參數 uint limit 如何被處理。ilXXXX 常數定義了 limitMode 的可能值:
允許在運行時獲取 Turbo Vision 常數名稱的新函式(例如 evCommand、kbShiftIns 等):
tvision/util.h 中的 hotKey、getAltChar 和 getCtrlChar 函式的基於字串的變體,可用於實現多位元組快捷鍵:
新的類別 TKey,可用於定義新的按鍵組合(例如 Shift+Alt+Up),方法是指定一個按鍵代碼和一個按鍵修飾符的遮罩:
允許使用計時事件的新方法:
setTimer 啟動一個計時器,該計時器將首先在 timeoutMs 毫秒後超時,然後每 periodMs 毫秒超時一次。
如果 periodMs 為負數,計時器只超時一次並自動清理。否則,它將持續週期性超時,直到調用 killTimer 為止。
當計時器超時時,會發出一個帶有命令 cmTimerExpired 的 evBroadcast 事件,並且 message.infoPtr 被設定為超時計時器的 TTimerId。
超時事件在 TProgram::idle() 中產生。因此,它們僅在沒有鍵盤或滑鼠事件可用時才被處理。
您可以在此處找到一些螢幕截圖。歡迎您添加自己的!
如果您知道任何原始程式碼尚未丟失且可能從此專案中受益的 Turbo Vision 應用程式,請告訴我。
如果您的應用程式基於此專案,並且您希望它出現在以下列表中,請告訴我。
Turbo Vision API 已擴展,以允許接收 Unicode 輸入並顯示 Unicode 文字。支援的編碼是 UTF-8,原因如下:
請注意,使用 Borland C++ 建置時,Turbo Vision 不支援 Unicode。但是,這不會影響編寫 Turbo Vision 應用程式的方式,因為 API 擴展旨在允許編碼無關的程式碼。
獲取按鍵事件文字的傳統方法如下:
然而,charScan.charCode 欄位只能容納單位元組字元,因此不支援 Unicode。為了向後相容,按鍵事件中的 charScan.charCode 欄位仍然包含字碼頁字元(CP437,除非由開發者覆寫)。
為了支援 Unicode,在 ev.keyDown(它是一個 KeyDownEvent 結構)中引入了兩個新欄位:
請注意,文字字串不是以 null 結尾的。為了不直接修改 text 和 textLength 欄位,您可以使用 getText() 方法,它返回一個字串視圖。
因此,可以通過以下方式從 TEvent 中檢索 Unicode 字元:
讓我們從另一個角度來看。如果使用者輸入 ñ,則會生成一個具有以下 keyDown 結構的 TEvent:
但是,如果他們輸入 €,則會發生以下情況:
如果按下按鍵快捷鍵,則文字為空:
總之:未考慮 Unicode 輸入的視圖將繼續像以前一樣工作,而想要支援 Unicode 的視圖也不會有問題。
Turbo Vision 的原始設計使用 16 位元來表示螢幕單元格——8 位元用於字元,8 位元用於 BIOS 顏色屬性。
在 <tvision/scrncell.h> 中定義了一個新的 TScreenCell 類型,除了擴展屬性(粗體、底線、斜體...)之外,它還可以容納有限數量的 UTF-8 編碼點。但是,您不應該直接寫入 TScreenCell,而應使用支援 Unicode 的 API 函式。
處理文字顯示的 Turbo Vision API 函式行為如下:
這意味著擴展 ASCII 字元可以與 UTF-8 混合,這對於向後相容很有用。但是,如果您依賴此行為,可能會得到意外的結果:例如,「\xC4\xBF」是一個有效的 UTF-8 序列,顯示為 Ŀ 而不是 ─┐。
Unicode 支援的另一個方面是雙寬字元和組合字元的出現。這與 Turbo Vision 的原始假設相衝突,即螢幕是一個由單個字元佔據的單元格網格。儘管如此,這些情況的處理方式如下:
雙寬字元可以繪製在螢幕的任何位置,並且它們與其他字元部分重疊也不會發生什麼壞事。
零寬字元會覆蓋前一個字元。例如,序列 में 由單寬字元 म 和組合字元 े 和 ं 組成。在此情況下,三個 Unicode 編碼點適合同一個單元格。
ZERO WIDTH JOINER (U+200D) 始終被省略,因為它會使事情變得過於複雜。例如,它可以將字串「👩👦」(寬度為 4 列)變成「👩👦」(寬度為 2 列)。並非所有終端機模擬器都支援 ZWJ,因此為了產生可預測的結果,Turbo Vision 將同時列印「👩👦」和「👩👦」為 👩👦。
只要您的終端機模擬器尊重 wcwidth 測量的字元寬度,就不會發生明顯的圖形故障。
以下是 Turbo 文字編輯器中此類字元的範例:
通常寫入螢幕的方式是使用 TDrawBuffer。其部分方法已更新以支援新功能:
c 被處理為字碼頁字元。
str 根據先前公開的規則進行處理,並且有兩個新參數:
返回值是複製文字的寬度(以列為單位)。
此函式實際上與 moveStr 相同。但是,它的存在是因為在引入 TStringView 之前,它是唯一可以用於非 null 終止字串的 TDrawBuffer 函式。
還有其他有用的 Unicode 感知函式:
根據上述規則返回 s 的顯示長度,忽略 ~ 字元。
在 Borland C++ 上,這些方法假設單一位元組編碼,所有字元寬度均為一。這使得編寫可以在兩個平台上運行的編碼無關的 draw() 和 handleEvent() 方法成為可能,而無需任何 #ifdef。
上述函式是使用 TText 命名空間中的函式實現的,這是另一個 API 擴展。如果您想手動填充 TScreenCell 物件或使用自訂字碼頁轉換表,您必須直接使用它們。舉例來說,以下是一些 TText 函式。您可以在 <tvision/ttext.h> 中找到所有這些函式及其完整描述。
對於將 TScreenCell 緩衝區繪製到視圖中,有以下方法可用:
盡可能簡單。讓我們修改 hello.cpp 如下:
以下是 TFileViewer::draw()(tvdemo 應用程式的一部分)的舊實作摘錄,它無法正確繪製 Unicode 文字:
它所做的只是將檔案行的一部分移動到 b 中,b 是 TDrawBuffer。delta 是代表文字視圖中捲動偏移量的 TPoint,i 是正在處理的可見行的索引。c 是文字顏色。存在一些問題:
以下是上述程式碼的修正版本,它能正確處理 Unicode:
這裡使用的 moveStr 重載是 TDrawBuffer::moveStr(ushort indent, TStringView str, TColorAttr attr, ushort maxStrWidth, ushort strIndent = 0)。此函式不僅提供 Unicode 支援,還幫助我們編寫更清晰的程式碼並克服先前存在的一些限制:
支援創建 Unicode 感知的視圖已到位,並且原始 Turbo Vision 函式庫中的大多數視圖都已適配以處理 Unicode。
以下視圖可以正確顯示 Unicode 文字。其中一些還支援水平捲動或自動換行;所有這些都應該能正常工作。
以下視圖還可以處理 Unicode 使用者輸入:
此列表之外的視圖可能不需要任何更正,或者我可能忘記修復它們。如果您發現任何不正常工作的內容,請提交一個 issue。
不支援 Unicode 的使用案例(非詳盡列表):
最初,Turbo Vision 沒有與系統剪貼簿整合,因為 MS-DOS 中沒有這樣的東西。
它確實提供了使用 TEditor 實例作為內部剪貼簿的可能性,通過 TEditor::clipboard 靜態成員。但是,TEditor 是唯一能夠與此剪貼簿互動的類別。例如,它無法與 TInputLine 一起使用。
Turbo Vision 應用程式現在最有可能通過終端機模擬器在圖形環境中運行。在此情境下,希望能夠像常規 GUI 應用程式一樣與系統剪貼簿互動。
為了解決這個問題,增加了一個新的類別 TClipboard,它允許存取系統剪貼簿。如果系統剪貼簿無法存取,它將改用內部剪貼簿。
在 Windows(包括 WSL)和 macOS 上,剪貼簿整合是開箱即用的。
在 macOS 以外的 Unix 系統上,需要安裝一些外部依賴項。請參閱 runtime requirements。
對於遠端運行的應用程式(例如通過 SSH),在以下情況下支援剪貼簿整合:
此外,始終可以通過終端機模擬器本身的剪下命令(通常是 Ctrl+Shift+V 或 Cmd+V)來貼上文字。
要使用 TClipboard 類別,請在包含 <tvision/tv.h> 之前定義巨集 Uses_TClipboard。
將系統剪貼簿的內容設定為 text。如果系統剪貼簿無法存取,則使用內部剪貼簿。
異步請求系統剪貼簿的內容,稍後將以常規 evKeyDown 事件的形式接收。如果系統剪貼簿無法存取,則使用內部剪貼簿。
Turbo Vision 應用程式可能由於兩種原因之一而收到 Paste 事件:
在這兩種情況下,應用程式都將以常規 evKeyDown 事件的形式接收剪貼簿內容。這些事件將在 keyDown.controlKeyState 中具有 kbPaste 旗標,以便與常規按鍵區分。
因此,如果您的視圖可以處理使用者輸入,它預設也會處理 Paste 事件。但是,如果使用者貼上 5000 個字元,應用程式的行為將如同使用者按下了鍵盤 5000 次。這涉及到繪製視圖、完成事件迴圈、更新螢幕...,如果您的視圖是文字編輯元件,這遠非最佳。
為了解決這個情況,還增加了一個函式:
textEvent() 嘗試從連續的 evKeyDown 事件中讀取文字,並將其儲存在使用者提供的緩衝區 dest 中。當沒有更多事件可用或找到非文字事件時,它返回 false,此時該事件將被儲存起來,以便在下一個事件迴圈迭代中處理。最後,它調用 clearEvent(event)。
讀取的確切位元組數儲存在輸出參數 length 中,該參數永遠不會大於 dest.size()。
以下是如何使用它的範例:
標準視圖 TEditor 和 TInputLine 會響應 cmCut、cmCopy 和 cmPaste 命令。但是,您的應用程式必須首先設定為使用這些命令。例如:
TEditor 和 TInputLine 會自動啟用和禁用這些命令。例如,如果 TEditor 或 TInputLine 處於焦點,則 cmPaste 命令將被啟用。如果存在選取的文字,則 cmCut 和 cmCopy 命令也將被啟用。如果沒有 TEditor 或 TInputLine 處於焦點,則這些命令將被禁用。
Turbo Vision API 已擴展,以支援超過原始 16 種顏色。
顏色可以使用以下任何格式指定:
儘管 Turbo Vision 應用程式很可能在終端機模擬器中運行,但 API 不對顯示裝置做任何假設。也就是說,處理終端機模擬器的複雜性對程式設計師隱藏,並由 Turbo Vision 本身管理。
例如:顏色支援因終端機而異。如果程式設計師使用的顏色格式不受終端機模擬器支援,Turbo Vision 將將其量化為終端機可以顯示的顏色。以下圖像代表了 24 位元 RGB 圖片到 256、16 和 8 種顏色調色盤的量化:
擴展顏色支援基本上歸結為以下幾點:
以下是針對開發人員的更詳細解釋。
首先,我們將解釋程式設計師需要了解的資料類型,以便利用擴展顏色支援。要存取它們,您可能需要定義巨集 Uses_TColorAttr,然後再包含 <tvision/tv.h>。
本節中描述的所有類型都是簡單的。這意味著它們可以通過 memset 和 memcpy 進行處理。但是,這些類型的變數在沒有初始化器聲明時是未初始化的,就像基本類型一樣。因此,請確保在初始化它們之前不要操作它們。
定義了幾種類型來表示不同的顏色格式。存在這些類型的原因是允許使用類型系統區分顏色格式。其中一些還具有公共欄位,便於操作單獨的位元。
TColorBIOS 代表 BIOS 顏色。它可以單獨存取 r、g、b 和 bright 位元,並且可以隱式轉換為/從 uint8_t。
在終端機模擬器中,BIOS 顏色映射到基本的 16 種 ANSI 顏色。
TColorRGB 代表 24 位元 RGB 中的顏色。它可以單獨存取 r、g 和 b 位元欄位,並且可以隱式轉換為/從 uint32_t。
TColorXTerm 代表 xterm-256color 顏色調色盤中的索引。它可以轉換為和從 uint8_t。
TColorDesired 代表程式設計師打算在螢幕上顯示的顏色,以任何支援的顏色類型進行編碼。
TColorDesired 可以通過以下方式初始化:
作為 BIOS 顏色:使用字元文字或 TColorBIOS 物件:
作為 RGB 顏色:使用整數文字或 TColorRGB 物件:
作為 XTerm 調色盤索引:使用 TColorXTerm 物件。
作為終端機預設顏色:通過零初始化:
TColorDesired 具有查詢包含顏色的方法,但您通常不需要使用它們。有關更多資訊,請參閱 <tvision/colors.h> 中的結構定義。
瑣事:名稱的靈感來自 Scintilla 的 ColourDesired。
TColorAttr 描述螢幕單元格的顏色屬性。如果您打算更改視圖中的顏色,這很可能是您需要互動的類型。
前景顏色,類型為 TColorDesired。
背景顏色,類型為 TColorDesired。
樣式位元遮罩,包含以下旗標的組合:
這些旗標基於可通過 ANSI 轉義碼選擇的基本顯示屬性。結果可能因終端機模擬器而異。slReverse 可能是其中最不可靠的:首選使用 TColorAttr reverseAttribute(TColorAttr attr) 自由函式,而不是設定此旗標。
創建 TColorAttr 最直接的方法是通過 TColorAttr(TColorDesired fg, TColorDesired bg, ushort style=0) 和 TColorAttr(int bios) 建構子:
可以使用以下自由函式存取 TColorAttr 的欄位:
TAttrPair 是 TColorAttr 的配對,由某些 API 函式用於一次傳遞兩個屬性。
您可以使用 TAttrPair(const TColorAttrs &lo, const TColorAttrs &hi) 建構子初始化 TAttrPair:
可以使用 [0] 和 [1] 索引存取屬性:
視圖通常通過 TDrawBuffer 繪製。大多數 TDrawBuffer 成員函式接受顏色屬性作為參數。例如:
然而,Turbo Vision 提供的視圖通常將其顏色資訊儲存在調色盤中。可以使用以下成員函式查詢視圖的調色盤:
mapColor 根據索引查找視圖調色盤中的單個顏色屬性。請記住,每個視圖類別的調色盤索引可以在 Turbo Vision 標頭檔中找到。例如,<tvision/views.h> 關於 TScrollBar 說明如下:
getColor 是一個輔助函式,允許一次查詢兩個單元格屬性。indices 中的每個位元組包含一個調色盤索引。TAttrPair 結果包含兩個單元格屬性。
例如,以下內容可以在 TMenuBar 的 draw 方法中找到:
作為 API 擴展,mapColor 方法已設為虛擬。這使得可以覆寫 Turbo Vision 的層次調色盤系統,採用自訂解決方案,而無需重寫 draw() 方法。
因此,總的來說,有三種方法可以在視圖中使用擴展顏色:
通過將擴展顏色屬性直接提供給 TDrawBuffer 方法,如果未使用調色盤系統。例如:
通過修改調色盤。有兩種方法可以做到這一點:
TScreen::screenMode 暴露了有關顯示器顏色支援的一些資訊:
先前定義的類型代表了對於 Borland C++ 開發也很重要的概念:
此專案的關鍵原則之一是,API 在 Borland C++ 和現代平台上的使用方式應相同,即無需 #ifdef。另一個原則是,舊程式碼應該開箱即用,並且適應新功能應盡可能少地增加複雜性。
向後相容性通過以下方式實現:
在 Borland C++ 中,TColorAttr 和 TAttrPair 被 typedef 為 uchar 和 ushort,分別。
在現代平台上,TColorAttr 和 TAttrPair 可以分別替換 uchar 和 ushort,因為它們能夠容納任何適合它們的值,並且可以隱式轉換為/從它們轉換。
使用 uchar 初始化並轉換回 uchar 時,會發生以下情況:
對於 TAttrPair 和 ushort 也是如此,考慮到它由兩個 TColorAttr 組成。
Turbo Vision 本身中的一個向後相容性使用案例是 TPalette 類別,它是調色盤系統的核心。在其原始設計中,它使用單一資料類型(uchar)來表示不同的內容:陣列長度、調色盤索引或顏色屬性。
新設計僅將 uchar 替換為 TColorAttr。這意味著 TPalette 的使用方式沒有改變,但 TPalette 現在能夠儲存擴展顏色屬性。
TColorDialog 沒有被重新設計,因此它不能用於在運行時選擇擴展顏色屬性。
以下程式碼模式在視圖的 draw 方法中很常見:
在此情況下,ushort 同時用作調色盤索引對和顏色屬性對。getColor 現在返回一個 TAttrPair,因此即使此程式碼開箱即用,擴展屬性也會在隱式轉換為 ushort 時丟失。
上述程式碼仍然像原來一樣工作。只有非 BIOS 顏色屬性無法產生預期的結果。由於 TAttrPair 和 ushort 之間的相容性,以下內容足以啟用擴展顏色屬性的支援:
沒有什麼可以阻止您為調色盤索引和顏色屬性使用不同的變數,這實際上應該這樣做。向後相容性的重點是能夠支援新功能而不改變程式的邏輯,也就是說,最小化增加程式碼複雜性或引入錯誤的風險。
Turbo Vision 2.0 的現代化移植版,經典的文字使用者介面框架。現已支援跨平台與 Unicode。